android_database_CursorWindow.cpp revision 0cde89f5f025b7826be009ebb9673b970e180e32
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
600cde89f5f025b7826be009ebb9673b970e180e32Jeff Brownstatic jint nativeCreate(JNIEnv* env, jclass clazz,
610cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        jstring nameObj, jint cursorWindowSize, jboolean localOnly) {
620cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    String8 name;
630cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (nameObj) {
640cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
650cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        name.setTo(nameStr);
660cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        env->ReleaseStringUTFChars(nameObj, nameStr);
670cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    }
680cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (name.size() == 0) {
690cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        name.setTo("<unnamed>");
700cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    }
710cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown
720cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    CursorWindow* window;
730cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = CursorWindow::create(name, cursorWindowSize, localOnly, &window);
740cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (status || !window) {
750cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        LOGE("Could not allocate CursorWindow '%s' of size %d due to error %d.",
760cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown                name.string(), cursorWindowSize, status);
773bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return 0;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
803bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("nativeInitializeEmpty: window = %p", window);
813bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    return reinterpret_cast<jint>(window);
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
840cde89f5f025b7826be009ebb9673b970e180e32Jeff Brownstatic jint nativeCreateFromParcel(JNIEnv* env, jclass clazz, jobject parcelObj) {
850cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    Parcel* parcel = parcelForJavaObject(env, parcelObj);
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
870cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    CursorWindow* window;
880cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = CursorWindow::createFromParcel(parcel, &window);
890cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (status || !window) {
900cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        LOGE("Could not create CursorWindow from Parcel due to error %d.", status);
913bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return 0;
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
943bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("nativeInitializeFromBinder: numRows = %d, numColumns = %d, window = %p",
953bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            window->getNumRows(), window->getNumColumns(), window);
963bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    return reinterpret_cast<jint>(window);
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
993bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic void nativeDispose(JNIEnv* env, jclass clazz, jint windowPtr) {
1003bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
1013bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (window) {
1023bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        LOG_WINDOW("Closing window %p", window);
1033bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        delete window;
1043bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    }
1053bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown}
1063bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown
1070cde89f5f025b7826be009ebb9673b970e180e32Jeff Brownstatic void nativeWriteToParcel(JNIEnv * env, jclass clazz, jint windowPtr,
1080cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        jobject parcelObj) {
1093bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
1100cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    Parcel* parcel = parcelForJavaObject(env, parcelObj);
1110cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown
1120cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = window->writeToParcel(parcel);
1130cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (status) {
1140cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        String8 msg;
1150cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        msg.appendFormat("Could not write CursorWindow to Parcel due to error %d.", status);
1160cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        jniThrowRuntimeException(env, msg.string());
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1203bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic void nativeClear(JNIEnv * env, jclass clazz, jint windowPtr) {
1213bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
1223bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("Clearing window %p", window);
1230cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = window->clear();
1240cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (status) {
1250cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        LOG_WINDOW("Could not clear window. error=%d", status);
1260cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    }
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1293bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jint nativeGetNumRows(JNIEnv* env, jclass clazz, jint windowPtr) {
1303bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
1313bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    return window->getNumRows();
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1343bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jboolean nativeSetNumColumns(JNIEnv* env, jclass clazz, jint windowPtr,
1353bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jint columnNum) {
1363bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
1370cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = window->setNumColumns(columnNum);
1380cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    return status == OK;
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1413bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jboolean nativeAllocRow(JNIEnv* env, jclass clazz, jint windowPtr) {
1423bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
1430cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = window->allocRow();
1440cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    return status == OK;
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1473bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic void nativeFreeLastRow(JNIEnv* env, jclass clazz, jint windowPtr) {
1483bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
1493bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    window->freeLastRow();
1503bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown}
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1523bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jint nativeGetType(JNIEnv* env, jclass clazz, jint windowPtr,
1533bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jint row, jint column) {
1543bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
1553bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("returning column type affinity for %d,%d from %p", row, column, window);
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1570cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
1583bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (!fieldSlot) {
159aa32c30b81134fc7ebd9408f4757d1dc4410f338Jeff Brown        // FIXME: This is really broken but we have CTS tests that depend
160aa32c30b81134fc7ebd9408f4757d1dc4410f338Jeff Brown        // on this legacy behavior.
161aa32c30b81134fc7ebd9408f4757d1dc4410f338Jeff Brown        //throwExceptionWithRowCol(env, row, column);
1620cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        return CursorWindow::FIELD_TYPE_NULL;
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1640cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    return window->getFieldSlotType(fieldSlot);
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1673bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jbyteArray nativeGetBlob(JNIEnv* env, jclass clazz, jint windowPtr,
1683bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jint row, jint column) {
1693bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
1703bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("Getting blob for %d,%d from %p", row, column, window);
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1720cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
1733bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (!fieldSlot) {
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throwExceptionWithRowCol(env, row, column);
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1780cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    int32_t type = window->getFieldSlotType(fieldSlot);
1790cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (type == CursorWindow::FIELD_TYPE_BLOB || type == CursorWindow::FIELD_TYPE_STRING) {
1800cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        size_t size;
1810cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        const void* value = window->getFieldSlotValueBlob(fieldSlot, &size);
1823bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jbyteArray byteArray = env->NewByteArray(size);
183e6044145bccf30e2b1785eb33a26de6496167986Vasu Nori        if (!byteArray) {
1843bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            env->ExceptionClear();
185e6044145bccf30e2b1785eb33a26de6496167986Vasu Nori            throw_sqlite3_exception(env, "Native could not create new byte[]");
186e6044145bccf30e2b1785eb33a26de6496167986Vasu Nori            return NULL;
187e6044145bccf30e2b1785eb33a26de6496167986Vasu Nori        }
1880cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        env->SetByteArrayRegion(byteArray, 0, size, static_cast<const jbyte*>(value));
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return byteArray;
1900cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_INTEGER) {
1913bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        throw_sqlite3_exception(env, "INTEGER data in nativeGetBlob ");
1920cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_FLOAT) {
1933bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        throw_sqlite3_exception(env, "FLOAT data in nativeGetBlob ");
1940cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_NULL) {
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // do nothing
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
1973bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        throwUnknownTypeException(env, type);
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return NULL;
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2023bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jstring nativeGetString(JNIEnv* env, jclass clazz, jint windowPtr,
2033bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jint row, jint column) {
2043bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
2053bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("Getting string for %d,%d from %p", row, column, window);
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2070cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
2083bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (!fieldSlot) {
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throwExceptionWithRowCol(env, row, column);
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2130cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    int32_t type = window->getFieldSlotType(fieldSlot);
2140cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (type == CursorWindow::FIELD_TYPE_STRING) {
2150cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        size_t sizeIncludingNull;
2160cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull);
2170cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        if (sizeIncludingNull <= 1) {
218715311fa5aeb39fd0904209e1428a3656c721c3dJeff Brown            return gEmptyString;
219715311fa5aeb39fd0904209e1428a3656c721c3dJeff Brown        }
220715311fa5aeb39fd0904209e1428a3656c721c3dJeff Brown        // Convert to UTF-16 here instead of calling NewStringUTF.  NewStringUTF
221715311fa5aeb39fd0904209e1428a3656c721c3dJeff Brown        // doesn't like UTF-8 strings with high codepoints.  It actually expects
222715311fa5aeb39fd0904209e1428a3656c721c3dJeff Brown        // Modified UTF-8 with encoded surrogate pairs.
2230cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        String16 utf16(value, sizeIncludingNull - 1);
224715311fa5aeb39fd0904209e1428a3656c721c3dJeff Brown        return env->NewString(reinterpret_cast<const jchar*>(utf16.string()), utf16.size());
2250cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_INTEGER) {
2263bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        int64_t value = window->getFieldSlotValueLong(fieldSlot);
2273bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        char buf[32];
2283bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        snprintf(buf, sizeof(buf), "%lld", value);
2293bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return env->NewStringUTF(buf);
2300cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_FLOAT) {
2313bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        double value = window->getFieldSlotValueDouble(fieldSlot);
2323bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        char buf[32];
2333bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        snprintf(buf, sizeof(buf), "%g", value);
2343bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return env->NewStringUTF(buf);
2350cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_NULL) {
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
2370cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_BLOB) {
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, "Unable to convert BLOB to string");
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
2413bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        throwUnknownTypeException(env, type);
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2463bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jcharArray allocCharArrayBuffer(JNIEnv* env, jobject bufferObj, size_t size) {
2473bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    jcharArray dataObj = jcharArray(env->GetObjectField(bufferObj,
2483bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            gCharArrayBufferClassInfo.data));
2493bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (dataObj && size) {
2503bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jsize capacity = env->GetArrayLength(dataObj);
2513bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        if (size_t(capacity) < size) {
2523bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            env->DeleteLocalRef(dataObj);
2533bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            dataObj = NULL;
2543bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        }
2553bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    }
2563bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (!dataObj) {
2573bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jsize capacity = size;
2583bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        if (capacity < 64) {
2593bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            capacity = 64;
2603bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        }
2613bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        dataObj = env->NewCharArray(capacity); // might throw OOM
2623bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        if (dataObj) {
2633bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            env->SetObjectField(bufferObj, gCharArrayBufferClassInfo.data, dataObj);
2643bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        }
2653bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    }
2663bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    return dataObj;
2673bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown}
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2693bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic void fillCharArrayBufferUTF(JNIEnv* env, jobject bufferObj,
2703bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        const char* str, size_t len) {
2713bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    ssize_t size = utf8_to_utf16_length(reinterpret_cast<const uint8_t*>(str), len);
2723bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (size < 0) {
2733bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        size = 0; // invalid UTF8 string
2743bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    }
2753bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    jcharArray dataObj = allocCharArrayBuffer(env, bufferObj, size);
2763bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (dataObj) {
2773bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        if (size) {
2783bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            jchar* data = static_cast<jchar*>(env->GetPrimitiveArrayCritical(dataObj, NULL));
279d0ff68da6a606602235fb8749473999e3d1bde53Jeff Brown            utf8_to_utf16_no_null_terminator(reinterpret_cast<const uint8_t*>(str), len,
2803bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown                    reinterpret_cast<char16_t*>(data));
2813bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            env->ReleasePrimitiveArrayCritical(dataObj, data, 0);
2823bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        }
2833bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        env->SetIntField(bufferObj, gCharArrayBufferClassInfo.sizeCopied, size);
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2853bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown}
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2873bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic void clearCharArrayBuffer(JNIEnv* env, jobject bufferObj) {
2883bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    jcharArray dataObj = allocCharArrayBuffer(env, bufferObj, 0);
2893bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (dataObj) {
2903bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        env->SetIntField(bufferObj, gCharArrayBufferClassInfo.sizeCopied, 0);
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2923bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown}
29303d9490758c9318cee6d14d3cc5007556dce92d0Fred Quintana
2943bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic void nativeCopyStringToBuffer(JNIEnv* env, jclass clazz, jint windowPtr,
2953bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jint row, jint column, jobject bufferObj) {
2963bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
2973bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("Copying string for %d,%d from %p", row, column, window);
2983bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown
2990cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
3003bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (!fieldSlot) {
3013bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        throwExceptionWithRowCol(env, row, column);
3023bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return;
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3043bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown
3050cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    int32_t type = window->getFieldSlotType(fieldSlot);
3060cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (type == CursorWindow::FIELD_TYPE_STRING) {
3070cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        size_t sizeIncludingNull;
3080cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull);
3090cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        if (sizeIncludingNull > 1) {
3100cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown            fillCharArrayBufferUTF(env, bufferObj, value, sizeIncludingNull - 1);
3113bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        } else {
3123bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            clearCharArrayBuffer(env, bufferObj);
3133bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        }
3140cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_INTEGER) {
3153bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        int64_t value = window->getFieldSlotValueLong(fieldSlot);
3163bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        char buf[32];
3173bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        snprintf(buf, sizeof(buf), "%lld", value);
3183bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        fillCharArrayBufferUTF(env, bufferObj, buf, strlen(buf));
3190cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_FLOAT) {
3203bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        double value = window->getFieldSlotValueDouble(fieldSlot);
3213bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        char buf[32];
3223bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        snprintf(buf, sizeof(buf), "%g", value);
3233bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        fillCharArrayBufferUTF(env, bufferObj, buf, strlen(buf));
3240cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_NULL) {
3253bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        clearCharArrayBuffer(env, bufferObj);
3260cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_BLOB) {
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, "Unable to convert BLOB to string");
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
3293bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        throwUnknownTypeException(env, type);
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3333bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jlong nativeGetLong(JNIEnv* env, jclass clazz, jint windowPtr,
3343bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jint row, jint column) {
3353bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
3363bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("Getting long for %d,%d from %p", row, column, window);
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3380cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
3393bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (!fieldSlot) {
3403bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        throwExceptionWithRowCol(env, row, column);
3413bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return 0;
3423bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    }
3433bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown
3440cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    int32_t type = window->getFieldSlotType(fieldSlot);
3450cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (type == CursorWindow::FIELD_TYPE_INTEGER) {
3463bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return window->getFieldSlotValueLong(fieldSlot);
3470cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_STRING) {
3480cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        size_t sizeIncludingNull;
3490cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull);
3500cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        return sizeIncludingNull > 1 ? strtoll(value, NULL, 0) : 0L;
3510cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_FLOAT) {
3523bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return jlong(window->getFieldSlotValueDouble(fieldSlot));
3530cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_NULL) {
3543bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return 0;
3550cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_BLOB) {
3563bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        throw_sqlite3_exception(env, "Unable to convert BLOB to long");
3573bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return 0;
3583bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    } else {
3593bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        throwUnknownTypeException(env, type);
3603bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return 0;
3613bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    }
3623bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown}
3633bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown
3643bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jdouble nativeGetDouble(JNIEnv* env, jclass clazz, jint windowPtr,
3653bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jint row, jint column) {
3663bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
3673bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("Getting double for %d,%d from %p", row, column, window);
3683bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown
3690cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
3703bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (!fieldSlot) {
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throwExceptionWithRowCol(env, row, column);
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0.0;
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3750cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    int32_t type = window->getFieldSlotType(fieldSlot);
3760cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (type == CursorWindow::FIELD_TYPE_FLOAT) {
3773bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return window->getFieldSlotValueDouble(fieldSlot);
3780cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_STRING) {
3790cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        size_t sizeIncludingNull;
3800cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull);
3810cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        return sizeIncludingNull > 1 ? strtod(value, NULL) : 0.0;
3820cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_INTEGER) {
3833bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        return jdouble(window->getFieldSlotValueLong(fieldSlot));
3840cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_NULL) {
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0.0;
3860cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    } else if (type == CursorWindow::FIELD_TYPE_BLOB) {
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw_sqlite3_exception(env, "Unable to convert BLOB to double");
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0.0;
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
3903bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        throwUnknownTypeException(env, type);
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0.0;
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3953bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jboolean nativePutBlob(JNIEnv* env, jclass clazz, jint windowPtr,
3963bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jbyteArray valueObj, jint row, jint column) {
3973bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
3983bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    jsize len = env->GetArrayLength(valueObj);
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4003bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    void* value = env->GetPrimitiveArrayCritical(valueObj, NULL);
4010cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = window->putBlob(row, column, value, len);
4023bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    env->ReleasePrimitiveArrayCritical(valueObj, value, JNI_ABORT);
4033bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown
4040cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (status) {
4050cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        LOG_WINDOW("Failed to put blob. error=%d", status);
4060cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        return false;
4070cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    }
4080cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown
4090cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    LOG_WINDOW("%d,%d is BLOB with %u bytes", row, column, len);
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return true;
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4133bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jboolean nativePutString(JNIEnv* env, jclass clazz, jint windowPtr,
4143bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jstring valueObj, jint row, jint column) {
4153bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4170cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    size_t sizeIncludingNull = env->GetStringUTFLength(valueObj) + 1;
4183bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    const char* valueStr = env->GetStringUTFChars(valueObj, NULL);
4193bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    if (!valueStr) {
4200cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        LOG_WINDOW("value can't be transferred to UTFChars");
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4230cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = window->putString(row, column, valueStr, sizeIncludingNull);
4240cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    env->ReleaseStringUTFChars(valueObj, valueStr);
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4260cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (status) {
4270cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        LOG_WINDOW("Failed to put string. error=%d", status);
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4310cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    LOG_WINDOW("%d,%d is TEXT with %u bytes", row, column, sizeIncludingNull);
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return true;
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4353bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jboolean nativePutLong(JNIEnv* env, jclass clazz, jint windowPtr,
4363bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jlong value, jint row, jint column) {
4373bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
4380cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = window->putLong(row, column, value);
4390cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown
4400cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (status) {
4410cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        LOG_WINDOW("Failed to put long. error=%d", status);
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4453bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("%d,%d is INTEGER 0x%016llx", row, column, value);
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return true;
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4493bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jboolean nativePutDouble(JNIEnv* env, jclass clazz, jint windowPtr,
4503bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jdouble value, jint row, jint column) {
4513bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
4520cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = window->putDouble(row, column, value);
4530cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown
4540cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (status) {
4550cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        LOG_WINDOW("Failed to put double. error=%d", status);
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4593bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("%d,%d is FLOAT %lf", row, column, value);
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return true;
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4633bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brownstatic jboolean nativePutNull(JNIEnv* env, jclass clazz, jint windowPtr,
4643bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        jint row, jint column) {
4653bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
4660cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    status_t status = window->putNull(row, column);
4670cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown
4680cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    if (status) {
4690cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown        LOG_WINDOW("Failed to put null. error=%d", status);
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4733bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_WINDOW("%d,%d is NULL", row, column);
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return true;
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic JNINativeMethod sMethods[] =
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
4793bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    /* name, signature, funcPtr */
4800cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    { "nativeCreate", "(Ljava/lang/String;IZ)I",
4810cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown            (void*)nativeCreate },
4820cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    { "nativeCreateFromParcel", "(Landroid/os/Parcel;)I",
4830cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown            (void*)nativeCreateFromParcel },
4843bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    { "nativeDispose", "(I)V",
4853bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeDispose },
4860cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown    { "nativeWriteToParcel", "(ILandroid/os/Parcel;)V",
4870cde89f5f025b7826be009ebb9673b970e180e32Jeff Brown            (void*)nativeWriteToParcel },
4883bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    { "nativeClear", "(I)V",
4893bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeClear },
4903bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    { "nativeGetNumRows", "(I)I",
4913bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeGetNumRows },
4923bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    { "nativeSetNumColumns", "(II)Z",
4933bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeSetNumColumns },
4943bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    { "nativeAllocRow", "(I)Z",
4953bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeAllocRow },
4963bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    { "nativeFreeLastRow", "(I)V",
4973bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeFreeLastRow },
4983bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    { "nativeGetType", "(III)I",
4993bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeGetType },
5003bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    { "nativeGetBlob", "(III)[B",
5013bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeGetBlob },
5023bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    { "nativeGetString", "(III)Ljava/lang/String;",
5033bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeGetString },
5043bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    { "nativeGetLong", "(III)J",
5053bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeGetLong },
5063bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    { "nativeGetDouble", "(III)D",
5073bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeGetDouble },
5083bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    { "nativeCopyStringToBuffer", "(IIILandroid/database/CharArrayBuffer;)V",
5093bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativeCopyStringToBuffer },
5103bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    { "nativePutBlob", "(I[BII)Z",
5113bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativePutBlob },
5123bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    { "nativePutString", "(ILjava/lang/String;II)Z",
5133bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativePutString },
5143bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    { "nativePutLong", "(IJII)Z",
5153bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativePutLong },
5163bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    { "nativePutDouble", "(IDII)Z",
5173bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativePutDouble },
5183bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    { "nativePutNull", "(III)Z",
5193bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            (void*)nativePutNull },
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5223bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown#define FIND_CLASS(var, className) \
5233bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        var = env->FindClass(className); \
5243bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        LOG_FATAL_IF(! var, "Unable to find class " className);
5253bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown
5263bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
5273bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
5283bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
5293bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint register_android_database_CursorWindow(JNIEnv * env)
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jclass clazz;
5333bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    FIND_CLASS(clazz, "android/database/CharArrayBuffer");
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5353bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    GET_FIELD_ID(gCharArrayBufferClassInfo.data, clazz,
5363bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            "data", "[C");
5373bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    GET_FIELD_ID(gCharArrayBufferClassInfo.sizeCopied, clazz,
5383bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown            "sizeCopied", "I");
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5403bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    gEmptyString = jstring(env->NewGlobalRef(env->NewStringUTF("")));
5413bc6bbc92cd2095f42039b5aadd0a14d0e5d9230Jeff Brown    LOG_FATAL_IF(!gEmptyString, "Unable to create empty string");
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return AndroidRuntime::registerNativeMethods(env, "android/database/CursorWindow",
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sMethods, NELEM(sMethods));
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} // namespace android
548