19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#undef LOG_TAG 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "CursorWindow" 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <jni.h> 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <JNIHelp.h> 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <android_runtime/AndroidRuntime.h> 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Log.h> 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/String8.h> 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/String16.h> 273bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown#include <utils/Unicode.h> 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <stdio.h> 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <string.h> 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <unistd.h> 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 332807df89af680e46cb35ee0035bb10b42d3136a2Mike Lockwood#include "binder/CursorWindow.h" 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "sqlite3_exception.h" 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "android_util_Binder.h" 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectnamespace android { 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 393bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic struct { 403bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jfieldID data; 413bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jfieldID sizeCopied; 423bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown} gCharArrayBufferClassInfo; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 443bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jstring gEmptyString; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 463bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic void throwExceptionWithRowCol(JNIEnv* env, jint row, jint column) { 473bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown String8 msg; 483bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown msg.appendFormat("Couldn't read row %d, col %d from CursorWindow. " 493bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown "Make sure the Cursor is initialized correctly before accessing data from it.", 503bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown row, column); 513bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jniThrowException(env, "java/lang/IllegalStateException", msg.string()); 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 543bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic void throwUnknownTypeException(JNIEnv * env, jint type) { 553bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown String8 msg; 563bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown msg.appendFormat("UNKNOWN type %d", type); 573bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jniThrowException(env, "java/lang/IllegalStateException", msg.string()); 583bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown} 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 605e5d6d8ba04d7579df840cda055cd5dfa9d7666fJeff Brownstatic jint nativeCreate(JNIEnv* env, jclass clazz, jstring nameObj, jint cursorWindowSize) { 610cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown String8 name; 620cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown if (nameObj) { 630cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown const char* nameStr = env->GetStringUTFChars(nameObj, NULL); 640cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown name.setTo(nameStr); 650cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown env->ReleaseStringUTFChars(nameObj, nameStr); 660cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } 670cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown if (name.size() == 0) { 680cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown name.setTo("<unnamed>"); 690cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } 700cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown 710cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown CursorWindow* window; 725e5d6d8ba04d7579df840cda055cd5dfa9d7666fJeff Brown status_t status = CursorWindow::create(name, cursorWindowSize, &window); 730cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown if (status || !window) { 740cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown LOGE("Could not allocate CursorWindow '%s' of size %d due to error %d.", 750cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown name.string(), cursorWindowSize, status); 763bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown return 0; 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 793bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown LOG_WINDOW("nativeInitializeEmpty: window = %p", window); 803bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown return reinterpret_cast<jint>(window); 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 830cde89f5f025b7826be009ebb9673b970e180e32Jeff Brownstatic jint nativeCreateFromParcel(JNIEnv* env, jclass clazz, jobject parcelObj) { 840cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown Parcel* parcel = parcelForJavaObject(env, parcelObj); 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 860cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown CursorWindow* window; 870cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown status_t status = CursorWindow::createFromParcel(parcel, &window); 880cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown if (status || !window) { 890cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown LOGE("Could not create CursorWindow from Parcel due to error %d.", status); 903bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown return 0; 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 933bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown LOG_WINDOW("nativeInitializeFromBinder: numRows = %d, numColumns = %d, window = %p", 943bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown window->getNumRows(), window->getNumColumns(), window); 953bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown return reinterpret_cast<jint>(window); 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 983bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic void nativeDispose(JNIEnv* env, jclass clazz, jint windowPtr) { 993bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); 1003bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown if (window) { 1013bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown LOG_WINDOW("Closing window %p", window); 1023bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown delete window; 1033bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown } 1043bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown} 1053bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown 10689101cd9d9b5c1a6ff1ed85eba0613ca4c4802e2Jeff Brownstatic jstring nativeGetName(JNIEnv* env, jclass clazz, jint windowPtr) { 10789101cd9d9b5c1a6ff1ed85eba0613ca4c4802e2Jeff Brown CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); 10889101cd9d9b5c1a6ff1ed85eba0613ca4c4802e2Jeff Brown return env->NewStringUTF(window->name().string()); 10989101cd9d9b5c1a6ff1ed85eba0613ca4c4802e2Jeff Brown} 11089101cd9d9b5c1a6ff1ed85eba0613ca4c4802e2Jeff Brown 1110cde89f5f025b7826be009ebb9673b970e180e32Jeff Brownstatic void nativeWriteToParcel(JNIEnv * env, jclass clazz, jint windowPtr, 1120cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown jobject parcelObj) { 1133bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); 1140cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown Parcel* parcel = parcelForJavaObject(env, parcelObj); 1150cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown 1160cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown status_t status = window->writeToParcel(parcel); 1170cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown if (status) { 1180cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown String8 msg; 1190cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown msg.appendFormat("Could not write CursorWindow to Parcel due to error %d.", status); 1200cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown jniThrowRuntimeException(env, msg.string()); 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1243bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic void nativeClear(JNIEnv * env, jclass clazz, jint windowPtr) { 1253bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); 1263bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown LOG_WINDOW("Clearing window %p", window); 1270cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown status_t status = window->clear(); 1280cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown if (status) { 1290cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown LOG_WINDOW("Could not clear window. error=%d", status); 1300cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1333bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jint nativeGetNumRows(JNIEnv* env, jclass clazz, jint windowPtr) { 1343bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); 1353bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown return window->getNumRows(); 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1383bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jboolean nativeSetNumColumns(JNIEnv* env, jclass clazz, jint windowPtr, 1393bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jint columnNum) { 1403bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); 1410cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown status_t status = window->setNumColumns(columnNum); 1420cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown return status == OK; 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1453bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jboolean nativeAllocRow(JNIEnv* env, jclass clazz, jint windowPtr) { 1463bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); 1470cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown status_t status = window->allocRow(); 1480cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown return status == OK; 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1513bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic void nativeFreeLastRow(JNIEnv* env, jclass clazz, jint windowPtr) { 1523bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); 1533bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown window->freeLastRow(); 1543bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown} 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1563bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jint nativeGetType(JNIEnv* env, jclass clazz, jint windowPtr, 1573bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jint row, jint column) { 1583bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); 1593bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown LOG_WINDOW("returning column type affinity for %d,%d from %p", row, column, window); 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1610cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column); 1623bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown if (!fieldSlot) { 163aa32c30b81134fc7ebd9408f4757d1dc4410f338Jeff Brown // FIXME: This is really broken but we have CTS tests that depend 164aa32c30b81134fc7ebd9408f4757d1dc4410f338Jeff Brown // on this legacy behavior. 165aa32c30b81134fc7ebd9408f4757d1dc4410f338Jeff Brown //throwExceptionWithRowCol(env, row, column); 1660cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown return CursorWindow::FIELD_TYPE_NULL; 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1680cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown return window->getFieldSlotType(fieldSlot); 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1713bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jbyteArray nativeGetBlob(JNIEnv* env, jclass clazz, jint windowPtr, 1723bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jint row, jint column) { 1733bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); 1743bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown LOG_WINDOW("Getting blob for %d,%d from %p", row, column, window); 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1760cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column); 1773bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown if (!fieldSlot) { 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throwExceptionWithRowCol(env, row, column); 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1820cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown int32_t type = window->getFieldSlotType(fieldSlot); 1830cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown if (type == CursorWindow::FIELD_TYPE_BLOB || type == CursorWindow::FIELD_TYPE_STRING) { 1840cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown size_t size; 1850cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown const void* value = window->getFieldSlotValueBlob(fieldSlot, &size); 1863bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jbyteArray byteArray = env->NewByteArray(size); 187e6044145bccf30e2b1785eb33a26de6496167986Vasu Nori if (!byteArray) { 1883bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown env->ExceptionClear(); 189e6044145bccf30e2b1785eb33a26de6496167986Vasu Nori throw_sqlite3_exception(env, "Native could not create new byte[]"); 190e6044145bccf30e2b1785eb33a26de6496167986Vasu Nori return NULL; 191e6044145bccf30e2b1785eb33a26de6496167986Vasu Nori } 1920cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown env->SetByteArrayRegion(byteArray, 0, size, static_cast<const jbyte*>(value)); 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return byteArray; 1940cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } else if (type == CursorWindow::FIELD_TYPE_INTEGER) { 1953bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown throw_sqlite3_exception(env, "INTEGER data in nativeGetBlob "); 1960cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } else if (type == CursorWindow::FIELD_TYPE_FLOAT) { 1973bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown throw_sqlite3_exception(env, "FLOAT data in nativeGetBlob "); 1980cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } else if (type == CursorWindow::FIELD_TYPE_NULL) { 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // do nothing 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2013bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown throwUnknownTypeException(env, type); 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2063bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jstring nativeGetString(JNIEnv* env, jclass clazz, jint windowPtr, 2073bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jint row, jint column) { 2083bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); 2093bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown LOG_WINDOW("Getting string for %d,%d from %p", row, column, window); 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2110cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column); 2123bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown if (!fieldSlot) { 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throwExceptionWithRowCol(env, row, column); 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2170cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown int32_t type = window->getFieldSlotType(fieldSlot); 2180cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown if (type == CursorWindow::FIELD_TYPE_STRING) { 2190cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown size_t sizeIncludingNull; 2200cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull); 2210cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown if (sizeIncludingNull <= 1) { 222715311fa5aeb39fd0904209e1428a3656c721c3dJeff Brown return gEmptyString; 223715311fa5aeb39fd0904209e1428a3656c721c3dJeff Brown } 224715311fa5aeb39fd0904209e1428a3656c721c3dJeff Brown // Convert to UTF-16 here instead of calling NewStringUTF. NewStringUTF 225715311fa5aeb39fd0904209e1428a3656c721c3dJeff Brown // doesn't like UTF-8 strings with high codepoints. It actually expects 226715311fa5aeb39fd0904209e1428a3656c721c3dJeff Brown // Modified UTF-8 with encoded surrogate pairs. 2270cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown String16 utf16(value, sizeIncludingNull - 1); 228715311fa5aeb39fd0904209e1428a3656c721c3dJeff Brown return env->NewString(reinterpret_cast<const jchar*>(utf16.string()), utf16.size()); 2290cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } else if (type == CursorWindow::FIELD_TYPE_INTEGER) { 2303bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown int64_t value = window->getFieldSlotValueLong(fieldSlot); 2313bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown char buf[32]; 2323bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown snprintf(buf, sizeof(buf), "%lld", value); 2333bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown return env->NewStringUTF(buf); 2340cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } else if (type == CursorWindow::FIELD_TYPE_FLOAT) { 2353bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown double value = window->getFieldSlotValueDouble(fieldSlot); 2363bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown char buf[32]; 2373bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown snprintf(buf, sizeof(buf), "%g", value); 2383bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown return env->NewStringUTF(buf); 2390cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } else if (type == CursorWindow::FIELD_TYPE_NULL) { 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 2410cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } else if (type == CursorWindow::FIELD_TYPE_BLOB) { 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw_sqlite3_exception(env, "Unable to convert BLOB to string"); 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2453bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown throwUnknownTypeException(env, type); 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2503bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jcharArray allocCharArrayBuffer(JNIEnv* env, jobject bufferObj, size_t size) { 2513bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jcharArray dataObj = jcharArray(env->GetObjectField(bufferObj, 2523bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown gCharArrayBufferClassInfo.data)); 2533bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown if (dataObj && size) { 2543bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jsize capacity = env->GetArrayLength(dataObj); 2553bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown if (size_t(capacity) < size) { 2563bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown env->DeleteLocalRef(dataObj); 2573bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown dataObj = NULL; 2583bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown } 2593bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown } 2603bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown if (!dataObj) { 2613bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jsize capacity = size; 2623bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown if (capacity < 64) { 2633bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown capacity = 64; 2643bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown } 2653bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown dataObj = env->NewCharArray(capacity); // might throw OOM 2663bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown if (dataObj) { 2673bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown env->SetObjectField(bufferObj, gCharArrayBufferClassInfo.data, dataObj); 2683bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown } 2693bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown } 2703bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown return dataObj; 2713bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown} 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2733bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic void fillCharArrayBufferUTF(JNIEnv* env, jobject bufferObj, 2743bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown const char* str, size_t len) { 2753bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown ssize_t size = utf8_to_utf16_length(reinterpret_cast<const uint8_t*>(str), len); 2763bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown if (size < 0) { 2773bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown size = 0; // invalid UTF8 string 2783bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown } 2793bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jcharArray dataObj = allocCharArrayBuffer(env, bufferObj, size); 2803bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown if (dataObj) { 2813bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown if (size) { 2823bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jchar* data = static_cast<jchar*>(env->GetPrimitiveArrayCritical(dataObj, NULL)); 283d0ff68da6a606602235fb8749473999e3d1bde53Jeff Brown utf8_to_utf16_no_null_terminator(reinterpret_cast<const uint8_t*>(str), len, 2843bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown reinterpret_cast<char16_t*>(data)); 2853bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown env->ReleasePrimitiveArrayCritical(dataObj, data, 0); 2863bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown } 2873bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown env->SetIntField(bufferObj, gCharArrayBufferClassInfo.sizeCopied, size); 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2893bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown} 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2913bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic void clearCharArrayBuffer(JNIEnv* env, jobject bufferObj) { 2923bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jcharArray dataObj = allocCharArrayBuffer(env, bufferObj, 0); 2933bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown if (dataObj) { 2943bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown env->SetIntField(bufferObj, gCharArrayBufferClassInfo.sizeCopied, 0); 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2963bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown} 29703d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana 2983bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic void nativeCopyStringToBuffer(JNIEnv* env, jclass clazz, jint windowPtr, 2993bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jint row, jint column, jobject bufferObj) { 3003bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); 3013bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown LOG_WINDOW("Copying string for %d,%d from %p", row, column, window); 3023bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown 3030cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column); 3043bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown if (!fieldSlot) { 3053bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown throwExceptionWithRowCol(env, row, column); 3063bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown return; 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3083bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown 3090cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown int32_t type = window->getFieldSlotType(fieldSlot); 3100cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown if (type == CursorWindow::FIELD_TYPE_STRING) { 3110cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown size_t sizeIncludingNull; 3120cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull); 3130cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown if (sizeIncludingNull > 1) { 3140cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown fillCharArrayBufferUTF(env, bufferObj, value, sizeIncludingNull - 1); 3153bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown } else { 3163bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown clearCharArrayBuffer(env, bufferObj); 3173bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown } 3180cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } else if (type == CursorWindow::FIELD_TYPE_INTEGER) { 3193bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown int64_t value = window->getFieldSlotValueLong(fieldSlot); 3203bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown char buf[32]; 3213bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown snprintf(buf, sizeof(buf), "%lld", value); 3223bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown fillCharArrayBufferUTF(env, bufferObj, buf, strlen(buf)); 3230cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } else if (type == CursorWindow::FIELD_TYPE_FLOAT) { 3243bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown double value = window->getFieldSlotValueDouble(fieldSlot); 3253bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown char buf[32]; 3263bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown snprintf(buf, sizeof(buf), "%g", value); 3273bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown fillCharArrayBufferUTF(env, bufferObj, buf, strlen(buf)); 3280cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } else if (type == CursorWindow::FIELD_TYPE_NULL) { 3293bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown clearCharArrayBuffer(env, bufferObj); 3300cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } else if (type == CursorWindow::FIELD_TYPE_BLOB) { 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw_sqlite3_exception(env, "Unable to convert BLOB to string"); 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3333bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown throwUnknownTypeException(env, type); 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3373bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jlong nativeGetLong(JNIEnv* env, jclass clazz, jint windowPtr, 3383bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jint row, jint column) { 3393bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); 3403bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown LOG_WINDOW("Getting long for %d,%d from %p", row, column, window); 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3420cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column); 3433bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown if (!fieldSlot) { 3443bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown throwExceptionWithRowCol(env, row, column); 3453bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown return 0; 3463bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown } 3473bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown 3480cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown int32_t type = window->getFieldSlotType(fieldSlot); 3490cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown if (type == CursorWindow::FIELD_TYPE_INTEGER) { 3503bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown return window->getFieldSlotValueLong(fieldSlot); 3510cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } else if (type == CursorWindow::FIELD_TYPE_STRING) { 3520cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown size_t sizeIncludingNull; 3530cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull); 3540cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown return sizeIncludingNull > 1 ? strtoll(value, NULL, 0) : 0L; 3550cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } else if (type == CursorWindow::FIELD_TYPE_FLOAT) { 3563bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown return jlong(window->getFieldSlotValueDouble(fieldSlot)); 3570cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } else if (type == CursorWindow::FIELD_TYPE_NULL) { 3583bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown return 0; 3590cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } else if (type == CursorWindow::FIELD_TYPE_BLOB) { 3603bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown throw_sqlite3_exception(env, "Unable to convert BLOB to long"); 3613bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown return 0; 3623bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown } else { 3633bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown throwUnknownTypeException(env, type); 3643bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown return 0; 3653bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown } 3663bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown} 3673bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown 3683bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jdouble nativeGetDouble(JNIEnv* env, jclass clazz, jint windowPtr, 3693bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jint row, jint column) { 3703bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); 3713bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown LOG_WINDOW("Getting double for %d,%d from %p", row, column, window); 3723bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown 3730cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column); 3743bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown if (!fieldSlot) { 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throwExceptionWithRowCol(env, row, column); 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0.0; 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3790cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown int32_t type = window->getFieldSlotType(fieldSlot); 3800cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown if (type == CursorWindow::FIELD_TYPE_FLOAT) { 3813bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown return window->getFieldSlotValueDouble(fieldSlot); 3820cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } else if (type == CursorWindow::FIELD_TYPE_STRING) { 3830cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown size_t sizeIncludingNull; 3840cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull); 3850cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown return sizeIncludingNull > 1 ? strtod(value, NULL) : 0.0; 3860cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } else if (type == CursorWindow::FIELD_TYPE_INTEGER) { 3873bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown return jdouble(window->getFieldSlotValueLong(fieldSlot)); 3880cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } else if (type == CursorWindow::FIELD_TYPE_NULL) { 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0.0; 3900cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } else if (type == CursorWindow::FIELD_TYPE_BLOB) { 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw_sqlite3_exception(env, "Unable to convert BLOB to double"); 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0.0; 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3943bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown throwUnknownTypeException(env, type); 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0.0; 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3993bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jboolean nativePutBlob(JNIEnv* env, jclass clazz, jint windowPtr, 4003bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jbyteArray valueObj, jint row, jint column) { 4013bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); 4023bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jsize len = env->GetArrayLength(valueObj); 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4043bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown void* value = env->GetPrimitiveArrayCritical(valueObj, NULL); 4050cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown status_t status = window->putBlob(row, column, value, len); 4063bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown env->ReleasePrimitiveArrayCritical(valueObj, value, JNI_ABORT); 4073bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown 4080cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown if (status) { 4090cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown LOG_WINDOW("Failed to put blob. error=%d", status); 4100cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown return false; 4110cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown } 4120cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown 4130cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown LOG_WINDOW("%d,%d is BLOB with %u bytes", row, column, len); 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4173bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jboolean nativePutString(JNIEnv* env, jclass clazz, jint windowPtr, 4183bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jstring valueObj, jint row, jint column) { 4193bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4210cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown size_t sizeIncludingNull = env->GetStringUTFLength(valueObj) + 1; 4223bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown const char* valueStr = env->GetStringUTFChars(valueObj, NULL); 4233bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown if (!valueStr) { 4240cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown LOG_WINDOW("value can't be transferred to UTFChars"); 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4270cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown status_t status = window->putString(row, column, valueStr, sizeIncludingNull); 4280cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown env->ReleaseStringUTFChars(valueObj, valueStr); 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4300cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown if (status) { 4310cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown LOG_WINDOW("Failed to put string. error=%d", status); 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4350cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown LOG_WINDOW("%d,%d is TEXT with %u bytes", row, column, sizeIncludingNull); 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4393bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jboolean nativePutLong(JNIEnv* env, jclass clazz, jint windowPtr, 4403bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jlong value, jint row, jint column) { 4413bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); 4420cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown status_t status = window->putLong(row, column, value); 4430cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown 4440cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown if (status) { 4450cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown LOG_WINDOW("Failed to put long. error=%d", status); 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4493bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown LOG_WINDOW("%d,%d is INTEGER 0x%016llx", row, column, value); 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4533bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jboolean nativePutDouble(JNIEnv* env, jclass clazz, jint windowPtr, 4543bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jdouble value, jint row, jint column) { 4553bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); 4560cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown status_t status = window->putDouble(row, column, value); 4570cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown 4580cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown if (status) { 4590cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown LOG_WINDOW("Failed to put double. error=%d", status); 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4633bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown LOG_WINDOW("%d,%d is FLOAT %lf", row, column, value); 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4673bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jboolean nativePutNull(JNIEnv* env, jclass clazz, jint windowPtr, 4683bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown jint row, jint column) { 4693bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr); 4700cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown status_t status = window->putNull(row, column); 4710cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown 4720cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown if (status) { 4730cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown LOG_WINDOW("Failed to put null. error=%d", status); 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4773bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown LOG_WINDOW("%d,%d is NULL", row, column); 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic JNINativeMethod sMethods[] = 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 4833bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown /* name, signature, funcPtr */ 4845e5d6d8ba04d7579df840cda055cd5dfa9d7666fJeff Brown { "nativeCreate", "(Ljava/lang/String;I)I", 4850cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown (void*)nativeCreate }, 4860cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown { "nativeCreateFromParcel", "(Landroid/os/Parcel;)I", 4870cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown (void*)nativeCreateFromParcel }, 4883bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown { "nativeDispose", "(I)V", 4893bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown (void*)nativeDispose }, 4900cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown { "nativeWriteToParcel", "(ILandroid/os/Parcel;)V", 4910cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown (void*)nativeWriteToParcel }, 49289101cd9d9b5c1a6ff1ed85eba0613ca4c4802e2Jeff Brown { "nativeGetName", "(I)Ljava/lang/String;", 49389101cd9d9b5c1a6ff1ed85eba0613ca4c4802e2Jeff Brown (void*)nativeGetName }, 4943bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown { "nativeClear", "(I)V", 4953bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown (void*)nativeClear }, 4963bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown { "nativeGetNumRows", "(I)I", 4973bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown (void*)nativeGetNumRows }, 4983bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown { "nativeSetNumColumns", "(II)Z", 4993bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown (void*)nativeSetNumColumns }, 5003bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown { "nativeAllocRow", "(I)Z", 5013bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown (void*)nativeAllocRow }, 5023bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown { "nativeFreeLastRow", "(I)V", 5033bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown (void*)nativeFreeLastRow }, 5043bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown { "nativeGetType", "(III)I", 5053bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown (void*)nativeGetType }, 5063bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown { "nativeGetBlob", "(III)[B", 5073bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown (void*)nativeGetBlob }, 5083bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown { "nativeGetString", "(III)Ljava/lang/String;", 5093bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown (void*)nativeGetString }, 5103bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown { "nativeGetLong", "(III)J", 5113bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown (void*)nativeGetLong }, 5123bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown { "nativeGetDouble", "(III)D", 5133bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown (void*)nativeGetDouble }, 5143bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown { "nativeCopyStringToBuffer", "(IIILandroid/database/CharArrayBuffer;)V", 5153bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown (void*)nativeCopyStringToBuffer }, 5163bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown { "nativePutBlob", "(I[BII)Z", 5173bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown (void*)nativePutBlob }, 5183bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown { "nativePutString", "(ILjava/lang/String;II)Z", 5193bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown (void*)nativePutString }, 5203bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown { "nativePutLong", "(IJII)Z", 5213bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown (void*)nativePutLong }, 5223bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown { "nativePutDouble", "(IDII)Z", 5233bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown (void*)nativePutDouble }, 5243bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown { "nativePutNull", "(III)Z", 5253bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown (void*)nativePutNull }, 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}; 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5283bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown#define FIND_CLASS(var, className) \ 5293bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown var = env->FindClass(className); \ 5303bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown LOG_FATAL_IF(! var, "Unable to find class " className); 5313bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown 5323bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ 5333bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ 5343bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown LOG_FATAL_IF(! var, "Unable to find field " fieldName); 5353bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint register_android_database_CursorWindow(JNIEnv * env) 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jclass clazz; 5393bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown FIND_CLASS(clazz, "android/database/CharArrayBuffer"); 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5413bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown GET_FIELD_ID(gCharArrayBufferClassInfo.data, clazz, 5423bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown "data", "[C"); 5433bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown GET_FIELD_ID(gCharArrayBufferClassInfo.sizeCopied, clazz, 5443bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown "sizeCopied", "I"); 5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5463bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown gEmptyString = jstring(env->NewGlobalRef(env->NewStringUTF(""))); 5473bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown LOG_FATAL_IF(!gEmptyString, "Unable to create empty string"); 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return AndroidRuntime::registerNativeMethods(env, "android/database/CursorWindow", 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sMethods, NELEM(sMethods)); 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} // namespace android 554