summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2011-10-06 13:11:04 -0700
committerJeff Brown <jeffbrown@google.com>2011-10-06 14:40:13 -0700
commit3bc6bbc92cd2095f42039b5aadd0a14d0e5d9230 (patch)
tree39b62affe30e0c2895a0f8a52212a7f91bd80dd7
parent3b2faf68e5a66ac67b28d6f79d4ba213b6c0d09c (diff)
downloadframeworks_base-3bc6bbc92cd2095f42039b5aadd0a14d0e5d9230.zip
frameworks_base-3bc6bbc92cd2095f42039b5aadd0a14d0e5d9230.tar.gz
frameworks_base-3bc6bbc92cd2095f42039b5aadd0a14d0e5d9230.tar.bz2
Clean up CursorWindow code.
Bug: 5332296 The code is functionally equivalent, but a little more efficient and much easier to maintain. Change-Id: I90670a13799df05831843a5137ab234929281b7c
-rw-r--r--core/java/android/database/CursorWindow.java792
-rw-r--r--core/java/android/database/CursorWindowAllocationException.java15
-rw-r--r--core/java/android/database/sqlite/SQLiteQuery.java4
-rw-r--r--core/jni/android_database_CursorWindow.cpp777
-rw-r--r--core/jni/android_database_SQLiteQuery.cpp12
-rw-r--r--include/android_runtime/AndroidRuntime.h4
-rw-r--r--include/binder/CursorWindow.h28
-rw-r--r--libs/binder/CursorWindow.cpp41
8 files changed, 815 insertions, 858 deletions
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index f7cbf7a..183662f 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -18,6 +18,7 @@ package android.database;
import android.content.res.Resources;
import android.database.sqlite.SQLiteClosable;
+import android.database.sqlite.SQLiteException;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
@@ -39,538 +40,613 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
Resources.getSystem().getInteger(
com.android.internal.R.integer.config_cursorWindowSize) * 1024;
- /** The pointer to the native window class. set by the native methods in
- * android_database_CursorWindow.cpp
+ /**
+ * The native CursorWindow object pointer. (FOR INTERNAL USE ONLY)
+ * @hide
*/
- private int nWindow;
+ public int mWindowPtr;
private int mStartPos;
- /**
- * Creates a new empty window.
+ private static native int nativeInitializeEmpty(int cursorWindowSize, boolean localOnly);
+ private static native int nativeInitializeFromBinder(IBinder nativeBinder);
+ private static native void nativeDispose(int windowPtr);
+ private static native IBinder nativeGetBinder(int windowPtr);
+
+ private static native void nativeClear(int windowPtr);
+
+ private static native int nativeGetNumRows(int windowPtr);
+ private static native boolean nativeSetNumColumns(int windowPtr, int columnNum);
+ private static native boolean nativeAllocRow(int windowPtr);
+ private static native void nativeFreeLastRow(int windowPtr);
+
+ private static native int nativeGetType(int windowPtr, int row, int column);
+ private static native byte[] nativeGetBlob(int windowPtr, int row, int column);
+ private static native String nativeGetString(int windowPtr, int row, int column);
+ private static native long nativeGetLong(int windowPtr, int row, int column);
+ private static native double nativeGetDouble(int windowPtr, int row, int column);
+ private static native void nativeCopyStringToBuffer(int windowPtr, int row, int column,
+ CharArrayBuffer buffer);
+
+ private static native boolean nativePutBlob(int windowPtr, byte[] value, int row, int column);
+ private static native boolean nativePutString(int windowPtr, String value, int row, int column);
+ private static native boolean nativePutLong(int windowPtr, long value, int row, int column);
+ private static native boolean nativePutDouble(int windowPtr, double value, int row, int column);
+ private static native boolean nativePutNull(int windowPtr, int row, int column);
+
+ /**
+ * Creates a new empty cursor window.
+ * <p>
+ * The cursor initially has no rows or columns. Call {@link #setNumColumns(int)} to
+ * set the number of columns before adding any rows to the cursor.
+ * </p>
*
- * @param localWindow true if this window will be used in this process only
+ * @param localWindow True if this window will be used in this process only,
+ * false if it might be sent to another processes.
*/
public CursorWindow(boolean localWindow) {
mStartPos = 0;
- int rslt = native_init(sCursorWindowSize, localWindow);
- printDebugMsgIfError(rslt);
- recordNewWindow(Binder.getCallingPid(), nWindow);
+ mWindowPtr = nativeInitializeEmpty(sCursorWindowSize, localWindow);
+ if (mWindowPtr == 0) {
+ throw new CursorWindowAllocationException("Cursor window allocation of " +
+ (sCursorWindowSize / 1024) + " kb failed. " + printStats());
+ }
+ recordNewWindow(Binder.getCallingPid(), mWindowPtr);
}
- private void printDebugMsgIfError(int rslt) {
- if (rslt > 0) {
- // cursor window allocation failed. either low memory or too many cursors being open.
- // print info to help in debugging this.
- throw new CursorWindowAllocationException("Cursor Window allocation of " +
- sCursorWindowSize/1024 + " kb failed. " + printStats());
+ private CursorWindow(Parcel source) {
+ IBinder binder = source.readStrongBinder();
+ mStartPos = source.readInt();
+ mWindowPtr = nativeInitializeFromBinder(binder);
+ if (mWindowPtr == 0) {
+ throw new CursorWindowAllocationException("Cursor window could not be "
+ + "created from binder.");
}
}
- /**
- * Returns the starting position of this window within the entire
- * Cursor's result set.
- *
- * @return the starting position of this window within the entire
- * Cursor's result set.
- */
- public int getStartPosition() {
- return mStartPos;
+ @Override
+ protected void finalize() {
+ dispose();
}
- /**
- * Set the start position of cursor window
- * @param pos
- */
- public void setStartPosition(int pos) {
- mStartPos = pos;
- }
-
- /**
- * Returns the number of rows in this window.
- *
- * @return the number of rows in this window.
- */
- public int getNumRows() {
- acquireReference();
- try {
- return getNumRows_native();
- } finally {
- releaseReference();
- }
- }
-
- private native int getNumRows_native();
- /**
- * Set number of Columns
- * @param columnNum
- * @return true if success
- */
- public boolean setNumColumns(int columnNum) {
- acquireReference();
- try {
- return setNumColumns_native(columnNum);
- } finally {
- releaseReference();
+ private void dispose() {
+ if (mWindowPtr != 0) {
+ recordClosingOfWindow(mWindowPtr);
+ nativeDispose(mWindowPtr);
+ mWindowPtr = 0;
}
}
-
- private native boolean setNumColumns_native(int columnNum);
-
+
/**
- * Allocate a row in cursor window
- * @return false if cursor window is out of memory
+ * Closes the cursor window and frees its underlying resources when all other
+ * remaining references have been released.
*/
- public boolean allocRow(){
- acquireReference();
- try {
- return allocRow_native();
- } finally {
- releaseReference();
- }
+ public void close() {
+ releaseReference();
}
-
- private native boolean allocRow_native();
-
+
/**
- * Free the last row
+ * Clears out the existing contents of the window, making it safe to reuse
+ * for new data.
+ * <p>
+ * The start position ({@link #getStartPosition()}), number of rows ({@link #getNumRows()}),
+ * and number of columns in the cursor are all reset to zero.
+ * </p>
*/
- public void freeLastRow(){
+ public void clear() {
acquireReference();
try {
- freeLastRow_native();
+ mStartPos = 0;
+ nativeClear(mWindowPtr);
} finally {
releaseReference();
}
}
-
- private native void freeLastRow_native();
/**
- * copy byte array to cursor window
- * @param value
- * @param row
- * @param col
- * @return false if fail to copy
+ * Gets the start position of this cursor window.
+ * The start position is the index of the first row that this window contains
+ * relative to the entire result set of the {@link Cursor}.
+ *
+ * @return The start position.
*/
- public boolean putBlob(byte[] value, int row, int col) {
- acquireReference();
- try {
- return putBlob_native(value, row - mStartPos, col);
- } finally {
- releaseReference();
- }
+ public int getStartPosition() {
+ return mStartPos;
}
-
- private native boolean putBlob_native(byte[] value, int row, int col);
/**
- * Copy String to cursor window
- * @param value
- * @param row
- * @param col
- * @return false if fail to copy
+ * Sets the start position of this cursor window.
+ * The start position is the index of the first row that this window contains
+ * relative to the entire result set of the {@link Cursor}.
+ *
+ * @param pos The new start position.
*/
- public boolean putString(String value, int row, int col) {
- acquireReference();
- try {
- return putString_native(value, row - mStartPos, col);
- } finally {
- releaseReference();
- }
+ public void setStartPosition(int pos) {
+ mStartPos = pos;
}
-
- private native boolean putString_native(String value, int row, int col);
-
+
/**
- * Copy integer to cursor window
- * @param value
- * @param row
- * @param col
- * @return false if fail to copy
+ * Gets the number of rows in this window.
+ *
+ * @return The number of rows in this cursor window.
*/
- public boolean putLong(long value, int row, int col) {
+ public int getNumRows() {
acquireReference();
try {
- return putLong_native(value, row - mStartPos, col);
+ return nativeGetNumRows(mWindowPtr);
} finally {
releaseReference();
}
}
-
- private native boolean putLong_native(long value, int row, int col);
-
/**
- * Copy double to cursor window
- * @param value
- * @param row
- * @param col
- * @return false if fail to copy
+ * Sets the number of columns in this window.
+ * <p>
+ * This method must be called before any rows are added to the window, otherwise
+ * it will fail to set the number of columns if it differs from the current number
+ * of columns.
+ * </p>
+ *
+ * @param columnNum The new number of columns.
+ * @return True if successful.
*/
- public boolean putDouble(double value, int row, int col) {
+ public boolean setNumColumns(int columnNum) {
acquireReference();
try {
- return putDouble_native(value, row - mStartPos, col);
+ return nativeSetNumColumns(mWindowPtr, columnNum);
} finally {
releaseReference();
}
}
-
- private native boolean putDouble_native(double value, int row, int col);
/**
- * Set the [row, col] value to NULL
- * @param row
- * @param col
- * @return false if fail to copy
+ * Allocates a new row at the end of this cursor window.
+ *
+ * @return True if successful, false if the cursor window is out of memory.
*/
- public boolean putNull(int row, int col) {
+ public boolean allocRow(){
acquireReference();
try {
- return putNull_native(row - mStartPos, col);
+ return nativeAllocRow(mWindowPtr);
} finally {
releaseReference();
}
}
-
- private native boolean putNull_native(int row, int col);
-
/**
- * Returns {@code true} if given field is {@code NULL}.
- *
- * @param row the row to read from, row - getStartPosition() being the actual row in the window
- * @param col the column to read from
- * @return {@code true} if given field is {@code NULL}
- * @deprecated use {@link #getType(int, int)} instead
- */
- @Deprecated
- public boolean isNull(int row, int col) {
- return getType(row, col) == Cursor.FIELD_TYPE_NULL;
- }
-
- /**
- * Returns a byte array for the given field.
- *
- * @param row the row to read from, row - getStartPosition() being the actual row in the window
- * @param col the column to read from
- * @return a String value for the given field
+ * Frees the last row in this cursor window.
*/
- public byte[] getBlob(int row, int col) {
+ public void freeLastRow(){
acquireReference();
try {
- return getBlob_native(row - mStartPos, col);
+ nativeFreeLastRow(mWindowPtr);
} finally {
releaseReference();
}
}
/**
- * Returns the value at (<code>row</code>, <code>col</code>) as a <code>byte</code> array.
- *
- * <p>If the value is null, then <code>null</code> is returned. If the
- * type of column <code>col</code> is a string type, then the result
- * is the array of bytes that make up the internal representation of the
- * string value. If the type of column <code>col</code> is integral or floating-point,
- * then an {@link SQLiteException} is thrown.
- */
- private native byte[] getBlob_native(int row, int col);
-
- /**
- * Returns data type of the given column's value.
- *<p>
- * Returned column types are
- * <ul>
- * <li>{@link Cursor#FIELD_TYPE_NULL}</li>
- * <li>{@link Cursor#FIELD_TYPE_INTEGER}</li>
- * <li>{@link Cursor#FIELD_TYPE_FLOAT}</li>
- * <li>{@link Cursor#FIELD_TYPE_STRING}</li>
- * <li>{@link Cursor#FIELD_TYPE_BLOB}</li>
- *</ul>
- *</p>
+ * Returns true if the field at the specified row and column index
+ * has type {@link Cursor#FIELD_TYPE_NULL}.
*
- * @param row the row to read from, row - getStartPosition() being the actual row in the window
- * @param col the column to read from
- * @return the value type
+ * @param row The zero-based row index, relative to the cursor window's
+ * start position ({@link #getStartPosition()}).
+ * @param column The zero-based column index.
+ * @return True if the field has type {@link Cursor#FIELD_TYPE_NULL}.
+ * @deprecated Use {@link #getType(int, int)} instead.
*/
- public int getType(int row, int col) {
- acquireReference();
- try {
- return getType_native(row - mStartPos, col);
- } finally {
- releaseReference();
- }
+ @Deprecated
+ public boolean isNull(int row, int column) {
+ return getType(row, column) == Cursor.FIELD_TYPE_NULL;
}
/**
- * Checks if a field contains either a blob or is null.
+ * Returns true if the field at the specified row and column index
+ * has type {@link Cursor#FIELD_TYPE_BLOB} or {@link Cursor#FIELD_TYPE_NULL}.
*
- * @param row the row to read from, row - getStartPosition() being the actual row in the window
- * @param col the column to read from
- * @return {@code true} if given field is {@code NULL} or a blob
- * @deprecated use {@link #getType(int, int)} instead
+ * @param row The zero-based row index, relative to the cursor window's
+ * start position ({@link #getStartPosition()}).
+ * @param column The zero-based column index.
+ * @return True if the field has type {@link Cursor#FIELD_TYPE_BLOB} or
+ * {@link Cursor#FIELD_TYPE_NULL}.
+ * @deprecated Use {@link #getType(int, int)} instead.
*/
@Deprecated
- public boolean isBlob(int row, int col) {
- int type = getType(row, col);
+ public boolean isBlob(int row, int column) {
+ int type = getType(row, column);
return type == Cursor.FIELD_TYPE_BLOB || type == Cursor.FIELD_TYPE_NULL;
}
/**
- * Checks if a field contains a long
+ * Returns true if the field at the specified row and column index
+ * has type {@link Cursor#FIELD_TYPE_INTEGER}.
*
- * @param row the row to read from, row - getStartPosition() being the actual row in the window
- * @param col the column to read from
- * @return {@code true} if given field is a long
- * @deprecated use {@link #getType(int, int)} instead
+ * @param row The zero-based row index, relative to the cursor window's
+ * start position ({@link #getStartPosition()}).
+ * @param column The zero-based column index.
+ * @return True if the field has type {@link Cursor#FIELD_TYPE_INTEGER}.
+ * @deprecated Use {@link #getType(int, int)} instead.
*/
@Deprecated
- public boolean isLong(int row, int col) {
- return getType(row, col) == Cursor.FIELD_TYPE_INTEGER;
+ public boolean isLong(int row, int column) {
+ return getType(row, column) == Cursor.FIELD_TYPE_INTEGER;
}
/**
- * Checks if a field contains a float.
+ * Returns true if the field at the specified row and column index
+ * has type {@link Cursor#FIELD_TYPE_FLOAT}.
*
- * @param row the row to read from, row - getStartPosition() being the actual row in the window
- * @param col the column to read from
- * @return {@code true} if given field is a float
- * @deprecated use {@link #getType(int, int)} instead
+ * @param row The zero-based row index, relative to the cursor window's
+ * start position ({@link #getStartPosition()}).
+ * @param column The zero-based column index.
+ * @return True if the field has type {@link Cursor#FIELD_TYPE_FLOAT}.
+ * @deprecated Use {@link #getType(int, int)} instead.
*/
@Deprecated
- public boolean isFloat(int row, int col) {
- return getType(row, col) == Cursor.FIELD_TYPE_FLOAT;
+ public boolean isFloat(int row, int column) {
+ return getType(row, column) == Cursor.FIELD_TYPE_FLOAT;
}
/**
- * Checks if a field contains either a String or is null.
+ * Returns true if the field at the specified row and column index
+ * has type {@link Cursor#FIELD_TYPE_STRING} or {@link Cursor#FIELD_TYPE_NULL}.
*
- * @param row the row to read from, row - getStartPosition() being the actual row in the window
- * @param col the column to read from
- * @return {@code true} if given field is {@code NULL} or a String
- * @deprecated use {@link #getType(int, int)} instead
+ * @param row The zero-based row index, relative to the cursor window's
+ * start position ({@link #getStartPosition()}).
+ * @param column The zero-based column index.
+ * @return True if the field has type {@link Cursor#FIELD_TYPE_STRING}
+ * or {@link Cursor#FIELD_TYPE_NULL}.
+ * @deprecated Use {@link #getType(int, int)} instead.
*/
@Deprecated
- public boolean isString(int row, int col) {
- int type = getType(row, col);
+ public boolean isString(int row, int column) {
+ int type = getType(row, column);
return type == Cursor.FIELD_TYPE_STRING || type == Cursor.FIELD_TYPE_NULL;
}
- private native int getType_native(int row, int col);
+ /**
+ * Returns the type of the field at the specified row and column index.
+ * <p>
+ * The returned field types are:
+ * <ul>
+ * <li>{@link Cursor#FIELD_TYPE_NULL}</li>
+ * <li>{@link Cursor#FIELD_TYPE_INTEGER}</li>
+ * <li>{@link Cursor#FIELD_TYPE_FLOAT}</li>
+ * <li>{@link Cursor#FIELD_TYPE_STRING}</li>
+ * <li>{@link Cursor#FIELD_TYPE_BLOB}</li>
+ * </ul>
+ * </p>
+ *
+ * @param row The zero-based row index, relative to the cursor window's
+ * start position ({@link #getStartPosition()}).
+ * @param column The zero-based column index.
+ * @return The field type.
+ */
+ public int getType(int row, int column) {
+ acquireReference();
+ try {
+ return nativeGetType(mWindowPtr, row - mStartPos, column);
+ } finally {
+ releaseReference();
+ }
+ }
/**
- * Returns a String for the given field.
- *
- * @param row the row to read from, row - getStartPosition() being the actual row in the window
- * @param col the column to read from
- * @return a String value for the given field
+ * Gets the value of the field at the specified row and column index as a byte array.
+ * <p>
+ * The result is determined as follows:
+ * <ul>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the result
+ * is <code>null</code>.</li>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then the result
+ * is the blob value.</li>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the result
+ * is the array of bytes that make up the internal representation of the
+ * string value.</li>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER} or
+ * {@link Cursor#FIELD_TYPE_FLOAT}, then a {@link SQLiteException} is thrown.</li>
+ * </ul>
+ * </p>
+ *
+ * @param row The zero-based row index, relative to the cursor window's
+ * start position ({@link #getStartPosition()}).
+ * @param column The zero-based column index.
+ * @return The value of the field as a byte array.
*/
- public String getString(int row, int col) {
+ public byte[] getBlob(int row, int column) {
acquireReference();
try {
- return getString_native(row - mStartPos, col);
+ return nativeGetBlob(mWindowPtr, row - mStartPos, column);
} finally {
releaseReference();
}
}
-
+
/**
- * Returns the value at (<code>row</code>, <code>col</code>) as a <code>String</code>.
+ * Gets the value of the field at the specified row and column index as a string.
+ * <p>
+ * The result is determined as follows:
+ * <ul>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the result
+ * is <code>null</code>.</li>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the result
+ * is the string value.</li>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER}, then the result
+ * is a string representation of the integer in decimal, obtained by formatting the
+ * value with the <code>printf</code> family of functions using
+ * format specifier <code>%lld</code>.</li>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_FLOAT}, then the result
+ * is a string representation of the floating-point value in decimal, obtained by
+ * formatting the value with the <code>printf</code> family of functions using
+ * format specifier <code>%g</code>.</li>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then a
+ * {@link SQLiteException} is thrown.</li>
+ * </ul>
+ * </p>
*
- * <p>If the value is null, then <code>null</code> is returned. If the
- * type of column <code>col</code> is integral, then the result is the string
- * that is obtained by formatting the integer value with the <code>printf</code>
- * family of functions using format specifier <code>%lld</code>. If the
- * type of column <code>col</code> is floating-point, then the result is the string
- * that is obtained by formatting the floating-point value with the
- * <code>printf</code> family of functions using format specifier <code>%g</code>.
- * If the type of column <code>col</code> is a blob type, then an
- * {@link SQLiteException} is thrown.
+ * @param row The zero-based row index, relative to the cursor window's
+ * start position ({@link #getStartPosition()}).
+ * @param column The zero-based column index.
+ * @return The value of the field as a string.
*/
- private native String getString_native(int row, int col);
+ public String getString(int row, int column) {
+ acquireReference();
+ try {
+ return nativeGetString(mWindowPtr, row - mStartPos, column);
+ } finally {
+ releaseReference();
+ }
+ }
/**
- * copy the text for the given field in the provided char array.
- *
- * @param row the row to read from, row - getStartPosition() being the actual row in the window
- * @param col the column to read from
- * @param buffer the CharArrayBuffer to copy the text into,
- * If the requested string is larger than the buffer
- * a new char buffer will be created to hold the string. and assigne to
- * CharArrayBuffer.data
+ * Copies the text of the field at the specified row and column index into
+ * a {@link CharArrayBuffer}.
+ * <p>
+ * The buffer is populated as follows:
+ * <ul>
+ * <li>If the buffer is too small for the value to be copied, then it is
+ * automatically resized.</li>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the buffer
+ * is set to an empty string.</li>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the buffer
+ * is set to the contents of the string.</li>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER}, then the buffer
+ * is set to a string representation of the integer in decimal, obtained by formatting the
+ * value with the <code>printf</code> family of functions using
+ * format specifier <code>%lld</code>.</li>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_FLOAT}, then the buffer is
+ * set to a string representation of the floating-point value in decimal, obtained by
+ * formatting the value with the <code>printf</code> family of functions using
+ * format specifier <code>%g</code>.</li>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then a
+ * {@link SQLiteException} is thrown.</li>
+ * </ul>
+ * </p>
+ *
+ * @param row The zero-based row index, relative to the cursor window's
+ * start position ({@link #getStartPosition()}).
+ * @param column The zero-based column index.
+ * @param buffer The {@link CharArrayBuffer} to hold the string. It is automatically
+ * resized if the requested string is larger than the buffer's current capacity.
*/
- public void copyStringToBuffer(int row, int col, CharArrayBuffer buffer) {
+ public void copyStringToBuffer(int row, int column, CharArrayBuffer buffer) {
if (buffer == null) {
throw new IllegalArgumentException("CharArrayBuffer should not be null");
}
- if (buffer.data == null) {
- buffer.data = new char[64];
- }
acquireReference();
try {
- char[] newbuf = copyStringToBuffer_native(
- row - mStartPos, col, buffer.data.length, buffer);
- if (newbuf != null) {
- buffer.data = newbuf;
- }
+ nativeCopyStringToBuffer(mWindowPtr, row, column, buffer);
} finally {
releaseReference();
}
}
-
- private native char[] copyStringToBuffer_native(
- int row, int col, int bufferSize, CharArrayBuffer buffer);
-
+
/**
- * Returns a long for the given field.
- * row is 0 based
- *
- * @param row the row to read from, row - getStartPosition() being the actual row in the window
- * @param col the column to read from
- * @return a long value for the given field
+ * Gets the value of the field at the specified row and column index as a <code>long</code>.
+ * <p>
+ * The result is determined as follows:
+ * <ul>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the result
+ * is <code>0L</code>.</li>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the result
+ * is the value obtained by parsing the string value with <code>strtoll</code>.
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER}, then the result
+ * is the <code>long</code> value.</li>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_FLOAT}, then the result
+ * is the floating-point value converted to a <code>long</code>.</li>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then a
+ * {@link SQLiteException} is thrown.</li>
+ * </ul>
+ * </p>
+ *
+ * @param row The zero-based row index, relative to the cursor window's
+ * start position ({@link #getStartPosition()}).
+ * @param column The zero-based column index.
+ * @return The value of the field as a <code>long</code>.
*/
- public long getLong(int row, int col) {
+ public long getLong(int row, int column) {
acquireReference();
try {
- return getLong_native(row - mStartPos, col);
+ return nativeGetLong(mWindowPtr, row - mStartPos, column);
} finally {
releaseReference();
}
}
-
- /**
- * Returns the value at (<code>row</code>, <code>col</code>) as a <code>long</code>.
- *
- * <p>If the value is null, then <code>0L</code> is returned. If the
- * type of column <code>col</code> is a string type, then the result
- * is the <code>long</code> that is obtained by parsing the string value with
- * <code>strtoll</code>. If the type of column <code>col</code> is
- * floating-point, then the result is the floating-point value casted to a <code>long</code>.
- * If the type of column <code>col</code> is a blob type, then an
- * {@link SQLiteException} is thrown.
- */
- private native long getLong_native(int row, int col);
/**
- * Returns a double for the given field.
- * row is 0 based
- *
- * @param row the row to read from, row - getStartPosition() being the actual row in the window
- * @param col the column to read from
- * @return a double value for the given field
+ * Gets the value of the field at the specified row and column index as a
+ * <code>double</code>.
+ * <p>
+ * The result is determined as follows:
+ * <ul>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the result
+ * is <code>0.0</code>.</li>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the result
+ * is the value obtained by parsing the string value with <code>strtod</code>.
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER}, then the result
+ * is the integer value converted to a <code>double</code>.</li>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_FLOAT}, then the result
+ * is the <code>double</code> value.</li>
+ * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then a
+ * {@link SQLiteException} is thrown.</li>
+ * </ul>
+ * </p>
+ *
+ * @param row The zero-based row index, relative to the cursor window's
+ * start position ({@link #getStartPosition()}).
+ * @param column The zero-based column index.
+ * @return The value of the field as a <code>double</code>.
*/
- public double getDouble(int row, int col) {
+ public double getDouble(int row, int column) {
acquireReference();
try {
- return getDouble_native(row - mStartPos, col);
+ return nativeGetDouble(mWindowPtr, row - mStartPos, column);
} finally {
releaseReference();
}
}
-
+
+ /**
+ * Gets the value of the field at the specified row and column index as a
+ * <code>short</code>.
+ * <p>
+ * The result is determined by invoking {@link #getLong} and converting the
+ * result to <code>short</code>.
+ * </p>
+ *
+ * @param row The zero-based row index, relative to the cursor window's
+ * start position ({@link #getStartPosition()}).
+ * @param column The zero-based column index.
+ * @return The value of the field as a <code>short</code>.
+ */
+ public short getShort(int row, int column) {
+ return (short) getLong(row, column);
+ }
+
+ /**
+ * Gets the value of the field at the specified row and column index as an
+ * <code>int</code>.
+ * <p>
+ * The result is determined by invoking {@link #getLong} and converting the
+ * result to <code>int</code>.
+ * </p>
+ *
+ * @param row The zero-based row index, relative to the cursor window's
+ * start position ({@link #getStartPosition()}).
+ * @param column The zero-based column index.
+ * @return The value of the field as an <code>int</code>.
+ */
+ public int getInt(int row, int column) {
+ return (int) getLong(row, column);
+ }
+
/**
- * Returns the value at (<code>row</code>, <code>col</code>) as a <code>double</code>.
+ * Gets the value of the field at the specified row and column index as a
+ * <code>float</code>.
+ * <p>
+ * The result is determined by invoking {@link #getDouble} and converting the
+ * result to <code>float</code>.
+ * </p>
*
- * <p>If the value is null, then <code>0.0</code> is returned. If the
- * type of column <code>col</code> is a string type, then the result
- * is the <code>double</code> that is obtained by parsing the string value with
- * <code>strtod</code>. If the type of column <code>col</code> is
- * integral, then the result is the integer value casted to a <code>double</code>.
- * If the type of column <code>col</code> is a blob type, then an
- * {@link SQLiteException} is thrown.
+ * @param row The zero-based row index, relative to the cursor window's
+ * start position ({@link #getStartPosition()}).
+ * @param column The zero-based column index.
+ * @return The value of the field as an <code>float</code>.
*/
- private native double getDouble_native(int row, int col);
+ public float getFloat(int row, int column) {
+ return (float) getDouble(row, column);
+ }
/**
- * Returns a short for the given field.
- * row is 0 based
- *
- * @param row the row to read from, row - getStartPosition() being the actual row in the window
- * @param col the column to read from
- * @return a short value for the given field
+ * Copies a byte array into the field at the specified row and column index.
+ *
+ * @param value The value to store.
+ * @param row The zero-based row index, relative to the cursor window's
+ * start position ({@link #getStartPosition()}).
+ * @param column The zero-based column index.
+ * @return True if successful.
*/
- public short getShort(int row, int col) {
+ public boolean putBlob(byte[] value, int row, int column) {
acquireReference();
try {
- return (short) getLong_native(row - mStartPos, col);
+ return nativePutBlob(mWindowPtr, value, row - mStartPos, column);
} finally {
releaseReference();
}
}
/**
- * Returns an int for the given field.
- *
- * @param row the row to read from, row - getStartPosition() being the actual row in the window
- * @param col the column to read from
- * @return an int value for the given field
+ * Copies a string into the field at the specified row and column index.
+ *
+ * @param value The value to store.
+ * @param row The zero-based row index, relative to the cursor window's
+ * start position ({@link #getStartPosition()}).
+ * @param column The zero-based column index.
+ * @return True if successful.
*/
- public int getInt(int row, int col) {
+ public boolean putString(String value, int row, int column) {
acquireReference();
try {
- return (int) getLong_native(row - mStartPos, col);
+ return nativePutString(mWindowPtr, value, row - mStartPos, column);
} finally {
releaseReference();
}
}
-
+
/**
- * Returns a float for the given field.
- * row is 0 based
- *
- * @param row the row to read from, row - getStartPosition() being the actual row in the window
- * @param col the column to read from
- * @return a float value for the given field
+ * Puts a long integer into the field at the specified row and column index.
+ *
+ * @param value The value to store.
+ * @param row The zero-based row index, relative to the cursor window's
+ * start position ({@link #getStartPosition()}).
+ * @param column The zero-based column index.
+ * @return True if successful.
*/
- public float getFloat(int row, int col) {
+ public boolean putLong(long value, int row, int column) {
acquireReference();
try {
- return (float) getDouble_native(row - mStartPos, col);
+ return nativePutLong(mWindowPtr, value, row - mStartPos, column);
} finally {
releaseReference();
}
- }
-
+ }
+
/**
- * Clears out the existing contents of the window, making it safe to reuse
- * for new data. Note that the number of columns in the window may NOT
- * change across a call to clear().
+ * Puts a double-precision floating point value into the field at the
+ * specified row and column index.
+ *
+ * @param value The value to store.
+ * @param row The zero-based row index, relative to the cursor window's
+ * start position ({@link #getStartPosition()}).
+ * @param column The zero-based column index.
+ * @return True if successful.
*/
- public void clear() {
+ public boolean putDouble(double value, int row, int column) {
acquireReference();
try {
- mStartPos = 0;
- native_clear();
+ return nativePutDouble(mWindowPtr, value, row - mStartPos, column);
} finally {
releaseReference();
}
}
- /** Clears out the native side of things */
- private native void native_clear();
-
/**
- * Cleans up the native resources associated with the window.
+ * Puts a null value into the field at the specified row and column index.
+ *
+ * @param row The zero-based row index, relative to the cursor window's
+ * start position ({@link #getStartPosition()}).
+ * @param column The zero-based column index.
+ * @return True if successful.
*/
- public void close() {
- releaseReference();
- }
-
- private native void close_native();
-
- @Override
- protected void finalize() {
- if (nWindow == 0) {
- return;
+ public boolean putNull(int row, int column) {
+ acquireReference();
+ try {
+ return nativePutNull(mWindowPtr, row - mStartPos, column);
+ } finally {
+ releaseReference();
}
- // due to bugs 3329504, 3502276, cursorwindow sometimes is closed in fialize()
- // don't print any warning saying "don't release cursor in finzlize"
- // because it is a bug in framework code - NOT an app bug.
- recordClosingOfWindow(nWindow);
- close_native();
}
-
+
public static final Parcelable.Creator<CursorWindow> CREATOR
= new Parcelable.Creator<CursorWindow>() {
public CursorWindow createFromParcel(Parcel source) {
@@ -591,30 +667,13 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
}
public void writeToParcel(Parcel dest, int flags) {
- dest.writeStrongBinder(native_getBinder());
+ dest.writeStrongBinder(nativeGetBinder(mWindowPtr));
dest.writeInt(mStartPos);
}
- private CursorWindow(Parcel source) {
- IBinder nativeBinder = source.readStrongBinder();
- mStartPos = source.readInt();
- int rslt = native_init(nativeBinder);
- printDebugMsgIfError(rslt);
- }
-
- /** Get the binder for the native side of the window */
- private native IBinder native_getBinder();
-
- /** Does the native side initialization for an empty window */
- private native int native_init(int cursorWindowSize, boolean localOnly);
-
- /** Does the native side initialization with an existing binder from another process */
- private native int native_init(IBinder nativeBinder);
-
@Override
protected void onAllReferencesReleased() {
- recordClosingOfWindow(nWindow);
- close_native();
+ dispose();
}
private static final SparseIntArray sWindowToPidMap = new SparseIntArray();
@@ -637,6 +696,7 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
sWindowToPidMap.delete(window);
}
}
+
private String printStats() {
StringBuilder buff = new StringBuilder();
int myPid = Process.myPid();
diff --git a/core/java/android/database/CursorWindowAllocationException.java b/core/java/android/database/CursorWindowAllocationException.java
index ba7df68..2e3227d 100644
--- a/core/java/android/database/CursorWindowAllocationException.java
+++ b/core/java/android/database/CursorWindowAllocationException.java
@@ -18,17 +18,12 @@ package android.database;
/**
* This exception is thrown when a CursorWindow couldn't be allocated,
- * most probably due to memory not being available
+ * most probably due to memory not being available.
+ *
+ * @hide
*/
-class CursorWindowAllocationException extends java.lang.RuntimeException
-{
- public CursorWindowAllocationException()
- {
- super();
- }
-
- public CursorWindowAllocationException(String description)
- {
+public class CursorWindowAllocationException extends RuntimeException {
+ public CursorWindowAllocationException(String description) {
super(description);
}
}
diff --git a/core/java/android/database/sqlite/SQLiteQuery.java b/core/java/android/database/sqlite/SQLiteQuery.java
index dc882d9..06a41b2 100644
--- a/core/java/android/database/sqlite/SQLiteQuery.java
+++ b/core/java/android/database/sqlite/SQLiteQuery.java
@@ -79,7 +79,7 @@ public class SQLiteQuery extends SQLiteProgram {
// if the start pos is not equal to 0, then most likely window is
// too small for the data set, loading by another thread
// is not safe in this situation. the native code will ignore maxRead
- int numRows = native_fill_window(window, window.getStartPosition(),
+ int numRows = native_fill_window(window.mWindowPtr, window.getStartPosition(),
mOffsetIndex, maxRead, lastPos);
mDatabase.logTimeStat(mSql, timeStart);
return numRows;
@@ -154,7 +154,7 @@ public class SQLiteQuery extends SQLiteProgram {
compileAndbindAllArgs();
}
- private final native int native_fill_window(CursorWindow window,
+ private final native int native_fill_window(int windowPtr,
int startPos, int offsetParam, int maxRead, int lastPos);
private final native int native_column_count();
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index 419e464..14c6397 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -24,6 +24,7 @@
#include <utils/Log.h>
#include <utils/String8.h>
#include <utils/String16.h>
+#include <utils/Unicode.h>
#include <stdio.h>
#include <string.h>
@@ -33,69 +34,75 @@
#include "sqlite3_exception.h"
#include "android_util_Binder.h"
-
namespace android {
-static jfieldID gWindowField;
-static jfieldID gBufferField;
-static jfieldID gSizeCopiedField;
+static struct {
+ jfieldID data;
+ jfieldID sizeCopied;
+} gCharArrayBufferClassInfo;
-#define GET_WINDOW(env, object) ((CursorWindow *)env->GetIntField(object, gWindowField))
-#define SET_WINDOW(env, object, window) (env->SetIntField(object, gWindowField, (int)window))
-#define SET_BUFFER(env, object, buf) (env->SetObjectField(object, gBufferField, buf))
-#define SET_SIZE_COPIED(env, object, size) (env->SetIntField(object, gSizeCopiedField, size))
+static jstring gEmptyString;
-CursorWindow * get_window_from_object(JNIEnv * env, jobject javaWindow)
-{
- return GET_WINDOW(env, javaWindow);
+static void throwExceptionWithRowCol(JNIEnv* env, jint row, jint column) {
+ String8 msg;
+ msg.appendFormat("Couldn't read row %d, col %d from CursorWindow. "
+ "Make sure the Cursor is initialized correctly before accessing data from it.",
+ row, column);
+ jniThrowException(env, "java/lang/IllegalStateException", msg.string());
}
-static jint native_init_empty(JNIEnv * env, jobject object, jint cursorWindowSize,
- jboolean localOnly)
-{
- uint8_t * data;
- size_t size;
- CursorWindow * window;
+static void throwUnknownTypeException(JNIEnv * env, jint type) {
+ String8 msg;
+ msg.appendFormat("UNKNOWN type %d", type);
+ jniThrowException(env, "java/lang/IllegalStateException", msg.string());
+}
- window = new CursorWindow(cursorWindowSize);
+static jint nativeInitializeEmpty(JNIEnv* env, jclass clazz,
+ jint cursorWindowSize, jboolean localOnly) {
+ CursorWindow* window = new CursorWindow(cursorWindowSize);
if (!window) {
- return 1;
+ return 0;
}
if (!window->initBuffer(localOnly)) {
delete window;
- return 1;
+ return 0;
}
- LOG_WINDOW("native_init_empty: window = %p", window);
- SET_WINDOW(env, object, window);
- return 0;
+ LOG_WINDOW("nativeInitializeEmpty: window = %p", window);
+ return reinterpret_cast<jint>(window);
}
-static jint native_init_memory(JNIEnv * env, jobject object, jobject memObj)
-{
- sp<IMemory> memory = interface_cast<IMemory>(ibinderForJavaObject(env, memObj));
+static jint nativeInitializeFromBinder(JNIEnv* env, jclass clazz, jobject binderObj) {
+ sp<IMemory> memory = interface_cast<IMemory>(ibinderForJavaObject(env, binderObj));
if (memory == NULL) {
jniThrowException(env, "java/lang/IllegalStateException", "Couldn't get native binder");
- return 1;
+ return 0;
}
- CursorWindow * window = new CursorWindow();
+ CursorWindow* window = new CursorWindow();
if (!window) {
- return 1;
+ return 0;
}
if (!window->setMemory(memory)) {
delete window;
- return 1;
+ return 0;
}
- LOG_WINDOW("native_init_memory: numRows = %d, numColumns = %d, window = %p", window->getNumRows(), window->getNumColumns(), window);
- SET_WINDOW(env, object, window);
- return 0;
+ LOG_WINDOW("nativeInitializeFromBinder: numRows = %d, numColumns = %d, window = %p",
+ window->getNumRows(), window->getNumColumns(), window);
+ return reinterpret_cast<jint>(window);
}
-static jobject native_getBinder(JNIEnv * env, jobject object)
-{
- CursorWindow * window = GET_WINDOW(env, object);
+static void nativeDispose(JNIEnv* env, jclass clazz, jint windowPtr) {
+ CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
+ if (window) {
+ LOG_WINDOW("Closing window %p", window);
+ delete window;
+ }
+}
+
+static jobject nativeGetBinder(JNIEnv * env, jclass clazz, jint windowPtr) {
+ CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
if (window) {
sp<IMemory> memory = window->getMemory();
if (memory != NULL) {
@@ -106,568 +113,484 @@ static jobject native_getBinder(JNIEnv * env, jobject object)
return NULL;
}
-static void native_clear(JNIEnv * env, jobject object)
-{
- CursorWindow * window = GET_WINDOW(env, object);
-LOG_WINDOW("Clearing window %p", window);
- if (window == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", "clear() called after close()");
- return;
- }
+static void nativeClear(JNIEnv * env, jclass clazz, jint windowPtr) {
+ CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
+ LOG_WINDOW("Clearing window %p", window);
window->clear();
}
-static void native_close(JNIEnv * env, jobject object)
-{
- CursorWindow * window = GET_WINDOW(env, object);
- if (window) {
-LOG_WINDOW("Closing window %p", window);
- delete window;
- SET_WINDOW(env, object, 0);
- }
+static jint nativeGetNumRows(JNIEnv* env, jclass clazz, jint windowPtr) {
+ CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
+ return window->getNumRows();
}
-static void throwExceptionWithRowCol(JNIEnv * env, jint row, jint column)
-{
- char buf[200];
- snprintf(buf, sizeof(buf), "Couldn't read row %d, col %d from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it",
- row, column);
- jniThrowException(env, "java/lang/IllegalStateException", buf);
+static jboolean nativeSetNumColumns(JNIEnv* env, jclass clazz, jint windowPtr,
+ jint columnNum) {
+ CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
+ return window->setNumColumns(columnNum);
}
-static void throwUnknowTypeException(JNIEnv * env, jint type)
-{
- char buf[80];
- snprintf(buf, sizeof(buf), "UNKNOWN type %d", type);
- jniThrowException(env, "java/lang/IllegalStateException", buf);
+static jboolean nativeAllocRow(JNIEnv* env, jclass clazz, jint windowPtr) {
+ CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
+ return window->allocRow() != NULL;
}
-static jlong getLong_native(JNIEnv * env, jobject object, jint row, jint column)
-{
- int32_t err;
- CursorWindow * window = GET_WINDOW(env, object);
-LOG_WINDOW("Getting long for %d,%d from %p", row, column, window);
+static void nativeFreeLastRow(JNIEnv* env, jclass clazz, jint windowPtr) {
+ CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
+ window->freeLastRow();
+}
- field_slot_t field;
- err = window->read_field_slot(row, column, &field);
- if (err != 0) {
- throwExceptionWithRowCol(env, row, column);
- return 0;
- }
+static jint nativeGetType(JNIEnv* env, jclass clazz, jint windowPtr,
+ jint row, jint column) {
+ CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
+ LOG_WINDOW("returning column type affinity for %d,%d from %p", row, column, window);
- uint8_t type = field.type;
- if (type == FIELD_TYPE_INTEGER) {
- int64_t value;
- if (window->getLong(row, column, &value)) {
- return value;
- }
- return 0;
- } else if (type == FIELD_TYPE_STRING) {
- uint32_t size = field.data.buffer.size;
- if (size > 0) {
-#if WINDOW_STORAGE_UTF8
- return strtoll((char const *)window->offsetToPtr(field.data.buffer.offset), NULL, 0);
-#else
- String8 ascii((char16_t *) window->offsetToPtr(field.data.buffer.offset), size / 2);
- char const * str = ascii.string();
- return strtoll(str, NULL, 0);
-#endif
- } else {
- return 0;
- }
- } else if (type == FIELD_TYPE_FLOAT) {
- double value;
- if (window->getDouble(row, column, &value)) {
- return value;
- }
- return 0;
- } else if (type == FIELD_TYPE_NULL) {
- return 0;
- } else if (type == FIELD_TYPE_BLOB) {
- throw_sqlite3_exception(env, "Unable to convert BLOB to long");
- return 0;
- } else {
- throwUnknowTypeException(env, type);
- return 0;
+ field_slot_t* fieldSlot = window->getFieldSlotWithCheck(row, column);
+ if (!fieldSlot) {
+ throwExceptionWithRowCol(env, row, column);
+ return NULL;
}
+ return fieldSlot->type;
}
-static jbyteArray getBlob_native(JNIEnv* env, jobject object, jint row, jint column)
-{
- int32_t err;
- CursorWindow * window = GET_WINDOW(env, object);
-LOG_WINDOW("Getting blob for %d,%d from %p", row, column, window);
+static jbyteArray nativeGetBlob(JNIEnv* env, jclass clazz, jint windowPtr,
+ jint row, jint column) {
+ CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
+ LOG_WINDOW("Getting blob for %d,%d from %p", row, column, window);
- field_slot_t field;
- err = window->read_field_slot(row, column, &field);
- if (err != 0) {
+ field_slot_t* fieldSlot = window->getFieldSlotWithCheck(row, column);
+ if (!fieldSlot) {
throwExceptionWithRowCol(env, row, column);
return NULL;
}
- uint8_t type = field.type;
+ uint8_t type = fieldSlot->type;
if (type == FIELD_TYPE_BLOB || type == FIELD_TYPE_STRING) {
- jbyteArray byteArray = env->NewByteArray(field.data.buffer.size);
+ uint32_t size = fieldSlot->data.buffer.size;
+ jbyteArray byteArray = env->NewByteArray(size);
if (!byteArray) {
+ env->ExceptionClear();
throw_sqlite3_exception(env, "Native could not create new byte[]");
return NULL;
}
- env->SetByteArrayRegion(byteArray, 0, field.data.buffer.size,
- (const jbyte*)window->offsetToPtr(field.data.buffer.offset));
+ env->SetByteArrayRegion(byteArray, 0, size,
+ reinterpret_cast<jbyte*>(window->offsetToPtr(fieldSlot->data.buffer.offset)));
return byteArray;
} else if (type == FIELD_TYPE_INTEGER) {
- throw_sqlite3_exception(env, "INTEGER data in getBlob_native ");
+ throw_sqlite3_exception(env, "INTEGER data in nativeGetBlob ");
} else if (type == FIELD_TYPE_FLOAT) {
- throw_sqlite3_exception(env, "FLOAT data in getBlob_native ");
+ throw_sqlite3_exception(env, "FLOAT data in nativeGetBlob ");
} else if (type == FIELD_TYPE_NULL) {
// do nothing
} else {
- throwUnknowTypeException(env, type);
+ throwUnknownTypeException(env, type);
}
return NULL;
}
-static jstring getString_native(JNIEnv* env, jobject object, jint row, jint column)
-{
- int32_t err;
- CursorWindow * window = GET_WINDOW(env, object);
-LOG_WINDOW("Getting string for %d,%d from %p", row, column, window);
+static jstring nativeGetString(JNIEnv* env, jclass clazz, jint windowPtr,
+ jint row, jint column) {
+ CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
+ LOG_WINDOW("Getting string for %d,%d from %p", row, column, window);
- field_slot_t field;
- err = window->read_field_slot(row, column, &field);
- if (err != 0) {
+ field_slot_t* fieldSlot = window->getFieldSlotWithCheck(row, column);
+ if (!fieldSlot) {
throwExceptionWithRowCol(env, row, column);
return NULL;
}
- uint8_t type = field.type;
+ uint8_t type = fieldSlot->type;
if (type == FIELD_TYPE_STRING) {
- uint32_t size = field.data.buffer.size;
- if (size > 0) {
+ uint32_t size = fieldSlot->data.buffer.size;
#if WINDOW_STORAGE_UTF8
- // Pass size - 1 since the UTF8 is null terminated and we don't want a null terminator on the UTF16 string
- String16 utf16((char const *)window->offsetToPtr(field.data.buffer.offset), size - 1);
- return env->NewString((jchar const *)utf16.string(), utf16.size());
+ return size > 1 ? env->NewStringUTF(window->getFieldSlotValueString(fieldSlot))
+ : gEmptyString;
#else
- return env->NewString((jchar const *)window->offsetToPtr(field.data.buffer.offset), size / 2);
+ size_t chars = size / sizeof(char16_t);
+ return chars ? env->NewString(reinterpret_cast<jchar*>(
+ window->getFieldSlotValueString(fieldSlot)), chars)
+ : gEmptyString;
#endif
- } else {
- return env->NewStringUTF("");
- }
} else if (type == FIELD_TYPE_INTEGER) {
- int64_t value;
- if (window->getLong(row, column, &value)) {
- char buf[32];
- snprintf(buf, sizeof(buf), "%lld", value);
- return env->NewStringUTF(buf);
- }
- return NULL;
+ int64_t value = window->getFieldSlotValueLong(fieldSlot);
+ char buf[32];
+ snprintf(buf, sizeof(buf), "%lld", value);
+ return env->NewStringUTF(buf);
} else if (type == FIELD_TYPE_FLOAT) {
- double value;
- if (window->getDouble(row, column, &value)) {
- char buf[32];
- snprintf(buf, sizeof(buf), "%g", value);
- return env->NewStringUTF(buf);
- }
- return NULL;
+ double value = window->getFieldSlotValueDouble(fieldSlot);
+ char buf[32];
+ snprintf(buf, sizeof(buf), "%g", value);
+ return env->NewStringUTF(buf);
} else if (type == FIELD_TYPE_NULL) {
return NULL;
} else if (type == FIELD_TYPE_BLOB) {
throw_sqlite3_exception(env, "Unable to convert BLOB to string");
return NULL;
} else {
- throwUnknowTypeException(env, type);
+ throwUnknownTypeException(env, type);
return NULL;
}
}
-/**
- * Use this only to convert characters that are known to be within the
- * 0-127 range for direct conversion to UTF-16
- */
-static jint charToJchar(const char* src, jchar* dst, jint bufferSize)
-{
- int32_t len = strlen(src);
+static jcharArray allocCharArrayBuffer(JNIEnv* env, jobject bufferObj, size_t size) {
+ jcharArray dataObj = jcharArray(env->GetObjectField(bufferObj,
+ gCharArrayBufferClassInfo.data));
+ if (dataObj && size) {
+ jsize capacity = env->GetArrayLength(dataObj);
+ if (size_t(capacity) < size) {
+ env->DeleteLocalRef(dataObj);
+ dataObj = NULL;
+ }
+ }
+ if (!dataObj) {
+ jsize capacity = size;
+ if (capacity < 64) {
+ capacity = 64;
+ }
+ dataObj = env->NewCharArray(capacity); // might throw OOM
+ if (dataObj) {
+ env->SetObjectField(bufferObj, gCharArrayBufferClassInfo.data, dataObj);
+ }
+ }
+ return dataObj;
+}
- if (bufferSize < len) {
- len = bufferSize;
+static void fillCharArrayBufferUTF(JNIEnv* env, jobject bufferObj,
+ const char* str, size_t len) {
+ ssize_t size = utf8_to_utf16_length(reinterpret_cast<const uint8_t*>(str), len);
+ if (size < 0) {
+ size = 0; // invalid UTF8 string
+ }
+ jcharArray dataObj = allocCharArrayBuffer(env, bufferObj, size);
+ if (dataObj) {
+ if (size) {
+ jchar* data = static_cast<jchar*>(env->GetPrimitiveArrayCritical(dataObj, NULL));
+ utf8_to_utf16(reinterpret_cast<const uint8_t*>(str), len,
+ reinterpret_cast<char16_t*>(data));
+ env->ReleasePrimitiveArrayCritical(dataObj, data, 0);
+ }
+ env->SetIntField(bufferObj, gCharArrayBufferClassInfo.sizeCopied, size);
}
+}
- for (int i = 0; i < len; i++) {
- *dst++ = (*src++ & 0x7F);
+#if !WINDOW_STORAGE_UTF8
+static void fillCharArrayBuffer(JNIEnv* env, jobject bufferObj,
+ const char16_t* str, size_t len) {
+ jcharArray dataObj = allocCharArrayBuffer(env, bufferObj, len);
+ if (dataObj) {
+ if (len) {
+ jchar* data = static_cast<jchar*>(env->GetPrimitiveArrayCritical(dataObj, NULL));
+ memcpy(data, str, len * sizeof(jchar));
+ env->ReleasePrimitiveArrayCritical(dataObj, data, 0);
+ }
+ env->SetIntField(bufferObj, gCharArrayBufferClassInfo.sizeCopied, len);
}
- return len;
}
+#endif
-static jcharArray copyStringToBuffer_native(JNIEnv* env, jobject object, jint row,
- jint column, jint bufferSize, jobject buf)
-{
- int32_t err;
- CursorWindow * window = GET_WINDOW(env, object);
-LOG_WINDOW("Copying string for %d,%d from %p", row, column, window);
-
- field_slot_t field;
- err = window->read_field_slot(row, column, &field);
- if (err != 0) {
- jniThrowException(env, "java/lang/IllegalStateException", "Unable to get field slot");
- return NULL;
+static void clearCharArrayBuffer(JNIEnv* env, jobject bufferObj) {
+ jcharArray dataObj = allocCharArrayBuffer(env, bufferObj, 0);
+ if (dataObj) {
+ env->SetIntField(bufferObj, gCharArrayBufferClassInfo.sizeCopied, 0);
}
+}
- jcharArray buffer = (jcharArray)env->GetObjectField(buf, gBufferField);
- if (buffer == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", "buf should not be null");
- return NULL;
+static void nativeCopyStringToBuffer(JNIEnv* env, jclass clazz, jint windowPtr,
+ jint row, jint column, jobject bufferObj) {
+ CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
+ LOG_WINDOW("Copying string for %d,%d from %p", row, column, window);
+
+ field_slot_t* fieldSlot = window->getFieldSlotWithCheck(row, column);
+ if (!fieldSlot) {
+ throwExceptionWithRowCol(env, row, column);
+ return;
}
- jchar* dst = env->GetCharArrayElements(buffer, NULL);
- uint8_t type = field.type;
- uint32_t sizeCopied = 0;
- jcharArray newArray = NULL;
+
+ uint8_t type = fieldSlot->type;
if (type == FIELD_TYPE_STRING) {
- uint32_t size = field.data.buffer.size;
- if (size > 0) {
+ uint32_t size = fieldSlot->data.buffer.size;
#if WINDOW_STORAGE_UTF8
- // Pass size - 1 since the UTF8 is null terminated and we don't want a null terminator on the UTF16 string
- String16 utf16((char const *)window->offsetToPtr(field.data.buffer.offset), size - 1);
- int32_t strSize = utf16.size();
- if (strSize > bufferSize || dst == NULL) {
- newArray = env->NewCharArray(strSize);
- env->SetCharArrayRegion(newArray, 0, strSize, (jchar const *)utf16.string());
- } else {
- memcpy(dst, (jchar const *)utf16.string(), strSize * 2);
- }
- sizeCopied = strSize;
+ if (size > 1) {
+ fillCharArrayBufferUTF(env, bufferObj,
+ window->getFieldSlotValueString(fieldSlot), size - 1);
+ } else {
+ clearCharArrayBuffer(env, bufferObj);
+ }
#else
- sizeCopied = size/2 + size % 2;
- if (size > bufferSize * 2 || dst == NULL) {
- newArray = env->NewCharArray(sizeCopied);
- memcpy(newArray, (jchar const *)window->offsetToPtr(field.data.buffer.offset), size);
- } else {
- memcpy(dst, (jchar const *)window->offsetToPtr(field.data.buffer.offset), size);
- }
-#endif
+ size_t chars = size / sizeof(char16_t);
+ if (chars) {
+ fillCharArrayBuffer(env, bufferObj,
+ window->getFieldSlotValueString(fieldSlot), chars);
+ } else {
+ clearCharArrayBuffer(env, bufferObj);
}
+#endif
} else if (type == FIELD_TYPE_INTEGER) {
- int64_t value;
- if (window->getLong(row, column, &value)) {
- char buf[32];
- int len;
- snprintf(buf, sizeof(buf), "%lld", value);
- sizeCopied = charToJchar(buf, dst, bufferSize);
- }
+ int64_t value = window->getFieldSlotValueLong(fieldSlot);
+ char buf[32];
+ snprintf(buf, sizeof(buf), "%lld", value);
+ fillCharArrayBufferUTF(env, bufferObj, buf, strlen(buf));
} else if (type == FIELD_TYPE_FLOAT) {
- double value;
- if (window->getDouble(row, column, &value)) {
- char tempbuf[32];
- snprintf(tempbuf, sizeof(tempbuf), "%g", value);
- sizeCopied = charToJchar(tempbuf, dst, bufferSize);
- }
+ double value = window->getFieldSlotValueDouble(fieldSlot);
+ char buf[32];
+ snprintf(buf, sizeof(buf), "%g", value);
+ fillCharArrayBufferUTF(env, bufferObj, buf, strlen(buf));
} else if (type == FIELD_TYPE_NULL) {
+ clearCharArrayBuffer(env, bufferObj);
} else if (type == FIELD_TYPE_BLOB) {
throw_sqlite3_exception(env, "Unable to convert BLOB to string");
} else {
- LOGE("Unknown field type %d", type);
- throw_sqlite3_exception(env, "UNKNOWN type in copyStringToBuffer_native()");
+ throwUnknownTypeException(env, type);
}
- SET_SIZE_COPIED(env, buf, sizeCopied);
- env->ReleaseCharArrayElements(buffer, dst, JNI_OK);
- return newArray;
}
-static jdouble getDouble_native(JNIEnv* env, jobject object, jint row, jint column)
-{
- int32_t err;
- CursorWindow * window = GET_WINDOW(env, object);
-LOG_WINDOW("Getting double for %d,%d from %p", row, column, window);
+static jlong nativeGetLong(JNIEnv* env, jclass clazz, jint windowPtr,
+ jint row, jint column) {
+ CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
+ LOG_WINDOW("Getting long for %d,%d from %p", row, column, window);
- field_slot_t field;
- err = window->read_field_slot(row, column, &field);
- if (err != 0) {
+ field_slot_t* fieldSlot = window->getFieldSlotWithCheck(row, column);
+ if (!fieldSlot) {
+ throwExceptionWithRowCol(env, row, column);
+ return 0;
+ }
+
+ uint8_t type = fieldSlot->type;
+ if (type == FIELD_TYPE_INTEGER) {
+ return window->getFieldSlotValueLong(fieldSlot);
+ } else if (type == FIELD_TYPE_STRING) {
+ uint32_t size = fieldSlot->data.buffer.size;
+#if WINDOW_STORAGE_UTF8
+ return size > 1 ? strtoll(window->getFieldSlotValueString(fieldSlot), NULL, 0) : 0L;
+#else
+ size_t chars = size / sizeof(char16_t);
+ return chars ? strtoll(String8(window->getFieldSlotValueString(fieldSlot), chars)
+ .string(), NULL, 0) : 0L;
+#endif
+ } else if (type == FIELD_TYPE_FLOAT) {
+ return jlong(window->getFieldSlotValueDouble(fieldSlot));
+ } else if (type == FIELD_TYPE_NULL) {
+ return 0;
+ } else if (type == FIELD_TYPE_BLOB) {
+ throw_sqlite3_exception(env, "Unable to convert BLOB to long");
+ return 0;
+ } else {
+ throwUnknownTypeException(env, type);
+ return 0;
+ }
+}
+
+static jdouble nativeGetDouble(JNIEnv* env, jclass clazz, jint windowPtr,
+ jint row, jint column) {
+ CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
+ LOG_WINDOW("Getting double for %d,%d from %p", row, column, window);
+
+ field_slot_t* fieldSlot = window->getFieldSlotWithCheck(row, column);
+ if (!fieldSlot) {
throwExceptionWithRowCol(env, row, column);
return 0.0;
}
- uint8_t type = field.type;
+ uint8_t type = fieldSlot->type;
if (type == FIELD_TYPE_FLOAT) {
- double value;
- if (window->getDouble(row, column, &value)) {
- return value;
- }
- return 0.0;
+ return window->getFieldSlotValueDouble(fieldSlot);
} else if (type == FIELD_TYPE_STRING) {
- uint32_t size = field.data.buffer.size;
- if (size > 0) {
+ uint32_t size = fieldSlot->data.buffer.size;
#if WINDOW_STORAGE_UTF8
- return strtod((char const *)window->offsetToPtr(field.data.buffer.offset), NULL);
+ return size > 1 ? strtod(window->getFieldSlotValueString(fieldSlot), NULL) : 0.0;
#else
- String8 ascii((char16_t *) window->offsetToPtr(field.data.buffer.offset), size / 2);
- char const * str = ascii.string();
- return strtod(str, NULL);
+ size_t chars = size / sizeof(char16_t);
+ return chars ? strtod(String8(window->getFieldSlotValueString(fieldSlot), chars)
+ .string(), NULL) : 0.0;
#endif
- } else {
- return 0.0;
- }
} else if (type == FIELD_TYPE_INTEGER) {
- int64_t value;
- if (window->getLong(row, column, &value)) {
- return (double) value;
- }
- return 0.0;
+ return jdouble(window->getFieldSlotValueLong(fieldSlot));
} else if (type == FIELD_TYPE_NULL) {
return 0.0;
} else if (type == FIELD_TYPE_BLOB) {
throw_sqlite3_exception(env, "Unable to convert BLOB to double");
return 0.0;
} else {
- throwUnknowTypeException(env, type);
+ throwUnknownTypeException(env, type);
return 0.0;
}
}
-bool isNull_native(CursorWindow *window, jint row, jint column)
-{
- LOG_WINDOW("Checking for NULL at %d,%d from %p", row, column, window);
-
- bool isNull;
- if (window->getNull(row, column, &isNull)) {
- return isNull;
- }
-
- //TODO throw execption?
- return true;
-}
-
-static jint getNumRows(JNIEnv * env, jobject object)
-{
- CursorWindow * window = GET_WINDOW(env, object);
- return window->getNumRows();
-}
-
-static jboolean setNumColumns(JNIEnv * env, jobject object, jint columnNum)
-{
- CursorWindow * window = GET_WINDOW(env, object);
- return window->setNumColumns(columnNum);
-}
-
-static jboolean allocRow(JNIEnv * env, jobject object)
-{
- CursorWindow * window = GET_WINDOW(env, object);
- return window->allocRow() != NULL;
-}
-
-static jboolean putBlob_native(JNIEnv * env, jobject object, jbyteArray value, jint row, jint col)
-{
- CursorWindow * window = GET_WINDOW(env, object);
- if (!value) {
- LOG_WINDOW("How did a null value send to here");
- return false;
- }
- field_slot_t * fieldSlot = window->getFieldSlotWithCheck(row, col);
+static jboolean nativePutBlob(JNIEnv* env, jclass clazz, jint windowPtr,
+ jbyteArray valueObj, jint row, jint column) {
+ CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
+ field_slot_t * fieldSlot = window->getFieldSlotWithCheck(row, column);
if (fieldSlot == NULL) {
LOG_WINDOW(" getFieldSlotWithCheck error ");
return false;
}
- jint len = env->GetArrayLength(value);
- int offset = window->alloc(len);
+ jsize len = env->GetArrayLength(valueObj);
+ uint32_t offset = window->alloc(len);
if (!offset) {
LOG_WINDOW("Failed allocating %u bytes", len);
return false;
}
- jbyte * bytes = env->GetByteArrayElements(value, NULL);
- window->copyIn(offset, (uint8_t const *)bytes, len);
- // This must be updated after the call to alloc(), since that
- // may move the field around in the window
+ void* value = env->GetPrimitiveArrayCritical(valueObj, NULL);
+ window->copyIn(offset, static_cast<const uint8_t*>(value), len);
+ env->ReleasePrimitiveArrayCritical(valueObj, value, JNI_ABORT);
+
fieldSlot->type = FIELD_TYPE_BLOB;
fieldSlot->data.buffer.offset = offset;
fieldSlot->data.buffer.size = len;
- env->ReleaseByteArrayElements(value, bytes, JNI_ABORT);
- LOG_WINDOW("%d,%d is BLOB with %u bytes @ %d", row, col, len, offset);
+ LOG_WINDOW("%d,%d is BLOB with %u bytes @ %d", row, column, len, offset);
return true;
}
-static jboolean putString_native(JNIEnv * env, jobject object, jstring value, jint row, jint col)
-{
- CursorWindow * window = GET_WINDOW(env, object);
- if (!value) {
- LOG_WINDOW("How did a null value send to here");
- return false;
- }
- field_slot_t * fieldSlot = window->getFieldSlotWithCheck(row, col);
+static jboolean nativePutString(JNIEnv* env, jclass clazz, jint windowPtr,
+ jstring valueObj, jint row, jint column) {
+ CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
+ field_slot_t * fieldSlot = window->getFieldSlotWithCheck(row, column);
if (fieldSlot == NULL) {
LOG_WINDOW(" getFieldSlotWithCheck error ");
return false;
}
#if WINDOW_STORAGE_UTF8
- int len = env->GetStringUTFLength(value) + 1;
- char const * valStr = env->GetStringUTFChars(value, NULL);
+ size_t size = env->GetStringUTFLength(valueObj) + 1;
+ const char* valueStr = env->GetStringUTFChars(valueObj, NULL);
#else
- int len = env->GetStringLength(value);
- // GetStringLength return number of chars and one char takes 2 bytes
- len *= 2;
- const jchar* valStr = env->GetStringChars(value, NULL);
+ size_t size = env->GetStringLength(valueObj) * sizeof(jchar);
+ const jchar* valueStr = env->GetStringChars(valueObj, NULL);
#endif
- if (!valStr) {
+ if (!valueStr) {
LOG_WINDOW("value can't be transfer to UTFChars");
return false;
}
- int offset = window->alloc(len);
+ uint32_t offset = window->alloc(size);
if (!offset) {
- LOG_WINDOW("Failed allocating %u bytes", len);
+ LOG_WINDOW("Failed allocating %u bytes", size);
#if WINDOW_STORAGE_UTF8
- env->ReleaseStringUTFChars(value, valStr);
+ env->ReleaseStringUTFChars(valueObj, valueStr);
#else
- env->ReleaseStringChars(value, valStr);
+ env->ReleaseStringChars(valueObj, valueStr);
#endif
return false;
}
- window->copyIn(offset, (uint8_t const *)valStr, len);
-
- // This must be updated after the call to alloc(), since that
- // may move the field around in the window
- fieldSlot->type = FIELD_TYPE_STRING;
- fieldSlot->data.buffer.offset = offset;
- fieldSlot->data.buffer.size = len;
+ window->copyIn(offset, reinterpret_cast<const uint8_t*>(valueStr), size);
- LOG_WINDOW("%d,%d is TEXT with %u bytes @ %d", row, col, len, offset);
#if WINDOW_STORAGE_UTF8
- env->ReleaseStringUTFChars(value, valStr);
+ env->ReleaseStringUTFChars(valueObj, valueStr);
#else
- env->ReleaseStringChars(value, valStr);
+ env->ReleaseStringChars(valueObj, valueStr);
#endif
+ fieldSlot->type = FIELD_TYPE_STRING;
+ fieldSlot->data.buffer.offset = offset;
+ fieldSlot->data.buffer.size = size;
+ LOG_WINDOW("%d,%d is TEXT with %u bytes @ %d", row, column, size, offset);
return true;
}
-static jboolean putLong_native(JNIEnv * env, jobject object, jlong value, jint row, jint col)
-{
- CursorWindow * window = GET_WINDOW(env, object);
- if (!window->putLong(row, col, value)) {
+static jboolean nativePutLong(JNIEnv* env, jclass clazz, jint windowPtr,
+ jlong value, jint row, jint column) {
+ CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
+ if (!window->putLong(row, column, value)) {
LOG_WINDOW(" getFieldSlotWithCheck error ");
return false;
}
- LOG_WINDOW("%d,%d is INTEGER 0x%016llx", row, col, value);
-
+ LOG_WINDOW("%d,%d is INTEGER 0x%016llx", row, column, value);
return true;
}
-static jboolean putDouble_native(JNIEnv * env, jobject object, jdouble value, jint row, jint col)
-{
- CursorWindow * window = GET_WINDOW(env, object);
- if (!window->putDouble(row, col, value)) {
+static jboolean nativePutDouble(JNIEnv* env, jclass clazz, jint windowPtr,
+ jdouble value, jint row, jint column) {
+ CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
+ if (!window->putDouble(row, column, value)) {
LOG_WINDOW(" getFieldSlotWithCheck error ");
return false;
}
- LOG_WINDOW("%d,%d is FLOAT %lf", row, col, value);
-
+ LOG_WINDOW("%d,%d is FLOAT %lf", row, column, value);
return true;
}
-static jboolean putNull_native(JNIEnv * env, jobject object, jint row, jint col)
-{
- CursorWindow * window = GET_WINDOW(env, object);
- if (!window->putNull(row, col)) {
+static jboolean nativePutNull(JNIEnv* env, jclass clazz, jint windowPtr,
+ jint row, jint column) {
+ CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
+ if (!window->putNull(row, column)) {
LOG_WINDOW(" getFieldSlotWithCheck error ");
return false;
}
- LOG_WINDOW("%d,%d is NULL", row, col);
-
+ LOG_WINDOW("%d,%d is NULL", row, column);
return true;
}
-// free the last row
-static void freeLastRow(JNIEnv * env, jobject object) {
- CursorWindow * window = GET_WINDOW(env, object);
- window->freeLastRow();
-}
-
-static jint getType_native(JNIEnv* env, jobject object, jint row, jint column)
-{
- int32_t err;
- CursorWindow * window = GET_WINDOW(env, object);
- LOG_WINDOW("returning column type affinity for %d,%d from %p", row, column, window);
-
- if (isNull_native(window, row, column)) {
- return FIELD_TYPE_NULL;
- }
-
- field_slot_t field;
- err = window->read_field_slot(row, column, &field);
- if (err != 0) {
- throwExceptionWithRowCol(env, row, column);
- return NULL;
- }
-
- return field.type;
-}
-
static JNINativeMethod sMethods[] =
{
- /* name, signature, funcPtr */
- {"native_init", "(IZ)I", (void *)native_init_empty},
- {"native_init", "(Landroid/os/IBinder;)I", (void *)native_init_memory},
- {"native_getBinder", "()Landroid/os/IBinder;", (void *)native_getBinder},
- {"native_clear", "()V", (void *)native_clear},
- {"close_native", "()V", (void *)native_close},
- {"getLong_native", "(II)J", (void *)getLong_native},
- {"getBlob_native", "(II)[B", (void *)getBlob_native},
- {"getString_native", "(II)Ljava/lang/String;", (void *)getString_native},
- {"copyStringToBuffer_native", "(IIILandroid/database/CharArrayBuffer;)[C", (void *)copyStringToBuffer_native},
- {"getDouble_native", "(II)D", (void *)getDouble_native},
- {"getNumRows_native", "()I", (void *)getNumRows},
- {"setNumColumns_native", "(I)Z", (void *)setNumColumns},
- {"allocRow_native", "()Z", (void *)allocRow},
- {"putBlob_native", "([BII)Z", (void *)putBlob_native},
- {"putString_native", "(Ljava/lang/String;II)Z", (void *)putString_native},
- {"putLong_native", "(JII)Z", (void *)putLong_native},
- {"putDouble_native", "(DII)Z", (void *)putDouble_native},
- {"freeLastRow_native", "()V", (void *)freeLastRow},
- {"putNull_native", "(II)Z", (void *)putNull_native},
- {"getType_native", "(II)I", (void *)getType_native},
+ /* name, signature, funcPtr */
+ { "nativeInitializeEmpty", "(IZ)I",
+ (void*)nativeInitializeEmpty },
+ { "nativeInitializeFromBinder", "(Landroid/os/IBinder;)I",
+ (void*)nativeInitializeFromBinder },
+ { "nativeDispose", "(I)V",
+ (void*)nativeDispose },
+ { "nativeGetBinder", "(I)Landroid/os/IBinder;",
+ (void*)nativeGetBinder },
+ { "nativeClear", "(I)V",
+ (void*)nativeClear },
+ { "nativeGetNumRows", "(I)I",
+ (void*)nativeGetNumRows },
+ { "nativeSetNumColumns", "(II)Z",
+ (void*)nativeSetNumColumns },
+ { "nativeAllocRow", "(I)Z",
+ (void*)nativeAllocRow },
+ { "nativeFreeLastRow", "(I)V",
+ (void*)nativeFreeLastRow },
+ { "nativeGetType", "(III)I",
+ (void*)nativeGetType },
+ { "nativeGetBlob", "(III)[B",
+ (void*)nativeGetBlob },
+ { "nativeGetString", "(III)Ljava/lang/String;",
+ (void*)nativeGetString },
+ { "nativeGetLong", "(III)J",
+ (void*)nativeGetLong },
+ { "nativeGetDouble", "(III)D",
+ (void*)nativeGetDouble },
+ { "nativeCopyStringToBuffer", "(IIILandroid/database/CharArrayBuffer;)V",
+ (void*)nativeCopyStringToBuffer },
+ { "nativePutBlob", "(I[BII)Z",
+ (void*)nativePutBlob },
+ { "nativePutString", "(ILjava/lang/String;II)Z",
+ (void*)nativePutString },
+ { "nativePutLong", "(IJII)Z",
+ (void*)nativePutLong },
+ { "nativePutDouble", "(IDII)Z",
+ (void*)nativePutDouble },
+ { "nativePutNull", "(III)Z",
+ (void*)nativePutNull },
};
+#define FIND_CLASS(var, className) \
+ var = env->FindClass(className); \
+ LOG_FATAL_IF(! var, "Unable to find class " className);
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
int register_android_database_CursorWindow(JNIEnv * env)
{
jclass clazz;
+ FIND_CLASS(clazz, "android/database/CharArrayBuffer");
- clazz = env->FindClass("android/database/CursorWindow");
- if (clazz == NULL) {
- LOGE("Can't find android/database/CursorWindow");
- return -1;
- }
-
- gWindowField = env->GetFieldID(clazz, "nWindow", "I");
-
- if (gWindowField == NULL) {
- LOGE("Error locating fields");
- return -1;
- }
-
- clazz = env->FindClass("android/database/CharArrayBuffer");
- if (clazz == NULL) {
- LOGE("Can't find android/database/CharArrayBuffer");
- return -1;
- }
+ GET_FIELD_ID(gCharArrayBufferClassInfo.data, clazz,
+ "data", "[C");
+ GET_FIELD_ID(gCharArrayBufferClassInfo.sizeCopied, clazz,
+ "sizeCopied", "I");
- gBufferField = env->GetFieldID(clazz, "data", "[C");
-
- if (gBufferField == NULL) {
- LOGE("Error locating fields data in CharArrayBuffer");
- return -1;
- }
-
- gSizeCopiedField = env->GetFieldID(clazz, "sizeCopied", "I");
-
- if (gSizeCopiedField == NULL) {
- LOGE("Error locating fields sizeCopied in CharArrayBuffer");
- return -1;
- }
+ gEmptyString = jstring(env->NewGlobalRef(env->NewStringUTF("")));
+ LOG_FATAL_IF(!gEmptyString, "Unable to create empty string");
return AndroidRuntime::registerNativeMethods(env, "android/database/CursorWindow",
sMethods, NELEM(sMethods));
diff --git a/core/jni/android_database_SQLiteQuery.cpp b/core/jni/android_database_SQLiteQuery.cpp
index 9e42189..fe62256 100644
--- a/core/jni/android_database_SQLiteQuery.cpp
+++ b/core/jni/android_database_SQLiteQuery.cpp
@@ -35,12 +35,6 @@
namespace android {
-sqlite3_stmt * compile(JNIEnv* env, jobject object,
- sqlite3 * handle, jstring sqlString);
-
-// From android_database_CursorWindow.cpp
-CursorWindow * get_window_from_object(JNIEnv * env, jobject javaWindow);
-
static jfieldID gHandleField;
static jfieldID gStatementField;
@@ -105,7 +99,7 @@ static int finish_program_and_get_row_count(sqlite3_stmt *statement) {
return numRows;
}
-static jint native_fill_window(JNIEnv* env, jobject object, jobject javaWindow,
+static jint native_fill_window(JNIEnv* env, jobject object, jint windowPtr,
jint startPos, jint offsetParam, jint maxRead, jint lastPos)
{
int err;
@@ -142,7 +136,7 @@ static jint native_fill_window(JNIEnv* env, jobject object, jobject javaWindow,
}
// Get the native window
- window = get_window_from_object(env, javaWindow);
+ window = reinterpret_cast<CursorWindow*>(windowPtr);
if (!window) {
LOGE("Invalid CursorWindow");
jniThrowException(env, "java/lang/IllegalArgumentException",
@@ -360,7 +354,7 @@ static jstring native_column_name(JNIEnv* env, jobject object, jint columnIndex)
static JNINativeMethod sMethods[] =
{
/* name, signature, funcPtr */
- {"native_fill_window", "(Landroid/database/CursorWindow;IIII)I",
+ {"native_fill_window", "(IIIII)I",
(void *)native_fill_window},
{"native_column_count", "()I", (void*)native_column_count},
{"native_column_name", "(I)Ljava/lang/String;", (void *)native_column_name},
diff --git a/include/android_runtime/AndroidRuntime.h b/include/android_runtime/AndroidRuntime.h
index 32cd4f5..fd33d59 100644
--- a/include/android_runtime/AndroidRuntime.h
+++ b/include/android_runtime/AndroidRuntime.h
@@ -31,8 +31,6 @@
namespace android {
-class CursorWindow;
-
class AndroidRuntime
{
public:
@@ -133,8 +131,6 @@ private:
static int javaThreadShell(void* args);
};
-extern CursorWindow * get_window_from_object(JNIEnv * env, jobject javaWindow);
-
}
#endif
diff --git a/include/binder/CursorWindow.h b/include/binder/CursorWindow.h
index f0b2909..d227244 100644
--- a/include/binder/CursorWindow.h
+++ b/include/binder/CursorWindow.h
@@ -143,8 +143,6 @@ public:
*/
uint32_t alloc(size_t size, bool aligned = false);
- uint32_t read_field_slot(int row, int column, field_slot_t * slot);
-
/**
* Copy data into the window at the given offset.
*/
@@ -181,6 +179,32 @@ public:
return ((field_slot_t *)offsetToPtr(fieldDirOffset)) + column;
}
+ int64_t getFieldSlotValueLong(field_slot_t* fieldSlot) {
+#if WINDOW_STORAGE_INLINE_NUMERICS
+ return fieldSlot->data.l;
+#else
+ return copyOutLong(fieldSlot->data.buffer.offset);
+#endif
+ }
+
+ double getFieldSlotValueDouble(field_slot_t* fieldSlot) {
+#if WINDOW_STORAGE_INLINE_NUMERICS
+ return fieldSlot->data.d;
+#else
+ return copyOutDouble(fieldSlot->data.buffer.offset);
+#endif
+ }
+
+#if WINDOW_STORAGE_UTF8
+ char* getFieldSlotValueString(field_slot_t* fieldSlot) {
+ return reinterpret_cast<char*>(offsetToPtr(fieldSlot->data.buffer.offset));
+ }
+#else
+ char16_t* getFieldSlotValueString(field_slot_t* fieldSlot) {
+ return reinterpret_cast<char16_t*>(offsetToPtr(fieldSlot->data.buffer.offset));
+ }
+#endif
+
private:
uint8_t * mData;
size_t mSize;
diff --git a/libs/binder/CursorWindow.cpp b/libs/binder/CursorWindow.cpp
index 47bbd04..b02374f 100644
--- a/libs/binder/CursorWindow.cpp
+++ b/libs/binder/CursorWindow.cpp
@@ -236,33 +236,6 @@ field_slot_t * CursorWindow::getFieldSlotWithCheck(int row, int column)
return ((field_slot_t *)offsetToPtr(fieldDirOffset)) + column;
}
-uint32_t CursorWindow::read_field_slot(int row, int column, field_slot_t * slotOut)
-{
- if (row < 0 || row >= mHeader->numRows || column < 0 || column >= mHeader->numColumns) {
- LOGE("Can't read row# %d, col# %d from CursorWindow. Make sure your Cursor is initialized correctly.",
- row, column);
- return -1;
- }
- row_slot_t * rowSlot = getRowSlot(row);
- if (!rowSlot) {
- LOGE("Failed to find rowSlot for row %d", row);
- return -1;
- }
- if (rowSlot->offset == 0 || rowSlot->offset >= mSize) {
- LOGE("Invalid rowSlot, offset = %d", rowSlot->offset);
- return -1;
- }
-LOG_WINDOW("Found field directory for %d,%d at rowSlot %d, offset %d", row, column, (uint8_t *)rowSlot - mData, rowSlot->offset);
- field_slot_t * fieldDir = (field_slot_t *)offsetToPtr(rowSlot->offset);
-LOG_WINDOW("Read field_slot_t %d,%d: offset = %d, size = %d, type = %d", row, column, fieldDir[column].data.buffer.offset, fieldDir[column].data.buffer.size, fieldDir[column].type);
-
- // Copy the data to the out param
- slotOut->data.buffer.offset = fieldDir[column].data.buffer.offset;
- slotOut->data.buffer.size = fieldDir[column].data.buffer.size;
- slotOut->type = fieldDir[column].type;
- return 0;
-}
-
void CursorWindow::copyIn(uint32_t offset, uint8_t const * data, size_t size)
{
assert(offset + size <= mSize);
@@ -370,12 +343,8 @@ bool CursorWindow::getLong(unsigned int row, unsigned int col, int64_t * valueOu
if (!fieldSlot || fieldSlot->type != FIELD_TYPE_INTEGER) {
return false;
}
-
-#if WINDOW_STORAGE_INLINE_NUMERICS
- *valueOut = fieldSlot->data.l;
-#else
- *valueOut = copyOutLong(fieldSlot->data.buffer.offset);
-#endif
+
+ *valueOut = getFieldSlotValueLong(fieldSlot);
return true;
}
@@ -386,11 +355,7 @@ bool CursorWindow::getDouble(unsigned int row, unsigned int col, double * valueO
return false;
}
-#if WINDOW_STORAGE_INLINE_NUMERICS
- *valueOut = fieldSlot->data.d;
-#else
- *valueOut = copyOutDouble(fieldSlot->data.buffer.offset);
-#endif
+ *valueOut = getFieldSlotValueDouble(fieldSlot);
return true;
}