android_database_SQLiteConnection.cpp revision 676c519ec4509c799049bae5f6b20748ee5210c1
1e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown/*
2e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Copyright (C) 2011 The Android Open Source Project
3e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *
4e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
5e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * you may not use this file except in compliance with the License.
6e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * You may obtain a copy of the License at
7e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *
8e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
9e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown *
10e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Unless required by applicable law or agreed to in writing, software
11e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
12e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * See the License for the specific language governing permissions and
14e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * limitations under the License.
15e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown */
16e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
17e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#define LOG_TAG "SQLiteConnection"
18e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
19e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#include <jni.h>
20e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#include <JNIHelp.h>
21e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#include <android_runtime/AndroidRuntime.h>
22e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
23e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#include <utils/Log.h>
24e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#include <utils/String8.h>
25e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#include <utils/String16.h>
26e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#include <cutils/ashmem.h>
27e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#include <sys/mman.h>
28e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
29e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#include <string.h>
30e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#include <unistd.h>
31e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
3249d2b1864c3dfec6faff74d67cb2527a8f1af5a8Mathias Agopian#include <androidfw/CursorWindow.h>
33e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
34e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#include <sqlite3.h>
35e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#include <sqlite3_android.h>
36e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
37e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#include "android_database_SQLiteCommon.h"
38e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
391d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown// Set to 1 to use UTF16 storage for localized indexes.
40e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#define UTF16_STORAGE 0
41e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
42e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownnamespace android {
43e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
44676c519ec4509c799049bae5f6b20748ee5210c1Jeff Brown/* Busy timeout in milliseconds.
45676c519ec4509c799049bae5f6b20748ee5210c1Jeff Brown * If another connection (possibly in another process) has the database locked for
46676c519ec4509c799049bae5f6b20748ee5210c1Jeff Brown * longer than this amount of time then SQLite will generate a SQLITE_BUSY error.
47676c519ec4509c799049bae5f6b20748ee5210c1Jeff Brown * The SQLITE_BUSY error is then raised as a SQLiteDatabaseLockedException.
48676c519ec4509c799049bae5f6b20748ee5210c1Jeff Brown *
49676c519ec4509c799049bae5f6b20748ee5210c1Jeff Brown * In ordinary usage, busy timeouts are quite rare.  Most databases only ever
50676c519ec4509c799049bae5f6b20748ee5210c1Jeff Brown * have a single open connection at a time unless they are using WAL.  When using
51676c519ec4509c799049bae5f6b20748ee5210c1Jeff Brown * WAL, a timeout could occur if one connection is busy performing an auto-checkpoint
52676c519ec4509c799049bae5f6b20748ee5210c1Jeff Brown * operation.  The busy timeout needs to be long enough to tolerate slow I/O write
53676c519ec4509c799049bae5f6b20748ee5210c1Jeff Brown * operations but not so long as to cause the application to hang indefinitely if
54676c519ec4509c799049bae5f6b20748ee5210c1Jeff Brown * there is a problem acquiring a database lock.
55676c519ec4509c799049bae5f6b20748ee5210c1Jeff Brown */
56676c519ec4509c799049bae5f6b20748ee5210c1Jeff Brownstatic const int BUSY_TIMEOUT_MS = 2500;
57676c519ec4509c799049bae5f6b20748ee5210c1Jeff Brown
58e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic struct {
59e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    jfieldID name;
60e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    jfieldID numArgs;
61e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    jmethodID dispatchCallback;
62e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown} gSQLiteCustomFunctionClassInfo;
63e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
64e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic struct {
65e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    jclass clazz;
66e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown} gStringClassInfo;
67e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
68e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstruct SQLiteConnection {
69e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Open flags.
70e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Must be kept in sync with the constants defined in SQLiteDatabase.java.
71e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    enum {
72e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        OPEN_READWRITE          = 0x00000000,
73e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        OPEN_READONLY           = 0x00000001,
74e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        OPEN_READ_MASK          = 0x00000001,
75e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        NO_LOCALIZED_COLLATORS  = 0x00000010,
76e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        CREATE_IF_NECESSARY     = 0x10000000,
77e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    };
78e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
79e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3* const db;
80e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    const int openFlags;
81e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    const String8 path;
82e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    const String8 label;
83e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
8475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    volatile bool canceled;
8575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
86e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection(sqlite3* db, int openFlags, const String8& path, const String8& label) :
8775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        db(db), openFlags(openFlags), path(path), label(label), canceled(false) { }
88e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown};
89e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
90e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown// Called each time a statement begins execution, when tracing is enabled.
91e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic void sqliteTraceCallback(void *data, const char *sql) {
92e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = static_cast<SQLiteConnection*>(data);
93e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    ALOG(LOG_VERBOSE, SQLITE_TRACE_TAG, "%s: \"%s\"\n",
94e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            connection->label.string(), sql);
95e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
96e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
97e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown// Called each time a statement finishes execution, when profiling is enabled.
98e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic void sqliteProfileCallback(void *data, const char *sql, sqlite3_uint64 tm) {
99e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = static_cast<SQLiteConnection*>(data);
100e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    ALOG(LOG_VERBOSE, SQLITE_PROFILE_TAG, "%s: \"%s\" took %0.3f ms\n",
101e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            connection->label.string(), sql, tm * 0.000001f);
102e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
103e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
10475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown// Called after each SQLite VM instruction when cancelation is enabled.
10575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brownstatic int sqliteProgressHandlerCallback(void* data) {
10675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    SQLiteConnection* connection = static_cast<SQLiteConnection*>(data);
10775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    return connection->canceled;
10875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown}
10975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
110e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
111e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic jint nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFlags,
112e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jstring labelStr, jboolean enableTrace, jboolean enableProfile) {
113e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int sqliteFlags;
114e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (openFlags & SQLiteConnection::CREATE_IF_NECESSARY) {
115e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        sqliteFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
116e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    } else if (openFlags & SQLiteConnection::OPEN_READONLY) {
117e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        sqliteFlags = SQLITE_OPEN_READONLY;
118e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    } else {
119e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        sqliteFlags = SQLITE_OPEN_READWRITE;
120e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
121e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
122e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    const char* pathChars = env->GetStringUTFChars(pathStr, NULL);
123e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    String8 path(pathChars);
124e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    env->ReleaseStringUTFChars(pathStr, pathChars);
125e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
126e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    const char* labelChars = env->GetStringUTFChars(labelStr, NULL);
127e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    String8 label(labelChars);
128e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    env->ReleaseStringUTFChars(labelStr, labelChars);
129e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
130e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3* db;
131e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int err = sqlite3_open_v2(path.string(), &db, sqliteFlags, NULL);
132e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (err != SQLITE_OK) {
133e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throw_sqlite3_exception_errcode(env, err, "Could not open database");
134e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        return 0;
135e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
136e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
137330ec91e02406ba0d62e5672c6f0e2ed271f6898Jeff Brown    // Check that the database is really read/write when that is what we asked for.
138330ec91e02406ba0d62e5672c6f0e2ed271f6898Jeff Brown    if ((sqliteFlags & SQLITE_OPEN_READWRITE) && sqlite3_db_readonly(db, NULL)) {
139330ec91e02406ba0d62e5672c6f0e2ed271f6898Jeff Brown        throw_sqlite3_exception(env, db, "Could not open the database in read/write mode.");
140330ec91e02406ba0d62e5672c6f0e2ed271f6898Jeff Brown        sqlite3_close(db);
141330ec91e02406ba0d62e5672c6f0e2ed271f6898Jeff Brown        return 0;
142330ec91e02406ba0d62e5672c6f0e2ed271f6898Jeff Brown    }
143330ec91e02406ba0d62e5672c6f0e2ed271f6898Jeff Brown
144676c519ec4509c799049bae5f6b20748ee5210c1Jeff Brown    // Set the default busy handler to retry automatically before returning SQLITE_BUSY.
145676c519ec4509c799049bae5f6b20748ee5210c1Jeff Brown    err = sqlite3_busy_timeout(db, BUSY_TIMEOUT_MS);
146e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (err != SQLITE_OK) {
147e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throw_sqlite3_exception(env, db, "Could not set busy timeout");
148e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        sqlite3_close(db);
149e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        return 0;
150e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
151e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
152e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Register custom Android functions.
153e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    err = register_android_functions(db, UTF16_STORAGE);
154e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (err) {
155e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throw_sqlite3_exception(env, db, "Could not register Android SQL functions.");
156e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        sqlite3_close(db);
157e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        return 0;
158e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
159e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
160e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Create wrapper object.
161e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = new SQLiteConnection(db, openFlags, path, label);
162e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
163e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Enable tracing and profiling if requested.
164e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (enableTrace) {
165e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        sqlite3_trace(db, &sqliteTraceCallback, connection);
166e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
167e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (enableProfile) {
168e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        sqlite3_profile(db, &sqliteProfileCallback, connection);
169e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
170e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
171e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    ALOGV("Opened connection %p with label '%s'", db, label.string());
172e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    return reinterpret_cast<jint>(connection);
173e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
174e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
175e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic void nativeClose(JNIEnv* env, jclass clazz, jint connectionPtr) {
176e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
177e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
178e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (connection) {
179e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        ALOGV("Closing connection %p", connection->db);
180e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        int err = sqlite3_close(connection->db);
181e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (err != SQLITE_OK) {
182e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // This can happen if sub-objects aren't closed first.  Make sure the caller knows.
183e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            ALOGE("sqlite3_close(%p) failed: %d", connection->db, err);
184e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throw_sqlite3_exception(env, connection->db, "Count not close db.");
185e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            return;
186e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
187e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
188e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        delete connection;
189e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
190e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
191e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
192e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown// Called each time a custom function is evaluated.
193e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic void sqliteCustomFunctionCallback(sqlite3_context *context,
194e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        int argc, sqlite3_value **argv) {
195e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    JNIEnv* env = AndroidRuntime::getJNIEnv();
196e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
197e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Get the callback function object.
198e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Create a new local reference to it in case the callback tries to do something
199e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // dumb like unregister the function (thereby destroying the global ref) while it is running.
200e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    jobject functionObjGlobal = reinterpret_cast<jobject>(sqlite3_user_data(context));
201e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    jobject functionObj = env->NewLocalRef(functionObjGlobal);
202e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
203e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    jobjectArray argsArray = env->NewObjectArray(argc, gStringClassInfo.clazz, NULL);
204e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (argsArray) {
205e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        for (int i = 0; i < argc; i++) {
206e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            const jchar* arg = static_cast<const jchar*>(sqlite3_value_text16(argv[i]));
207e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (!arg) {
208e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                ALOGW("NULL argument in custom_function_callback.  This should not happen.");
209e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } else {
210e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                size_t argLen = sqlite3_value_bytes16(argv[i]) / sizeof(jchar);
211e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                jstring argStr = env->NewString(arg, argLen);
212e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                if (!argStr) {
213e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    goto error; // out of memory error
214e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                }
215e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                env->SetObjectArrayElement(argsArray, i, argStr);
216e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                env->DeleteLocalRef(argStr);
217e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
218e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
219e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
220e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // TODO: Support functions that return values.
221e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        env->CallVoidMethod(functionObj,
222e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                gSQLiteCustomFunctionClassInfo.dispatchCallback, argsArray);
223e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
224e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownerror:
225e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        env->DeleteLocalRef(argsArray);
226e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
227e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
228e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    env->DeleteLocalRef(functionObj);
229e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
230e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (env->ExceptionCheck()) {
231e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        ALOGE("An exception was thrown by custom SQLite function.");
232e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        LOGE_EX(env);
233e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        env->ExceptionClear();
234e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
235e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
236e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
237e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown// Called when a custom function is destroyed.
238e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic void sqliteCustomFunctionDestructor(void* data) {
239e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    jobject functionObjGlobal = reinterpret_cast<jobject>(data);
240e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
241e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    JNIEnv* env = AndroidRuntime::getJNIEnv();
242e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    env->DeleteGlobalRef(functionObjGlobal);
243e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
244e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
245e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic void nativeRegisterCustomFunction(JNIEnv* env, jclass clazz, jint connectionPtr,
246e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jobject functionObj) {
247e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
248e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
249e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    jstring nameStr = jstring(env->GetObjectField(
250e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            functionObj, gSQLiteCustomFunctionClassInfo.name));
251e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    jint numArgs = env->GetIntField(functionObj, gSQLiteCustomFunctionClassInfo.numArgs);
252e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
253e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    jobject functionObjGlobal = env->NewGlobalRef(functionObj);
254e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
255e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    const char* name = env->GetStringUTFChars(nameStr, NULL);
256e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int err = sqlite3_create_function_v2(connection->db, name, numArgs, SQLITE_UTF16,
257e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            reinterpret_cast<void*>(functionObjGlobal),
258e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            &sqliteCustomFunctionCallback, NULL, NULL, &sqliteCustomFunctionDestructor);
259e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    env->ReleaseStringUTFChars(nameStr, name);
260e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
261e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (err != SQLITE_OK) {
262e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        ALOGE("sqlite3_create_function returned %d", err);
263e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        env->DeleteGlobalRef(functionObjGlobal);
264e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throw_sqlite3_exception(env, connection->db);
265e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        return;
266e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
267e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
268e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
2691d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brownstatic void nativeRegisterLocalizedCollators(JNIEnv* env, jclass clazz, jint connectionPtr,
2701d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown        jstring localeStr) {
271e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
272e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
2731d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown    const char* locale = env->GetStringUTFChars(localeStr, NULL);
2741d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown    int err = register_localized_collators(connection->db, locale, UTF16_STORAGE);
2751d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown    env->ReleaseStringUTFChars(localeStr, locale);
276e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
277e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (err != SQLITE_OK) {
278e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throw_sqlite3_exception(env, connection->db);
279e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
280e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
281e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
282e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic jint nativePrepareStatement(JNIEnv* env, jclass clazz, jint connectionPtr,
283e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jstring sqlString) {
284e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
285e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
286e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    jsize sqlLength = env->GetStringLength(sqlString);
287e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    const jchar* sql = env->GetStringCritical(sqlString, NULL);
288e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3_stmt* statement;
289e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int err = sqlite3_prepare16_v2(connection->db,
290e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            sql, sqlLength * sizeof(jchar), &statement, NULL);
291e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    env->ReleaseStringCritical(sqlString, sql);
292e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
293e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (err != SQLITE_OK) {
294e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // Error messages like 'near ")": syntax error' are not
295e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // always helpful enough, so construct an error string that
296e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        // includes the query itself.
297e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        const char *query = env->GetStringUTFChars(sqlString, NULL);
298e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        char *message = (char*) malloc(strlen(query) + 50);
299e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (message) {
300e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            strcpy(message, ", while compiling: "); // less than 50 chars
301e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            strcat(message, query);
302e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
303e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        env->ReleaseStringUTFChars(sqlString, query);
304e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throw_sqlite3_exception(env, connection->db, message);
305e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        free(message);
306e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        return 0;
307e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
308e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
309e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    ALOGV("Prepared statement %p on connection %p", statement, connection->db);
310e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    return reinterpret_cast<jint>(statement);
311e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
312e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
313e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic void nativeFinalizeStatement(JNIEnv* env, jclass clazz, jint connectionPtr,
314e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jint statementPtr) {
315e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
316e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
317e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
318958cbbab6a35e1668419a2f7e2a2b75b9c8db807Jeff Brown    // We ignore the result of sqlite3_finalize because it is really telling us about
319958cbbab6a35e1668419a2f7e2a2b75b9c8db807Jeff Brown    // whether any errors occurred while executing the statement.  The statement itself
320958cbbab6a35e1668419a2f7e2a2b75b9c8db807Jeff Brown    // is always finalized regardless.
321e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    ALOGV("Finalized statement %p on connection %p", statement, connection->db);
322958cbbab6a35e1668419a2f7e2a2b75b9c8db807Jeff Brown    sqlite3_finalize(statement);
323e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
324e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
325e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic jint nativeGetParameterCount(JNIEnv* env, jclass clazz, jint connectionPtr,
326e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jint statementPtr) {
327e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
328e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
329e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
330e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    return sqlite3_bind_parameter_count(statement);
331e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
332e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
333e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic jboolean nativeIsReadOnly(JNIEnv* env, jclass clazz, jint connectionPtr,
334e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jint statementPtr) {
335e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
336e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
337e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
338e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    return sqlite3_stmt_readonly(statement) != 0;
339e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
340e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
341e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic jint nativeGetColumnCount(JNIEnv* env, jclass clazz, jint connectionPtr,
342e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jint statementPtr) {
343e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
344e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
345e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
346e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    return sqlite3_column_count(statement);
347e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
348e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
349e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic jstring nativeGetColumnName(JNIEnv* env, jclass clazz, jint connectionPtr,
350e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jint statementPtr, jint index) {
351e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
352e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
353e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
354e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    const jchar* name = static_cast<const jchar*>(sqlite3_column_name16(statement, index));
355e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (name) {
356e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        size_t length = 0;
357e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        while (name[length]) {
358e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            length += 1;
359e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
360e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        return env->NewString(name, length);
361e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
362e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    return NULL;
363e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
364e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
365e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic void nativeBindNull(JNIEnv* env, jclass clazz, jint connectionPtr,
366e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jint statementPtr, jint index) {
367e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
368e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
369e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
370e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int err = sqlite3_bind_null(statement, index);
371e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (err != SQLITE_OK) {
372e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throw_sqlite3_exception(env, connection->db, NULL);
373e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
374e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
375e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
376e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic void nativeBindLong(JNIEnv* env, jclass clazz, jint connectionPtr,
377e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jint statementPtr, jint index, jlong value) {
378e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
379e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
380e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
381e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int err = sqlite3_bind_int64(statement, index, value);
382e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (err != SQLITE_OK) {
383e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throw_sqlite3_exception(env, connection->db, NULL);
384e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
385e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
386e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
387e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic void nativeBindDouble(JNIEnv* env, jclass clazz, jint connectionPtr,
388e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jint statementPtr, jint index, jdouble value) {
389e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
390e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
391e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
392e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int err = sqlite3_bind_double(statement, index, value);
393e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (err != SQLITE_OK) {
394e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throw_sqlite3_exception(env, connection->db, NULL);
395e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
396e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
397e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
398e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic void nativeBindString(JNIEnv* env, jclass clazz, jint connectionPtr,
399e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jint statementPtr, jint index, jstring valueString) {
400e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
401e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
402e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
403e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    jsize valueLength = env->GetStringLength(valueString);
404e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    const jchar* value = env->GetStringCritical(valueString, NULL);
405e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int err = sqlite3_bind_text16(statement, index, value, valueLength * sizeof(jchar),
406e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            SQLITE_TRANSIENT);
407e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    env->ReleaseStringCritical(valueString, value);
408e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (err != SQLITE_OK) {
409e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throw_sqlite3_exception(env, connection->db, NULL);
410e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
411e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
412e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
413e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic void nativeBindBlob(JNIEnv* env, jclass clazz, jint connectionPtr,
414e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jint statementPtr, jint index, jbyteArray valueArray) {
415e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
416e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
417e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
418e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    jsize valueLength = env->GetArrayLength(valueArray);
419e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    jbyte* value = static_cast<jbyte*>(env->GetPrimitiveArrayCritical(valueArray, NULL));
420e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int err = sqlite3_bind_blob(statement, index, value, valueLength, SQLITE_TRANSIENT);
421e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    env->ReleasePrimitiveArrayCritical(valueArray, value, JNI_ABORT);
422e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (err != SQLITE_OK) {
423e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throw_sqlite3_exception(env, connection->db, NULL);
424e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
425e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
426e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
427e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic void nativeResetStatementAndClearBindings(JNIEnv* env, jclass clazz, jint connectionPtr,
428e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jint statementPtr) {
429e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
430e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
431e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
432e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int err = sqlite3_reset(statement);
433e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (err == SQLITE_OK) {
434e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        err = sqlite3_clear_bindings(statement);
435e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
436e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (err != SQLITE_OK) {
437e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throw_sqlite3_exception(env, connection->db, NULL);
438e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
439e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
440e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
441e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic int executeNonQuery(JNIEnv* env, SQLiteConnection* connection, sqlite3_stmt* statement) {
442e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int err = sqlite3_step(statement);
443e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (err == SQLITE_ROW) {
444e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throw_sqlite3_exception(env,
445e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                "Queries can be performed using SQLiteDatabase query or rawQuery methods only.");
446e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    } else if (err != SQLITE_DONE) {
447e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throw_sqlite3_exception_errcode(env, err, sqlite3_errmsg(connection->db));
448e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
449e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    return err;
450e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
451e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
452e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic void nativeExecute(JNIEnv* env, jclass clazz, jint connectionPtr,
453e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jint statementPtr) {
454e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
455e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
456e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
457e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    executeNonQuery(env, connection, statement);
458e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
459e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
460e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic jint nativeExecuteForChangedRowCount(JNIEnv* env, jclass clazz,
461e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jint connectionPtr, jint statementPtr) {
462e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
463e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
464e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
465e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int err = executeNonQuery(env, connection, statement);
466e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    return err == SQLITE_DONE ? sqlite3_changes(connection->db) : -1;
467e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
468e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
469e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic jlong nativeExecuteForLastInsertedRowId(JNIEnv* env, jclass clazz,
470e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jint connectionPtr, jint statementPtr) {
471e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
472e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
473e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
474e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int err = executeNonQuery(env, connection, statement);
475e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    return err == SQLITE_DONE && sqlite3_changes(connection->db) > 0
476e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            ? sqlite3_last_insert_rowid(connection->db) : -1;
477e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
478e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
479e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic int executeOneRowQuery(JNIEnv* env, SQLiteConnection* connection, sqlite3_stmt* statement) {
480e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int err = sqlite3_step(statement);
481e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (err != SQLITE_ROW) {
482e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throw_sqlite3_exception_errcode(env, err, sqlite3_errmsg(connection->db));
483e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
484e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    return err;
485e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
486e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
487e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic jlong nativeExecuteForLong(JNIEnv* env, jclass clazz,
488e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jint connectionPtr, jint statementPtr) {
489e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
490e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
491e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
492e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int err = executeOneRowQuery(env, connection, statement);
493e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (err == SQLITE_ROW && sqlite3_column_count(statement) >= 1) {
494e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        return sqlite3_column_int64(statement, 0);
495e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
496e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    return -1;
497e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
498e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
499e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic jstring nativeExecuteForString(JNIEnv* env, jclass clazz,
500e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jint connectionPtr, jint statementPtr) {
501e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
502e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
503e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
504e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int err = executeOneRowQuery(env, connection, statement);
505e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (err == SQLITE_ROW && sqlite3_column_count(statement) >= 1) {
506e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        const jchar* text = static_cast<const jchar*>(sqlite3_column_text16(statement, 0));
507e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (text) {
508e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            size_t length = sqlite3_column_bytes16(statement, 0) / sizeof(jchar);
509e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            return env->NewString(text, length);
510e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
511e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
512e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    return NULL;
513e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
514e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
515e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic int createAshmemRegionWithData(JNIEnv* env, const void* data, size_t length) {
516e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int error = 0;
517e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int fd = ashmem_create_region(NULL, length);
518e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (fd < 0) {
519e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        error = errno;
520e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        ALOGE("ashmem_create_region failed: %s", strerror(error));
521e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    } else {
522e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (length > 0) {
523e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            void* ptr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
524e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (ptr == MAP_FAILED) {
525e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                error = errno;
526e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                ALOGE("mmap failed: %s", strerror(error));
527e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } else {
528e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                memcpy(ptr, data, length);
529e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                munmap(ptr, length);
530e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
531e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
532e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
533e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (!error) {
534e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
535e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                error = errno;
536e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                ALOGE("ashmem_set_prot_region failed: %s", strerror(errno));
537e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } else {
538e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                return fd;
539e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
540e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
541e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
542e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        close(fd);
543e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
544e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
545e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    jniThrowIOException(env, error);
546e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    return -1;
547e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
548e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
549e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic jint nativeExecuteForBlobFileDescriptor(JNIEnv* env, jclass clazz,
550e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jint connectionPtr, jint statementPtr) {
551e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
552e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
553e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
554e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int err = executeOneRowQuery(env, connection, statement);
555e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (err == SQLITE_ROW && sqlite3_column_count(statement) >= 1) {
556e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        const void* blob = sqlite3_column_blob(statement, 0);
557e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (blob) {
558e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            int length = sqlite3_column_bytes(statement, 0);
559e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (length >= 0) {
560e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                return createAshmemRegionWithData(env, blob, length);
561e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
562e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
563e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
564e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    return -1;
565e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
566e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
567e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownenum CopyRowResult {
568e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    CPR_OK,
569e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    CPR_FULL,
570e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    CPR_ERROR,
571e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown};
572e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
573e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic CopyRowResult copyRow(JNIEnv* env, CursorWindow* window,
574e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        sqlite3_stmt* statement, int numColumns, int startPos, int addedRows) {
575e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Allocate a new field directory for the row.
576e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    status_t status = window->allocRow();
577e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (status) {
578e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        LOG_WINDOW("Failed allocating fieldDir at startPos %d row %d, error=%d",
579e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                startPos, addedRows, status);
580e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        return CPR_FULL;
581e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
582e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
583e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Pack the row into the window.
584e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    CopyRowResult result = CPR_OK;
585e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    for (int i = 0; i < numColumns; i++) {
586e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        int type = sqlite3_column_type(statement, i);
587e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (type == SQLITE_TEXT) {
588e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // TEXT data
589e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            const char* text = reinterpret_cast<const char*>(
590e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    sqlite3_column_text(statement, i));
591e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // SQLite does not include the NULL terminator in size, but does
592e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // ensure all strings are NULL terminated, so increase size by
593e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // one to make sure we store the terminator.
594e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            size_t sizeIncludingNull = sqlite3_column_bytes(statement, i) + 1;
595e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            status = window->putString(addedRows, i, text, sizeIncludingNull);
596e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (status) {
597e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                LOG_WINDOW("Failed allocating %u bytes for text at %d,%d, error=%d",
598e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        sizeIncludingNull, startPos + addedRows, i, status);
599e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                result = CPR_FULL;
600e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                break;
601e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
602e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            LOG_WINDOW("%d,%d is TEXT with %u bytes",
603e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    startPos + addedRows, i, sizeIncludingNull);
604e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } else if (type == SQLITE_INTEGER) {
605e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // INTEGER data
606e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            int64_t value = sqlite3_column_int64(statement, i);
607e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            status = window->putLong(addedRows, i, value);
608e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (status) {
609e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                LOG_WINDOW("Failed allocating space for a long in column %d, error=%d",
610e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        i, status);
611e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                result = CPR_FULL;
612e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                break;
613e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
614e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            LOG_WINDOW("%d,%d is INTEGER 0x%016llx", startPos + addedRows, i, value);
615e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } else if (type == SQLITE_FLOAT) {
616e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // FLOAT data
617e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            double value = sqlite3_column_double(statement, i);
618e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            status = window->putDouble(addedRows, i, value);
619e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (status) {
620e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                LOG_WINDOW("Failed allocating space for a double in column %d, error=%d",
621e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        i, status);
622e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                result = CPR_FULL;
623e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                break;
624e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
625e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            LOG_WINDOW("%d,%d is FLOAT %lf", startPos + addedRows, i, value);
626e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } else if (type == SQLITE_BLOB) {
627e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // BLOB data
628e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            const void* blob = sqlite3_column_blob(statement, i);
629e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            size_t size = sqlite3_column_bytes(statement, i);
630e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            status = window->putBlob(addedRows, i, blob, size);
631e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (status) {
632e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                LOG_WINDOW("Failed allocating %u bytes for blob at %d,%d, error=%d",
633e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        size, startPos + addedRows, i, status);
634e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                result = CPR_FULL;
635e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                break;
636e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
637e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            LOG_WINDOW("%d,%d is Blob with %u bytes",
638e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                    startPos + addedRows, i, size);
639e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } else if (type == SQLITE_NULL) {
640e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // NULL field
641e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            status = window->putNull(addedRows, i);
642e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (status) {
643e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                LOG_WINDOW("Failed allocating space for a null in column %d, error=%d",
644e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                        i, status);
645e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                result = CPR_FULL;
646e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                break;
647e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
648e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
649e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            LOG_WINDOW("%d,%d is NULL", startPos + addedRows, i);
650e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } else {
651e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // Unknown data
652e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            ALOGE("Unknown column type when filling database window");
653e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throw_sqlite3_exception(env, "Unknown column type when filling window");
654e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            result = CPR_ERROR;
655e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            break;
656e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
657e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
658e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
659e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Free the last row if if was not successfully copied.
660e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (result != CPR_OK) {
661e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        window->freeLastRow();
662e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
663e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    return result;
664e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
665e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
666e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic jlong nativeExecuteForCursorWindow(JNIEnv* env, jclass clazz,
667e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jint connectionPtr, jint statementPtr, jint windowPtr,
668e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        jint startPos, jint requiredPos, jboolean countAllRows) {
669e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
670e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
671e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
672e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
673e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    status_t status = window->clear();
674e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (status) {
675e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        String8 msg;
676e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        msg.appendFormat("Failed to clear the cursor window, status=%d", status);
677e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throw_sqlite3_exception(env, connection->db, msg.string());
678e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        return 0;
679e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
680e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
681e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int numColumns = sqlite3_column_count(statement);
682e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    status = window->setNumColumns(numColumns);
683e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (status) {
684e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        String8 msg;
685e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        msg.appendFormat("Failed to set the cursor window column count to %d, status=%d",
686e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                numColumns, status);
687e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        throw_sqlite3_exception(env, connection->db, msg.string());
688e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        return 0;
689e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
690e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
691e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int retryCount = 0;
692e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int totalRows = 0;
693e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int addedRows = 0;
694e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    bool windowFull = false;
695e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    bool gotException = false;
696e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    while (!gotException && (!windowFull || countAllRows)) {
697e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        int err = sqlite3_step(statement);
698e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        if (err == SQLITE_ROW) {
699e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            LOG_WINDOW("Stepped statement %p to row %d", statement, totalRows);
700e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            retryCount = 0;
701e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            totalRows += 1;
702e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
703e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // Skip the row if the window is full or we haven't reached the start position yet.
704e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (startPos >= totalRows || windowFull) {
705e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                continue;
706e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
707e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
708e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            CopyRowResult cpr = copyRow(env, window, statement, numColumns, startPos, addedRows);
709e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (cpr == CPR_FULL && addedRows && startPos + addedRows < requiredPos) {
710e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                // We filled the window before we got to the one row that we really wanted.
711e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                // Clear the window and start filling it again from here.
712e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                // TODO: Would be nicer if we could progressively replace earlier rows.
713e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                window->clear();
714e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                window->setNumColumns(numColumns);
715e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                startPos += addedRows;
716e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                addedRows = 0;
717e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                cpr = copyRow(env, window, statement, numColumns, startPos, addedRows);
718e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
719e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
720e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (cpr == CPR_OK) {
721e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                addedRows += 1;
722e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } else if (cpr == CPR_FULL) {
723e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                windowFull = true;
724e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } else {
725e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                gotException = true;
726e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
727e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } else if (err == SQLITE_DONE) {
728e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // All rows processed, bail
729e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            LOG_WINDOW("Processed all rows");
730e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            break;
731e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } else if (err == SQLITE_LOCKED || err == SQLITE_BUSY) {
732e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            // The table is locked, retry
733e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            LOG_WINDOW("Database locked, retrying");
734e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            if (retryCount > 50) {
735e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                ALOGE("Bailing on database busy retry");
736e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                throw_sqlite3_exception(env, connection->db, "retrycount exceeded");
737e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                gotException = true;
738e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            } else {
739e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                // Sleep to give the thread holding the lock a chance to finish
740e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                usleep(1000);
741e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown                retryCount++;
742e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            }
743e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        } else {
744e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            throw_sqlite3_exception(env, connection->db);
745e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            gotException = true;
746e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        }
747e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
748e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
749e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    LOG_WINDOW("Resetting statement %p after fetching %d rows and adding %d rows"
750e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            "to the window in %d bytes",
751e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            statement, totalRows, addedRows, window->size() - window->freeSpace());
752e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3_reset(statement);
753e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
754e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    // Report the total number of rows on request.
755e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    if (startPos > totalRows) {
756e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        ALOGE("startPos %d > actual rows %d", startPos, totalRows);
757e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    }
758e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    jlong result = jlong(startPos) << 32 | jlong(totalRows);
759e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    return result;
760e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
761e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
762e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic jint nativeGetDbLookaside(JNIEnv* env, jobject clazz, jint connectionPtr) {
763e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
764e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
765e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int cur = -1;
766e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    int unused;
767e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    sqlite3_db_status(connection->db, SQLITE_DBSTATUS_LOOKASIDE_USED, &cur, &unused, 0);
768e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    return cur;
769e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
770e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
77175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brownstatic void nativeCancel(JNIEnv* env, jobject clazz, jint connectionPtr) {
77275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
77375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    connection->canceled = true;
77475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown}
77575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
77675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brownstatic void nativeResetCancel(JNIEnv* env, jobject clazz, jint connectionPtr,
77775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        jboolean cancelable) {
77875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
77975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    connection->canceled = false;
78075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
78175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    if (cancelable) {
78275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        sqlite3_progress_handler(connection->db, 4, sqliteProgressHandlerCallback,
78375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                connection);
78475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    } else {
78575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        sqlite3_progress_handler(connection->db, 0, NULL, NULL);
78675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
78775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown}
78875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
789e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
790e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownstatic JNINativeMethod sMethods[] =
791e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown{
792e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    /* name, signature, funcPtr */
793e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeOpen", "(Ljava/lang/String;ILjava/lang/String;ZZ)I",
794e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeOpen },
795e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeClose", "(I)V",
796e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeClose },
797e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeRegisterCustomFunction", "(ILandroid/database/sqlite/SQLiteCustomFunction;)V",
798e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeRegisterCustomFunction },
7991d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown    { "nativeRegisterLocalizedCollators", "(ILjava/lang/String;)V",
8001d9f742e001ed8280fa93fd9ba0b1125ce6d00aeJeff Brown            (void*)nativeRegisterLocalizedCollators },
801e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativePrepareStatement", "(ILjava/lang/String;)I",
802e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativePrepareStatement },
803e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeFinalizeStatement", "(II)V",
804e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeFinalizeStatement },
805e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeGetParameterCount", "(II)I",
806e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeGetParameterCount },
807e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeIsReadOnly", "(II)Z",
808e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeIsReadOnly },
809e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeGetColumnCount", "(II)I",
810e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeGetColumnCount },
811e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeGetColumnName", "(III)Ljava/lang/String;",
812e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeGetColumnName },
813e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeBindNull", "(III)V",
814e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeBindNull },
815e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeBindLong", "(IIIJ)V",
816e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeBindLong },
817e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeBindDouble", "(IIID)V",
818e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeBindDouble },
819e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeBindString", "(IIILjava/lang/String;)V",
820e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeBindString },
821e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeBindBlob", "(III[B)V",
822e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeBindBlob },
823e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeResetStatementAndClearBindings", "(II)V",
824e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeResetStatementAndClearBindings },
825e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeExecute", "(II)V",
826e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeExecute },
827e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeExecuteForLong", "(II)J",
828e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeExecuteForLong },
829e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeExecuteForString", "(II)Ljava/lang/String;",
830e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeExecuteForString },
831e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeExecuteForBlobFileDescriptor", "(II)I",
832e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeExecuteForBlobFileDescriptor },
833e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeExecuteForChangedRowCount", "(II)I",
834e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeExecuteForChangedRowCount },
835e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeExecuteForLastInsertedRowId", "(II)J",
836e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeExecuteForLastInsertedRowId },
837e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeExecuteForCursorWindow", "(IIIIIZ)J",
838e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeExecuteForCursorWindow },
839e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    { "nativeGetDbLookaside", "(I)I",
840e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            (void*)nativeGetDbLookaside },
84175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    { "nativeCancel", "(I)V",
84275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            (void*)nativeCancel },
84375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    { "nativeResetCancel", "(IZ)V",
84475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            (void*)nativeResetCancel },
845e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown};
846e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
847e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#define FIND_CLASS(var, className) \
848e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        var = env->FindClass(className); \
849e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        LOG_FATAL_IF(! var, "Unable to find class " className);
850e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
851e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
852e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
853e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        LOG_FATAL_IF(! var, "Unable to find method" methodName);
854e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
855e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
856e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
857e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
858e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
859e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brownint register_android_database_SQLiteConnection(JNIEnv *env)
860e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown{
861e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    jclass clazz;
862e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    FIND_CLASS(clazz, "android/database/sqlite/SQLiteCustomFunction");
863e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
864e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    GET_FIELD_ID(gSQLiteCustomFunctionClassInfo.name, clazz,
865e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            "name", "Ljava/lang/String;");
866e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    GET_FIELD_ID(gSQLiteCustomFunctionClassInfo.numArgs, clazz,
867e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            "numArgs", "I");
868e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    GET_METHOD_ID(gSQLiteCustomFunctionClassInfo.dispatchCallback,
869e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            clazz, "dispatchCallback", "([Ljava/lang/String;)V");
870e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
871e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    FIND_CLASS(clazz, "java/lang/String");
872e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    gStringClassInfo.clazz = jclass(env->NewGlobalRef(clazz));
873e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
874e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown    return AndroidRuntime::registerNativeMethods(env, "android/database/sqlite/SQLiteConnection",
875e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown            sMethods, NELEM(sMethods));
876e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown}
877e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown
878e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown} // namespace android
879