diff --git a/jni/net_sqlcipher_CursorWindow.cpp b/jni/net_sqlcipher_CursorWindow.cpp
index c1e53af0..98eb9cc9 100644
--- a/jni/net_sqlcipher_CursorWindow.cpp
+++ b/jni/net_sqlcipher_CursorWindow.cpp
@@ -271,6 +271,22 @@ LOG_WINDOW("Checking if column is an integer for %d,%d from %p", row, column, wi
return field.type == FIELD_TYPE_INTEGER;
}
+static jint getType_native(JNIEnv* env, jobject object, jint row, jint column)
+{
+ int32_t err;
+ CursorWindow * window = GET_WINDOW(env, object);
+LOG_WINDOW("Getting type for %d,%d from %p", row, column, window);
+
+ 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 jboolean isFloat_native(JNIEnv* env, jobject object, jint row, jint column)
{
int32_t err;
@@ -677,6 +693,7 @@ static JNINativeMethod sMethods[] =
{"isString_native", "(II)Z", (void *)isString_native},
{"isFloat_native", "(II)Z", (void *)isFloat_native},
{"isInteger_native", "(II)Z", (void *)isInteger_native},
+ {"getType_native", "(II)I", (void *)getType_native},
};
int register_android_database_CursorWindow(JNIEnv * env)
diff --git a/src/net/sqlcipher/AbstractCursor.java b/src/net/sqlcipher/AbstractCursor.java
index 651a1fea..bfb4e3c6 100644
--- a/src/net/sqlcipher/AbstractCursor.java
+++ b/src/net/sqlcipher/AbstractCursor.java
@@ -56,6 +56,10 @@ public abstract class AbstractCursor implements android.database.CrossProcessCur
abstract public double getDouble(int column);
abstract public boolean isNull(int column);
+ public int getType(int column) {
+ throw new UnsupportedOperationException();
+ }
+
// TODO implement getBlob in all cursor types
public byte[] getBlob(int column) {
throw new UnsupportedOperationException("getBlob is not supported");
@@ -151,6 +155,8 @@ public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
result.getChars(0, result.length(), data, 0);
}
buffer.sizeCopied = result.length();
+ } else {
+ buffer.sizeCopied = 0;
}
}
@@ -205,7 +211,7 @@ public final boolean moveToPosition(int position) {
* @param window
*/
public void fillWindow(int position, android.database.CursorWindow window) {
- if (position < 0 || position > getCount()) {
+ if (position < 0 || position >= getCount()) {
return;
}
window.acquireReference();
@@ -523,6 +529,10 @@ public void setNotificationUri(ContentResolver cr, Uri notifyUri) {
}
}
+ public Uri getNotificationUri() {
+ return mNotifyUri;
+ }
+
public boolean getWantsAllOnMoveCalls() {
return false;
}
@@ -630,6 +640,12 @@ public void onChange(boolean selfChange) {
protected int mRowIdColumnIndex;
protected int mPos;
+
+ /**
+ * If {@link #mRowIdColumnIndex} is not -1 this contains contains the value of
+ * the column at {@link #mRowIdColumnIndex} for the current row this cursor is
+ * pointing at.
+ */
protected Long mCurrentRowID;
protected ContentResolver mContentResolver;
protected boolean mClosed = false;
diff --git a/src/net/sqlcipher/AbstractWindowedCursor.java b/src/net/sqlcipher/AbstractWindowedCursor.java
index c1f707d2..ec48e709 100644
--- a/src/net/sqlcipher/AbstractWindowedCursor.java
+++ b/src/net/sqlcipher/AbstractWindowedCursor.java
@@ -210,6 +210,12 @@ public boolean isFloat(int columnIndex)
return mWindow.isFloat(mPos, columnIndex);
}
+ @Override
+ public int getType(int columnIndex) {
+ checkPosition();
+ return mWindow.getType(mPos, columnIndex);
+ }
+
@Override
protected void checkPosition()
{
diff --git a/src/net/sqlcipher/CursorWindow.java b/src/net/sqlcipher/CursorWindow.java
index 78d08882..ec4d25b9 100644
--- a/src/net/sqlcipher/CursorWindow.java
+++ b/src/net/sqlcipher/CursorWindow.java
@@ -17,9 +17,17 @@
package net.sqlcipher;
import android.database.CharArrayBuffer;
+import android.database.Cursor;
+
+import android.content.res.Resources;
+import android.database.sqlite.SQLiteClosable;
+import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.Process;
+import android.util.Log;
+import android.util.SparseIntArray;
/**
* A buffer containing multiple cursor rows.
@@ -27,6 +35,10 @@
public class CursorWindow extends android.database.CursorWindow implements Parcelable {
/** The pointer to the native window class */
@SuppressWarnings("unused")
+
+ /** The pointer to the native window class. set by the native methods in
+ * android_database_CursorWindow.cpp
+ */
private int nWindow;
private int mStartPos;
@@ -227,9 +239,9 @@ public boolean isNull(int row, int col) {
releaseReference();
}
}
-
+
private native boolean isNull_native(int row, int col);
-
+
/**
* Returns a byte array for the given field.
*
@@ -246,14 +258,50 @@ public byte[] getBlob(int row, int col) {
}
}
+ /**
+ * Returns the value at (row
, col
) as a byte
array.
+ *
+ *
If the value is null, then null
is returned. If the
+ * type of column col
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 col
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.
+ *
+ * Returned column types are + *
row
, col
) as a String
.
+ *
+ * If the value is null, then null
is returned. If the
+ * type of column col
is integral, then the result is the string
+ * that is obtained by formatting the integer value with the printf
+ * family of functions using format specifier %lld
. If the
+ * type of column col
is floating-point, then the result is the string
+ * that is obtained by formatting the floating-point value with the
+ * printf
family of functions using format specifier %g
.
+ * If the type of column col
is a blob type, then an
+ * {@link SQLiteException} is thrown.
+ */
private native String getString_native(int row, int col);
/**
@@ -384,6 +450,17 @@ public long getLong(int row, int col) {
}
}
+ /**
+ * Returns the value at (row
, col
) as a long
.
+ *
+ *
If the value is null, then 0L
is returned. If the
+ * type of column col
is a string type, then the result
+ * is the long
that is obtained by parsing the string value with
+ * strtoll
. If the type of column col
is
+ * floating-point, then the result is the floating-point value casted to a long
.
+ * If the type of column col
is a blob type, then an
+ * {@link SQLiteException} is thrown.
+ */
private native long getLong_native(int row, int col);
/**
@@ -403,6 +480,17 @@ public double getDouble(int row, int col) {
}
}
+ /**
+ * Returns the value at (row
, col
) as a double
.
+ *
+ *
If the value is null, then 0.0
is returned. If the
+ * type of column col
is a string type, then the result
+ * is the double
that is obtained by parsing the string value with
+ * strtod
. If the type of column col
is
+ * integral, then the result is the integer value casted to a double
.
+ * If the type of column col
is a blob type, then an
+ * {@link SQLiteException} is thrown.
+ */
private native double getDouble_native(int row, int col);
/**
@@ -485,6 +573,9 @@ public void close() {
@Override
protected void finalize() {
// Just in case someone forgot to call close...
+ if (nWindow == 0) {
+ return;
+ }
close_native();
}
@@ -534,6 +625,7 @@ public CursorWindow(Parcel source,int foo) {
@Override
protected void onAllReferencesReleased() {
close_native();
- super.onAllReferencesReleased();
+
+ super.onAllReferencesReleased();
}
}
diff --git a/src/net/sqlcipher/DatabaseUtils.java b/src/net/sqlcipher/DatabaseUtils.java
index 34b9a220..ceaf5e13 100644
--- a/src/net/sqlcipher/DatabaseUtils.java
+++ b/src/net/sqlcipher/DatabaseUtils.java
@@ -194,6 +194,37 @@ public static void bindObjectToProgram(SQLiteProgram prog, int index,
}
}
+ /**
+ * Returns data type of the given object's value.
+ *
+ * Returned values are + *