diff options
Diffstat (limited to 'core/jni')
-rw-r--r-- | core/jni/android_database_CursorWindow.cpp | 777 | ||||
-rw-r--r-- | core/jni/android_database_SQLiteQuery.cpp | 12 |
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}, |