android_database_SQLiteConnection.cpp revision 330ec91e02406ba0d62e5672c6f0e2ed271f6898
1/* 2 * Copyright (C) 2011 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#define LOG_TAG "SQLiteConnection" 18 19#include <jni.h> 20#include <JNIHelp.h> 21#include <android_runtime/AndroidRuntime.h> 22 23#include <utils/Log.h> 24#include <utils/String8.h> 25#include <utils/String16.h> 26#include <cutils/ashmem.h> 27#include <sys/mman.h> 28 29#include <string.h> 30#include <unistd.h> 31 32#include <androidfw/CursorWindow.h> 33 34#include <sqlite3.h> 35#include <sqlite3_android.h> 36 37#include "android_database_SQLiteCommon.h" 38 39// Set to 1 to use UTF16 storage for localized indexes. 40#define UTF16_STORAGE 0 41 42namespace android { 43 44static struct { 45 jfieldID name; 46 jfieldID numArgs; 47 jmethodID dispatchCallback; 48} gSQLiteCustomFunctionClassInfo; 49 50static struct { 51 jclass clazz; 52} gStringClassInfo; 53 54struct SQLiteConnection { 55 // Open flags. 56 // Must be kept in sync with the constants defined in SQLiteDatabase.java. 57 enum { 58 OPEN_READWRITE = 0x00000000, 59 OPEN_READONLY = 0x00000001, 60 OPEN_READ_MASK = 0x00000001, 61 NO_LOCALIZED_COLLATORS = 0x00000010, 62 CREATE_IF_NECESSARY = 0x10000000, 63 }; 64 65 sqlite3* const db; 66 const int openFlags; 67 const String8 path; 68 const String8 label; 69 70 volatile bool canceled; 71 72 SQLiteConnection(sqlite3* db, int openFlags, const String8& path, const String8& label) : 73 db(db), openFlags(openFlags), path(path), label(label), canceled(false) { } 74}; 75 76// Called each time a statement begins execution, when tracing is enabled. 77static void sqliteTraceCallback(void *data, const char *sql) { 78 SQLiteConnection* connection = static_cast<SQLiteConnection*>(data); 79 ALOG(LOG_VERBOSE, SQLITE_TRACE_TAG, "%s: \"%s\"\n", 80 connection->label.string(), sql); 81} 82 83// Called each time a statement finishes execution, when profiling is enabled. 84static void sqliteProfileCallback(void *data, const char *sql, sqlite3_uint64 tm) { 85 SQLiteConnection* connection = static_cast<SQLiteConnection*>(data); 86 ALOG(LOG_VERBOSE, SQLITE_PROFILE_TAG, "%s: \"%s\" took %0.3f ms\n", 87 connection->label.string(), sql, tm * 0.000001f); 88} 89 90// Called after each SQLite VM instruction when cancelation is enabled. 91static int sqliteProgressHandlerCallback(void* data) { 92 SQLiteConnection* connection = static_cast<SQLiteConnection*>(data); 93 return connection->canceled; 94} 95 96 97static jint nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFlags, 98 jstring labelStr, jboolean enableTrace, jboolean enableProfile) { 99 int sqliteFlags; 100 if (openFlags & SQLiteConnection::CREATE_IF_NECESSARY) { 101 sqliteFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; 102 } else if (openFlags & SQLiteConnection::OPEN_READONLY) { 103 sqliteFlags = SQLITE_OPEN_READONLY; 104 } else { 105 sqliteFlags = SQLITE_OPEN_READWRITE; 106 } 107 108 const char* pathChars = env->GetStringUTFChars(pathStr, NULL); 109 String8 path(pathChars); 110 env->ReleaseStringUTFChars(pathStr, pathChars); 111 112 const char* labelChars = env->GetStringUTFChars(labelStr, NULL); 113 String8 label(labelChars); 114 env->ReleaseStringUTFChars(labelStr, labelChars); 115 116 sqlite3* db; 117 int err = sqlite3_open_v2(path.string(), &db, sqliteFlags, NULL); 118 if (err != SQLITE_OK) { 119 throw_sqlite3_exception_errcode(env, err, "Could not open database"); 120 return 0; 121 } 122 123 // Check that the database is really read/write when that is what we asked for. 124 if ((sqliteFlags & SQLITE_OPEN_READWRITE) && sqlite3_db_readonly(db, NULL)) { 125 throw_sqlite3_exception(env, db, "Could not open the database in read/write mode."); 126 sqlite3_close(db); 127 return 0; 128 } 129 130 // Set the default busy handler to retry for 1000ms and then return SQLITE_BUSY 131 err = sqlite3_busy_timeout(db, 1000 /* ms */); 132 if (err != SQLITE_OK) { 133 throw_sqlite3_exception(env, db, "Could not set busy timeout"); 134 sqlite3_close(db); 135 return 0; 136 } 137 138 // Register custom Android functions. 139 err = register_android_functions(db, UTF16_STORAGE); 140 if (err) { 141 throw_sqlite3_exception(env, db, "Could not register Android SQL functions."); 142 sqlite3_close(db); 143 return 0; 144 } 145 146 // Create wrapper object. 147 SQLiteConnection* connection = new SQLiteConnection(db, openFlags, path, label); 148 149 // Enable tracing and profiling if requested. 150 if (enableTrace) { 151 sqlite3_trace(db, &sqliteTraceCallback, connection); 152 } 153 if (enableProfile) { 154 sqlite3_profile(db, &sqliteProfileCallback, connection); 155 } 156 157 ALOGV("Opened connection %p with label '%s'", db, label.string()); 158 return reinterpret_cast<jint>(connection); 159} 160 161static void nativeClose(JNIEnv* env, jclass clazz, jint connectionPtr) { 162 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 163 164 if (connection) { 165 ALOGV("Closing connection %p", connection->db); 166 int err = sqlite3_close(connection->db); 167 if (err != SQLITE_OK) { 168 // This can happen if sub-objects aren't closed first. Make sure the caller knows. 169 ALOGE("sqlite3_close(%p) failed: %d", connection->db, err); 170 throw_sqlite3_exception(env, connection->db, "Count not close db."); 171 return; 172 } 173 174 delete connection; 175 } 176} 177 178// Called each time a custom function is evaluated. 179static void sqliteCustomFunctionCallback(sqlite3_context *context, 180 int argc, sqlite3_value **argv) { 181 JNIEnv* env = AndroidRuntime::getJNIEnv(); 182 183 // Get the callback function object. 184 // Create a new local reference to it in case the callback tries to do something 185 // dumb like unregister the function (thereby destroying the global ref) while it is running. 186 jobject functionObjGlobal = reinterpret_cast<jobject>(sqlite3_user_data(context)); 187 jobject functionObj = env->NewLocalRef(functionObjGlobal); 188 189 jobjectArray argsArray = env->NewObjectArray(argc, gStringClassInfo.clazz, NULL); 190 if (argsArray) { 191 for (int i = 0; i < argc; i++) { 192 const jchar* arg = static_cast<const jchar*>(sqlite3_value_text16(argv[i])); 193 if (!arg) { 194 ALOGW("NULL argument in custom_function_callback. This should not happen."); 195 } else { 196 size_t argLen = sqlite3_value_bytes16(argv[i]) / sizeof(jchar); 197 jstring argStr = env->NewString(arg, argLen); 198 if (!argStr) { 199 goto error; // out of memory error 200 } 201 env->SetObjectArrayElement(argsArray, i, argStr); 202 env->DeleteLocalRef(argStr); 203 } 204 } 205 206 // TODO: Support functions that return values. 207 env->CallVoidMethod(functionObj, 208 gSQLiteCustomFunctionClassInfo.dispatchCallback, argsArray); 209 210error: 211 env->DeleteLocalRef(argsArray); 212 } 213 214 env->DeleteLocalRef(functionObj); 215 216 if (env->ExceptionCheck()) { 217 ALOGE("An exception was thrown by custom SQLite function."); 218 LOGE_EX(env); 219 env->ExceptionClear(); 220 } 221} 222 223// Called when a custom function is destroyed. 224static void sqliteCustomFunctionDestructor(void* data) { 225 jobject functionObjGlobal = reinterpret_cast<jobject>(data); 226 227 JNIEnv* env = AndroidRuntime::getJNIEnv(); 228 env->DeleteGlobalRef(functionObjGlobal); 229} 230 231static void nativeRegisterCustomFunction(JNIEnv* env, jclass clazz, jint connectionPtr, 232 jobject functionObj) { 233 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 234 235 jstring nameStr = jstring(env->GetObjectField( 236 functionObj, gSQLiteCustomFunctionClassInfo.name)); 237 jint numArgs = env->GetIntField(functionObj, gSQLiteCustomFunctionClassInfo.numArgs); 238 239 jobject functionObjGlobal = env->NewGlobalRef(functionObj); 240 241 const char* name = env->GetStringUTFChars(nameStr, NULL); 242 int err = sqlite3_create_function_v2(connection->db, name, numArgs, SQLITE_UTF16, 243 reinterpret_cast<void*>(functionObjGlobal), 244 &sqliteCustomFunctionCallback, NULL, NULL, &sqliteCustomFunctionDestructor); 245 env->ReleaseStringUTFChars(nameStr, name); 246 247 if (err != SQLITE_OK) { 248 ALOGE("sqlite3_create_function returned %d", err); 249 env->DeleteGlobalRef(functionObjGlobal); 250 throw_sqlite3_exception(env, connection->db); 251 return; 252 } 253} 254 255static void nativeRegisterLocalizedCollators(JNIEnv* env, jclass clazz, jint connectionPtr, 256 jstring localeStr) { 257 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 258 259 const char* locale = env->GetStringUTFChars(localeStr, NULL); 260 int err = register_localized_collators(connection->db, locale, UTF16_STORAGE); 261 env->ReleaseStringUTFChars(localeStr, locale); 262 263 if (err != SQLITE_OK) { 264 throw_sqlite3_exception(env, connection->db); 265 } 266} 267 268static jint nativePrepareStatement(JNIEnv* env, jclass clazz, jint connectionPtr, 269 jstring sqlString) { 270 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 271 272 jsize sqlLength = env->GetStringLength(sqlString); 273 const jchar* sql = env->GetStringCritical(sqlString, NULL); 274 sqlite3_stmt* statement; 275 int err = sqlite3_prepare16_v2(connection->db, 276 sql, sqlLength * sizeof(jchar), &statement, NULL); 277 env->ReleaseStringCritical(sqlString, sql); 278 279 if (err != SQLITE_OK) { 280 // Error messages like 'near ")": syntax error' are not 281 // always helpful enough, so construct an error string that 282 // includes the query itself. 283 const char *query = env->GetStringUTFChars(sqlString, NULL); 284 char *message = (char*) malloc(strlen(query) + 50); 285 if (message) { 286 strcpy(message, ", while compiling: "); // less than 50 chars 287 strcat(message, query); 288 } 289 env->ReleaseStringUTFChars(sqlString, query); 290 throw_sqlite3_exception(env, connection->db, message); 291 free(message); 292 return 0; 293 } 294 295 ALOGV("Prepared statement %p on connection %p", statement, connection->db); 296 return reinterpret_cast<jint>(statement); 297} 298 299static void nativeFinalizeStatement(JNIEnv* env, jclass clazz, jint connectionPtr, 300 jint statementPtr) { 301 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 302 sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr); 303 304 // We ignore the result of sqlite3_finalize because it is really telling us about 305 // whether any errors occurred while executing the statement. The statement itself 306 // is always finalized regardless. 307 ALOGV("Finalized statement %p on connection %p", statement, connection->db); 308 sqlite3_finalize(statement); 309} 310 311static jint nativeGetParameterCount(JNIEnv* env, jclass clazz, jint connectionPtr, 312 jint statementPtr) { 313 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 314 sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr); 315 316 return sqlite3_bind_parameter_count(statement); 317} 318 319static jboolean nativeIsReadOnly(JNIEnv* env, jclass clazz, jint connectionPtr, 320 jint statementPtr) { 321 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 322 sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr); 323 324 return sqlite3_stmt_readonly(statement) != 0; 325} 326 327static jint nativeGetColumnCount(JNIEnv* env, jclass clazz, jint connectionPtr, 328 jint statementPtr) { 329 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 330 sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr); 331 332 return sqlite3_column_count(statement); 333} 334 335static jstring nativeGetColumnName(JNIEnv* env, jclass clazz, jint connectionPtr, 336 jint statementPtr, jint index) { 337 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 338 sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr); 339 340 const jchar* name = static_cast<const jchar*>(sqlite3_column_name16(statement, index)); 341 if (name) { 342 size_t length = 0; 343 while (name[length]) { 344 length += 1; 345 } 346 return env->NewString(name, length); 347 } 348 return NULL; 349} 350 351static void nativeBindNull(JNIEnv* env, jclass clazz, jint connectionPtr, 352 jint statementPtr, jint index) { 353 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 354 sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr); 355 356 int err = sqlite3_bind_null(statement, index); 357 if (err != SQLITE_OK) { 358 throw_sqlite3_exception(env, connection->db, NULL); 359 } 360} 361 362static void nativeBindLong(JNIEnv* env, jclass clazz, jint connectionPtr, 363 jint statementPtr, jint index, jlong value) { 364 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 365 sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr); 366 367 int err = sqlite3_bind_int64(statement, index, value); 368 if (err != SQLITE_OK) { 369 throw_sqlite3_exception(env, connection->db, NULL); 370 } 371} 372 373static void nativeBindDouble(JNIEnv* env, jclass clazz, jint connectionPtr, 374 jint statementPtr, jint index, jdouble value) { 375 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 376 sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr); 377 378 int err = sqlite3_bind_double(statement, index, value); 379 if (err != SQLITE_OK) { 380 throw_sqlite3_exception(env, connection->db, NULL); 381 } 382} 383 384static void nativeBindString(JNIEnv* env, jclass clazz, jint connectionPtr, 385 jint statementPtr, jint index, jstring valueString) { 386 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 387 sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr); 388 389 jsize valueLength = env->GetStringLength(valueString); 390 const jchar* value = env->GetStringCritical(valueString, NULL); 391 int err = sqlite3_bind_text16(statement, index, value, valueLength * sizeof(jchar), 392 SQLITE_TRANSIENT); 393 env->ReleaseStringCritical(valueString, value); 394 if (err != SQLITE_OK) { 395 throw_sqlite3_exception(env, connection->db, NULL); 396 } 397} 398 399static void nativeBindBlob(JNIEnv* env, jclass clazz, jint connectionPtr, 400 jint statementPtr, jint index, jbyteArray valueArray) { 401 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 402 sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr); 403 404 jsize valueLength = env->GetArrayLength(valueArray); 405 jbyte* value = static_cast<jbyte*>(env->GetPrimitiveArrayCritical(valueArray, NULL)); 406 int err = sqlite3_bind_blob(statement, index, value, valueLength, SQLITE_TRANSIENT); 407 env->ReleasePrimitiveArrayCritical(valueArray, value, JNI_ABORT); 408 if (err != SQLITE_OK) { 409 throw_sqlite3_exception(env, connection->db, NULL); 410 } 411} 412 413static void nativeResetStatementAndClearBindings(JNIEnv* env, jclass clazz, jint connectionPtr, 414 jint statementPtr) { 415 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 416 sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr); 417 418 int err = sqlite3_reset(statement); 419 if (err == SQLITE_OK) { 420 err = sqlite3_clear_bindings(statement); 421 } 422 if (err != SQLITE_OK) { 423 throw_sqlite3_exception(env, connection->db, NULL); 424 } 425} 426 427static int executeNonQuery(JNIEnv* env, SQLiteConnection* connection, sqlite3_stmt* statement) { 428 int err = sqlite3_step(statement); 429 if (err == SQLITE_ROW) { 430 throw_sqlite3_exception(env, 431 "Queries can be performed using SQLiteDatabase query or rawQuery methods only."); 432 } else if (err != SQLITE_DONE) { 433 throw_sqlite3_exception_errcode(env, err, sqlite3_errmsg(connection->db)); 434 } 435 return err; 436} 437 438static void nativeExecute(JNIEnv* env, jclass clazz, jint connectionPtr, 439 jint statementPtr) { 440 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 441 sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr); 442 443 executeNonQuery(env, connection, statement); 444} 445 446static jint nativeExecuteForChangedRowCount(JNIEnv* env, jclass clazz, 447 jint connectionPtr, jint statementPtr) { 448 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 449 sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr); 450 451 int err = executeNonQuery(env, connection, statement); 452 return err == SQLITE_DONE ? sqlite3_changes(connection->db) : -1; 453} 454 455static jlong nativeExecuteForLastInsertedRowId(JNIEnv* env, jclass clazz, 456 jint connectionPtr, jint statementPtr) { 457 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 458 sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr); 459 460 int err = executeNonQuery(env, connection, statement); 461 return err == SQLITE_DONE && sqlite3_changes(connection->db) > 0 462 ? sqlite3_last_insert_rowid(connection->db) : -1; 463} 464 465static int executeOneRowQuery(JNIEnv* env, SQLiteConnection* connection, sqlite3_stmt* statement) { 466 int err = sqlite3_step(statement); 467 if (err != SQLITE_ROW) { 468 throw_sqlite3_exception_errcode(env, err, sqlite3_errmsg(connection->db)); 469 } 470 return err; 471} 472 473static jlong nativeExecuteForLong(JNIEnv* env, jclass clazz, 474 jint connectionPtr, jint statementPtr) { 475 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 476 sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr); 477 478 int err = executeOneRowQuery(env, connection, statement); 479 if (err == SQLITE_ROW && sqlite3_column_count(statement) >= 1) { 480 return sqlite3_column_int64(statement, 0); 481 } 482 return -1; 483} 484 485static jstring nativeExecuteForString(JNIEnv* env, jclass clazz, 486 jint connectionPtr, jint statementPtr) { 487 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 488 sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr); 489 490 int err = executeOneRowQuery(env, connection, statement); 491 if (err == SQLITE_ROW && sqlite3_column_count(statement) >= 1) { 492 const jchar* text = static_cast<const jchar*>(sqlite3_column_text16(statement, 0)); 493 if (text) { 494 size_t length = sqlite3_column_bytes16(statement, 0) / sizeof(jchar); 495 return env->NewString(text, length); 496 } 497 } 498 return NULL; 499} 500 501static int createAshmemRegionWithData(JNIEnv* env, const void* data, size_t length) { 502 int error = 0; 503 int fd = ashmem_create_region(NULL, length); 504 if (fd < 0) { 505 error = errno; 506 ALOGE("ashmem_create_region failed: %s", strerror(error)); 507 } else { 508 if (length > 0) { 509 void* ptr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 510 if (ptr == MAP_FAILED) { 511 error = errno; 512 ALOGE("mmap failed: %s", strerror(error)); 513 } else { 514 memcpy(ptr, data, length); 515 munmap(ptr, length); 516 } 517 } 518 519 if (!error) { 520 if (ashmem_set_prot_region(fd, PROT_READ) < 0) { 521 error = errno; 522 ALOGE("ashmem_set_prot_region failed: %s", strerror(errno)); 523 } else { 524 return fd; 525 } 526 } 527 528 close(fd); 529 } 530 531 jniThrowIOException(env, error); 532 return -1; 533} 534 535static jint nativeExecuteForBlobFileDescriptor(JNIEnv* env, jclass clazz, 536 jint connectionPtr, jint statementPtr) { 537 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 538 sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr); 539 540 int err = executeOneRowQuery(env, connection, statement); 541 if (err == SQLITE_ROW && sqlite3_column_count(statement) >= 1) { 542 const void* blob = sqlite3_column_blob(statement, 0); 543 if (blob) { 544 int length = sqlite3_column_bytes(statement, 0); 545 if (length >= 0) { 546 return createAshmemRegionWithData(env, blob, length); 547 } 548 } 549 } 550 return -1; 551} 552 553enum CopyRowResult { 554 CPR_OK, 555 CPR_FULL, 556 CPR_ERROR, 557}; 558 559static CopyRowResult copyRow(JNIEnv* env, CursorWindow* window, 560 sqlite3_stmt* statement, int numColumns, int startPos, int addedRows) { 561 // Allocate a new field directory for the row. 562 status_t status = window->allocRow(); 563 if (status) { 564 LOG_WINDOW("Failed allocating fieldDir at startPos %d row %d, error=%d", 565 startPos, addedRows, status); 566 return CPR_FULL; 567 } 568 569 // Pack the row into the window. 570 CopyRowResult result = CPR_OK; 571 for (int i = 0; i < numColumns; i++) { 572 int type = sqlite3_column_type(statement, i); 573 if (type == SQLITE_TEXT) { 574 // TEXT data 575 const char* text = reinterpret_cast<const char*>( 576 sqlite3_column_text(statement, i)); 577 // SQLite does not include the NULL terminator in size, but does 578 // ensure all strings are NULL terminated, so increase size by 579 // one to make sure we store the terminator. 580 size_t sizeIncludingNull = sqlite3_column_bytes(statement, i) + 1; 581 status = window->putString(addedRows, i, text, sizeIncludingNull); 582 if (status) { 583 LOG_WINDOW("Failed allocating %u bytes for text at %d,%d, error=%d", 584 sizeIncludingNull, startPos + addedRows, i, status); 585 result = CPR_FULL; 586 break; 587 } 588 LOG_WINDOW("%d,%d is TEXT with %u bytes", 589 startPos + addedRows, i, sizeIncludingNull); 590 } else if (type == SQLITE_INTEGER) { 591 // INTEGER data 592 int64_t value = sqlite3_column_int64(statement, i); 593 status = window->putLong(addedRows, i, value); 594 if (status) { 595 LOG_WINDOW("Failed allocating space for a long in column %d, error=%d", 596 i, status); 597 result = CPR_FULL; 598 break; 599 } 600 LOG_WINDOW("%d,%d is INTEGER 0x%016llx", startPos + addedRows, i, value); 601 } else if (type == SQLITE_FLOAT) { 602 // FLOAT data 603 double value = sqlite3_column_double(statement, i); 604 status = window->putDouble(addedRows, i, value); 605 if (status) { 606 LOG_WINDOW("Failed allocating space for a double in column %d, error=%d", 607 i, status); 608 result = CPR_FULL; 609 break; 610 } 611 LOG_WINDOW("%d,%d is FLOAT %lf", startPos + addedRows, i, value); 612 } else if (type == SQLITE_BLOB) { 613 // BLOB data 614 const void* blob = sqlite3_column_blob(statement, i); 615 size_t size = sqlite3_column_bytes(statement, i); 616 status = window->putBlob(addedRows, i, blob, size); 617 if (status) { 618 LOG_WINDOW("Failed allocating %u bytes for blob at %d,%d, error=%d", 619 size, startPos + addedRows, i, status); 620 result = CPR_FULL; 621 break; 622 } 623 LOG_WINDOW("%d,%d is Blob with %u bytes", 624 startPos + addedRows, i, size); 625 } else if (type == SQLITE_NULL) { 626 // NULL field 627 status = window->putNull(addedRows, i); 628 if (status) { 629 LOG_WINDOW("Failed allocating space for a null in column %d, error=%d", 630 i, status); 631 result = CPR_FULL; 632 break; 633 } 634 635 LOG_WINDOW("%d,%d is NULL", startPos + addedRows, i); 636 } else { 637 // Unknown data 638 ALOGE("Unknown column type when filling database window"); 639 throw_sqlite3_exception(env, "Unknown column type when filling window"); 640 result = CPR_ERROR; 641 break; 642 } 643 } 644 645 // Free the last row if if was not successfully copied. 646 if (result != CPR_OK) { 647 window->freeLastRow(); 648 } 649 return result; 650} 651 652static jlong nativeExecuteForCursorWindow(JNIEnv* env, jclass clazz, 653 jint connectionPtr, jint statementPtr, jint windowPtr, 654 jint startPos, jint requiredPos, jboolean countAllRows) { 655 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 656 sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr); 657 CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); 658 659 status_t status = window->clear(); 660 if (status) { 661 String8 msg; 662 msg.appendFormat("Failed to clear the cursor window, status=%d", status); 663 throw_sqlite3_exception(env, connection->db, msg.string()); 664 return 0; 665 } 666 667 int numColumns = sqlite3_column_count(statement); 668 status = window->setNumColumns(numColumns); 669 if (status) { 670 String8 msg; 671 msg.appendFormat("Failed to set the cursor window column count to %d, status=%d", 672 numColumns, status); 673 throw_sqlite3_exception(env, connection->db, msg.string()); 674 return 0; 675 } 676 677 int retryCount = 0; 678 int totalRows = 0; 679 int addedRows = 0; 680 bool windowFull = false; 681 bool gotException = false; 682 while (!gotException && (!windowFull || countAllRows)) { 683 int err = sqlite3_step(statement); 684 if (err == SQLITE_ROW) { 685 LOG_WINDOW("Stepped statement %p to row %d", statement, totalRows); 686 retryCount = 0; 687 totalRows += 1; 688 689 // Skip the row if the window is full or we haven't reached the start position yet. 690 if (startPos >= totalRows || windowFull) { 691 continue; 692 } 693 694 CopyRowResult cpr = copyRow(env, window, statement, numColumns, startPos, addedRows); 695 if (cpr == CPR_FULL && addedRows && startPos + addedRows < requiredPos) { 696 // We filled the window before we got to the one row that we really wanted. 697 // Clear the window and start filling it again from here. 698 // TODO: Would be nicer if we could progressively replace earlier rows. 699 window->clear(); 700 window->setNumColumns(numColumns); 701 startPos += addedRows; 702 addedRows = 0; 703 cpr = copyRow(env, window, statement, numColumns, startPos, addedRows); 704 } 705 706 if (cpr == CPR_OK) { 707 addedRows += 1; 708 } else if (cpr == CPR_FULL) { 709 windowFull = true; 710 } else { 711 gotException = true; 712 } 713 } else if (err == SQLITE_DONE) { 714 // All rows processed, bail 715 LOG_WINDOW("Processed all rows"); 716 break; 717 } else if (err == SQLITE_LOCKED || err == SQLITE_BUSY) { 718 // The table is locked, retry 719 LOG_WINDOW("Database locked, retrying"); 720 if (retryCount > 50) { 721 ALOGE("Bailing on database busy retry"); 722 throw_sqlite3_exception(env, connection->db, "retrycount exceeded"); 723 gotException = true; 724 } else { 725 // Sleep to give the thread holding the lock a chance to finish 726 usleep(1000); 727 retryCount++; 728 } 729 } else { 730 throw_sqlite3_exception(env, connection->db); 731 gotException = true; 732 } 733 } 734 735 LOG_WINDOW("Resetting statement %p after fetching %d rows and adding %d rows" 736 "to the window in %d bytes", 737 statement, totalRows, addedRows, window->size() - window->freeSpace()); 738 sqlite3_reset(statement); 739 740 // Report the total number of rows on request. 741 if (startPos > totalRows) { 742 ALOGE("startPos %d > actual rows %d", startPos, totalRows); 743 } 744 jlong result = jlong(startPos) << 32 | jlong(totalRows); 745 return result; 746} 747 748static jint nativeGetDbLookaside(JNIEnv* env, jobject clazz, jint connectionPtr) { 749 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 750 751 int cur = -1; 752 int unused; 753 sqlite3_db_status(connection->db, SQLITE_DBSTATUS_LOOKASIDE_USED, &cur, &unused, 0); 754 return cur; 755} 756 757static void nativeCancel(JNIEnv* env, jobject clazz, jint connectionPtr) { 758 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 759 connection->canceled = true; 760} 761 762static void nativeResetCancel(JNIEnv* env, jobject clazz, jint connectionPtr, 763 jboolean cancelable) { 764 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); 765 connection->canceled = false; 766 767 if (cancelable) { 768 sqlite3_progress_handler(connection->db, 4, sqliteProgressHandlerCallback, 769 connection); 770 } else { 771 sqlite3_progress_handler(connection->db, 0, NULL, NULL); 772 } 773} 774 775 776static JNINativeMethod sMethods[] = 777{ 778 /* name, signature, funcPtr */ 779 { "nativeOpen", "(Ljava/lang/String;ILjava/lang/String;ZZ)I", 780 (void*)nativeOpen }, 781 { "nativeClose", "(I)V", 782 (void*)nativeClose }, 783 { "nativeRegisterCustomFunction", "(ILandroid/database/sqlite/SQLiteCustomFunction;)V", 784 (void*)nativeRegisterCustomFunction }, 785 { "nativeRegisterLocalizedCollators", "(ILjava/lang/String;)V", 786 (void*)nativeRegisterLocalizedCollators }, 787 { "nativePrepareStatement", "(ILjava/lang/String;)I", 788 (void*)nativePrepareStatement }, 789 { "nativeFinalizeStatement", "(II)V", 790 (void*)nativeFinalizeStatement }, 791 { "nativeGetParameterCount", "(II)I", 792 (void*)nativeGetParameterCount }, 793 { "nativeIsReadOnly", "(II)Z", 794 (void*)nativeIsReadOnly }, 795 { "nativeGetColumnCount", "(II)I", 796 (void*)nativeGetColumnCount }, 797 { "nativeGetColumnName", "(III)Ljava/lang/String;", 798 (void*)nativeGetColumnName }, 799 { "nativeBindNull", "(III)V", 800 (void*)nativeBindNull }, 801 { "nativeBindLong", "(IIIJ)V", 802 (void*)nativeBindLong }, 803 { "nativeBindDouble", "(IIID)V", 804 (void*)nativeBindDouble }, 805 { "nativeBindString", "(IIILjava/lang/String;)V", 806 (void*)nativeBindString }, 807 { "nativeBindBlob", "(III[B)V", 808 (void*)nativeBindBlob }, 809 { "nativeResetStatementAndClearBindings", "(II)V", 810 (void*)nativeResetStatementAndClearBindings }, 811 { "nativeExecute", "(II)V", 812 (void*)nativeExecute }, 813 { "nativeExecuteForLong", "(II)J", 814 (void*)nativeExecuteForLong }, 815 { "nativeExecuteForString", "(II)Ljava/lang/String;", 816 (void*)nativeExecuteForString }, 817 { "nativeExecuteForBlobFileDescriptor", "(II)I", 818 (void*)nativeExecuteForBlobFileDescriptor }, 819 { "nativeExecuteForChangedRowCount", "(II)I", 820 (void*)nativeExecuteForChangedRowCount }, 821 { "nativeExecuteForLastInsertedRowId", "(II)J", 822 (void*)nativeExecuteForLastInsertedRowId }, 823 { "nativeExecuteForCursorWindow", "(IIIIIZ)J", 824 (void*)nativeExecuteForCursorWindow }, 825 { "nativeGetDbLookaside", "(I)I", 826 (void*)nativeGetDbLookaside }, 827 { "nativeCancel", "(I)V", 828 (void*)nativeCancel }, 829 { "nativeResetCancel", "(IZ)V", 830 (void*)nativeResetCancel }, 831}; 832 833#define FIND_CLASS(var, className) \ 834 var = env->FindClass(className); \ 835 LOG_FATAL_IF(! var, "Unable to find class " className); 836 837#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \ 838 var = env->GetMethodID(clazz, methodName, fieldDescriptor); \ 839 LOG_FATAL_IF(! var, "Unable to find method" methodName); 840 841#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ 842 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ 843 LOG_FATAL_IF(! var, "Unable to find field " fieldName); 844 845int register_android_database_SQLiteConnection(JNIEnv *env) 846{ 847 jclass clazz; 848 FIND_CLASS(clazz, "android/database/sqlite/SQLiteCustomFunction"); 849 850 GET_FIELD_ID(gSQLiteCustomFunctionClassInfo.name, clazz, 851 "name", "Ljava/lang/String;"); 852 GET_FIELD_ID(gSQLiteCustomFunctionClassInfo.numArgs, clazz, 853 "numArgs", "I"); 854 GET_METHOD_ID(gSQLiteCustomFunctionClassInfo.dispatchCallback, 855 clazz, "dispatchCallback", "([Ljava/lang/String;)V"); 856 857 FIND_CLASS(clazz, "java/lang/String"); 858 gStringClassInfo.clazz = jclass(env->NewGlobalRef(clazz)); 859 860 return AndroidRuntime::registerNativeMethods(env, "android/database/sqlite/SQLiteConnection", 861 sMethods, NELEM(sMethods)); 862} 863 864} // namespace android 865