1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "SQLiteConnection"
18 
19 #include <jni.h>
20 #include <nativehelper/JNIHelp.h>
21 #include <android_runtime/AndroidRuntime.h>
22 #include <android_runtime/Log.h>
23 
24 #include <utils/Log.h>
25 #include <utils/String8.h>
26 #include <utils/String16.h>
27 #include <cutils/ashmem.h>
28 #include <sys/mman.h>
29 
30 #include <string.h>
31 #include <unistd.h>
32 
33 #include <androidfw/CursorWindow.h>
34 
35 #include <sqlite3.h>
36 #include <sqlite3_android.h>
37 
38 #include "android_database_SQLiteCommon.h"
39 
40 #include "core_jni_helpers.h"
41 
42 // Set to 1 to use UTF16 storage for localized indexes.
43 #define UTF16_STORAGE 0
44 
45 namespace android {
46 
47 /* Busy timeout in milliseconds.
48  * If another connection (possibly in another process) has the database locked for
49  * longer than this amount of time then SQLite will generate a SQLITE_BUSY error.
50  * The SQLITE_BUSY error is then raised as a SQLiteDatabaseLockedException.
51  *
52  * In ordinary usage, busy timeouts are quite rare.  Most databases only ever
53  * have a single open connection at a time unless they are using WAL.  When using
54  * WAL, a timeout could occur if one connection is busy performing an auto-checkpoint
55  * operation.  The busy timeout needs to be long enough to tolerate slow I/O write
56  * operations but not so long as to cause the application to hang indefinitely if
57  * there is a problem acquiring a database lock.
58  */
59 static const int BUSY_TIMEOUT_MS = 2500;
60 
61 static struct {
62     jmethodID apply;
63 } gUnaryOperator;
64 
65 static struct {
66     jmethodID apply;
67 } gBinaryOperator;
68 
69 struct SQLiteConnection {
70     // Open flags.
71     // Must be kept in sync with the constants defined in SQLiteDatabase.java.
72     enum {
73         OPEN_READWRITE          = 0x00000000,
74         OPEN_READONLY           = 0x00000001,
75         OPEN_READ_MASK          = 0x00000001,
76         NO_LOCALIZED_COLLATORS  = 0x00000010,
77         CREATE_IF_NECESSARY     = 0x10000000,
78     };
79 
80     sqlite3* const db;
81     const int openFlags;
82     const String8 path;
83     const String8 label;
84 
85     volatile bool canceled;
86 
SQLiteConnectionandroid::SQLiteConnection87     SQLiteConnection(sqlite3* db, int openFlags, const String8& path, const String8& label) :
88         db(db), openFlags(openFlags), path(path), label(label), canceled(false) { }
89 };
90 
91 // Called each time a statement begins execution, when tracing is enabled.
sqliteTraceCallback(void * data,const char * sql)92 static void sqliteTraceCallback(void *data, const char *sql) {
93     SQLiteConnection* connection = static_cast<SQLiteConnection*>(data);
94     ALOG(LOG_VERBOSE, SQLITE_TRACE_TAG, "%s: \"%s\"\n",
95             connection->label.string(), sql);
96 }
97 
98 // Called each time a statement finishes execution, when profiling is enabled.
sqliteProfileCallback(void * data,const char * sql,sqlite3_uint64 tm)99 static void sqliteProfileCallback(void *data, const char *sql, sqlite3_uint64 tm) {
100     SQLiteConnection* connection = static_cast<SQLiteConnection*>(data);
101     ALOG(LOG_VERBOSE, SQLITE_PROFILE_TAG, "%s: \"%s\" took %0.3f ms\n",
102             connection->label.string(), sql, tm * 0.000001f);
103 }
104 
105 // Called after each SQLite VM instruction when cancelation is enabled.
sqliteProgressHandlerCallback(void * data)106 static int sqliteProgressHandlerCallback(void* data) {
107     SQLiteConnection* connection = static_cast<SQLiteConnection*>(data);
108     return connection->canceled;
109 }
110 
111 
nativeOpen(JNIEnv * env,jclass clazz,jstring pathStr,jint openFlags,jstring labelStr,jboolean enableTrace,jboolean enableProfile,jint lookasideSz,jint lookasideCnt)112 static jlong nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFlags,
113         jstring labelStr, jboolean enableTrace, jboolean enableProfile, jint lookasideSz,
114         jint lookasideCnt) {
115     int sqliteFlags;
116     if (openFlags & SQLiteConnection::CREATE_IF_NECESSARY) {
117         sqliteFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
118     } else if (openFlags & SQLiteConnection::OPEN_READONLY) {
119         sqliteFlags = SQLITE_OPEN_READONLY;
120     } else {
121         sqliteFlags = SQLITE_OPEN_READWRITE;
122     }
123 
124     const char* pathChars = env->GetStringUTFChars(pathStr, NULL);
125     String8 path(pathChars);
126     env->ReleaseStringUTFChars(pathStr, pathChars);
127 
128     const char* labelChars = env->GetStringUTFChars(labelStr, NULL);
129     String8 label(labelChars);
130     env->ReleaseStringUTFChars(labelStr, labelChars);
131 
132     sqlite3* db;
133     int err = sqlite3_open_v2(path.string(), &db, sqliteFlags, NULL);
134     if (err != SQLITE_OK) {
135         throw_sqlite3_exception_errcode(env, err, "Could not open database");
136         return 0;
137     }
138 
139     if (lookasideSz >= 0 && lookasideCnt >= 0) {
140         int err = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, NULL, lookasideSz, lookasideCnt);
141         if (err != SQLITE_OK) {
142             ALOGE("sqlite3_db_config(..., %d, %d) failed: %d", lookasideSz, lookasideCnt, err);
143             throw_sqlite3_exception(env, db, "Cannot set lookaside");
144             sqlite3_close(db);
145             return 0;
146         }
147     }
148 
149     // Check that the database is really read/write when that is what we asked for.
150     if ((sqliteFlags & SQLITE_OPEN_READWRITE) && sqlite3_db_readonly(db, NULL)) {
151         throw_sqlite3_exception(env, db, "Could not open the database in read/write mode.");
152         sqlite3_close(db);
153         return 0;
154     }
155 
156     // Set the default busy handler to retry automatically before returning SQLITE_BUSY.
157     err = sqlite3_busy_timeout(db, BUSY_TIMEOUT_MS);
158     if (err != SQLITE_OK) {
159         throw_sqlite3_exception(env, db, "Could not set busy timeout");
160         sqlite3_close(db);
161         return 0;
162     }
163 
164     // Register custom Android functions.
165     err = register_android_functions(db, UTF16_STORAGE);
166     if (err) {
167         throw_sqlite3_exception(env, db, "Could not register Android SQL functions.");
168         sqlite3_close(db);
169         return 0;
170     }
171 
172     // Create wrapper object.
173     SQLiteConnection* connection = new SQLiteConnection(db, openFlags, path, label);
174 
175     // Enable tracing and profiling if requested.
176     if (enableTrace) {
177         sqlite3_trace(db, &sqliteTraceCallback, connection);
178     }
179     if (enableProfile) {
180         sqlite3_profile(db, &sqliteProfileCallback, connection);
181     }
182 
183     ALOGV("Opened connection %p with label '%s'", db, label.string());
184     return reinterpret_cast<jlong>(connection);
185 }
186 
nativeClose(JNIEnv * env,jclass clazz,jlong connectionPtr)187 static void nativeClose(JNIEnv* env, jclass clazz, jlong connectionPtr) {
188     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
189 
190     if (connection) {
191         ALOGV("Closing connection %p", connection->db);
192         int err = sqlite3_close(connection->db);
193         if (err != SQLITE_OK) {
194             // This can happen if sub-objects aren't closed first.  Make sure the caller knows.
195             ALOGE("sqlite3_close(%p) failed: %d", connection->db, err);
196             throw_sqlite3_exception(env, connection->db, "Count not close db.");
197             return;
198         }
199 
200         delete connection;
201     }
202 }
203 
sqliteCustomScalarFunctionCallback(sqlite3_context * context,int argc,sqlite3_value ** argv)204 static void sqliteCustomScalarFunctionCallback(sqlite3_context *context,
205         int argc, sqlite3_value **argv) {
206     JNIEnv* env = AndroidRuntime::getJNIEnv();
207     jobject functionObjGlobal = reinterpret_cast<jobject>(sqlite3_user_data(context));
208     ScopedLocalRef<jobject> functionObj(env, env->NewLocalRef(functionObjGlobal));
209     ScopedLocalRef<jstring> argString(env,
210             env->NewStringUTF(reinterpret_cast<const char*>(sqlite3_value_text(argv[0]))));
211     ScopedLocalRef<jstring> resString(env,
212             (jstring) env->CallObjectMethod(functionObj.get(), gUnaryOperator.apply, argString.get()));
213 
214     if (env->ExceptionCheck()) {
215         ALOGE("Exception thrown by custom scalar function");
216         sqlite3_result_error(context, "Exception thrown by custom scalar function", -1);
217         env->ExceptionDescribe();
218         env->ExceptionClear();
219         return;
220     }
221 
222     if (resString.get() == nullptr) {
223         sqlite3_result_null(context);
224     } else {
225         ScopedUtfChars res(env, resString.get());
226         sqlite3_result_text(context, res.c_str(), -1, SQLITE_TRANSIENT);
227     }
228 }
229 
sqliteCustomScalarFunctionDestructor(void * data)230 static void sqliteCustomScalarFunctionDestructor(void* data) {
231     jobject functionObjGlobal = reinterpret_cast<jobject>(data);
232 
233     JNIEnv* env = AndroidRuntime::getJNIEnv();
234     env->DeleteGlobalRef(functionObjGlobal);
235 }
236 
nativeRegisterCustomScalarFunction(JNIEnv * env,jclass clazz,jlong connectionPtr,jstring functionName,jobject functionObj)237 static void nativeRegisterCustomScalarFunction(JNIEnv* env, jclass clazz, jlong connectionPtr,
238         jstring functionName, jobject functionObj) {
239     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
240 
241     jobject functionObjGlobal = env->NewGlobalRef(functionObj);
242     ScopedUtfChars functionNameChars(env, functionName);
243     int err = sqlite3_create_function_v2(connection->db,
244             functionNameChars.c_str(), 1, SQLITE_UTF8,
245             reinterpret_cast<void*>(functionObjGlobal),
246             &sqliteCustomScalarFunctionCallback,
247             nullptr,
248             nullptr,
249             &sqliteCustomScalarFunctionDestructor);
250 
251     if (err != SQLITE_OK) {
252         ALOGE("sqlite3_create_function returned %d", err);
253         env->DeleteGlobalRef(functionObjGlobal);
254         throw_sqlite3_exception(env, connection->db);
255         return;
256     }
257 }
258 
sqliteCustomAggregateFunctionStep(sqlite3_context * context,int argc,sqlite3_value ** argv)259 static void sqliteCustomAggregateFunctionStep(sqlite3_context *context,
260         int argc, sqlite3_value **argv) {
261     char** agg = reinterpret_cast<char**>(
262             sqlite3_aggregate_context(context, sizeof(const char**)));
263     if (agg == nullptr) {
264         return;
265     } else if (*agg == nullptr) {
266         // During our first call the best we can do is allocate our result
267         // holder and populate it with our first value; we'll reduce it
268         // against any additional values in future calls
269         const char* res = reinterpret_cast<const char*>(sqlite3_value_text(argv[0]));
270         if (res == nullptr) {
271             *agg = nullptr;
272         } else {
273             *agg = strdup(res);
274         }
275         return;
276     }
277 
278     JNIEnv* env = AndroidRuntime::getJNIEnv();
279     jobject functionObjGlobal = reinterpret_cast<jobject>(sqlite3_user_data(context));
280     ScopedLocalRef<jobject> functionObj(env, env->NewLocalRef(functionObjGlobal));
281     ScopedLocalRef<jstring> arg0String(env,
282             env->NewStringUTF(reinterpret_cast<const char*>(*agg)));
283     ScopedLocalRef<jstring> arg1String(env,
284             env->NewStringUTF(reinterpret_cast<const char*>(sqlite3_value_text(argv[0]))));
285     ScopedLocalRef<jstring> resString(env,
286             (jstring) env->CallObjectMethod(functionObj.get(), gBinaryOperator.apply,
287                     arg0String.get(), arg1String.get()));
288 
289     if (env->ExceptionCheck()) {
290         ALOGE("Exception thrown by custom aggregate function");
291         sqlite3_result_error(context, "Exception thrown by custom aggregate function", -1);
292         env->ExceptionDescribe();
293         env->ExceptionClear();
294         return;
295     }
296 
297     // One way or another, we have a new value to collect, and we need to
298     // free our previous value
299     if (*agg != nullptr) {
300         free(*agg);
301     }
302     if (resString.get() == nullptr) {
303         *agg = nullptr;
304     } else {
305         ScopedUtfChars res(env, resString.get());
306         *agg = strdup(res.c_str());
307     }
308 }
309 
sqliteCustomAggregateFunctionFinal(sqlite3_context * context)310 static void sqliteCustomAggregateFunctionFinal(sqlite3_context *context) {
311     // We pass zero size here to avoid allocating for empty sets
312     char** agg = reinterpret_cast<char**>(
313             sqlite3_aggregate_context(context, 0));
314     if (agg == nullptr) {
315         return;
316     } else if (*agg == nullptr) {
317         sqlite3_result_null(context);
318     } else {
319         sqlite3_result_text(context, *agg, -1, SQLITE_TRANSIENT);
320         free(*agg);
321     }
322 }
323 
sqliteCustomAggregateFunctionDestructor(void * data)324 static void sqliteCustomAggregateFunctionDestructor(void* data) {
325     jobject functionObjGlobal = reinterpret_cast<jobject>(data);
326 
327     JNIEnv* env = AndroidRuntime::getJNIEnv();
328     env->DeleteGlobalRef(functionObjGlobal);
329 }
330 
nativeRegisterCustomAggregateFunction(JNIEnv * env,jclass clazz,jlong connectionPtr,jstring functionName,jobject functionObj)331 static void nativeRegisterCustomAggregateFunction(JNIEnv* env, jclass clazz, jlong connectionPtr,
332         jstring functionName, jobject functionObj) {
333     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
334 
335     jobject functionObjGlobal = env->NewGlobalRef(functionObj);
336     ScopedUtfChars functionNameChars(env, functionName);
337     int err = sqlite3_create_function_v2(connection->db,
338             functionNameChars.c_str(), 1, SQLITE_UTF8,
339             reinterpret_cast<void*>(functionObjGlobal),
340             nullptr,
341             &sqliteCustomAggregateFunctionStep,
342             &sqliteCustomAggregateFunctionFinal,
343             &sqliteCustomAggregateFunctionDestructor);
344 
345     if (err != SQLITE_OK) {
346         ALOGE("sqlite3_create_function returned %d", err);
347         env->DeleteGlobalRef(functionObjGlobal);
348         throw_sqlite3_exception(env, connection->db);
349         return;
350     }
351 }
352 
nativeRegisterLocalizedCollators(JNIEnv * env,jclass clazz,jlong connectionPtr,jstring localeStr)353 static void nativeRegisterLocalizedCollators(JNIEnv* env, jclass clazz, jlong connectionPtr,
354         jstring localeStr) {
355     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
356 
357     const char* locale = env->GetStringUTFChars(localeStr, NULL);
358     int err = register_localized_collators(connection->db, locale, UTF16_STORAGE);
359     env->ReleaseStringUTFChars(localeStr, locale);
360 
361     if (err != SQLITE_OK) {
362         throw_sqlite3_exception(env, connection->db);
363     }
364 }
365 
nativePrepareStatement(JNIEnv * env,jclass clazz,jlong connectionPtr,jstring sqlString)366 static jlong nativePrepareStatement(JNIEnv* env, jclass clazz, jlong connectionPtr,
367         jstring sqlString) {
368     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
369 
370     jsize sqlLength = env->GetStringLength(sqlString);
371     const jchar* sql = env->GetStringCritical(sqlString, NULL);
372     sqlite3_stmt* statement;
373     int err = sqlite3_prepare16_v2(connection->db,
374             sql, sqlLength * sizeof(jchar), &statement, NULL);
375     env->ReleaseStringCritical(sqlString, sql);
376 
377     if (err != SQLITE_OK) {
378         // Error messages like 'near ")": syntax error' are not
379         // always helpful enough, so construct an error string that
380         // includes the query itself.
381         const char *query = env->GetStringUTFChars(sqlString, NULL);
382         char *message = (char*) malloc(strlen(query) + 50);
383         if (message) {
384             strcpy(message, ", while compiling: "); // less than 50 chars
385             strcat(message, query);
386         }
387         env->ReleaseStringUTFChars(sqlString, query);
388         throw_sqlite3_exception(env, connection->db, message);
389         free(message);
390         return 0;
391     }
392 
393     ALOGV("Prepared statement %p on connection %p", statement, connection->db);
394     return reinterpret_cast<jlong>(statement);
395 }
396 
nativeFinalizeStatement(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr)397 static void nativeFinalizeStatement(JNIEnv* env, jclass clazz, jlong connectionPtr,
398         jlong statementPtr) {
399     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
400     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
401 
402     // We ignore the result of sqlite3_finalize because it is really telling us about
403     // whether any errors occurred while executing the statement.  The statement itself
404     // is always finalized regardless.
405     ALOGV("Finalized statement %p on connection %p", statement, connection->db);
406     sqlite3_finalize(statement);
407 }
408 
nativeGetParameterCount(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr)409 static jint nativeGetParameterCount(JNIEnv* env, jclass clazz, jlong connectionPtr,
410         jlong statementPtr) {
411     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
412 
413     return sqlite3_bind_parameter_count(statement);
414 }
415 
nativeIsReadOnly(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr)416 static jboolean nativeIsReadOnly(JNIEnv* env, jclass clazz, jlong connectionPtr,
417         jlong statementPtr) {
418     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
419 
420     return sqlite3_stmt_readonly(statement) != 0;
421 }
422 
nativeGetColumnCount(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr)423 static jint nativeGetColumnCount(JNIEnv* env, jclass clazz, jlong connectionPtr,
424         jlong statementPtr) {
425     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
426 
427     return sqlite3_column_count(statement);
428 }
429 
nativeGetColumnName(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr,jint index)430 static jstring nativeGetColumnName(JNIEnv* env, jclass clazz, jlong connectionPtr,
431         jlong statementPtr, jint index) {
432     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
433 
434     const jchar* name = static_cast<const jchar*>(sqlite3_column_name16(statement, index));
435     if (name) {
436         size_t length = 0;
437         while (name[length]) {
438             length += 1;
439         }
440         return env->NewString(name, length);
441     }
442     return NULL;
443 }
444 
nativeBindNull(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr,jint index)445 static void nativeBindNull(JNIEnv* env, jclass clazz, jlong connectionPtr,
446         jlong statementPtr, jint index) {
447     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
448     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
449 
450     int err = sqlite3_bind_null(statement, index);
451     if (err != SQLITE_OK) {
452         throw_sqlite3_exception(env, connection->db, NULL);
453     }
454 }
455 
nativeBindLong(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr,jint index,jlong value)456 static void nativeBindLong(JNIEnv* env, jclass clazz, jlong connectionPtr,
457         jlong statementPtr, jint index, jlong value) {
458     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
459     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
460 
461     int err = sqlite3_bind_int64(statement, index, value);
462     if (err != SQLITE_OK) {
463         throw_sqlite3_exception(env, connection->db, NULL);
464     }
465 }
466 
nativeBindDouble(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr,jint index,jdouble value)467 static void nativeBindDouble(JNIEnv* env, jclass clazz, jlong connectionPtr,
468         jlong statementPtr, jint index, jdouble value) {
469     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
470     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
471 
472     int err = sqlite3_bind_double(statement, index, value);
473     if (err != SQLITE_OK) {
474         throw_sqlite3_exception(env, connection->db, NULL);
475     }
476 }
477 
nativeBindString(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr,jint index,jstring valueString)478 static void nativeBindString(JNIEnv* env, jclass clazz, jlong connectionPtr,
479         jlong statementPtr, jint index, jstring valueString) {
480     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
481     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
482 
483     jsize valueLength = env->GetStringLength(valueString);
484     const jchar* value = env->GetStringCritical(valueString, NULL);
485     int err = sqlite3_bind_text16(statement, index, value, valueLength * sizeof(jchar),
486             SQLITE_TRANSIENT);
487     env->ReleaseStringCritical(valueString, value);
488     if (err != SQLITE_OK) {
489         throw_sqlite3_exception(env, connection->db, NULL);
490     }
491 }
492 
nativeBindBlob(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr,jint index,jbyteArray valueArray)493 static void nativeBindBlob(JNIEnv* env, jclass clazz, jlong connectionPtr,
494         jlong statementPtr, jint index, jbyteArray valueArray) {
495     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
496     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
497 
498     jsize valueLength = env->GetArrayLength(valueArray);
499     jbyte* value = static_cast<jbyte*>(env->GetPrimitiveArrayCritical(valueArray, NULL));
500     int err = sqlite3_bind_blob(statement, index, value, valueLength, SQLITE_TRANSIENT);
501     env->ReleasePrimitiveArrayCritical(valueArray, value, JNI_ABORT);
502     if (err != SQLITE_OK) {
503         throw_sqlite3_exception(env, connection->db, NULL);
504     }
505 }
506 
nativeResetStatementAndClearBindings(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr)507 static void nativeResetStatementAndClearBindings(JNIEnv* env, jclass clazz, jlong connectionPtr,
508         jlong statementPtr) {
509     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
510     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
511 
512     int err = sqlite3_reset(statement);
513     if (err == SQLITE_OK) {
514         err = sqlite3_clear_bindings(statement);
515     }
516     if (err != SQLITE_OK) {
517         throw_sqlite3_exception(env, connection->db, NULL);
518     }
519 }
520 
executeNonQuery(JNIEnv * env,SQLiteConnection * connection,sqlite3_stmt * statement,bool isPragmaStmt)521 static int executeNonQuery(JNIEnv* env, SQLiteConnection* connection, sqlite3_stmt* statement,
522         bool isPragmaStmt) {
523     int rc = sqlite3_step(statement);
524     if (isPragmaStmt) {
525         while (rc == SQLITE_ROW) {
526             rc = sqlite3_step(statement);
527         }
528     }
529     if (rc == SQLITE_ROW) {
530         throw_sqlite3_exception(env,
531                 "Queries can be performed using SQLiteDatabase query or rawQuery methods only.");
532     } else if (rc != SQLITE_DONE) {
533         throw_sqlite3_exception(env, connection->db);
534     }
535     return rc;
536 }
537 
nativeExecute(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr,jboolean isPragmaStmt)538 static void nativeExecute(JNIEnv* env, jclass clazz, jlong connectionPtr, jlong statementPtr,
539         jboolean isPragmaStmt) {
540     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
541     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
542 
543     executeNonQuery(env, connection, statement, isPragmaStmt);
544 }
545 
nativeExecuteForChangedRowCount(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr)546 static jint nativeExecuteForChangedRowCount(JNIEnv* env, jclass clazz,
547         jlong connectionPtr, jlong statementPtr) {
548     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
549     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
550 
551     int err = executeNonQuery(env, connection, statement, false);
552     return err == SQLITE_DONE ? sqlite3_changes(connection->db) : -1;
553 }
554 
nativeExecuteForLastInsertedRowId(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr)555 static jlong nativeExecuteForLastInsertedRowId(JNIEnv* env, jclass clazz,
556         jlong connectionPtr, jlong statementPtr) {
557     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
558     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
559 
560     int err = executeNonQuery(env, connection, statement, false);
561     return err == SQLITE_DONE && sqlite3_changes(connection->db) > 0
562             ? sqlite3_last_insert_rowid(connection->db) : -1;
563 }
564 
executeOneRowQuery(JNIEnv * env,SQLiteConnection * connection,sqlite3_stmt * statement)565 static int executeOneRowQuery(JNIEnv* env, SQLiteConnection* connection, sqlite3_stmt* statement) {
566     int err = sqlite3_step(statement);
567     if (err != SQLITE_ROW) {
568         throw_sqlite3_exception(env, connection->db);
569     }
570     return err;
571 }
572 
nativeExecuteForLong(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr)573 static jlong nativeExecuteForLong(JNIEnv* env, jclass clazz,
574         jlong connectionPtr, jlong statementPtr) {
575     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
576     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
577 
578     int err = executeOneRowQuery(env, connection, statement);
579     if (err == SQLITE_ROW && sqlite3_column_count(statement) >= 1) {
580         return sqlite3_column_int64(statement, 0);
581     }
582     return -1;
583 }
584 
nativeExecuteForString(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr)585 static jstring nativeExecuteForString(JNIEnv* env, jclass clazz,
586         jlong connectionPtr, jlong statementPtr) {
587     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
588     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
589 
590     int err = executeOneRowQuery(env, connection, statement);
591     if (err == SQLITE_ROW && sqlite3_column_count(statement) >= 1) {
592         const jchar* text = static_cast<const jchar*>(sqlite3_column_text16(statement, 0));
593         if (text) {
594             size_t length = sqlite3_column_bytes16(statement, 0) / sizeof(jchar);
595             return env->NewString(text, length);
596         }
597     }
598     return NULL;
599 }
600 
createAshmemRegionWithData(JNIEnv * env,const void * data,size_t length)601 static int createAshmemRegionWithData(JNIEnv* env, const void* data, size_t length) {
602     int error = 0;
603     int fd = ashmem_create_region(NULL, length);
604     if (fd < 0) {
605         error = errno;
606         ALOGE("ashmem_create_region failed: %s", strerror(error));
607     } else {
608         if (length > 0) {
609             void* ptr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
610             if (ptr == MAP_FAILED) {
611                 error = errno;
612                 ALOGE("mmap failed: %s", strerror(error));
613             } else {
614                 memcpy(ptr, data, length);
615                 munmap(ptr, length);
616             }
617         }
618 
619         if (!error) {
620             if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
621                 error = errno;
622                 ALOGE("ashmem_set_prot_region failed: %s", strerror(errno));
623             } else {
624                 return fd;
625             }
626         }
627 
628         close(fd);
629     }
630 
631     jniThrowIOException(env, error);
632     return -1;
633 }
634 
nativeExecuteForBlobFileDescriptor(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr)635 static jint nativeExecuteForBlobFileDescriptor(JNIEnv* env, jclass clazz,
636         jlong connectionPtr, jlong statementPtr) {
637     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
638     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
639 
640     int err = executeOneRowQuery(env, connection, statement);
641     if (err == SQLITE_ROW && sqlite3_column_count(statement) >= 1) {
642         const void* blob = sqlite3_column_blob(statement, 0);
643         if (blob) {
644             int length = sqlite3_column_bytes(statement, 0);
645             if (length >= 0) {
646                 return createAshmemRegionWithData(env, blob, length);
647             }
648         }
649     }
650     return -1;
651 }
652 
653 enum CopyRowResult {
654     CPR_OK,
655     CPR_FULL,
656     CPR_ERROR,
657 };
658 
copyRow(JNIEnv * env,CursorWindow * window,sqlite3_stmt * statement,int numColumns,int startPos,int addedRows)659 static CopyRowResult copyRow(JNIEnv* env, CursorWindow* window,
660         sqlite3_stmt* statement, int numColumns, int startPos, int addedRows) {
661     // Allocate a new field directory for the row.
662     status_t status = window->allocRow();
663     if (status) {
664         LOG_WINDOW("Failed allocating fieldDir at startPos %d row %d, error=%d",
665                 startPos, addedRows, status);
666         return CPR_FULL;
667     }
668 
669     // Pack the row into the window.
670     CopyRowResult result = CPR_OK;
671     for (int i = 0; i < numColumns; i++) {
672         int type = sqlite3_column_type(statement, i);
673         if (type == SQLITE_TEXT) {
674             // TEXT data
675             const char* text = reinterpret_cast<const char*>(
676                     sqlite3_column_text(statement, i));
677             // SQLite does not include the NULL terminator in size, but does
678             // ensure all strings are NULL terminated, so increase size by
679             // one to make sure we store the terminator.
680             size_t sizeIncludingNull = sqlite3_column_bytes(statement, i) + 1;
681             status = window->putString(addedRows, i, text, sizeIncludingNull);
682             if (status) {
683                 LOG_WINDOW("Failed allocating %zu bytes for text at %d,%d, error=%d",
684                         sizeIncludingNull, startPos + addedRows, i, status);
685                 result = CPR_FULL;
686                 break;
687             }
688             LOG_WINDOW("%d,%d is TEXT with %zu bytes",
689                     startPos + addedRows, i, sizeIncludingNull);
690         } else if (type == SQLITE_INTEGER) {
691             // INTEGER data
692             int64_t value = sqlite3_column_int64(statement, i);
693             status = window->putLong(addedRows, i, value);
694             if (status) {
695                 LOG_WINDOW("Failed allocating space for a long in column %d, error=%d",
696                         i, status);
697                 result = CPR_FULL;
698                 break;
699             }
700             LOG_WINDOW("%d,%d is INTEGER %" PRId64, startPos + addedRows, i, value);
701         } else if (type == SQLITE_FLOAT) {
702             // FLOAT data
703             double value = sqlite3_column_double(statement, i);
704             status = window->putDouble(addedRows, i, value);
705             if (status) {
706                 LOG_WINDOW("Failed allocating space for a double in column %d, error=%d",
707                         i, status);
708                 result = CPR_FULL;
709                 break;
710             }
711             LOG_WINDOW("%d,%d is FLOAT %lf", startPos + addedRows, i, value);
712         } else if (type == SQLITE_BLOB) {
713             // BLOB data
714             const void* blob = sqlite3_column_blob(statement, i);
715             size_t size = sqlite3_column_bytes(statement, i);
716             status = window->putBlob(addedRows, i, blob, size);
717             if (status) {
718                 LOG_WINDOW("Failed allocating %zu bytes for blob at %d,%d, error=%d",
719                         size, startPos + addedRows, i, status);
720                 result = CPR_FULL;
721                 break;
722             }
723             LOG_WINDOW("%d,%d is Blob with %zu bytes",
724                     startPos + addedRows, i, size);
725         } else if (type == SQLITE_NULL) {
726             // NULL field
727             status = window->putNull(addedRows, i);
728             if (status) {
729                 LOG_WINDOW("Failed allocating space for a null in column %d, error=%d",
730                         i, status);
731                 result = CPR_FULL;
732                 break;
733             }
734 
735             LOG_WINDOW("%d,%d is NULL", startPos + addedRows, i);
736         } else {
737             // Unknown data
738             ALOGE("Unknown column type when filling database window");
739             throw_sqlite3_exception(env, "Unknown column type when filling window");
740             result = CPR_ERROR;
741             break;
742         }
743     }
744 
745     // Free the last row if if was not successfully copied.
746     if (result != CPR_OK) {
747         window->freeLastRow();
748     }
749     return result;
750 }
751 
nativeExecuteForCursorWindow(JNIEnv * env,jclass clazz,jlong connectionPtr,jlong statementPtr,jlong windowPtr,jint startPos,jint requiredPos,jboolean countAllRows)752 static jlong nativeExecuteForCursorWindow(JNIEnv* env, jclass clazz,
753         jlong connectionPtr, jlong statementPtr, jlong windowPtr,
754         jint startPos, jint requiredPos, jboolean countAllRows) {
755     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
756     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
757     CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
758 
759     status_t status = window->clear();
760     if (status) {
761         String8 msg;
762         msg.appendFormat("Failed to clear the cursor window, status=%d", status);
763         throw_sqlite3_exception(env, connection->db, msg.string());
764         return 0;
765     }
766 
767     int numColumns = sqlite3_column_count(statement);
768     status = window->setNumColumns(numColumns);
769     if (status) {
770         String8 msg;
771         msg.appendFormat("Failed to set the cursor window column count to %d, status=%d",
772                 numColumns, status);
773         throw_sqlite3_exception(env, connection->db, msg.string());
774         return 0;
775     }
776 
777     int retryCount = 0;
778     int totalRows = 0;
779     int addedRows = 0;
780     bool windowFull = false;
781     bool gotException = false;
782     while (!gotException && (!windowFull || countAllRows)) {
783         int err = sqlite3_step(statement);
784         if (err == SQLITE_ROW) {
785             LOG_WINDOW("Stepped statement %p to row %d", statement, totalRows);
786             retryCount = 0;
787             totalRows += 1;
788 
789             // Skip the row if the window is full or we haven't reached the start position yet.
790             if (startPos >= totalRows || windowFull) {
791                 continue;
792             }
793 
794             CopyRowResult cpr = copyRow(env, window, statement, numColumns, startPos, addedRows);
795             if (cpr == CPR_FULL && addedRows && startPos + addedRows <= requiredPos) {
796                 // We filled the window before we got to the one row that we really wanted.
797                 // Clear the window and start filling it again from here.
798                 // TODO: Would be nicer if we could progressively replace earlier rows.
799                 window->clear();
800                 window->setNumColumns(numColumns);
801                 startPos += addedRows;
802                 addedRows = 0;
803                 cpr = copyRow(env, window, statement, numColumns, startPos, addedRows);
804             }
805 
806             if (cpr == CPR_OK) {
807                 addedRows += 1;
808             } else if (cpr == CPR_FULL) {
809                 windowFull = true;
810             } else {
811                 gotException = true;
812             }
813         } else if (err == SQLITE_DONE) {
814             // All rows processed, bail
815             LOG_WINDOW("Processed all rows");
816             break;
817         } else if (err == SQLITE_LOCKED || err == SQLITE_BUSY) {
818             // The table is locked, retry
819             LOG_WINDOW("Database locked, retrying");
820             if (retryCount > 50) {
821                 ALOGE("Bailing on database busy retry");
822                 throw_sqlite3_exception(env, connection->db, "retrycount exceeded");
823                 gotException = true;
824             } else {
825                 // Sleep to give the thread holding the lock a chance to finish
826                 usleep(1000);
827                 retryCount++;
828             }
829         } else {
830             throw_sqlite3_exception(env, connection->db);
831             gotException = true;
832         }
833     }
834 
835     LOG_WINDOW("Resetting statement %p after fetching %d rows and adding %d rows "
836             "to the window in %zu bytes",
837             statement, totalRows, addedRows, window->size() - window->freeSpace());
838     sqlite3_reset(statement);
839 
840     // Report the total number of rows on request.
841     if (startPos > totalRows) {
842         ALOGE("startPos %d > actual rows %d", startPos, totalRows);
843     }
844     if (totalRows > 0 && addedRows == 0) {
845         String8 msg;
846         msg.appendFormat("Row too big to fit into CursorWindow requiredPos=%d, totalRows=%d",
847                 requiredPos, totalRows);
848         throw_sqlite3_exception(env, SQLITE_TOOBIG, NULL, msg.string());
849         return 0;
850     }
851 
852     jlong result = jlong(startPos) << 32 | jlong(totalRows);
853     return result;
854 }
855 
nativeGetDbLookaside(JNIEnv * env,jobject clazz,jlong connectionPtr)856 static jint nativeGetDbLookaside(JNIEnv* env, jobject clazz, jlong connectionPtr) {
857     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
858 
859     int cur = -1;
860     int unused;
861     sqlite3_db_status(connection->db, SQLITE_DBSTATUS_LOOKASIDE_USED, &cur, &unused, 0);
862     return cur;
863 }
864 
nativeCancel(JNIEnv * env,jobject clazz,jlong connectionPtr)865 static void nativeCancel(JNIEnv* env, jobject clazz, jlong connectionPtr) {
866     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
867     connection->canceled = true;
868 }
869 
nativeResetCancel(JNIEnv * env,jobject clazz,jlong connectionPtr,jboolean cancelable)870 static void nativeResetCancel(JNIEnv* env, jobject clazz, jlong connectionPtr,
871         jboolean cancelable) {
872     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
873     connection->canceled = false;
874 
875     if (cancelable) {
876         sqlite3_progress_handler(connection->db, 4, sqliteProgressHandlerCallback,
877                 connection);
878     } else {
879         sqlite3_progress_handler(connection->db, 0, NULL, NULL);
880     }
881 }
882 
883 
884 static const JNINativeMethod sMethods[] =
885 {
886     /* name, signature, funcPtr */
887     { "nativeOpen", "(Ljava/lang/String;ILjava/lang/String;ZZII)J",
888             (void*)nativeOpen },
889     { "nativeClose", "(J)V",
890             (void*)nativeClose },
891     { "nativeRegisterCustomScalarFunction", "(JLjava/lang/String;Ljava/util/function/UnaryOperator;)V",
892             (void*)nativeRegisterCustomScalarFunction },
893     { "nativeRegisterCustomAggregateFunction", "(JLjava/lang/String;Ljava/util/function/BinaryOperator;)V",
894             (void*)nativeRegisterCustomAggregateFunction },
895     { "nativeRegisterLocalizedCollators", "(JLjava/lang/String;)V",
896             (void*)nativeRegisterLocalizedCollators },
897     { "nativePrepareStatement", "(JLjava/lang/String;)J",
898             (void*)nativePrepareStatement },
899     { "nativeFinalizeStatement", "(JJ)V",
900             (void*)nativeFinalizeStatement },
901     { "nativeGetParameterCount", "(JJ)I",
902             (void*)nativeGetParameterCount },
903     { "nativeIsReadOnly", "(JJ)Z",
904             (void*)nativeIsReadOnly },
905     { "nativeGetColumnCount", "(JJ)I",
906             (void*)nativeGetColumnCount },
907     { "nativeGetColumnName", "(JJI)Ljava/lang/String;",
908             (void*)nativeGetColumnName },
909     { "nativeBindNull", "(JJI)V",
910             (void*)nativeBindNull },
911     { "nativeBindLong", "(JJIJ)V",
912             (void*)nativeBindLong },
913     { "nativeBindDouble", "(JJID)V",
914             (void*)nativeBindDouble },
915     { "nativeBindString", "(JJILjava/lang/String;)V",
916             (void*)nativeBindString },
917     { "nativeBindBlob", "(JJI[B)V",
918             (void*)nativeBindBlob },
919     { "nativeResetStatementAndClearBindings", "(JJ)V",
920             (void*)nativeResetStatementAndClearBindings },
921     { "nativeExecute", "(JJZ)V",
922             (void*)nativeExecute },
923     { "nativeExecuteForLong", "(JJ)J",
924             (void*)nativeExecuteForLong },
925     { "nativeExecuteForString", "(JJ)Ljava/lang/String;",
926             (void*)nativeExecuteForString },
927     { "nativeExecuteForBlobFileDescriptor", "(JJ)I",
928             (void*)nativeExecuteForBlobFileDescriptor },
929     { "nativeExecuteForChangedRowCount", "(JJ)I",
930             (void*)nativeExecuteForChangedRowCount },
931     { "nativeExecuteForLastInsertedRowId", "(JJ)J",
932             (void*)nativeExecuteForLastInsertedRowId },
933     { "nativeExecuteForCursorWindow", "(JJJIIZ)J",
934             (void*)nativeExecuteForCursorWindow },
935     { "nativeGetDbLookaside", "(J)I",
936             (void*)nativeGetDbLookaside },
937     { "nativeCancel", "(J)V",
938             (void*)nativeCancel },
939     { "nativeResetCancel", "(JZ)V",
940             (void*)nativeResetCancel },
941 };
942 
register_android_database_SQLiteConnection(JNIEnv * env)943 int register_android_database_SQLiteConnection(JNIEnv *env)
944 {
945     jclass unaryClazz = FindClassOrDie(env, "java/util/function/UnaryOperator");
946     gUnaryOperator.apply = GetMethodIDOrDie(env, unaryClazz,
947             "apply", "(Ljava/lang/Object;)Ljava/lang/Object;");
948 
949     jclass binaryClazz = FindClassOrDie(env, "java/util/function/BinaryOperator");
950     gBinaryOperator.apply = GetMethodIDOrDie(env, binaryClazz,
951             "apply", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
952 
953     return RegisterMethodsOrDie(env, "android/database/sqlite/SQLiteConnection", sMethods,
954                                 NELEM(sMethods));
955 }
956 
957 } // namespace android
958