JniHookState rollbackHook;
JniHookState trace;
JniHookState updateHook;
+ JniHookState authHook;
#ifdef SQLITE_ENABLE_FTS5
jobject jFtsApi /* global ref to s3jni_fts5_api_from_db() */;
#endif
UNHOOK(commitHook, 0);
UNHOOK(rollbackHook, 0);
UNHOOK(updateHook, 0);
+ UNHOOK(authHook, 0);
UNHOOK(collation, 1);
UNHOOK(collationNeeded, 1);
UNHOOK(busyHandler, 1);
return s3jni_commit_rollback_hook(0, env, jDb, jHook);
}
+/* sqlite3_set_authorizer() callback proxy. */
+static int s3jni_xAuth(void* pState, int op,const char*z0, const char*z1,
+ const char*z2,const char*z3){
+ PerDbStateJni * const ps = pState;
+ JNIEnv * const env = ps->env;
+ jstring const s0 = z0 ? (*env)->NewStringUTF(env, z0) : 0;
+ jstring const s1 = z1 ? (*env)->NewStringUTF(env, z1) : 0;
+ jstring const s2 = z2 ? (*env)->NewStringUTF(env, z2) : 0;
+ jstring const s3 = z3 ? (*env)->NewStringUTF(env, z3) : 0;
+ JniHookState const * const pHook = &ps->authHook;
+ int rc;
+
+ assert( pHook->jObj );
+ rc = (*env)->CallIntMethod(env, pHook->jObj, pHook->midCallback, (jint)op,
+ s0, s1, s3, s3);
+ IFTHREW{
+ EXCEPTION_WARN_CALLBACK_THREW("sqlite3_set_authorizer() callback");
+ EXCEPTION_CLEAR;
+ }
+ UNREF_L(s0);
+ UNREF_L(s1);
+ UNREF_L(s2);
+ UNREF_L(s3);
+ return rc;
+}
+
+JDECL(jint,1set_1authorizer)(JENV_JSELF,jobject jDb, jobject jHook){
+ PerDbStateJni * const ps = PerDbStateJni_for_db(env, jDb, 0, 0);
+ JniHookState * const pHook = ps ? &ps->authHook : 0;
+
+ if( !ps ) return SQLITE_MISUSE;
+ else if( !jHook ){
+ JniHookState_unref(env, pHook, 0);
+ return (jint)sqlite3_set_authorizer( ps->pDb, 0, 0 );
+ }else{
+ int rc = 0;
+ if( pHook->jObj ){
+ if( (*env)->IsSameObject(env, pHook->jObj, jHook) ){
+ /* Same object - this is a no-op. */
+ return 0;
+ }
+ JniHookState_unref(env, pHook, 0);
+ }
+ pHook->jObj = REF_G(jHook);
+ pHook->klazz = REF_G((*env)->GetObjectClass(env, jHook));
+ pHook->midCallback = (*env)->GetMethodID(env, pHook->klazz,
+ "xAuth",
+ "(I"
+ "Ljava/lang/String;"
+ "Ljava/lang/String;"
+ "Ljava/lang/String;"
+ "Ljava/lang/String;"
+ ")I");
+ IFTHREW {
+ JniHookState_unref(env, pHook, 0);
+ return s3jni_db_error(ps->pDb, SQLITE_ERROR,
+ "Error setting up Java parts of authorizer hook.");
+ }
+ rc = sqlite3_set_authorizer(ps->pDb, s3jni_xAuth, ps);
+ if( rc ) JniHookState_unref(env, pHook, 0);
+ return rc;
+ }
+}
+
+
JDECL(void,1set_1last_1insert_1rowid)(JENV_JSELF, jobject jpDb, jlong rowId){
sqlite3_set_last_insert_rowid(PtrGet_sqlite3_context(jpDb),
(sqlite3_int64)rowId);
JNIEXPORT jobject JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1rollback_1hook
(JNIEnv *, jclass, jobject, jobject);
+/*
+ * Class: org_sqlite_jni_SQLite3Jni
+ * Method: sqlite3_set_authorizer
+ * Signature: (Lorg/sqlite/jni/sqlite3;Lorg/sqlite/jni/Authorizer;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1set_1authorizer
+ (JNIEnv *, jclass, jobject, jobject);
+
/*
* Class: org_sqlite_jni_SQLite3Jni
* Method: sqlite3_set_last_insert_rowid
--- /dev/null
+/*
+** 2023-08-05
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file is part of the JNI bindings for the sqlite3 C API.
+*/
+package org.sqlite.jni;
+
+/**
+ A wrapper for use with sqlite3_set_authorizer().
+*/
+public interface Authorizer {
+ /**
+ Must functions as described for the sqlite3_set_authorizer()
+ callback, with one caveat: the string values passed here were
+ initially (at the C level) encoded in standard UTF-8. If they
+ contained any constructs which are not compatible with MUTF-8,
+ these strings will not have the expected values. The strings
+ passed through the authorizer would only be adversely affected by
+ that if the database tables and columns use "highly exotic"
+ names. Any names which contain no NUL bytes, nor characters
+ outside of the Basic Multilingual Plane are unaffected by this
+ discrepancy.
+
+ Must not throw.
+ */
+ int xAuth(int opId, @Nullable String s1, @Nullable String s2,
+ @Nullable String s3, @Nullable String s4);
+}
primarily for testing of the JNI bindings and is not information
which client-level code should use to make any informed
decisions.
-*/
+ */
public static synchronized native boolean uncacheJniEnv();
//////////////////////////////////////////////////////////////////////
- // Maintenance reminder: please keep the functions alphabetized.
- // The SQLITE_... values. on the other hand, are grouped by category.
+ // Maintenance reminder: please keep the sqlite3_.... functions
+ // alphabetized. The SQLITE_... values. on the other hand, are
+ // grouped by category.
public static int sqlite3_bind_blob(@NotNull sqlite3_stmt stmt, int ndx,
@Nullable byte[] data){
public static native RollbackHook sqlite3_rollback_hook(@NotNull sqlite3 db,
@Nullable RollbackHook hook);
+ //! Sets or unsets (if auth is null) the current authorizer.
+ public static native int sqlite3_set_authorizer(@NotNull sqlite3 db,
+ @Nullable Authorizer auth);
+
public static native void sqlite3_set_last_insert_rowid(@NotNull sqlite3 db, long rowid);
public static native int sqlite3_sleep(int ms);
}
if( 0==sqlChunk.length ) break;
rc = sqlite3_prepare_v2(db, sqlChunk, stmt, oTail);
- affirm(0 == rc);
+ if(throwOnError) affirm(0 == rc);
+ else if( 0!=rc ) break;
pos = oTail.getValue();
affirm(0 != stmt.getNativePointer());
while( SQLITE_ROW == (rc = sqlite3_step(stmt)) ){
}
}
}
+ sqlite3_finalize(stmt);
if(SQLITE_ROW==rc || SQLITE_DONE==rc) rc = 0;
return rc;
}
}
}
+ private static void testAuthorizer(){
+ final sqlite3 db = createNewDb();
+ final ValueHolder<Integer> counter = new ValueHolder<>(0);
+ final ValueHolder<Integer> authRc = new ValueHolder<>(0);
+ final Authorizer auth = new Authorizer(){
+ public int xAuth(int op, String s0, String s1, String s2, String s3){
+ ++counter.value;
+ //outln("xAuth(): "+s0+" "+s1+" "+s2+" "+s3);
+ return authRc.value;
+ }
+ };
+ execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES('a'),('b'),('c')");
+ sqlite3_set_authorizer(db, auth);
+ execSql(db, "UPDATE t SET a=1");
+ affirm( 1 == counter.value );
+ authRc.value = SQLITE_DENY;
+ int rc = execSql(db, false, "UPDATE t SET a=2");
+ affirm( SQLITE_AUTH==rc );
+ // TODO: expand these tests considerably
+ sqlite3_close(db);
+ }
+
private static void testSleep(){
out("Sleeping briefly... ");
sqlite3_sleep(600);
testCommitHook();
testRollbackHook();
testUpdateHook();
+ testAuthorizer();
testFts5();
//testSleep();
if(liArgs.indexOf("-v")>0){
-C Refactor\sthe\sper-JNIEnv\scache\sfrom\sa\sfixed-size\sstatic\sarray\sto\sa\slinked\slist\sof\sdynamically-allocated\sentries.\sUncache\sall\sper-db\sstate\s(which\sis\snecessarily\sJNIEnv-specific)\swhen\sthe\scorresponding\sJNIEnv\sis\suncached.
-D 2023-08-05T21:35:58.833
+C Bind\ssqlite3_set_authorizer()\sto\sJNI.
+D 2023-08-05T22:41:36.472
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
F ext/jni/GNUmakefile bb4cd99bd8da534215cb6d278f05a626283eb5d2e8aebdb4d35e548637d35a9a
F ext/jni/README.md 6ff7e1f4100dee980434a6ee37a199b653bceec62e233a6e2ccde6e7ae0c58bf
-F ext/jni/src/c/sqlite3-jni.c a894cb1b6a7479d376d98f7df0e29a713d2b6b6cbc0d4543505b90eb38593592
-F ext/jni/src/c/sqlite3-jni.h cd9b6367a260f55a14833861ceb1d87cb729c5414ba5d26fbb8854b0f22c7249
+F ext/jni/src/c/sqlite3-jni.c b81dcf92a1fbd7ada98dbc0f526b02e9e97e2be84cb331092e933c7d8feeafe2
+F ext/jni/src/c/sqlite3-jni.h 1db6075134d7efc71f634e4a212e41d0178346e68c7c615f220d753e4bd23382
+F ext/jni/src/org/sqlite/jni/Authorizer.java 189e7fa2155466ded5a52eed1ccb46581b5b45d70fcef49f538c0b93ea88e337
F ext/jni/src/org/sqlite/jni/BusyHandler.java 1b1d3e5c86cd796a0580c81b6af6550ad943baa25e47ada0dcca3aff3ebe978c
F ext/jni/src/org/sqlite/jni/Collation.java 8dffbb00938007ad0967b2ab424d3c908413af1bbd3d212b9c9899910f1218d1
F ext/jni/src/org/sqlite/jni/CollationNeeded.java ebc7cd96d46a70daa76016a308e80f70a3f21d3282787c8d139aa840fdcb1bd7
F ext/jni/src/org/sqlite/jni/ProgressHandler.java 5979450e996416d28543f1d42634d308439565a99332a8bd84e424af667116cc
F ext/jni/src/org/sqlite/jni/RollbackHook.java b04c8abcc6ade44a8a57129e33765793f69df0ba909e49ba18d73f4268d92564
F ext/jni/src/org/sqlite/jni/SQLFunction.java 09ce81c1c637e31c3a830d4c859cce95d65f5e02ff45f8bd1985b3479381bc46
-F ext/jni/src/org/sqlite/jni/SQLite3Jni.java f8fec24eea4ff9a62467648f377391506883eff4bedfc50d69d8cb3dc78d1ab9
-F ext/jni/src/org/sqlite/jni/Tester1.java 868b5ea60b788a43f8b15c1b642015341fed8856abb1bb74e2eb4845ade50a4e
+F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 850012ad011d5d60a8aaaf9b8db562c60277988982793135814892e82ac77b97
+F ext/jni/src/org/sqlite/jni/Tester1.java 214985f8a700ac56a174809c04196215fef5d7bb8b86e095d9d0abf436349ffb
F ext/jni/src/org/sqlite/jni/TesterFts5.java cf2d687baafffdeba219b77cf611fd47a0556248820ea794ae3e8259bfbdc5ee
F ext/jni/src/org/sqlite/jni/Tracer.java a5cece9f947b0af27669b8baec300b6dd7ff859c3e6a6e4a1bd8b50f9714775d
F ext/jni/src/org/sqlite/jni/UpdateHook.java e58645a1727f8a9bbe72dc072ec5b40d9f9362cb0aa24acfe93f49ff56a9016d
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 7468f8761bece58f7ced3d112bbe2fb454432d9c54c9b96cedb5a15bc2926d0f
-R c28f39c95821b6209d9e0ded55b1b7ca
+P 9dd8b78419e19e88bc3fbff9bf200390b146b2461af2bb6b93d8467036619e33
+R bf3d1c30171f035a2002cb68468caf2a
U stephan
-Z 6d5410b49d781e986fb3ebb97da80215
+Z a910bd2897a92249409319f7eba80e4a
# Remove this line to create a well-formed Fossil manifest.
-9dd8b78419e19e88bc3fbff9bf200390b146b2461af2bb6b93d8467036619e33
\ No newline at end of file
+e0fa03135942cd2fe732a74510d380ba78ab230c452168e638f32b4aee04b3f7
\ No newline at end of file