Skip to content

Commit 4830c36

Browse files
Merge pull request #80 from brodyspark/cursor-api-fix-1
Add cursor changes to get the type of retrieved data (API 11)
2 parents 8093d53 + 4ce316b commit 4830c36

File tree

6 files changed

+171
-4
lines changed

6 files changed

+171
-4
lines changed

jni/net_sqlcipher_CursorWindow.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,22 @@ LOG_WINDOW("Checking if column is an integer for %d,%d from %p", row, column, wi
271271
return field.type == FIELD_TYPE_INTEGER;
272272
}
273273

274+
static jint getType_native(JNIEnv* env, jobject object, jint row, jint column)
275+
{
276+
int32_t err;
277+
CursorWindow * window = GET_WINDOW(env, object);
278+
LOG_WINDOW("Getting type for %d,%d from %p", row, column, window);
279+
280+
field_slot_t field;
281+
err = window->read_field_slot(row, column, &field);
282+
if (err != 0) {
283+
throwExceptionWithRowCol(env, row, column);
284+
return NULL;
285+
}
286+
287+
return field.type;
288+
}
289+
274290
static jboolean isFloat_native(JNIEnv* env, jobject object, jint row, jint column)
275291
{
276292
int32_t err;
@@ -677,6 +693,7 @@ static JNINativeMethod sMethods[] =
677693
{"isString_native", "(II)Z", (void *)isString_native},
678694
{"isFloat_native", "(II)Z", (void *)isFloat_native},
679695
{"isInteger_native", "(II)Z", (void *)isInteger_native},
696+
{"getType_native", "(II)I", (void *)getType_native},
680697
};
681698

682699
int register_android_database_CursorWindow(JNIEnv * env)

src/net/sqlcipher/AbstractCursor.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ public abstract class AbstractCursor implements android.database.CrossProcessCur
5656
abstract public double getDouble(int column);
5757
abstract public boolean isNull(int column);
5858

59+
public int getType(int column) {
60+
throw new UnsupportedOperationException();
61+
}
62+
5963
// TODO implement getBlob in all cursor types
6064
public byte[] getBlob(int column) {
6165
throw new UnsupportedOperationException("getBlob is not supported");
@@ -151,6 +155,8 @@ public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
151155
result.getChars(0, result.length(), data, 0);
152156
}
153157
buffer.sizeCopied = result.length();
158+
} else {
159+
buffer.sizeCopied = 0;
154160
}
155161
}
156162

@@ -205,7 +211,7 @@ public final boolean moveToPosition(int position) {
205211
* @param window
206212
*/
207213
public void fillWindow(int position, android.database.CursorWindow window) {
208-
if (position < 0 || position > getCount()) {
214+
if (position < 0 || position >= getCount()) {
209215
return;
210216
}
211217
window.acquireReference();
@@ -523,6 +529,10 @@ public void setNotificationUri(ContentResolver cr, Uri notifyUri) {
523529
}
524530
}
525531

532+
public Uri getNotificationUri() {
533+
return mNotifyUri;
534+
}
535+
526536
public boolean getWantsAllOnMoveCalls() {
527537
return false;
528538
}
@@ -630,6 +640,12 @@ public void onChange(boolean selfChange) {
630640
protected int mRowIdColumnIndex;
631641

632642
protected int mPos;
643+
644+
/**
645+
* If {@link #mRowIdColumnIndex} is not -1 this contains contains the value of
646+
* the column at {@link #mRowIdColumnIndex} for the current row this cursor is
647+
* pointing at.
648+
*/
633649
protected Long mCurrentRowID;
634650
protected ContentResolver mContentResolver;
635651
protected boolean mClosed = false;

src/net/sqlcipher/AbstractWindowedCursor.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,12 @@ public boolean isFloat(int columnIndex)
210210
return mWindow.isFloat(mPos, columnIndex);
211211
}
212212

213+
@Override
214+
public int getType(int columnIndex) {
215+
checkPosition();
216+
return mWindow.getType(mPos, columnIndex);
217+
}
218+
213219
@Override
214220
protected void checkPosition()
215221
{

src/net/sqlcipher/CursorWindow.java

Lines changed: 95 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,28 @@
1717
package net.sqlcipher;
1818

1919
import android.database.CharArrayBuffer;
20+
import android.database.Cursor;
21+
22+
import android.content.res.Resources;
23+
import android.database.sqlite.SQLiteClosable;
24+
import android.os.Binder;
2025
import android.os.IBinder;
2126
import android.os.Parcel;
2227
import android.os.Parcelable;
28+
import android.os.Process;
29+
import android.util.Log;
30+
import android.util.SparseIntArray;
2331

2432
/**
2533
* A buffer containing multiple cursor rows.
2634
*/
2735
public class CursorWindow extends android.database.CursorWindow implements Parcelable {
2836
/** The pointer to the native window class */
2937
@SuppressWarnings("unused")
38+
39+
/** The pointer to the native window class. set by the native methods in
40+
* android_database_CursorWindow.cpp
41+
*/
3042
private int nWindow;
3143

3244
private int mStartPos;
@@ -227,9 +239,9 @@ public boolean isNull(int row, int col) {
227239
releaseReference();
228240
}
229241
}
230-
242+
231243
private native boolean isNull_native(int row, int col);
232-
244+
233245
/**
234246
* Returns a byte array for the given field.
235247
*
@@ -246,14 +258,50 @@ public byte[] getBlob(int row, int col) {
246258
}
247259
}
248260

261+
/**
262+
* Returns the value at (<code>row</code>, <code>col</code>) as a <code>byte</code> array.
263+
*
264+
* <p>If the value is null, then <code>null</code> is returned. If the
265+
* type of column <code>col</code> is a string type, then the result
266+
* is the array of bytes that make up the internal representation of the
267+
* string value. If the type of column <code>col</code> is integral or floating-point,
268+
* then an {@link SQLiteException} is thrown.
269+
*/
249270
private native byte[] getBlob_native(int row, int col);
250271

272+
/**
273+
* Returns data type of the given column's value.
274+
*<p>
275+
* Returned column types are
276+
* <ul>
277+
* <li>{@link Cursor#FIELD_TYPE_NULL}</li>
278+
* <li>{@link Cursor#FIELD_TYPE_INTEGER}</li>
279+
* <li>{@link Cursor#FIELD_TYPE_FLOAT}</li>
280+
* <li>{@link Cursor#FIELD_TYPE_STRING}</li>
281+
* <li>{@link Cursor#FIELD_TYPE_BLOB}</li>
282+
*</ul>
283+
*</p>
284+
*
285+
* @param row the row to read from, row - getStartPosition() being the actual row in the window
286+
* @param col the column to read from
287+
* @return the value type
288+
*/
289+
public int getType(int row, int col) {
290+
acquireReference();
291+
try {
292+
return getType_native(row - mStartPos, col);
293+
} finally {
294+
releaseReference();
295+
}
296+
}
297+
251298
/**
252299
* Checks if a field contains either a blob or is null.
253300
*
254301
* @param row the row to read from, row - getStartPosition() being the actual row in the window
255302
* @param col the column to read from
256303
* @return {@code true} if given field is {@code NULL} or a blob
304+
* @deprecated use {@link #getType(int, int)} instead
257305
*/
258306
public boolean isBlob(int row, int col) {
259307
acquireReference();
@@ -270,6 +318,7 @@ public boolean isBlob(int row, int col) {
270318
* @param row the row to read from, row - getStartPosition() being the actual row in the window
271319
* @param col the column to read from
272320
* @return {@code true} if given field is a long
321+
* @deprecated use {@link #getType(int, int)} instead
273322
*/
274323
public boolean isLong(int row, int col) {
275324
acquireReference();
@@ -286,6 +335,7 @@ public boolean isLong(int row, int col) {
286335
* @param row the row to read from, row - getStartPosition() being the actual row in the window
287336
* @param col the column to read from
288337
* @return {@code true} if given field is a float
338+
* @deprecated use {@link #getType(int, int)} instead
289339
*/
290340
public boolean isFloat(int row, int col) {
291341
acquireReference();
@@ -302,6 +352,7 @@ public boolean isFloat(int row, int col) {
302352
* @param row the row to read from, row - getStartPosition() being the actual row in the window
303353
* @param col the column to read from
304354
* @return {@code true} if given field is {@code NULL} or a String
355+
* @deprecated use {@link #getType(int, int)} instead
305356
*/
306357
public boolean isString(int row, int col) {
307358
acquireReference();
@@ -317,6 +368,8 @@ public boolean isString(int row, int col) {
317368
private native boolean isInteger_native(int row, int col);
318369
private native boolean isFloat_native(int row, int col);
319370

371+
private native int getType_native(int row, int col);
372+
320373
/**
321374
* Returns a String for the given field.
322375
*
@@ -333,6 +386,19 @@ public String getString(int row, int col) {
333386
}
334387
}
335388

389+
/**
390+
* Returns the value at (<code>row</code>, <code>col</code>) as a <code>String</code>.
391+
*
392+
* <p>If the value is null, then <code>null</code> is returned. If the
393+
* type of column <code>col</code> is integral, then the result is the string
394+
* that is obtained by formatting the integer value with the <code>printf</code>
395+
* family of functions using format specifier <code>%lld</code>. If the
396+
* type of column <code>col</code> is floating-point, then the result is the string
397+
* that is obtained by formatting the floating-point value with the
398+
* <code>printf</code> family of functions using format specifier <code>%g</code>.
399+
* If the type of column <code>col</code> is a blob type, then an
400+
* {@link SQLiteException} is thrown.
401+
*/
336402
private native String getString_native(int row, int col);
337403

338404
/**
@@ -384,6 +450,17 @@ public long getLong(int row, int col) {
384450
}
385451
}
386452

453+
/**
454+
* Returns the value at (<code>row</code>, <code>col</code>) as a <code>long</code>.
455+
*
456+
* <p>If the value is null, then <code>0L</code> is returned. If the
457+
* type of column <code>col</code> is a string type, then the result
458+
* is the <code>long</code> that is obtained by parsing the string value with
459+
* <code>strtoll</code>. If the type of column <code>col</code> is
460+
* floating-point, then the result is the floating-point value casted to a <code>long</code>.
461+
* If the type of column <code>col</code> is a blob type, then an
462+
* {@link SQLiteException} is thrown.
463+
*/
387464
private native long getLong_native(int row, int col);
388465

389466
/**
@@ -403,6 +480,17 @@ public double getDouble(int row, int col) {
403480
}
404481
}
405482

483+
/**
484+
* Returns the value at (<code>row</code>, <code>col</code>) as a <code>double</code>.
485+
*
486+
* <p>If the value is null, then <code>0.0</code> is returned. If the
487+
* type of column <code>col</code> is a string type, then the result
488+
* is the <code>double</code> that is obtained by parsing the string value with
489+
* <code>strtod</code>. If the type of column <code>col</code> is
490+
* integral, then the result is the integer value casted to a <code>double</code>.
491+
* If the type of column <code>col</code> is a blob type, then an
492+
* {@link SQLiteException} is thrown.
493+
*/
406494
private native double getDouble_native(int row, int col);
407495

408496
/**
@@ -485,6 +573,9 @@ public void close() {
485573
@Override
486574
protected void finalize() {
487575
// Just in case someone forgot to call close...
576+
if (nWindow == 0) {
577+
return;
578+
}
488579
close_native();
489580
}
490581

@@ -534,6 +625,7 @@ public CursorWindow(Parcel source,int foo) {
534625
@Override
535626
protected void onAllReferencesReleased() {
536627
close_native();
537-
super.onAllReferencesReleased();
628+
629+
super.onAllReferencesReleased();
538630
}
539631
}

src/net/sqlcipher/DatabaseUtils.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,37 @@ public static void bindObjectToProgram(SQLiteProgram prog, int index,
194194
}
195195
}
196196

197+
/**
198+
* Returns data type of the given object's value.
199+
*<p>
200+
* Returned values are
201+
* <ul>
202+
* <li>{@link Cursor#FIELD_TYPE_NULL}</li>
203+
* <li>{@link Cursor#FIELD_TYPE_INTEGER}</li>
204+
* <li>{@link Cursor#FIELD_TYPE_FLOAT}</li>
205+
* <li>{@link Cursor#FIELD_TYPE_STRING}</li>
206+
* <li>{@link Cursor#FIELD_TYPE_BLOB}</li>
207+
*</ul>
208+
*</p>
209+
*
210+
* @param obj the object whose value type is to be returned
211+
* @return object value type
212+
* @hide
213+
*/
214+
public static int getTypeOfObject(Object obj) {
215+
if (obj == null) {
216+
return 0; /* Cursor.FIELD_TYPE_NULL */
217+
} else if (obj instanceof byte[]) {
218+
return 4; /* Cursor.FIELD_TYPE_BLOB */
219+
} else if (obj instanceof Float || obj instanceof Double) {
220+
return 2; /* Cursor.FIELD_TYPE_FLOAT */
221+
} else if (obj instanceof Long || obj instanceof Integer) {
222+
return 1; /* Cursor.FIELD_TYPE_INTEGER */
223+
} else {
224+
return 3; /* Cursor.FIELD_TYPE_STRING */
225+
}
226+
}
227+
197228
/**
198229
* Appends an SQL string to the given StringBuilder, including the opening
199230
* and closing single quotes. Any single quotes internal to sqlString will

src/net/sqlcipher/MatrixCursor.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,11 @@ public double getDouble(int column) {
274274
return Double.parseDouble(value.toString());
275275
}
276276

277+
@Override
278+
public int getType(int column) {
279+
return DatabaseUtils.getTypeOfObject(get(column));
280+
}
281+
277282
@Override
278283
public boolean isNull(int column) {
279284
return get(column) == null;

0 commit comments

Comments
 (0)