jint JNICALL Java_com_baidu_javalite_PrepareStmt_sqlite3_1bind_1parameter_1index( JNIEnv *env, jclass cls, jlong handle, jstring zName) { if (handle == 0) { throwSqliteException(env, "handle is NULL"); return 0; } if (zName == 0) { throwSqliteException(env, "zName is NULL"); return 0; } sqlite3_stmt* stmt = (sqlite3_stmt*) handle; const char* cn = (*env)->GetStringUTFChars(env, zName, 0); int rc = sqlite3_bind_parameter_index(stmt, cn); (*env)->ReleaseStringUTFChars(env, zName, cn); return rc; }
void JNICALL Java_com_baidu_javalite_PrepareStmt_sqlite3_1bind_1blob( JNIEnv *env, jclass cls, jlong handle, jint column, jbyteArray value) { if (handle == 0) { throwSqliteException(env, "handle is NULL"); return; } if (value == 0) { throwSqliteException(env, "value is NULL"); return; } sqlite3_stmt* stmt = (sqlite3_stmt*) handle; const int len = (*env)->GetArrayLength(env, value); char buf[len]; (*env)->GetByteArrayRegion(env, value, 0, len, (jbyte*) buf); int rc = sqlite3_bind_blob(stmt, column, (void*) buf, len, SQLITE_TRANSIENT); if (rc != SQLITE_OK) { sqlite3* conn = sqlite3_db_handle(stmt); throwSqliteException2(env, sqlite3_errcode(conn), sqlite3_errmsg(conn)); } }
void JNICALL Java_com_baidu_javalite_PrepareStmt_sqlite3_1bind_1text( JNIEnv *env, jclass cls, jlong handle, jint column, jstring value) { if (handle == 0) { throwSqliteException(env, "handle is NULL"); return; } if (value == 0) { throwSqliteException(env, "value is NULL"); return; } sqlite3_stmt* stmt = (sqlite3_stmt*) handle; const char* cstr = (*env)->GetStringUTFChars(env, value, 0); const size_t len = strlen(cstr); int rc = sqlite3_bind_text(stmt, column, cstr, len, SQLITE_TRANSIENT); (*env)->ReleaseStringUTFChars(env, value, cstr); if (rc != SQLITE_OK) { sqlite3* conn = sqlite3_db_handle(stmt); throwSqliteException2(env, sqlite3_errcode(conn), sqlite3_errmsg(conn)); } }
static void JNI_Setup(JNIEnv* jenv) { if (initialized) return; jclass lObjectClass = jenv->FindClass("java/lang/Object"); jclass lStringClass = jenv->FindClass("java/lang/String"); jclass lByteBufferClass = jenv->FindClass("java/nio/ByteBuffer"); jclass lCursorClass = jenv->FindClass("org/mozilla/gecko/sqlite/MatrixBlobCursor"); if (lStringClass == nullptr || lObjectClass == nullptr || lByteBufferClass == nullptr || lCursorClass == nullptr) { throwSqliteException(jenv, "FindClass error"); return; } // Those are only local references. Make them global so they work // across calls and threads. objectClass = (jclass)jenv->NewGlobalRef(lObjectClass); stringClass = (jclass)jenv->NewGlobalRef(lStringClass); byteBufferClass = (jclass)jenv->NewGlobalRef(lByteBufferClass); cursorClass = (jclass)jenv->NewGlobalRef(lCursorClass); if (stringClass == nullptr || objectClass == nullptr || byteBufferClass == nullptr || cursorClass == nullptr) { throwSqliteException(jenv, "NewGlobalRef error"); return; } // public static ByteBuffer allocateDirect(int capacity) jByteBufferAllocateDirect = jenv->GetStaticMethodID(byteBufferClass, "allocateDirect", "(I)Ljava/nio/ByteBuffer;"); // new MatrixBlobCursor(String []) jCursorConstructor = jenv->GetMethodID(cursorClass, "<init>", "([Ljava/lang/String;)V"); // public void addRow (Object[] columnValues) jCursorAddRow = jenv->GetMethodID(cursorClass, "addRow", "([Ljava/lang/Object;)V"); if (jByteBufferAllocateDirect == nullptr || jCursorConstructor == nullptr || jCursorAddRow == nullptr) { throwSqliteException(jenv, "GetMethodId error"); return; } initialized = true; }
jstring JNICALL Java_com_baidu_javalite_PrepareStmt_sqlite3_1column_1text( JNIEnv *env, jclass cls, jlong handle, jint column) { if (handle == 0) { throwSqliteException(env, "handle is NULL"); return 0; } sqlite3_stmt* stmt = (sqlite3_stmt*) handle; const unsigned char* cn = sqlite3_column_text(stmt, column); int bytes = sqlite3_column_bytes(stmt, column); if (bytes == 0) { return (*env)->NewStringUTF(env, ""); } else { char* text = (char*) malloc(bytes + 1); // bytes 的大小无法在编译时确定 memset(text, 0, bytes + 1); strncpy(text, (const char*) cn, bytes); jstring rs = (*env)->NewStringUTF(env, text); free(text); return rs; } }
jbyteArray JNICALL Java_com_baidu_javalite_PrepareStmt_sqlite3_1column_1blob( JNIEnv *env, jclass cls, jlong handle, jint column) { if (handle == 0) { throwSqliteException(env, "handle is NULL"); return 0; } sqlite3_stmt* stmt = (sqlite3_stmt*) handle; const void* data = sqlite3_column_blob(stmt, column); int bytes = sqlite3_column_bytes(stmt, column); jbyteArray array; if (bytes != 0) { array = (*env)->NewByteArray(env, bytes); jbyte* bin = (jbyte*) data; (*env)->SetByteArrayRegion(env, array, 0, bytes, bin); } else { array = (*env)->NewByteArray(env, 0); } return array; }
jboolean JNICALL Java_com_baidu_javalite_PrepareStmt_sqlite3_1step(JNIEnv *env, jclass cls, jlong handle) { if (handle == 0) { throwSqliteException(env, "handle is NULL"); return JNI_FALSE; } sqlite3_stmt* stmt = (sqlite3_stmt*) handle; int rc = sqlite3_step(stmt); if (rc == SQLITE_ROW) { return JNI_TRUE; } else if (rc == SQLITE_DONE) { return JNI_FALSE; } else { sqlite3* conn = sqlite3_db_handle(stmt); throwSqliteException2(env, sqlite3_errcode(conn), sqlite3_errmsg(conn)); return JNI_FALSE; } }
extern "C" NS_EXPORT jobject MOZ_JNICALL Java_org_mozilla_gecko_sqlite_SQLiteBridge_sqliteCall(JNIEnv* jenv, jclass, jstring jDb, jstring jQuery, jobjectArray jParams, jlongArray jQueryRes) { JNI_Setup(jenv); int rc; jobject jCursor = nullptr; const char* dbPath; sqlite3 *db; dbPath = jenv->GetStringUTFChars(jDb, nullptr); rc = f_sqlite3_open(dbPath, &db); jenv->ReleaseStringUTFChars(jDb, dbPath); if (rc != SQLITE_OK) { throwSqliteException(jenv, "Can't open database: %s", f_sqlite3_errmsg(db)); f_sqlite3_close(db); // close db even if open failed return nullptr; } jCursor = sqliteInternalCall(jenv, db, jQuery, jParams, jQueryRes); f_sqlite3_close(db); return jCursor; }
jint JNICALL Java_com_baidu_javalite_PrepareStmt_sqlite3_1column_1count( JNIEnv *env, jclass cls, jlong handle) { if (handle == 0) { throwSqliteException(env, "handle is NULL"); return 0; } sqlite3_stmt* stmt = (sqlite3_stmt*) handle; return sqlite3_column_count(stmt); }
jboolean JNICALL Java_com_baidu_javalite_PrepareStmt_sqlite3_1stmt_1readonly( JNIEnv *env, jclass cls, jlong handle) { if (handle == 0) { throwSqliteException(env, "handle is NULL"); return 0; } sqlite3_stmt* stmt = (sqlite3_stmt*) handle; return sqlite3_stmt_readonly(stmt) != 0; }
void JNICALL Java_com_baidu_javalite_PrepareStmt_sqlite3_1bind_1zeroblob( JNIEnv *env, jclass cls, jlong handle, jint column, jint bytes) { if (handle == 0) { throwSqliteException(env, "handle is NULL"); return; } sqlite3_stmt* stmt = (sqlite3_stmt*) handle; int rc = sqlite3_bind_zeroblob(stmt, column, bytes); if (rc != SQLITE_OK) { sqlite3* conn = sqlite3_db_handle(stmt); throwSqliteException2(env, sqlite3_errcode(conn), sqlite3_errmsg(conn)); } }
void JNICALL Java_com_baidu_javalite_PrepareStmt_sqlite3_1reset(JNIEnv *env, jclass cls, jlong handle) { if (handle == 0) { throwSqliteException(env, "handle is NULL"); return; } sqlite3_stmt* stmt = (sqlite3_stmt*) handle; int rc = sqlite3_reset(stmt); if (rc != SQLITE_OK) { sqlite3* conn = sqlite3_db_handle(stmt); throwSqliteException2(env, sqlite3_errcode(conn), sqlite3_errmsg(conn)); } }
jstring JNICALL Java_com_baidu_javalite_PrepareStmt_sqlite3_1column_1name( JNIEnv *env, jclass cls, jlong handle, jint column) { if (handle == 0) { throwSqliteException(env, "handle is NULL"); return 0; } sqlite3_stmt* stmt = (sqlite3_stmt*) handle; const char* cn = sqlite3_column_name(stmt, column); if (cn == 0) { return (*env)->NewStringUTF(env, ""); } else { return (*env)->NewStringUTF(env, cn); } }
jstring JNICALL Java_com_baidu_javalite_PrepareStmt_sqlite3_1sql(JNIEnv *env, jclass cls, jlong handle) { if (handle == 0) { throwSqliteException(env, "handle is NULL"); return 0; } sqlite3_stmt* stmt = (sqlite3_stmt*) handle; const char* csql = sqlite3_sql(stmt); if (csql == 0) { return (*env)->NewStringUTF(env, ""); } else { return (*env)->NewStringUTF(env, csql); } }
jstring JNICALL Java_com_baidu_javalite_PrepareStmt_sqlite3_1bind_1parameter_1name( JNIEnv *env, jclass cls, jlong handle, jint index) { if (handle == 0) { throwSqliteException(env, "handle is NULL"); return 0; } sqlite3_stmt* stmt = (sqlite3_stmt*) handle; const char* name = sqlite3_bind_parameter_name(stmt, index); if (name == 0) { return (*env)->NewStringUTF(env, ""); } else { return (*env)->NewStringUTF(env, name); } }
extern "C" NS_EXPORT jlong MOZ_JNICALL Java_org_mozilla_gecko_sqlite_SQLiteBridge_openDatabase(JNIEnv* jenv, jclass, jstring jDb) { JNI_Setup(jenv); int rc; const char* dbPath; sqlite3 *db; dbPath = jenv->GetStringUTFChars(jDb, nullptr); rc = f_sqlite3_open(dbPath, &db); jenv->ReleaseStringUTFChars(jDb, dbPath); if (rc != SQLITE_OK) { throwSqliteException(jenv, "Can't open database: %s", f_sqlite3_errmsg(db)); f_sqlite3_close(db); // close db even if open failed return 0; } return (jlong)db; }
static jobject sqliteInternalCall(JNIEnv* jenv, sqlite3 *db, jstring jQuery, jobjectArray jParams, jlongArray jQueryRes) { JNI_Setup(jenv); jobject jCursor = nullptr; jsize numPars = 0; const char *pzTail; sqlite3_stmt *ppStmt; int rc; const char* queryStr; queryStr = jenv->GetStringUTFChars(jQuery, nullptr); rc = f_sqlite3_prepare_v2(db, queryStr, -1, &ppStmt, &pzTail); if (rc != SQLITE_OK || ppStmt == nullptr) { throwSqliteException(jenv, "Can't prepare statement: %s", f_sqlite3_errmsg(db)); return nullptr; } jenv->ReleaseStringUTFChars(jQuery, queryStr); // Check if number of parameters matches if (jParams != nullptr) { numPars = jenv->GetArrayLength(jParams); } int sqlNumPars; sqlNumPars = f_sqlite3_bind_parameter_count(ppStmt); if (numPars != sqlNumPars) { throwSqliteException(jenv, "Passed parameter count (%d) " "doesn't match SQL parameter count (%d)", numPars, sqlNumPars); return nullptr; } if (jParams != nullptr) { // Bind parameters, if any if (numPars > 0) { for (int i = 0; i < numPars; i++) { jobject jObjectParam = jenv->GetObjectArrayElement(jParams, i); // IsInstanceOf or isAssignableFrom? String is final, so IsInstanceOf // should be OK. jboolean isString = jenv->IsInstanceOf(jObjectParam, stringClass); if (isString != JNI_TRUE) { throwSqliteException(jenv, "Parameter is not of String type"); return nullptr; } // SQLite parameters index from 1. if (jObjectParam == nullptr) { rc = f_sqlite3_bind_null(ppStmt, i + 1); } else { jstring jStringParam = (jstring) jObjectParam; const char* paramStr = jenv->GetStringUTFChars(jStringParam, nullptr); rc = f_sqlite3_bind_text(ppStmt, i + 1, paramStr, -1, SQLITE_TRANSIENT); jenv->ReleaseStringUTFChars(jStringParam, paramStr); } if (rc != SQLITE_OK) { throwSqliteException(jenv, "Error binding query parameter"); return nullptr; } } } } // Execute the query and step through the results rc = f_sqlite3_step(ppStmt); if (rc != SQLITE_ROW && rc != SQLITE_DONE) { throwSqliteException(jenv, "Can't step statement: (%d) %s", rc, f_sqlite3_errmsg(db)); return nullptr; } // Get the column count and names int cols; cols = f_sqlite3_column_count(ppStmt); { // Allocate a String[cols] jobjectArray jStringArray = jenv->NewObjectArray(cols, stringClass, nullptr); if (jStringArray == nullptr) { throwSqliteException(jenv, "Can't allocate String[]"); return nullptr; } // Assign column names to the String[] for (int i = 0; i < cols; i++) { const char* colName = f_sqlite3_column_name(ppStmt, i); jstring jStr = jenv->NewStringUTF(colName); jenv->SetObjectArrayElement(jStringArray, i, jStr); } // Construct the MatrixCursor(String[]) with given column names jCursor = jenv->NewObject(cursorClass, jCursorConstructor, jStringArray); if (jCursor == nullptr) { throwSqliteException(jenv, "Can't allocate MatrixBlobCursor"); return nullptr; } } // Return the id and number of changed rows in jQueryRes { jlong id = f_sqlite3_last_insert_rowid(db); jenv->SetLongArrayRegion(jQueryRes, 0, 1, &id); jlong changed = f_sqlite3_changes(db); jenv->SetLongArrayRegion(jQueryRes, 1, 1, &changed); } // For each row, add an Object[] to the passed ArrayList, // with that containing either String or ByteArray objects // containing the columns while (rc != SQLITE_DONE) { // Process row // Construct Object[] jobjectArray jRow = jenv->NewObjectArray(cols, objectClass, nullptr); if (jRow == nullptr) { throwSqliteException(jenv, "Can't allocate jRow Object[]"); return nullptr; } for (int i = 0; i < cols; i++) { int colType = f_sqlite3_column_type(ppStmt, i); if (colType == SQLITE_BLOB) { // Treat as blob const void* blob = f_sqlite3_column_blob(ppStmt, i); int colLen = f_sqlite3_column_bytes(ppStmt, i); // Construct ByteBuffer of correct size jobject jByteBuffer = jenv->CallStaticObjectMethod(byteBufferClass, jByteBufferAllocateDirect, colLen); if (jByteBuffer == nullptr) { throwSqliteException(jenv, "Failure calling ByteBuffer.allocateDirect"); return nullptr; } // Get its backing array void* bufferArray = jenv->GetDirectBufferAddress(jByteBuffer); if (bufferArray == nullptr) { throwSqliteException(jenv, "Failure calling GetDirectBufferAddress"); return nullptr; } memcpy(bufferArray, blob, colLen); jenv->SetObjectArrayElement(jRow, i, jByteBuffer); jenv->DeleteLocalRef(jByteBuffer); } else if (colType == SQLITE_NULL) { jenv->SetObjectArrayElement(jRow, i, nullptr); } else { // Treat everything else as text const char* txt = (const char*)f_sqlite3_column_text(ppStmt, i); jstring jStr = jenv->NewStringUTF(txt); jenv->SetObjectArrayElement(jRow, i, jStr); jenv->DeleteLocalRef(jStr); } } // Append Object[] to Cursor jenv->CallVoidMethod(jCursor, jCursorAddRow, jRow); // Clean up jenv->DeleteLocalRef(jRow); // Get next row rc = f_sqlite3_step(ppStmt); // Real error? if (rc != SQLITE_ROW && rc != SQLITE_DONE) { throwSqliteException(jenv, "Can't re-step statement:(%d) %s", rc, f_sqlite3_errmsg(db)); return nullptr; } } rc = f_sqlite3_finalize(ppStmt); if (rc != SQLITE_OK) { throwSqliteException(jenv, "Can't finalize statement: %s", f_sqlite3_errmsg(db)); return nullptr; } return jCursor; }