summaryrefslogtreecommitdiffstats
path: root/core/jni
diff options
context:
space:
mode:
Diffstat (limited to 'core/jni')
-rw-r--r--core/jni/android_database_CursorWindow.cpp777
-rw-r--r--core/jni/android_database_SQLiteQuery.cpp12
2 files changed, 353 insertions, 436 deletions
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},