1 /* 2 * Copyright (C) 2006-2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #undef LOG_TAG 18 #define LOG_TAG "Database" 19 20 #include <utils/Log.h> 21 #include <utils/String8.h> 22 #include <utils/String16.h> 23 24 #include <jni.h> 25 #include <JNIHelp.h> 26 #include <android_runtime/AndroidRuntime.h> 27 28 #include <sqlite3.h> 29 #include <sqlite3_android.h> 30 #include <string.h> 31 #include <utils/Log.h> 32 #include <utils/threads.h> 33 #include <utils/List.h> 34 #include <utils/Errors.h> 35 #include <ctype.h> 36 37 #include <stdio.h> 38 #include <sys/types.h> 39 #include <sys/socket.h> 40 #include <netinet/in.h> 41 #include <string.h> 42 #include <netdb.h> 43 #include <sys/ioctl.h> 44 45 #include "sqlite3_exception.h" 46 47 #define UTF16_STORAGE 0 48 #define INVALID_VERSION -1 49 #define SQLITE_SOFT_HEAP_LIMIT (4 * 1024 * 1024) 50 #define ANDROID_TABLE "android_metadata" 51 /* uncomment the next line to force-enable logging of all statements */ 52 // #define DB_LOG_STATEMENTS 53 54 namespace android { 55 56 enum { 57 OPEN_READWRITE = 0x00000000, 58 OPEN_READONLY = 0x00000001, 59 OPEN_READ_MASK = 0x00000001, 60 NO_LOCALIZED_COLLATORS = 0x00000010, 61 CREATE_IF_NECESSARY = 0x10000000 62 }; 63 64 static jfieldID offset_db_handle; 65 66 static char *createStr(const char *path) { 67 int len = strlen(path); 68 char *str = (char *)malloc(len + 1); 69 strncpy(str, path, len); 70 str[len] = NULL; 71 return str; 72 } 73 74 static void sqlLogger(void *databaseName, int iErrCode, const char *zMsg) { 75 // skip printing this message if it is due to certain types of errors 76 if (iErrCode == SQLITE_CONSTRAINT) return; 77 LOGI("sqlite returned: error code = %d, msg = %s\n", iErrCode, zMsg); 78 } 79 80 // register the logging func on sqlite. needs to be done BEFORE any sqlite3 func is called. 81 static void registerLoggingFunc(const char *path) { 82 static bool loggingFuncSet = false; 83 if (loggingFuncSet) { 84 return; 85 } 86 87 LOGV("Registering sqlite logging func \n"); 88 int err = sqlite3_config(SQLITE_CONFIG_LOG, &sqlLogger, (void *)createStr(path)); 89 if (err != SQLITE_OK) { 90 LOGE("sqlite_config failed error_code = %d. THIS SHOULD NEVER occur.\n", err); 91 return; 92 } 93 loggingFuncSet = true; 94 } 95 96 /* public native void dbopen(String path, int flags, String locale); */ 97 static void dbopen(JNIEnv* env, jobject object, jstring pathString, jint flags) 98 { 99 int err; 100 sqlite3 * handle = NULL; 101 sqlite3_stmt * statement = NULL; 102 char const * path8 = env->GetStringUTFChars(pathString, NULL); 103 int sqliteFlags; 104 105 // register the logging func on sqlite. needs to be done BEFORE any sqlite3 func is called. 106 registerLoggingFunc(path8); 107 108 // convert our flags into the sqlite flags 109 if (flags & CREATE_IF_NECESSARY) { 110 sqliteFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; 111 } else if (flags & OPEN_READONLY) { 112 sqliteFlags = SQLITE_OPEN_READONLY; 113 } else { 114 sqliteFlags = SQLITE_OPEN_READWRITE; 115 } 116 117 err = sqlite3_open_v2(path8, &handle, sqliteFlags, NULL); 118 if (err != SQLITE_OK) { 119 LOGE("sqlite3_open_v2(\"%s\", &handle, %d, NULL) failed\n", path8, sqliteFlags); 120 throw_sqlite3_exception(env, handle); 121 goto done; 122 } 123 124 // The soft heap limit prevents the page cache allocations from growing 125 // beyond the given limit, no matter what the max page cache sizes are 126 // set to. The limit does not, as of 3.5.0, affect any other allocations. 127 sqlite3_soft_heap_limit(SQLITE_SOFT_HEAP_LIMIT); 128 129 // Set the default busy handler to retry for 1000ms and then return SQLITE_BUSY 130 err = sqlite3_busy_timeout(handle, 1000 /* ms */); 131 if (err != SQLITE_OK) { 132 LOGE("sqlite3_busy_timeout(handle, 1000) failed for \"%s\"\n", path8); 133 throw_sqlite3_exception(env, handle); 134 goto done; 135 } 136 137 #ifdef DB_INTEGRITY_CHECK 138 static const char* integritySql = "pragma integrity_check(1);"; 139 err = sqlite3_prepare_v2(handle, integritySql, -1, &statement, NULL); 140 if (err != SQLITE_OK) { 141 LOGE("sqlite_prepare_v2(handle, \"%s\") failed for \"%s\"\n", integritySql, path8); 142 throw_sqlite3_exception(env, handle); 143 goto done; 144 } 145 146 // first is OK or error message 147 err = sqlite3_step(statement); 148 if (err != SQLITE_ROW) { 149 LOGE("integrity check failed for \"%s\"\n", integritySql, path8); 150 throw_sqlite3_exception(env, handle); 151 goto done; 152 } else { 153 const char *text = (const char*)sqlite3_column_text(statement, 0); 154 if (strcmp(text, "ok") != 0) { 155 LOGE("integrity check failed for \"%s\": %s\n", integritySql, path8, text); 156 jniThrowException(env, "android/database/sqlite/SQLiteDatabaseCorruptException", text); 157 goto done; 158 } 159 } 160 #endif 161 162 err = register_android_functions(handle, UTF16_STORAGE); 163 if (err) { 164 throw_sqlite3_exception(env, handle); 165 goto done; 166 } 167 168 LOGV("Opened '%s' - %p\n", path8, handle); 169 env->SetIntField(object, offset_db_handle, (int) handle); 170 handle = NULL; // The caller owns the handle now. 171 172 done: 173 // Release allocated resources 174 if (path8 != NULL) env->ReleaseStringUTFChars(pathString, path8); 175 if (statement != NULL) sqlite3_finalize(statement); 176 if (handle != NULL) sqlite3_close(handle); 177 } 178 179 static char *getDatabaseName(JNIEnv* env, sqlite3 * handle, jstring databaseName) { 180 char const *path = env->GetStringUTFChars(databaseName, NULL); 181 if (path == NULL) { 182 LOGE("Failure in getDatabaseName(). VM ran out of memory?\n"); 183 return NULL; // VM would have thrown OutOfMemoryError 184 } 185 char *dbNameStr = createStr(path); 186 env->ReleaseStringUTFChars(databaseName, path); 187 return dbNameStr; 188 } 189 190 static void sqlTrace(void *databaseName, const char *sql) { 191 LOGI("sql_statement|%s|%s\n", (char *)databaseName, sql); 192 } 193 194 /* public native void enableSqlTracing(); */ 195 static void enableSqlTracing(JNIEnv* env, jobject object, jstring databaseName) 196 { 197 sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle); 198 sqlite3_trace(handle, &sqlTrace, (void *)getDatabaseName(env, handle, databaseName)); 199 } 200 201 static void sqlProfile(void *databaseName, const char *sql, sqlite3_uint64 tm) { 202 double d = tm/1000000.0; 203 LOGI("elapsedTime4Sql|%s|%.3f ms|%s\n", (char *)databaseName, d, sql); 204 } 205 206 /* public native void enableSqlProfiling(); */ 207 static void enableSqlProfiling(JNIEnv* env, jobject object, jstring databaseName) 208 { 209 sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle); 210 sqlite3_profile(handle, &sqlProfile, (void *)getDatabaseName(env, handle, databaseName)); 211 } 212 213 214 /* public native void close(); */ 215 static void dbclose(JNIEnv* env, jobject object) 216 { 217 sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle); 218 219 if (handle != NULL) { 220 // release the memory associated with the traceFuncArg in enableSqlTracing function 221 void *traceFuncArg = sqlite3_trace(handle, &sqlTrace, NULL); 222 if (traceFuncArg != NULL) { 223 free(traceFuncArg); 224 } 225 // release the memory associated with the traceFuncArg in enableSqlProfiling function 226 traceFuncArg = sqlite3_profile(handle, &sqlProfile, NULL); 227 if (traceFuncArg != NULL) { 228 free(traceFuncArg); 229 } 230 LOGV("Closing database: handle=%p\n", handle); 231 int result = sqlite3_close(handle); 232 if (result == SQLITE_OK) { 233 LOGV("Closed %p\n", handle); 234 env->SetIntField(object, offset_db_handle, 0); 235 } else { 236 // This can happen if sub-objects aren't closed first. Make sure the caller knows. 237 throw_sqlite3_exception(env, handle); 238 LOGE("sqlite3_close(%p) failed: %d\n", handle, result); 239 } 240 } 241 } 242 243 /* public native void native_execSQL(String sql); */ 244 static void native_execSQL(JNIEnv* env, jobject object, jstring sqlString) 245 { 246 int err; 247 int stepErr; 248 sqlite3_stmt * statement = NULL; 249 sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle); 250 jchar const * sql = env->GetStringChars(sqlString, NULL); 251 jsize sqlLen = env->GetStringLength(sqlString); 252 253 if (sql == NULL || sqlLen == 0) { 254 jniThrowException(env, "java/lang/IllegalArgumentException", "You must supply an SQL string"); 255 return; 256 } 257 258 err = sqlite3_prepare16_v2(handle, sql, sqlLen * 2, &statement, NULL); 259 260 env->ReleaseStringChars(sqlString, sql); 261 262 if (err != SQLITE_OK) { 263 char const * sql8 = env->GetStringUTFChars(sqlString, NULL); 264 LOGE("Failure %d (%s) on %p when preparing '%s'.\n", err, sqlite3_errmsg(handle), handle, sql8); 265 throw_sqlite3_exception(env, handle, sql8); 266 env->ReleaseStringUTFChars(sqlString, sql8); 267 return; 268 } 269 270 stepErr = sqlite3_step(statement); 271 err = sqlite3_finalize(statement); 272 273 if (stepErr != SQLITE_DONE) { 274 if (stepErr == SQLITE_ROW) { 275 throw_sqlite3_exception(env, "Queries cannot be performed using execSQL(), use query() instead."); 276 } else { 277 char const * sql8 = env->GetStringUTFChars(sqlString, NULL); 278 LOGE("Failure %d (%s) on %p when executing '%s'\n", err, sqlite3_errmsg(handle), handle, sql8); 279 throw_sqlite3_exception(env, handle, sql8); 280 env->ReleaseStringUTFChars(sqlString, sql8); 281 282 } 283 } else 284 #ifndef DB_LOG_STATEMENTS 285 IF_LOGV() 286 #endif 287 { 288 char const * sql8 = env->GetStringUTFChars(sqlString, NULL); 289 LOGV("Success on %p when executing '%s'\n", handle, sql8); 290 env->ReleaseStringUTFChars(sqlString, sql8); 291 } 292 } 293 294 /* native long lastInsertRow(); */ 295 static jlong lastInsertRow(JNIEnv* env, jobject object) 296 { 297 sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle); 298 299 return sqlite3_last_insert_rowid(handle); 300 } 301 302 /* native int lastChangeCount(); */ 303 static jint lastChangeCount(JNIEnv* env, jobject object) 304 { 305 sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle); 306 307 return sqlite3_changes(handle); 308 } 309 310 /* native int native_getDbLookaside(); */ 311 static jint native_getDbLookaside(JNIEnv* env, jobject object) 312 { 313 sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle); 314 int pCur = -1; 315 int unused; 316 sqlite3_db_status(handle, SQLITE_DBSTATUS_LOOKASIDE_USED, &pCur, &unused, 0); 317 return pCur; 318 } 319 320 /* set locale in the android_metadata table, install localized collators, and rebuild indexes */ 321 static void native_setLocale(JNIEnv* env, jobject object, jstring localeString, jint flags) 322 { 323 if ((flags & NO_LOCALIZED_COLLATORS)) return; 324 325 int err; 326 char const* locale8 = env->GetStringUTFChars(localeString, NULL); 327 sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle); 328 sqlite3_stmt* stmt = NULL; 329 char** meta = NULL; 330 int rowCount, colCount; 331 char* dbLocale = NULL; 332 333 // create the table, if necessary and possible 334 if (!(flags & OPEN_READONLY)) { 335 static const char *createSql ="CREATE TABLE IF NOT EXISTS " ANDROID_TABLE " (locale TEXT)"; 336 err = sqlite3_exec(handle, createSql, NULL, NULL, NULL); 337 if (err != SQLITE_OK) { 338 LOGE("CREATE TABLE " ANDROID_TABLE " failed\n"); 339 throw_sqlite3_exception(env, handle); 340 goto done; 341 } 342 } 343 344 // try to read from the table 345 static const char *selectSql = "SELECT locale FROM " ANDROID_TABLE " LIMIT 1"; 346 err = sqlite3_get_table(handle, selectSql, &meta, &rowCount, &colCount, NULL); 347 if (err != SQLITE_OK) { 348 LOGE("SELECT locale FROM " ANDROID_TABLE " failed\n"); 349 throw_sqlite3_exception(env, handle); 350 goto done; 351 } 352 353 dbLocale = (rowCount >= 1) ? meta[colCount] : NULL; 354 355 if (dbLocale != NULL && !strcmp(dbLocale, locale8)) { 356 // database locale is the same as the desired locale; set up the collators and go 357 err = register_localized_collators(handle, locale8, UTF16_STORAGE); 358 if (err != SQLITE_OK) throw_sqlite3_exception(env, handle); 359 goto done; // no database changes needed 360 } 361 362 if ((flags & OPEN_READONLY)) { 363 // read-only database, so we're going to have to put up with whatever we got 364 // For registering new index. Not for modifing the read-only database. 365 err = register_localized_collators(handle, locale8, UTF16_STORAGE); 366 if (err != SQLITE_OK) throw_sqlite3_exception(env, handle); 367 goto done; 368 } 369 370 // need to update android_metadata and indexes atomically, so use a transaction... 371 err = sqlite3_exec(handle, "BEGIN TRANSACTION", NULL, NULL, NULL); 372 if (err != SQLITE_OK) { 373 LOGE("BEGIN TRANSACTION failed setting locale\n"); 374 throw_sqlite3_exception(env, handle); 375 goto done; 376 } 377 378 err = register_localized_collators(handle, locale8, UTF16_STORAGE); 379 if (err != SQLITE_OK) { 380 LOGE("register_localized_collators() failed setting locale\n"); 381 throw_sqlite3_exception(env, handle); 382 goto rollback; 383 } 384 385 err = sqlite3_exec(handle, "DELETE FROM " ANDROID_TABLE, NULL, NULL, NULL); 386 if (err != SQLITE_OK) { 387 LOGE("DELETE failed setting locale\n"); 388 throw_sqlite3_exception(env, handle); 389 goto rollback; 390 } 391 392 static const char *sql = "INSERT INTO " ANDROID_TABLE " (locale) VALUES(?);"; 393 err = sqlite3_prepare_v2(handle, sql, -1, &stmt, NULL); 394 if (err != SQLITE_OK) { 395 LOGE("sqlite3_prepare_v2(\"%s\") failed\n", sql); 396 throw_sqlite3_exception(env, handle); 397 goto rollback; 398 } 399 400 err = sqlite3_bind_text(stmt, 1, locale8, -1, SQLITE_TRANSIENT); 401 if (err != SQLITE_OK) { 402 LOGE("sqlite3_bind_text() failed setting locale\n"); 403 throw_sqlite3_exception(env, handle); 404 goto rollback; 405 } 406 407 err = sqlite3_step(stmt); 408 if (err != SQLITE_OK && err != SQLITE_DONE) { 409 LOGE("sqlite3_step(\"%s\") failed setting locale\n", sql); 410 throw_sqlite3_exception(env, handle); 411 goto rollback; 412 } 413 414 err = sqlite3_exec(handle, "REINDEX LOCALIZED", NULL, NULL, NULL); 415 if (err != SQLITE_OK) { 416 LOGE("REINDEX LOCALIZED failed\n"); 417 throw_sqlite3_exception(env, handle); 418 goto rollback; 419 } 420 421 // all done, yay! 422 err = sqlite3_exec(handle, "COMMIT TRANSACTION", NULL, NULL, NULL); 423 if (err != SQLITE_OK) { 424 LOGE("COMMIT TRANSACTION failed setting locale\n"); 425 throw_sqlite3_exception(env, handle); 426 goto done; 427 } 428 429 rollback: 430 if (err != SQLITE_OK) { 431 sqlite3_exec(handle, "ROLLBACK TRANSACTION", NULL, NULL, NULL); 432 } 433 434 done: 435 if (locale8 != NULL) env->ReleaseStringUTFChars(localeString, locale8); 436 if (stmt != NULL) sqlite3_finalize(stmt); 437 if (meta != NULL) sqlite3_free_table(meta); 438 } 439 440 static jint native_releaseMemory(JNIEnv *env, jobject clazz) 441 { 442 // Attempt to release as much memory from the 443 return sqlite3_release_memory(SQLITE_SOFT_HEAP_LIMIT); 444 } 445 446 static JNINativeMethod sMethods[] = 447 { 448 /* name, signature, funcPtr */ 449 {"dbopen", "(Ljava/lang/String;I)V", (void *)dbopen}, 450 {"dbclose", "()V", (void *)dbclose}, 451 {"enableSqlTracing", "(Ljava/lang/String;)V", (void *)enableSqlTracing}, 452 {"enableSqlProfiling", "(Ljava/lang/String;)V", (void *)enableSqlProfiling}, 453 {"native_execSQL", "(Ljava/lang/String;)V", (void *)native_execSQL}, 454 {"lastInsertRow", "()J", (void *)lastInsertRow}, 455 {"lastChangeCount", "()I", (void *)lastChangeCount}, 456 {"native_setLocale", "(Ljava/lang/String;I)V", (void *)native_setLocale}, 457 {"native_getDbLookaside", "()I", (void *)native_getDbLookaside}, 458 {"releaseMemory", "()I", (void *)native_releaseMemory}, 459 }; 460 461 int register_android_database_SQLiteDatabase(JNIEnv *env) 462 { 463 jclass clazz; 464 465 clazz = env->FindClass("android/database/sqlite/SQLiteDatabase"); 466 if (clazz == NULL) { 467 LOGE("Can't find android/database/sqlite/SQLiteDatabase\n"); 468 return -1; 469 } 470 471 offset_db_handle = env->GetFieldID(clazz, "mNativeHandle", "I"); 472 if (offset_db_handle == NULL) { 473 LOGE("Can't find SQLiteDatabase.mNativeHandle\n"); 474 return -1; 475 } 476 477 return AndroidRuntime::registerNativeMethods(env, "android/database/sqlite/SQLiteDatabase", sMethods, NELEM(sMethods)); 478 } 479 480 /* throw a SQLiteException with a message appropriate for the error in handle */ 481 void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle) { 482 throw_sqlite3_exception(env, handle, NULL); 483 } 484 485 /* throw a SQLiteException with the given message */ 486 void throw_sqlite3_exception(JNIEnv* env, const char* message) { 487 throw_sqlite3_exception(env, NULL, message); 488 } 489 490 /* throw a SQLiteException with a message appropriate for the error in handle 491 concatenated with the given message 492 */ 493 void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle, const char* message) { 494 if (handle) { 495 throw_sqlite3_exception(env, sqlite3_errcode(handle), 496 sqlite3_errmsg(handle), message); 497 } else { 498 // we use SQLITE_OK so that a generic SQLiteException is thrown; 499 // any code not specified in the switch statement below would do. 500 throw_sqlite3_exception(env, SQLITE_OK, "unknown error", message); 501 } 502 } 503 504 /* throw a SQLiteException for a given error code */ 505 void throw_sqlite3_exception_errcode(JNIEnv* env, int errcode, const char* message) { 506 if (errcode == SQLITE_DONE) { 507 throw_sqlite3_exception(env, errcode, NULL, message); 508 } else { 509 char temp[21]; 510 sprintf(temp, "error code %d", errcode); 511 throw_sqlite3_exception(env, errcode, temp, message); 512 } 513 } 514 515 /* throw a SQLiteException for a given error code, sqlite3message, and 516 user message 517 */ 518 void throw_sqlite3_exception(JNIEnv* env, int errcode, 519 const char* sqlite3Message, const char* message) { 520 const char* exceptionClass; 521 switch (errcode) { 522 case SQLITE_IOERR: 523 exceptionClass = "android/database/sqlite/SQLiteDiskIOException"; 524 break; 525 case SQLITE_CORRUPT: 526 exceptionClass = "android/database/sqlite/SQLiteDatabaseCorruptException"; 527 break; 528 case SQLITE_CONSTRAINT: 529 exceptionClass = "android/database/sqlite/SQLiteConstraintException"; 530 break; 531 case SQLITE_ABORT: 532 exceptionClass = "android/database/sqlite/SQLiteAbortException"; 533 break; 534 case SQLITE_DONE: 535 exceptionClass = "android/database/sqlite/SQLiteDoneException"; 536 break; 537 case SQLITE_FULL: 538 exceptionClass = "android/database/sqlite/SQLiteFullException"; 539 break; 540 case SQLITE_MISUSE: 541 exceptionClass = "android/database/sqlite/SQLiteMisuseException"; 542 break; 543 default: 544 exceptionClass = "android/database/sqlite/SQLiteException"; 545 break; 546 } 547 548 if (sqlite3Message != NULL && message != NULL) { 549 char* fullMessage = (char *)malloc(strlen(sqlite3Message) + strlen(message) + 3); 550 if (fullMessage != NULL) { 551 strcpy(fullMessage, sqlite3Message); 552 strcat(fullMessage, ": "); 553 strcat(fullMessage, message); 554 jniThrowException(env, exceptionClass, fullMessage); 555 free(fullMessage); 556 } else { 557 jniThrowException(env, exceptionClass, sqlite3Message); 558 } 559 } else if (sqlite3Message != NULL) { 560 jniThrowException(env, exceptionClass, sqlite3Message); 561 } else { 562 jniThrowException(env, exceptionClass, message); 563 } 564 } 565 566 567 } // namespace android 568