summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/database/BulkCursorNative.java4
-rw-r--r--core/java/android/database/CursorToBulkCursorAdaptor.java11
-rw-r--r--core/java/android/database/CursorWindow.java18
-rw-r--r--core/java/android/database/DatabaseUtils.java26
-rw-r--r--core/java/android/database/IBulkCursor.java12
-rw-r--r--core/java/android/database/sqlite/SQLiteCursor.java26
-rw-r--r--core/java/android/database/sqlite/SQLiteQuery.java36
-rw-r--r--core/jni/android_database_CursorWindow.cpp7
-rw-r--r--core/jni/android_database_SQLiteQuery.cpp223
-rw-r--r--libs/binder/CursorWindow.cpp2
10 files changed, 240 insertions, 125 deletions
diff --git a/core/java/android/database/BulkCursorNative.java b/core/java/android/database/BulkCursorNative.java
index 20a9c67198b2..67cf0f82700a 100644
--- a/core/java/android/database/BulkCursorNative.java
+++ b/core/java/android/database/BulkCursorNative.java
@@ -180,13 +180,13 @@ final class BulkCursorProxy implements IBulkCursor {
return mRemote;
}
- public CursorWindow getWindow(int startPos) throws RemoteException
+ public CursorWindow getWindow(int position) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IBulkCursor.descriptor);
- data.writeInt(startPos);
+ data.writeInt(position);
mRemote.transact(GET_CURSOR_WINDOW_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
diff --git a/core/java/android/database/CursorToBulkCursorAdaptor.java b/core/java/android/database/CursorToBulkCursorAdaptor.java
index 215035de3076..aa0f61e377e4 100644
--- a/core/java/android/database/CursorToBulkCursorAdaptor.java
+++ b/core/java/android/database/CursorToBulkCursorAdaptor.java
@@ -132,11 +132,11 @@ public final class CursorToBulkCursorAdaptor extends BulkCursorNative
}
@Override
- public CursorWindow getWindow(int startPos) {
+ public CursorWindow getWindow(int position) {
synchronized (mLock) {
throwIfCursorIsClosed();
- if (!mCursor.moveToPosition(startPos)) {
+ if (!mCursor.moveToPosition(position)) {
closeFilledWindowLocked();
return null;
}
@@ -149,12 +149,11 @@ public final class CursorToBulkCursorAdaptor extends BulkCursorNative
if (window == null) {
mFilledWindow = new CursorWindow(mProviderName);
window = mFilledWindow;
- mCursor.fillWindow(startPos, window);
- } else if (startPos < window.getStartPosition()
- || startPos >= window.getStartPosition() + window.getNumRows()) {
+ } else if (position < window.getStartPosition()
+ || position >= window.getStartPosition() + window.getNumRows()) {
window.clear();
- mCursor.fillWindow(startPos, window);
}
+ mCursor.fillWindow(position, window);
}
// Acquire a reference before returning from this RPC.
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index 31e6f02c371e..e9675e8a1d22 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -55,6 +55,7 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
public int mWindowPtr;
private int mStartPos;
+ private final String mName;
private final CloseGuard mCloseGuard = CloseGuard.get();
@@ -84,6 +85,8 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
private static native boolean nativePutDouble(int windowPtr, double value, int row, int column);
private static native boolean nativePutNull(int windowPtr, int row, int column);
+ private static native String nativeGetName(int windowPtr);
+
/**
* Creates a new empty cursor window and gives it a name.
* <p>
@@ -95,6 +98,7 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
*/
public CursorWindow(String name) {
mStartPos = 0;
+ mName = name;
mWindowPtr = nativeCreate(name, sCursorWindowSize);
if (mWindowPtr == 0) {
throw new CursorWindowAllocationException("Cursor window allocation of " +
@@ -129,6 +133,7 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
throw new CursorWindowAllocationException("Cursor window could not be "
+ "created from binder.");
}
+ mName = nativeGetName(mWindowPtr);
mCloseGuard.open("close");
}
@@ -156,6 +161,14 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
}
/**
+ * Gets the name of this cursor window.
+ * @hide
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
* Closes the cursor window and frees its underlying resources when all other
* remaining references have been released.
*/
@@ -758,4 +771,9 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
String s = (buff.length() > 980) ? buff.substring(0, 980) : buff.toString();
return "# Open Cursors=" + total + s;
}
+
+ @Override
+ public String toString() {
+ return getName() + " {" + Integer.toHexString(mWindowPtr) + "}";
+ }
}
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index a10ca1502a77..a8ba9a36ad2e 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -726,6 +726,32 @@ public class DatabaseUtils {
}
/**
+ * Picks a start position for {@link Cursor#fillWindow} such that the
+ * window will contain the requested row and a useful range of rows
+ * around it.
+ *
+ * When the data set is too large to fit in a cursor window, seeking the
+ * cursor can become a very expensive operation since we have to run the
+ * query again when we move outside the bounds of the current window.
+ *
+ * We try to choose a start position for the cursor window such that
+ * 1/3 of the window's capacity is used to hold rows before the requested
+ * position and 2/3 of the window's capacity is used to hold rows after the
+ * requested position.
+ *
+ * @param cursorPosition The row index of the row we want to get.
+ * @param cursorWindowCapacity The estimated number of rows that can fit in
+ * a cursor window, or 0 if unknown.
+ * @return The recommended start position, always less than or equal to
+ * the requested row.
+ * @hide
+ */
+ public static int cursorPickFillWindowStartPosition(
+ int cursorPosition, int cursorWindowCapacity) {
+ return Math.max(cursorPosition - cursorWindowCapacity / 3, 0);
+ }
+
+ /**
* Query the table for the number of rows in the table.
* @param db the database the table is in
* @param table the name of the table to query
diff --git a/core/java/android/database/IBulkCursor.java b/core/java/android/database/IBulkCursor.java
index 7c967970a34f..0f4500a7aec8 100644
--- a/core/java/android/database/IBulkCursor.java
+++ b/core/java/android/database/IBulkCursor.java
@@ -30,11 +30,17 @@ import android.os.RemoteException;
*/
public interface IBulkCursor extends IInterface {
/**
- * Returns a BulkCursorWindow, which either has a reference to a shared
- * memory segment with the rows, or an array of JSON strings.
+ * Gets a cursor window that contains the specified position.
+ * The window will contain a range of rows around the specified position.
*/
- public CursorWindow getWindow(int startPos) throws RemoteException;
+ public CursorWindow getWindow(int position) throws RemoteException;
+ /**
+ * Notifies the cursor that the position has changed.
+ * Only called when {@link #getWantsAllOnMoveCalls()} returns true.
+ *
+ * @param position The new position
+ */
public void onMove(int position) throws RemoteException;
/**
diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index c24acd456908..8dcedf2fdd05 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -18,6 +18,7 @@ package android.database.sqlite;
import android.database.AbstractWindowedCursor;
import android.database.CursorWindow;
+import android.database.DatabaseUtils;
import android.os.StrictMode;
import android.util.Log;
@@ -48,7 +49,10 @@ public class SQLiteCursor extends AbstractWindowedCursor {
private final SQLiteCursorDriver mDriver;
/** The number of rows in the cursor */
- private volatile int mCount = NO_COUNT;
+ private int mCount = NO_COUNT;
+
+ /** The number of rows that can fit in the cursor window, 0 if unknown */
+ private int mCursorWindowCapacity;
/** A mapping of column names to column indices, to speed up lookups */
private Map<String, Integer> mColumnNameMap;
@@ -158,18 +162,20 @@ public class SQLiteCursor extends AbstractWindowedCursor {
return mCount;
}
- private void fillWindow(int startPos) {
+ private void fillWindow(int requiredPos) {
clearOrCreateWindow(getDatabase().getPath());
- mWindow.setStartPosition(startPos);
- int count = getQuery().fillWindow(mWindow);
- if (startPos == 0) { // fillWindow returns count(*) only for startPos = 0
+
+ if (mCount == NO_COUNT) {
+ int startPos = DatabaseUtils.cursorPickFillWindowStartPosition(requiredPos, 0);
+ mCount = getQuery().fillWindow(mWindow, startPos, requiredPos, true);
+ mCursorWindowCapacity = mWindow.getNumRows();
if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "received count(*) from native_fill_window: " + count);
+ Log.d(TAG, "received count(*) from native_fill_window: " + mCount);
}
- mCount = count;
- } else if (mCount <= 0) {
- throw new IllegalStateException("Row count should never be zero or negative "
- + "when the start position is non-zero");
+ } else {
+ int startPos = DatabaseUtils.cursorPickFillWindowStartPosition(requiredPos,
+ mCursorWindowCapacity);
+ getQuery().fillWindow(mWindow, startPos, requiredPos, false);
}
}
diff --git a/core/java/android/database/sqlite/SQLiteQuery.java b/core/java/android/database/sqlite/SQLiteQuery.java
index 7db0914140b2..5229f1286149 100644
--- a/core/java/android/database/sqlite/SQLiteQuery.java
+++ b/core/java/android/database/sqlite/SQLiteQuery.java
@@ -30,8 +30,10 @@ import android.util.Log;
public class SQLiteQuery extends SQLiteProgram {
private static final String TAG = "SQLiteQuery";
- private static native int nativeFillWindow(int databasePtr, int statementPtr, int windowPtr,
- int startPos, int offsetParam);
+ private static final boolean DEBUG_FILL_WINDOW_PERFORMANCE = false;
+
+ private static native long nativeFillWindow(int databasePtr, int statementPtr, int windowPtr,
+ int offsetParam, int startPos, int requiredPos, boolean countAllRows);
private static native int nativeColumnCount(int statementPtr);
private static native String nativeColumnName(int statementPtr, int columnIndex);
@@ -71,19 +73,39 @@ public class SQLiteQuery extends SQLiteProgram {
* Reads rows into a buffer. This method acquires the database lock.
*
* @param window The window to fill into
- * @return number of total rows in the query
+ * @param startPos The start position for filling the window.
+ * @param requiredPos The position of a row that MUST be in the window.
+ * If it won't fit, then the query should discard part of what it filled.
+ * @param countAllRows True to count all rows that the query would
+ * return regardless of whether they fit in the window.
+ * @return Number of rows that were enumerated. Might not be all rows
+ * unless countAllRows is true.
*/
- /* package */ int fillWindow(CursorWindow window) {
+ /* package */ int fillWindow(CursorWindow window,
+ int startPos, int requiredPos, boolean countAllRows) {
mDatabase.lock(mSql);
long timeStart = SystemClock.uptimeMillis();
try {
acquireReference();
try {
window.acquireReference();
- int numRows = nativeFillWindow(nHandle, nStatement, window.mWindowPtr,
- window.getStartPosition(), mOffsetIndex);
+ long result = nativeFillWindow(nHandle, nStatement, window.mWindowPtr,
+ mOffsetIndex, startPos, requiredPos, countAllRows);
+ int actualPos = (int)(result >> 32);
+ int countedRows = (int)result;
+ window.setStartPosition(actualPos);
+ if (DEBUG_FILL_WINDOW_PERFORMANCE) {
+ Log.d(TAG, "fillWindow: window=\"" + window
+ + "\", startPos=" + startPos + ", requiredPos=" + requiredPos
+ + ", countAllRows=" + countAllRows
+ + ", offset=" + mOffsetIndex
+ + ", actualPos=" + actualPos + ", filledRows=" + window.getNumRows()
+ + ", countedRows=" + countedRows
+ + ", took " + (SystemClock.uptimeMillis() - timeStart)
+ + " ms, query=\"" + mSql + "\"");
+ }
mDatabase.logTimeStat(mSql, timeStart);
- return numRows;
+ return countedRows;
} catch (IllegalStateException e){
// simply ignore it
return 0;
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index 4a9fcf22c71a..9a87a10d83f5 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -103,6 +103,11 @@ static void nativeDispose(JNIEnv* env, jclass clazz, jint windowPtr) {
}
}
+static jstring nativeGetName(JNIEnv* env, jclass clazz, jint windowPtr) {
+ CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
+ return env->NewStringUTF(window->name().string());
+}
+
static void nativeWriteToParcel(JNIEnv * env, jclass clazz, jint windowPtr,
jobject parcelObj) {
CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
@@ -484,6 +489,8 @@ static JNINativeMethod sMethods[] =
(void*)nativeDispose },
{ "nativeWriteToParcel", "(ILandroid/os/Parcel;)V",
(void*)nativeWriteToParcel },
+ { "nativeGetName", "(I)Ljava/lang/String;",
+ (void*)nativeGetName },
{ "nativeClear", "(I)V",
(void*)nativeClear },
{ "nativeGetNumRows", "(I)I",
diff --git a/core/jni/android_database_SQLiteQuery.cpp b/core/jni/android_database_SQLiteQuery.cpp
index 8170f46ecb29..ea4200a59231 100644
--- a/core/jni/android_database_SQLiteQuery.cpp
+++ b/core/jni/android_database_SQLiteQuery.cpp
@@ -35,8 +35,110 @@
namespace android {
-static jint nativeFillWindow(JNIEnv* env, jclass clazz, jint databasePtr,
- jint statementPtr, jint windowPtr, jint startPos, jint offsetParam) {
+enum CopyRowResult {
+ CPR_OK,
+ CPR_FULL,
+ CPR_ERROR,
+};
+
+static CopyRowResult copyRow(JNIEnv* env, CursorWindow* window,
+ sqlite3_stmt* statement, int numColumns, int startPos, int addedRows) {
+ // Allocate a new field directory for the row. This pointer is not reused
+ // since it may be possible for it to be relocated on a call to alloc() when
+ // the field data is being allocated.
+ status_t status = window->allocRow();
+ if (status) {
+ LOG_WINDOW("Failed allocating fieldDir at startPos %d row %d, error=%d",
+ startPos, addedRows, status);
+ return CPR_FULL;
+ }
+
+ // Pack the row into the window.
+ CopyRowResult result = CPR_OK;
+ for (int i = 0; i < numColumns; i++) {
+ int type = sqlite3_column_type(statement, i);
+ if (type == SQLITE_TEXT) {
+ // TEXT data
+ const char* text = reinterpret_cast<const char*>(
+ sqlite3_column_text(statement, i));
+ // SQLite does not include the NULL terminator in size, but does
+ // ensure all strings are NULL terminated, so increase size by
+ // one to make sure we store the terminator.
+ size_t sizeIncludingNull = sqlite3_column_bytes(statement, i) + 1;
+ status = window->putString(addedRows, i, text, sizeIncludingNull);
+ if (status) {
+ LOG_WINDOW("Failed allocating %u bytes for text at %d,%d, error=%d",
+ sizeIncludingNull, startPos + addedRows, i, status);
+ result = CPR_FULL;
+ break;
+ }
+ LOG_WINDOW("%d,%d is TEXT with %u bytes",
+ startPos + addedRows, i, sizeIncludingNull);
+ } else if (type == SQLITE_INTEGER) {
+ // INTEGER data
+ int64_t value = sqlite3_column_int64(statement, i);
+ status = window->putLong(addedRows, i, value);
+ if (status) {
+ LOG_WINDOW("Failed allocating space for a long in column %d, error=%d",
+ i, status);
+ result = CPR_FULL;
+ break;
+ }
+ LOG_WINDOW("%d,%d is INTEGER 0x%016llx", startPos + addedRows, i, value);
+ } else if (type == SQLITE_FLOAT) {
+ // FLOAT data
+ double value = sqlite3_column_double(statement, i);
+ status = window->putDouble(addedRows, i, value);
+ if (status) {
+ LOG_WINDOW("Failed allocating space for a double in column %d, error=%d",
+ i, status);
+ result = CPR_FULL;
+ break;
+ }
+ LOG_WINDOW("%d,%d is FLOAT %lf", startPos + addedRows, i, value);
+ } else if (type == SQLITE_BLOB) {
+ // BLOB data
+ const void* blob = sqlite3_column_blob(statement, i);
+ size_t size = sqlite3_column_bytes(statement, i);
+ status = window->putBlob(addedRows, i, blob, size);
+ if (status) {
+ LOG_WINDOW("Failed allocating %u bytes for blob at %d,%d, error=%d",
+ size, startPos + addedRows, i, status);
+ result = CPR_FULL;
+ break;
+ }
+ LOG_WINDOW("%d,%d is Blob with %u bytes",
+ startPos + addedRows, i, size);
+ } else if (type == SQLITE_NULL) {
+ // NULL field
+ status = window->putNull(addedRows, i);
+ if (status) {
+ LOG_WINDOW("Failed allocating space for a null in column %d, error=%d",
+ i, status);
+ result = CPR_FULL;
+ break;
+ }
+
+ LOG_WINDOW("%d,%d is NULL", startPos + addedRows, i);
+ } else {
+ // Unknown data
+ LOGE("Unknown column type when filling database window");
+ throw_sqlite3_exception(env, "Unknown column type when filling window");
+ result = CPR_ERROR;
+ break;
+ }
+ }
+
+ // Free the last row if if was not successfully copied.
+ if (result != CPR_OK) {
+ window->freeLastRow();
+ }
+ return result;
+}
+
+static jlong nativeFillWindow(JNIEnv* env, jclass clazz, jint databasePtr,
+ jint statementPtr, jint windowPtr, jint offsetParam,
+ jint startPos, jint requiredPos, jboolean countAllRows) {
sqlite3* database = reinterpret_cast<sqlite3*>(databasePtr);
sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
@@ -45,15 +147,17 @@ static jint nativeFillWindow(JNIEnv* env, jclass clazz, jint databasePtr,
// offsetParam will be set to 0, an invalid value.
if (offsetParam > 0) {
// Bind the offset parameter, telling the program which row to start with
+ // If an offset parameter is used, we cannot simply clear the window if it
+ // turns out that the requiredPos won't fit because the result set may
+ // depend on startPos, so we set startPos to requiredPos.
+ startPos = requiredPos;
int err = sqlite3_bind_int(statement, offsetParam, startPos);
if (err != SQLITE_OK) {
LOGE("Unable to bind offset position, offsetParam = %d", offsetParam);
throw_sqlite3_exception(env, database);
return 0;
}
- LOG_WINDOW("Bound to startPos %d", startPos);
- } else {
- LOG_WINDOW("Not binding to startPos %d", startPos);
+ LOG_WINDOW("Bound offset position to startPos %d", startPos);
}
// We assume numRows is initially 0.
@@ -73,7 +177,6 @@ static jint nativeFillWindow(JNIEnv* env, jclass clazz, jint databasePtr,
int addedRows = 0;
bool windowFull = false;
bool gotException = false;
- const bool countAllRows = (startPos == 0); // when startPos is 0, we count all rows
while (!gotException && (!windowFull || countAllRows)) {
int err = sqlite3_step(statement);
if (err == SQLITE_ROW) {
@@ -86,97 +189,24 @@ static jint nativeFillWindow(JNIEnv* env, jclass clazz, jint databasePtr,
continue;
}
- // Allocate a new field directory for the row. This pointer is not reused
- // since it may be possible for it to be relocated on a call to alloc() when
- // the field data is being allocated.
- status = window->allocRow();
- if (status) {
- LOG_WINDOW("Failed allocating fieldDir at startPos %d row %d, error=%d",
- startPos, addedRows, status);
- windowFull = true;
- continue;
- }
-
- // Pack the row into the window.
- for (int i = 0; i < numColumns; i++) {
- int type = sqlite3_column_type(statement, i);
- if (type == SQLITE_TEXT) {
- // TEXT data
- const char* text = reinterpret_cast<const char*>(
- sqlite3_column_text(statement, i));
- // SQLite does not include the NULL terminator in size, but does
- // ensure all strings are NULL terminated, so increase size by
- // one to make sure we store the terminator.
- size_t sizeIncludingNull = sqlite3_column_bytes(statement, i) + 1;
- status = window->putString(addedRows, i, text, sizeIncludingNull);
- if (status) {
- LOG_WINDOW("Failed allocating %u bytes for text at %d,%d, error=%d",
- sizeIncludingNull, startPos + addedRows, i, status);
- windowFull = true;
- break;
- }
- LOG_WINDOW("%d,%d is TEXT with %u bytes",
- startPos + addedRows, i, sizeIncludingNull);
- } else if (type == SQLITE_INTEGER) {
- // INTEGER data
- int64_t value = sqlite3_column_int64(statement, i);
- status = window->putLong(addedRows, i, value);
- if (status) {
- LOG_WINDOW("Failed allocating space for a long in column %d, error=%d",
- i, status);
- windowFull = true;
- break;
- }
- LOG_WINDOW("%d,%d is INTEGER 0x%016llx", startPos + addedRows, i, value);
- } else if (type == SQLITE_FLOAT) {
- // FLOAT data
- double value = sqlite3_column_double(statement, i);
- status = window->putDouble(addedRows, i, value);
- if (status) {
- LOG_WINDOW("Failed allocating space for a double in column %d, error=%d",
- i, status);
- windowFull = true;
- break;
- }
- LOG_WINDOW("%d,%d is FLOAT %lf", startPos + addedRows, i, value);
- } else if (type == SQLITE_BLOB) {
- // BLOB data
- const void* blob = sqlite3_column_blob(statement, i);
- size_t size = sqlite3_column_bytes(statement, i);
- status = window->putBlob(addedRows, i, blob, size);
- if (status) {
- LOG_WINDOW("Failed allocating %u bytes for blob at %d,%d, error=%d",
- size, startPos + addedRows, i, status);
- windowFull = true;
- break;
- }
- LOG_WINDOW("%d,%d is Blob with %u bytes",
- startPos + addedRows, i, size);
- } else if (type == SQLITE_NULL) {
- // NULL field
- status = window->putNull(addedRows, i);
- if (status) {
- LOG_WINDOW("Failed allocating space for a null in column %d, error=%d",
- i, status);
- windowFull = true;
- break;
- }
-
- LOG_WINDOW("%d,%d is NULL", startPos + addedRows, i);
- } else {
- // Unknown data
- LOGE("Unknown column type when filling database window");
- throw_sqlite3_exception(env, "Unknown column type when filling window");
- gotException = true;
- break;
- }
+ 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);
}
- // Update the final row tally.
- if (windowFull || gotException) {
- window->freeLastRow();
- } else {
+ 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
@@ -209,7 +239,8 @@ static jint nativeFillWindow(JNIEnv* env, jclass clazz, jint databasePtr,
if (startPos > totalRows) {
LOGE("startPos %d > actual rows %d", startPos, totalRows);
}
- return countAllRows ? totalRows : 0;
+ jlong result = jlong(startPos) << 32 | jlong(totalRows);
+ return result;
}
static jint nativeColumnCount(JNIEnv* env, jclass clazz, jint statementPtr) {
@@ -228,7 +259,7 @@ static jstring nativeColumnName(JNIEnv* env, jclass clazz, jint statementPtr,
static JNINativeMethod sMethods[] =
{
/* name, signature, funcPtr */
- { "nativeFillWindow", "(IIIII)I",
+ { "nativeFillWindow", "(IIIIIIZ)J",
(void*)nativeFillWindow },
{ "nativeColumnCount", "(I)I",
(void*)nativeColumnCount},
diff --git a/libs/binder/CursorWindow.cpp b/libs/binder/CursorWindow.cpp
index bf8d7a6f8f8e..07333787cbb0 100644
--- a/libs/binder/CursorWindow.cpp
+++ b/libs/binder/CursorWindow.cpp
@@ -209,7 +209,7 @@ uint32_t CursorWindow::alloc(size_t size, bool aligned) {
uint32_t offset = mHeader->freeOffset + padding;
uint32_t nextFreeOffset = offset + size;
if (nextFreeOffset > mSize) {
- LOGE("Window is full: requested allocation %d bytes, "
+ LOGW("Window is full: requested allocation %d bytes, "
"free space %d bytes, window size %d bytes",
size, freeSpace(), mSize);
return 0;