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 
87     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.
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.
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.
106 static int sqliteProgressHandlerCallback(void* data) {
107     SQLiteConnection* connection = static_cast<SQLiteConnection*>(data);
108     return connection->canceled;
109 }
110 
111 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
521 static int executeNonQuery(JNIEnv* env, SQLiteConnection* connection, sqlite3_stmt* statement) {
522     int err = sqlite3_step(statement);
523     if (err == SQLITE_ROW) {
524         throw_sqlite3_exception(env,
525                 "Queries can be performed using SQLiteDatabase query or rawQuery methods only.");
526     } else if (err != SQLITE_DONE) {
527         throw_sqlite3_exception(env, connection->db);
528     }
529     return err;
530 }
531 
532 static void nativeExecute(JNIEnv* env, jclass clazz, jlong connectionPtr,
533         jlong statementPtr) {
534     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
535     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
536 
537     executeNonQuery(env, connection, statement);
538 }
539 
540 static jint nativeExecuteForChangedRowCount(JNIEnv* env, jclass clazz,
541         jlong connectionPtr, jlong statementPtr) {
542     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
543     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
544 
545     int err = executeNonQuery(env, connection, statement);
546     return err == SQLITE_DONE ? sqlite3_changes(connection->db) : -1;
547 }
548 
549 static jlong nativeExecuteForLastInsertedRowId(JNIEnv* env, jclass clazz,
550         jlong connectionPtr, jlong statementPtr) {
551     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
552     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
553 
554     int err = executeNonQuery(env, connection, statement);
555     return err == SQLITE_DONE && sqlite3_changes(connection->db) > 0
556             ? sqlite3_last_insert_rowid(connection->db) : -1;
557 }
558 
559 static int executeOneRowQuery(JNIEnv* env, SQLiteConnection* connection, sqlite3_stmt* statement) {
560     int err = sqlite3_step(statement);
561     if (err != SQLITE_ROW) {
562         throw_sqlite3_exception(env, connection->db);
563     }
564     return err;
565 }
566 
567 static jlong nativeExecuteForLong(JNIEnv* env, jclass clazz,
568         jlong connectionPtr, jlong statementPtr) {
569     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
570     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
571 
572     int err = executeOneRowQuery(env, connection, statement);
573     if (err == SQLITE_ROW && sqlite3_column_count(statement) >= 1) {
574         return sqlite3_column_int64(statement, 0);
575     }
576     return -1;
577 }
578 
579 static jstring nativeExecuteForString(JNIEnv* env, jclass clazz,
580         jlong connectionPtr, jlong statementPtr) {
581     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
582     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
583 
584     int err = executeOneRowQuery(env, connection, statement);
585     if (err == SQLITE_ROW && sqlite3_column_count(statement) >= 1) {
586         const jchar* text = static_cast<const jchar*>(sqlite3_column_text16(statement, 0));
587         if (text) {
588             size_t length = sqlite3_column_bytes16(statement, 0) / sizeof(jchar);
589             return env->NewString(text, length);
590         }
591     }
592     return NULL;
593 }
594 
595 static int createAshmemRegionWithData(JNIEnv* env, const void* data, size_t length) {
596     int error = 0;
597     int fd = ashmem_create_region(NULL, length);
598     if (fd < 0) {
599         error = errno;
600         ALOGE("ashmem_create_region failed: %s", strerror(error));
601     } else {
602         if (length > 0) {
603             void* ptr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
604             if (ptr == MAP_FAILED) {
605                 error = errno;
606                 ALOGE("mmap failed: %s", strerror(error));
607             } else {
608                 memcpy(ptr, data, length);
609                 munmap(ptr, length);
610             }
611         }
612 
613         if (!error) {
614             if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
615                 error = errno;
616                 ALOGE("ashmem_set_prot_region failed: %s", strerror(errno));
617             } else {
618                 return fd;
619             }
620         }
621 
622         close(fd);
623     }
624 
625     jniThrowIOException(env, error);
626     return -1;
627 }
628 
629 static jint nativeExecuteForBlobFileDescriptor(JNIEnv* env, jclass clazz,
630         jlong connectionPtr, jlong statementPtr) {
631     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
632     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
633 
634     int err = executeOneRowQuery(env, connection, statement);
635     if (err == SQLITE_ROW && sqlite3_column_count(statement) >= 1) {
636         const void* blob = sqlite3_column_blob(statement, 0);
637         if (blob) {
638             int length = sqlite3_column_bytes(statement, 0);
639             if (length >= 0) {
640                 return createAshmemRegionWithData(env, blob, length);
641             }
642         }
643     }
644     return -1;
645 }
646 
647 enum CopyRowResult {
648     CPR_OK,
649     CPR_FULL,
650     CPR_ERROR,
651 };
652 
653 static CopyRowResult copyRow(JNIEnv* env, CursorWindow* window,
654         sqlite3_stmt* statement, int numColumns, int startPos, int addedRows) {
655     // Allocate a new field directory for the row.
656     status_t status = window->allocRow();
657     if (status) {
658         LOG_WINDOW("Failed allocating fieldDir at startPos %d row %d, error=%d",
659                 startPos, addedRows, status);
660         return CPR_FULL;
661     }
662 
663     // Pack the row into the window.
664     CopyRowResult result = CPR_OK;
665     for (int i = 0; i < numColumns; i++) {
666         int type = sqlite3_column_type(statement, i);
667         if (type == SQLITE_TEXT) {
668             // TEXT data
669             const char* text = reinterpret_cast<const char*>(
670                     sqlite3_column_text(statement, i));
671             // SQLite does not include the NULL terminator in size, but does
672             // ensure all strings are NULL terminated, so increase size by
673             // one to make sure we store the terminator.
674             size_t sizeIncludingNull = sqlite3_column_bytes(statement, i) + 1;
675             status = window->putString(addedRows, i, text, sizeIncludingNull);
676             if (status) {
677                 LOG_WINDOW("Failed allocating %zu bytes for text at %d,%d, error=%d",
678                         sizeIncludingNull, startPos + addedRows, i, status);
679                 result = CPR_FULL;
680                 break;
681             }
682             LOG_WINDOW("%d,%d is TEXT with %zu bytes",
683                     startPos + addedRows, i, sizeIncludingNull);
684         } else if (type == SQLITE_INTEGER) {
685             // INTEGER data
686             int64_t value = sqlite3_column_int64(statement, i);
687             status = window->putLong(addedRows, i, value);
688             if (status) {
689                 LOG_WINDOW("Failed allocating space for a long in column %d, error=%d",
690                         i, status);
691                 result = CPR_FULL;
692                 break;
693             }
694             LOG_WINDOW("%d,%d is INTEGER %" PRId64, startPos + addedRows, i, value);
695         } else if (type == SQLITE_FLOAT) {
696             // FLOAT data
697             double value = sqlite3_column_double(statement, i);
698             status = window->putDouble(addedRows, i, value);
699             if (status) {
700                 LOG_WINDOW("Failed allocating space for a double in column %d, error=%d",
701                         i, status);
702                 result = CPR_FULL;
703                 break;
704             }
705             LOG_WINDOW("%d,%d is FLOAT %lf", startPos + addedRows, i, value);
706         } else if (type == SQLITE_BLOB) {
707             // BLOB data
708             const void* blob = sqlite3_column_blob(statement, i);
709             size_t size = sqlite3_column_bytes(statement, i);
710             status = window->putBlob(addedRows, i, blob, size);
711             if (status) {
712                 LOG_WINDOW("Failed allocating %zu bytes for blob at %d,%d, error=%d",
713                         size, startPos + addedRows, i, status);
714                 result = CPR_FULL;
715                 break;
716             }
717             LOG_WINDOW("%d,%d is Blob with %zu bytes",
718                     startPos + addedRows, i, size);
719         } else if (type == SQLITE_NULL) {
720             // NULL field
721             status = window->putNull(addedRows, i);
722             if (status) {
723                 LOG_WINDOW("Failed allocating space for a null in column %d, error=%d",
724                         i, status);
725                 result = CPR_FULL;
726                 break;
727             }
728 
729             LOG_WINDOW("%d,%d is NULL", startPos + addedRows, i);
730         } else {
731             // Unknown data
732             ALOGE("Unknown column type when filling database window");
733             throw_sqlite3_exception(env, "Unknown column type when filling window");
734             result = CPR_ERROR;
735             break;
736         }
737     }
738 
739     // Free the last row if if was not successfully copied.
740     if (result != CPR_OK) {
741         window->freeLastRow();
742     }
743     return result;
744 }
745 
746 static jlong nativeExecuteForCursorWindow(JNIEnv* env, jclass clazz,
747         jlong connectionPtr, jlong statementPtr, jlong windowPtr,
748         jint startPos, jint requiredPos, jboolean countAllRows) {
749     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
750     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
751     CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
752 
753     status_t status = window->clear();
754     if (status) {
755         String8 msg;
756         msg.appendFormat("Failed to clear the cursor window, status=%d", status);
757         throw_sqlite3_exception(env, connection->db, msg.string());
758         return 0;
759     }
760 
761     int numColumns = sqlite3_column_count(statement);
762     status = window->setNumColumns(numColumns);
763     if (status) {
764         String8 msg;
765         msg.appendFormat("Failed to set the cursor window column count to %d, status=%d",
766                 numColumns, status);
767         throw_sqlite3_exception(env, connection->db, msg.string());
768         return 0;
769     }
770 
771     int retryCount = 0;
772     int totalRows = 0;
773     int addedRows = 0;
774     bool windowFull = false;
775     bool gotException = false;
776     while (!gotException && (!windowFull || countAllRows)) {
777         int err = sqlite3_step(statement);
778         if (err == SQLITE_ROW) {
779             LOG_WINDOW("Stepped statement %p to row %d", statement, totalRows);
780             retryCount = 0;
781             totalRows += 1;
782 
783             // Skip the row if the window is full or we haven't reached the start position yet.
784             if (startPos >= totalRows || windowFull) {
785                 continue;
786             }
787 
788             CopyRowResult cpr = copyRow(env, window, statement, numColumns, startPos, addedRows);
789             if (cpr == CPR_FULL && addedRows && startPos + addedRows <= requiredPos) {
790                 // We filled the window before we got to the one row that we really wanted.
791                 // Clear the window and start filling it again from here.
792                 // TODO: Would be nicer if we could progressively replace earlier rows.
793                 window->clear();
794                 window->setNumColumns(numColumns);
795                 startPos += addedRows;
796                 addedRows = 0;
797                 cpr = copyRow(env, window, statement, numColumns, startPos, addedRows);
798             }
799 
800             if (cpr == CPR_OK) {
801                 addedRows += 1;
802             } else if (cpr == CPR_FULL) {
803                 windowFull = true;
804             } else {
805                 gotException = true;
806             }
807         } else if (err == SQLITE_DONE) {
808             // All rows processed, bail
809             LOG_WINDOW("Processed all rows");
810             break;
811         } else if (err == SQLITE_LOCKED || err == SQLITE_BUSY) {
812             // The table is locked, retry
813             LOG_WINDOW("Database locked, retrying");
814             if (retryCount > 50) {
815                 ALOGE("Bailing on database busy retry");
816                 throw_sqlite3_exception(env, connection->db, "retrycount exceeded");
817                 gotException = true;
818             } else {
819                 // Sleep to give the thread holding the lock a chance to finish
820                 usleep(1000);
821                 retryCount++;
822             }
823         } else {
824             throw_sqlite3_exception(env, connection->db);
825             gotException = true;
826         }
827     }
828 
829     LOG_WINDOW("Resetting statement %p after fetching %d rows and adding %d rows "
830             "to the window in %zu bytes",
831             statement, totalRows, addedRows, window->size() - window->freeSpace());
832     sqlite3_reset(statement);
833 
834     // Report the total number of rows on request.
835     if (startPos > totalRows) {
836         ALOGE("startPos %d > actual rows %d", startPos, totalRows);
837     }
838     if (totalRows > 0 && addedRows == 0) {
839         String8 msg;
840         msg.appendFormat("Row too big to fit into CursorWindow requiredPos=%d, totalRows=%d",
841                 requiredPos, totalRows);
842         throw_sqlite3_exception(env, SQLITE_TOOBIG, NULL, msg.string());
843         return 0;
844     }
845 
846     jlong result = jlong(startPos) << 32 | jlong(totalRows);
847     return result;
848 }
849 
850 static jint nativeGetDbLookaside(JNIEnv* env, jobject clazz, jlong connectionPtr) {
851     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
852 
853     int cur = -1;
854     int unused;
855     sqlite3_db_status(connection->db, SQLITE_DBSTATUS_LOOKASIDE_USED, &cur, &unused, 0);
856     return cur;
857 }
858 
859 static void nativeCancel(JNIEnv* env, jobject clazz, jlong connectionPtr) {
860     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
861     connection->canceled = true;
862 }
863 
864 static void nativeResetCancel(JNIEnv* env, jobject clazz, jlong connectionPtr,
865         jboolean cancelable) {
866     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
867     connection->canceled = false;
868 
869     if (cancelable) {
870         sqlite3_progress_handler(connection->db, 4, sqliteProgressHandlerCallback,
871                 connection);
872     } else {
873         sqlite3_progress_handler(connection->db, 0, NULL, NULL);
874     }
875 }
876 
877 
878 static const JNINativeMethod sMethods[] =
879 {
880     /* name, signature, funcPtr */
881     { "nativeOpen", "(Ljava/lang/String;ILjava/lang/String;ZZII)J",
882             (void*)nativeOpen },
883     { "nativeClose", "(J)V",
884             (void*)nativeClose },
885     { "nativeRegisterCustomScalarFunction", "(JLjava/lang/String;Ljava/util/function/UnaryOperator;)V",
886             (void*)nativeRegisterCustomScalarFunction },
887     { "nativeRegisterCustomAggregateFunction", "(JLjava/lang/String;Ljava/util/function/BinaryOperator;)V",
888             (void*)nativeRegisterCustomAggregateFunction },
889     { "nativeRegisterLocalizedCollators", "(JLjava/lang/String;)V",
890             (void*)nativeRegisterLocalizedCollators },
891     { "nativePrepareStatement", "(JLjava/lang/String;)J",
892             (void*)nativePrepareStatement },
893     { "nativeFinalizeStatement", "(JJ)V",
894             (void*)nativeFinalizeStatement },
895     { "nativeGetParameterCount", "(JJ)I",
896             (void*)nativeGetParameterCount },
897     { "nativeIsReadOnly", "(JJ)Z",
898             (void*)nativeIsReadOnly },
899     { "nativeGetColumnCount", "(JJ)I",
900             (void*)nativeGetColumnCount },
901     { "nativeGetColumnName", "(JJI)Ljava/lang/String;",
902             (void*)nativeGetColumnName },
903     { "nativeBindNull", "(JJI)V",
904             (void*)nativeBindNull },
905     { "nativeBindLong", "(JJIJ)V",
906             (void*)nativeBindLong },
907     { "nativeBindDouble", "(JJID)V",
908             (void*)nativeBindDouble },
909     { "nativeBindString", "(JJILjava/lang/String;)V",
910             (void*)nativeBindString },
911     { "nativeBindBlob", "(JJI[B)V",
912             (void*)nativeBindBlob },
913     { "nativeResetStatementAndClearBindings", "(JJ)V",
914             (void*)nativeResetStatementAndClearBindings },
915     { "nativeExecute", "(JJ)V",
916             (void*)nativeExecute },
917     { "nativeExecuteForLong", "(JJ)J",
918             (void*)nativeExecuteForLong },
919     { "nativeExecuteForString", "(JJ)Ljava/lang/String;",
920             (void*)nativeExecuteForString },
921     { "nativeExecuteForBlobFileDescriptor", "(JJ)I",
922             (void*)nativeExecuteForBlobFileDescriptor },
923     { "nativeExecuteForChangedRowCount", "(JJ)I",
924             (void*)nativeExecuteForChangedRowCount },
925     { "nativeExecuteForLastInsertedRowId", "(JJ)J",
926             (void*)nativeExecuteForLastInsertedRowId },
927     { "nativeExecuteForCursorWindow", "(JJJIIZ)J",
928             (void*)nativeExecuteForCursorWindow },
929     { "nativeGetDbLookaside", "(J)I",
930             (void*)nativeGetDbLookaside },
931     { "nativeCancel", "(J)V",
932             (void*)nativeCancel },
933     { "nativeResetCancel", "(JZ)V",
934             (void*)nativeResetCancel },
935 };
936 
937 int register_android_database_SQLiteConnection(JNIEnv *env)
938 {
939     jclass unaryClazz = FindClassOrDie(env, "java/util/function/UnaryOperator");
940     gUnaryOperator.apply = GetMethodIDOrDie(env, unaryClazz,
941             "apply", "(Ljava/lang/Object;)Ljava/lang/Object;");
942 
943     jclass binaryClazz = FindClassOrDie(env, "java/util/function/BinaryOperator");
944     gBinaryOperator.apply = GetMethodIDOrDie(env, binaryClazz,
945             "apply", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
946 
947     return RegisterMethodsOrDie(env, "android/database/sqlite/SQLiteConnection", sMethods,
948                                 NELEM(sMethods));
949 }
950 
951 } // namespace android
952