static jboolean setNumColumns(JNIEnv * env, jobject object, jint columnNum) { CursorWindow * window = GET_WINDOW(env, object); return window->setNumColumns(columnNum); }
static jboolean nativeSetNumColumns(JNIEnv* env, jclass clazz, jlong windowPtr, jint columnNum) { CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); status_t status = window->setNumColumns(columnNum); return status == OK; }
static jlong nativeExecuteForCursorWindow(JNIEnv* env, jclass clazz, jlong connectionPtr, jlong statementPtr, jlong windowPtr, jint startPos, jint requiredPos, jboolean countAllRows) { SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr); sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr); CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); status_t status = window->clear(); if (status) { String8 msg; msg.appendFormat("Failed to clear the cursor window, status=%d", status); throw_sqlite3_exception(env, connection->db, msg.string()); return 0; } int numColumns = sqlite3_column_count(statement); status = window->setNumColumns(numColumns); if (status) { String8 msg; msg.appendFormat("Failed to set the cursor window column count to %d, status=%d", numColumns, status); throw_sqlite3_exception(env, connection->db, msg.string()); return 0; } int retryCount = 0; int totalRows = 0; int addedRows = 0; bool windowFull = false; bool gotException = false; while (!gotException && (!windowFull || countAllRows)) { int err = sqlite3_step(statement); if (err == SQLITE_ROW) { LOG_WINDOW("Stepped statement %p to row %d", statement, totalRows); retryCount = 0; totalRows += 1; // Skip the row if the window is full or we haven't reached the start position yet. if (startPos >= totalRows || windowFull) { continue; } CopyRowResult cpr = copyRow(env, window, statement, numColumns, startPos, addedRows); if (cpr == CPR_FULL && addedRows && startPos + addedRows <= requiredPos) { // We filled the window before we got to the one row that we really wanted. // Clear the window and start filling it again from here. // TODO: Would be nicer if we could progressively replace earlier rows. window->clear(); window->setNumColumns(numColumns); startPos += addedRows; addedRows = 0; cpr = copyRow(env, window, statement, numColumns, startPos, addedRows); } if (cpr == CPR_OK) { addedRows += 1; } else if (cpr == CPR_FULL) { windowFull = true; } else { gotException = true; } } else if (err == SQLITE_DONE) { // All rows processed, bail LOG_WINDOW("Processed all rows"); break; } else if (err == SQLITE_LOCKED || err == SQLITE_BUSY) { // The table is locked, retry LOG_WINDOW("Database locked, retrying"); if (retryCount > 50) { ALOGE("Bailing on database busy retry"); throw_sqlite3_exception(env, connection->db, "retrycount exceeded"); gotException = true; } else { // Sleep to give the thread holding the lock a chance to finish usleep(1000); retryCount++; } } else { throw_sqlite3_exception(env, connection->db); gotException = true; } } LOG_WINDOW("Resetting statement %p after fetching %d rows and adding %d rows" "to the window in %d bytes", statement, totalRows, addedRows, window->size() - window->freeSpace()); sqlite3_reset(statement); // Report the total number of rows on request. if (startPos > totalRows) { ALOGE("startPos %d > actual rows %d", startPos, totalRows); } jlong result = jlong(startPos) << 32 | jlong(totalRows); return result; }