struct {
S3JniEnvCache * aHead /* Linked list of in-use instances */;
S3JniEnvCache * aFree /* Linked list of free instances */;
+ sqlite3_mutex * mutex /* mutex for aHead and aFree */;
+ void const * locker /* env mutex is held on this object's behalf */;
} envCache;
struct {
S3JniDb * aUsed /* Linked list of in-use instances */;
S3JniDb * aFree /* Linked list of free instances */;
+ sqlite3_mutex * mutex /* mutex for aUsed and aFree */;
+ void const * locker /* perDb mutex is held on this object's behalf */;
} perDb;
struct {
unsigned nphCacheHits;
#if S3JNI_ENABLE_AUTOEXT
struct {
S3JniAutoExtension *pHead /* Head of the auto-extension list */;
- S3JniDb * psOpening /* handle to the being-opened db. We
- need this so that auto extensions
- can have a consistent view of the
- cross-language db connection and
- behave property if they call further
- db APIs. */;
- int isRunning /* True while auto extensions are
- running. This is used to prohibit
- manipulation of the auto-extension
- list while extensions are
- running. */;
+ S3JniDb * psOpening /* FIXME: move into envCache. Handle to the
+ being-opened db. We need this so that auto
+ extensions can have a consistent view of
+ the cross-language db connection and
+ behave property if they call further db
+ APIs. */;
+ int isRunning /* True while auto extensions are
+ running. This is used to prohibit
+ manipulation of the auto-extension
+ list while extensions are
+ running. */;
} autoExt;
#endif
} S3JniGlobal;
+#define MUTEX_ASSERT_LOCKER_ENV \
+ assert( (env) == S3JniGlobal.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" )
+#define MUTEX_ASSERT_LOCKER_PDB \
+ assert( 0 != S3JniGlobal.perDb.locker && "Misuse of S3JniGlobal.perDb.mutex" )
+#define MUTEX_ASSERT_NOTLOCKER_ENV \
+ assert( (env) != S3JniGlobal.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" )
+#define MUTEX_ASSERT_NOTLOCKER_PDB \
+ assert( 0 == S3JniGlobal.perDb.locker && "Misuse of S3JniGlobal.perDb.mutex" )
+#define MUTEX_ENTER_ENV \
+ /*MARKER(("Entering ENV mutex@%p %s.\n", env, __func__));*/ \
+ MUTEX_ASSERT_NOTLOCKER_ENV; \
+ sqlite3_mutex_enter( S3JniGlobal.envCache.mutex ); \
+ S3JniGlobal.envCache.locker = env
+#define MUTEX_LEAVE_ENV \
+ /*MARKER(("Leaving ENV mutex @%p %s.\n", env, __func__));*/ \
+ MUTEX_ASSERT_LOCKER_ENV; \
+ S3JniGlobal.envCache.locker = 0; \
+ sqlite3_mutex_leave( S3JniGlobal.envCache.mutex )
+#define MUTEX_ENTER_PDB \
+ /*MARKER(("Entering PerDb mutex@%p %s.\n", env, __func__));*/ \
+ MUTEX_ASSERT_NOTLOCKER_PDB; \
+ sqlite3_mutex_enter( S3JniGlobal.perDb.mutex ); \
+ S3JniGlobal.perDb.locker = env;
+#define MUTEX_LEAVE_PDB \
+ /*MARKER(("Leaving PerDb mutex@%p %s.\n", env, __func__));*/ \
+ MUTEX_ASSERT_LOCKER_PDB; \
+ S3JniGlobal.perDb.locker = 0; \
+ sqlite3_mutex_leave( S3JniGlobal.perDb.mutex )
+
#define OOM_CHECK(VAR) if(!(VAR)) s3jni_oom(env)
static void s3jni_oom(JNIEnv * const env){
(*env)->FatalError(env, "Out of memory.") /* does not return */;
insofar as possible. Calls (*env)->FatalError() if allocation of
an entry fails. That's hypothetically possible but "shouldn't happen."
*/
-FIXME_THREADING(S3JniEnvCache)
static S3JniEnvCache * S3JniGlobal_env_cache(JNIEnv * const env){
- struct S3JniEnvCache * row = S3JniGlobal.envCache.aHead;
+ struct S3JniEnvCache * row;
+ MUTEX_ENTER_ENV;
+ row = S3JniGlobal.envCache.aHead;
for( ; row; row = row->pNext ){
if( row->env == env ){
++S3JniGlobal.metrics.envCacheHits;
+ MUTEX_LEAVE_ENV;
return row;
}
}
if( row->pNext ) row->pNext->pPrev = 0;
}else{
row = sqlite3_malloc(sizeof(S3JniEnvCache));
- if( !row ){
- (*env)->FatalError(env, "Maintenance required: S3JniEnvCache is full.")
- /* Does not return, but cc doesn't know that */;
- return NULL;
- }
+ OOM_CHECK(row);
}
memset(row, 0, sizeof(*row));
row->pNext = S3JniGlobal.envCache.aHead;
EXCEPTION_IS_FATAL("Error getting reference to StndardCharsets class.");
fUtf8 = (*env)->GetStaticFieldID(env, klazzSC, "UTF_8",
"Ljava/nio/charset/Charset;");
- EXCEPTION_IS_FATAL("Error getting StndardCharsets.UTF_8 field.");
+ EXCEPTION_IS_FATAL("Error getting StandardCharsets.UTF_8 field.");
row->g.oCharsetUtf8 =
REF_G((*env)->GetStaticObjectField(env, klazzSC, fUtf8));
EXCEPTION_IS_FATAL("Error getting reference to StandardCharsets.UTF_8.");
}
+ MUTEX_LEAVE_ENV;
return row;
}
System.out.println(e.getMessage()); // Hi
}
*/
-FIXME_THREADING(S3JniEnvCache)
static char * s3jni_exception_error_msg(JNIEnv * const env, jthrowable jx ){
S3JniEnvCache * const jc = S3JniGlobal_env_cache(env);
jmethodID mid;
/**
Clears s's state and moves it to the free-list.
*/
-FIXME_THREADING(perDb)
static void S3JniDb_set_aside(S3JniDb * const s){
if(s){
JNIEnv * const env = s->env;
+ MUTEX_ASSERT_LOCKER_PDB;
assert(s->pDb && "Else this object is already in the free-list.");
//MARKER(("state@%p for db@%p setting aside\n", s, s->pDb));
assert(s->pPrev != s);
//if(s->pNext) MARKER(("next: %p->pPrev@%p\n", s->pNext, s->pNext->pPrev));
}
}
-
-/**
- Requires that p has been snipped from any linked list it is
- in. Clears all Java refs p holds and zeroes out p.
-*/
-static void S3JniEnvCache_clear(S3JniEnvCache * const p){
- JNIEnv * const env = p->env;
- if(env){
- int i;
- UNREF_G(p->g.cObj);
- UNREF_G(p->g.cLong);
- UNREF_G(p->g.cString);
- UNREF_G(p->g.oCharsetUtf8);
-#ifdef SQLITE_ENABLE_FTS5
- UNREF_G(p->jFtsExt);
- UNREF_G(p->jPhraseIter.klazz);
-#endif
- for( i = 0; i < NphCache_SIZE; ++i ){
- S3JniNphCache_clear(env, &p->nph[i]);
- }
- memset(p, 0, sizeof(S3JniEnvCache));
- }
-}
-
/**
Cleans up all state in S3JniGlobal.perDb for th given JNIEnv.
Results are undefined if a Java-side db uses the API
from the given JNIEnv after this call.
*/
-FIXME_THREADING(perDb)
static void S3JniDb_free_for_env(JNIEnv *env){
- S3JniDb * ps = S3JniGlobal.perDb.aUsed;
+ S3JniDb * ps;
S3JniDb * pNext = 0;
+ MUTEX_ENTER_PDB;
+ ps = S3JniGlobal.perDb.aUsed;
for( ; ps; ps = pNext ){
pNext = ps->pNext;
if(ps->env == env){
pNext = pPrev;
}
}
+ MUTEX_LEAVE_PDB;
}
/**
what would otherwise be stale references.
*/
static int S3JniGlobal_env_uncache(JNIEnv * const env){
- struct S3JniEnvCache * row = S3JniGlobal.envCache.aHead;
+ struct S3JniEnvCache * row;
+ int i;
+ assert( 0!=S3JniGlobal.envCache.mutex && "Env mutex misuse.");
+ row = S3JniGlobal.envCache.aHead;
for( ; row; row = row->pNext ){
if( row->env == env ){
break;
}
}
- if( !row ) return 0;
+ if( !row ){
+ return 0;
+ }
if( row->pNext ) row->pNext->pPrev = row->pPrev;
if( row->pPrev ) row->pPrev->pNext = row->pNext;
if( S3JniGlobal.envCache.aHead == row ){
assert( !row->pPrev );
S3JniGlobal.envCache.aHead = row->pNext;
}
- S3JniEnvCache_clear(row);
- assert( !row->pNext );
- assert( !row->pPrev );
+ S3JniDb_free_for_env(env);
+ UNREF_G(row->g.cObj);
+ UNREF_G(row->g.cLong);
+ UNREF_G(row->g.cString);
+ UNREF_G(row->g.oCharsetUtf8);
+#ifdef SQLITE_ENABLE_FTS5
+ UNREF_G(row->jFtsExt);
+ UNREF_G(row->jPhraseIter.klazz);
+#endif
+ for( i = 0; i < NphCache_SIZE; ++i ){
+ S3JniNphCache_clear(env, &row->nph[i]);
+ }
+ memset(row, 0, sizeof(S3JniEnvCache));
row->pNext = S3JniGlobal.envCache.aFree;
if( row->pNext ) row->pNext->pPrev = row;
S3JniGlobal.envCache.aFree = row;
- S3JniDb_free_for_env(env);
return 1;
}
-static void S3JniGlobal_S3JniEnvCache_clear(void){
- while( S3JniGlobal.envCache.aHead ){
- S3JniGlobal_env_uncache( S3JniGlobal.envCache.aHead->env );
- }
-}
-
/**
Searches the NativePointerHolder cache for the given combination.
If it finds one, it returns it as-is. If it doesn't AND the cache
}
/**
- Extracts the new S3JniDb instance from the free-list, or
- allocates one if needed, associats it with pDb, and returns.
- Returns NULL on OOM. pDb MUST be associated with jDb via
- NativePointerHolder_set().
+ Extracts the new S3JniDb instance from the free-list, or allocates
+ one if needed, associats it with pDb, and returns. Returns NULL on
+ OOM. pDb MUST, on success of the calling operation, subsequently be
+ associated with jDb via NativePointerHolder_set().
*/
static S3JniDb * S3JniDb_alloc(JNIEnv * const env, sqlite3 *pDb,
jobject jDb){
S3JniDb * rv;
+ MUTEX_ASSERT_LOCKER_PDB;
if(S3JniGlobal.perDb.aFree){
rv = S3JniGlobal.perDb.aFree;
//MARKER(("state@%p for db allocating for db@%p from free-list\n", rv, pDb));
#endif
/**
- Returns the S3JniDb object for the given db. If allocIfNeeded is
- true then a new instance will be allocated if no mapping currently
- exists, else NULL is returned if no mapping is found.
-
- The 3rd and 4th args should normally only be non-0 for
- sqlite3_open(_v2)(). For most other cases, they must be 0, in which
- case the db handle will be fished out of the jDb object and NULL is
- returned if jDb does not have any associated S3JniDb.
-
- If called with a NULL jDb and non-NULL pDb then allocIfNeeded MUST
- be false and it will look for a matching db object. That usage is
- required for functions, like sqlite3_context_db_handle(), which
- return a (sqlite3*) but do not take one as an argument.
+ Returns the S3JniDb object for the given db.
+
+ The 3rd argument should normally only be non-0 for routines which
+ are called from the C library and pass a native db handle instead of
+ a Java handle. In normal usage, the 2nd argument is a Java-side sqlite3
+ object, from which the db is fished out.
+
+ Returns NULL if jDb and pDb are both NULL or if there is no
+ matching S3JniDb entry for pDb or the pointer fished out of jDb.
*/
FIXME_THREADING(S3JniEnvCache)
FIXME_THREADING(perDb)
-static S3JniDb * S3JniDb_for_db(JNIEnv * const env, jobject jDb,
- sqlite3 *pDb, int allocIfNeeded){
- S3JniDb * s = S3JniGlobal.perDb.aUsed;
- if(!jDb){
- if(pDb){
- assert(!allocIfNeeded);
- }else{
- return 0;
+static S3JniDb * S3JniDb_for_db(JNIEnv * const env, jobject jDb, sqlite3 *pDb){
+ S3JniDb * s = 0;
+ if(jDb || pDb){
+ MUTEX_ENTER_PDB;
+ s = S3JniGlobal.perDb.aUsed;
+ if(!pDb){
+ assert( jDb );
+ pDb = PtrGet_sqlite3(jDb);
}
- }
- assert(allocIfNeeded ? !!pDb : 1);
- if(!allocIfNeeded && !pDb){
- pDb = PtrGet_sqlite3(jDb);
- }
- for( ; pDb && s; s = s->pNext){
- if(s->pDb == pDb) return s;
- }
- if(allocIfNeeded){
- s = S3JniDb_alloc(env, pDb, jDb);
+ for( ; pDb && s; s = s->pNext){
+ if(s->pDb == pDb){
+ break;
+ }
+ }
+ MUTEX_LEAVE_PDB;
}
return s;
}
-#if 0
-/**
- An alternative form which searches for the S3JniDb instance for
- pDb with no JNIEnv-specific info. This can be (but _should_ it be?)
- called from the context of a separate JNIEnv than the one mapped
- to in the returned object. Returns 0 if no match is found.
-*/
-FIXME_THREADING(perDb)
-static S3JniDb * S3JniDb_for_db2(sqlite3 *pDb){
- S3JniDb * s = S3JniGlobal.perDb.aUsed;
- for( ; pDb && s; s = s->pNext){
- if(s->pDb == pDb) return s;
- }
- return 0;
-}
-#endif
-
#if S3JNI_ENABLE_AUTOEXT
/**
Unlink ax from S3JniGlobal.autoExt and free it.
FIXME_THREADING(S3JniEnvCache)
JDECL(jint,1busy_1handler)(JENV_CSELF, jobject jDb, jobject jBusy){
- S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0);
+ S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0);
int rc = 0;
if(!ps) return (jint)SQLITE_NOMEM;
if(jBusy){
FIXME_THREADING(S3JniEnvCache)
FIXME_THREADING(perDb)
JDECL(jint,1busy_1timeout)(JENV_CSELF, jobject jDb, jint ms){
- S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0);
+ S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0);
if( ps ){
S3JniHook_unref(env, &ps->busyHandler, 1);
return sqlite3_busy_timeout(ps->pDb, (int)ms);
int rc = 0;
S3JniDb * ps = 0;
assert(version == 1 || version == 2);
- ps = S3JniDb_for_db(env, jDb, 0, 0);
+ ps = S3JniDb_for_db(env, jDb, 0);
if(ps){
- //MARKER(("close()ing db@%p\n", ps->pDb));
rc = 1==version ? (jint)sqlite3_close(ps->pDb) : (jint)sqlite3_close_v2(ps->pDb);
+ MUTEX_ENTER_PDB;
S3JniDb_set_aside(ps)
/* MUST come after close() because of ps->trace. */;
+ MUTEX_LEAVE_PDB;
NativePointerHolder_set(env, jDb, 0, S3JniClassNames.sqlite3);
}
return (jint)rc;
FIXME_THREADING(S3JniEnvCache)
FIXME_THREADING(perDb)
JDECL(jint,1collation_1needed)(JENV_CSELF, jobject jDb, jobject jHook){
- S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0);
+ S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0);
jclass klazz;
jobject pOld = 0;
jmethodID xCallback;
FIXME_THREADING(perDb)
static jobject s3jni_commit_rollback_hook(int isCommit, JNIEnv * const env,jobject jDb,
jobject jHook){
- S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0);
+ S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0);
jclass klazz;
jobject pOld = 0;
jmethodID xCallback;
FIXME_THREADING(perDb)
JDECL(jobject,1context_1db_1handle)(JENV_CSELF, jobject jpCx){
sqlite3 * const pDb = sqlite3_context_db_handle(PtrGet_sqlite3_context(jpCx));
- S3JniDb * const ps = pDb ? S3JniDb_for_db(env, 0, pDb, 0) : 0;
+ S3JniDb * const ps = pDb ? S3JniDb_for_db(env, 0, pDb) : 0;
return ps ? ps->jDb : 0;
}
JDECL(jint,1create_1collation)(JENV_CSELF, jobject jDb,
jstring name, jint eTextRep,
jobject oCollation){
- S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0);
+ S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0);
jclass klazz;
int rc;
const char *zName;
JDECL(int,1db_1config__Lorg_sqlite_jni_sqlite3_2ILjava_lang_String_2)(
JENV_CSELF, jobject jDb, jint op, jstring jStr
){
- S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0);
+ S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0);
int rc;
char *zStr;
JDECL(jint,1db_1config__Lorg_sqlite_jni_sqlite3_2IILorg_sqlite_jni_OutputPointer_Int32_2)(
JENV_CSELF, jobject jDb, jint op, jint onOff, jobject jOut
){
- S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0);
+ S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0);
int rc;
switch( ps ? op : 0 ){
case SQLITE_DBCONFIG_ENABLE_FKEY:
}
JDECL(jstring,1db_1filename)(JENV_CSELF, jobject jDb, jstring jDbName){
- S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0);
+ S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0);
S3JniEnvCache * const jc = S3JniGlobal_env_cache(env);
char *zDbName;
jstring jRv = 0;
*zDbName = 0;
return SQLITE_NOMEM;
}
+ MUTEX_ENTER_PDB;
*ps = S3JniDb_alloc(env, 0, *jDb);
+ MUTEX_LEAVE_PDB;
#if S3JNI_ENABLE_AUTOEXT
if(*ps){
assert(!S3JniGlobal.autoExt.psOpening);
#endif
if(*ppDb){
assert(ps->jDb);
-#if S3JNI_ENABLE_AUTOEXT
- //MARKER(("*autoExt.pHead=%p, ppDb=%p, ps->pDb=%p\n", S3JniGlobal.autoExt.pHead, *ppDb, ps->pDb));
- // invalid when an autoext triggers another open():
- // assert( S3JniGlobal.autoExt.pHead ? *ppDb==ps->pDb : 0==ps->pDb );
-#endif
ps->pDb = *ppDb;
NativePointerHolder_set(env, ps->jDb, *ppDb, S3JniClassNames.sqlite3);
}else{
+ MUTEX_ENTER_PDB;
S3JniDb_set_aside(ps);
+ MUTEX_LEAVE_PDB;
ps = 0;
}
OutputPointer_set_sqlite3(env, jOut, ps ? ps->jDb : 0);
}
JDECL(void,1progress_1handler)(JENV_CSELF,jobject jDb, jint n, jobject jProgress){
- S3JniDb * ps = S3JniDb_for_db(env, jDb, 0, 0);
+ S3JniDb * ps = S3JniDb_for_db(env, jDb, 0);
jclass klazz;
jmethodID xCallback;
if( n<1 || !jProgress ){
}
JDECL(jint,1set_1authorizer)(JENV_CSELF,jobject jDb, jobject jHook){
- S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0);
+ S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0);
S3JniHook * const pHook = ps ? &ps->authHook : 0;
if( !ps ) return SQLITE_MISUSE;
}
JDECL(jint,1shutdown)(JENV_CSELF){
- S3JniGlobal_S3JniEnvCache_clear();
+ MUTEX_ENTER_ENV;
+ while( S3JniGlobal.envCache.aHead ){
+ S3JniGlobal_env_uncache( S3JniGlobal.envCache.aHead->env );
+ }
+ MUTEX_LEAVE_ENV;
/* Do not clear S3JniGlobal.jvm: it's legal to call
sqlite3_initialize() again to restart the lib. */
return sqlite3_shutdown();
}
JDECL(jint,1trace_1v2)(JENV_CSELF,jobject jDb, jint traceMask, jobject jTracer){
- S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0);
+ S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0);
jclass klazz;
if( !traceMask || !jTracer ){
if(ps){
JDECL(jobject,1update_1hook)(JENV_CSELF, jobject jDb, jobject jHook){
- S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0);
+ S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0);
jclass klazz;
jobject pOld = 0;
jmethodID xCallback;
}
JDECLFtsApi(jobject,getInstanceForDb)(JENV_CSELF,jobject jDb){
- S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0, 0);
+ S3JniDb * const ps = S3JniDb_for_db(env, jDb, 0);
jobject rv = 0;
if(!ps) return 0;
else if(ps->jFtsApi){
*/
JNIEXPORT jboolean JNICALL
Java_org_sqlite_jni_SQLite3Jni_uncacheJniEnv(JENV_CSELF){
- return S3JniGlobal_env_uncache(env) ? JNI_TRUE : JNI_FALSE;
+ int rc;
+ MUTEX_ENTER_ENV;
+ rc = S3JniGlobal_env_uncache(env);
+ MUTEX_LEAVE_ENV;
+ return rc ? JNI_TRUE : JNI_FALSE;
}
/**
(*env)->FatalError(env, "GetJavaVM() failure shouldn't be possible.");
return;
}
+ S3JniGlobal.envCache.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+ OOM_CHECK( S3JniGlobal.envCache.mutex );
+ S3JniGlobal.perDb.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+ OOM_CHECK( S3JniGlobal.perDb.mutex );
#if 0
/* Just for sanity checking... */
(void)S3JniGlobal_env_cache(env);
Achtung: it is as yet unknown whether auto extensions registered
from one JNIEnv (thread) can be safely called from another.
*/
- public static synchronized native int sqlite3_auto_extension(@NotNull AutoExtension callback);
+ public static native int sqlite3_auto_extension(@NotNull AutoExtension callback);
public static int sqlite3_bind_blob(
@NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data
: sqlite3_bind_blob(stmt, ndx, data, data.length);
}
- private static synchronized native int sqlite3_bind_blob(
+ private static native int sqlite3_bind_blob(
@NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data, int n
);
- public static synchronized native int sqlite3_bind_double(
+ public static native int sqlite3_bind_double(
@NotNull sqlite3_stmt stmt, int ndx, double v
);
- public static synchronized native int sqlite3_bind_int(
+ public static native int sqlite3_bind_int(
@NotNull sqlite3_stmt stmt, int ndx, int v
);
- public static synchronized native int sqlite3_bind_int64(
+ public static native int sqlite3_bind_int64(
@NotNull sqlite3_stmt stmt, int ndx, long v
);
- public static synchronized native int sqlite3_bind_null(
+ public static native int sqlite3_bind_null(
@NotNull sqlite3_stmt stmt, int ndx
);
- public static synchronized native int sqlite3_bind_parameter_count(
+ public static native int sqlite3_bind_parameter_count(
@NotNull sqlite3_stmt stmt
);
/** A level of indirection required to ensure that the input to the
C-level function of the same name is a NUL-terminated UTF-8
string. */
- private static synchronized native int sqlite3_bind_parameter_index(
+ private static native int sqlite3_bind_parameter_index(
@NotNull sqlite3_stmt stmt, byte[] paramName
);
SQLITE_TRANSIENT for the final parameter and (B) behaves like
sqlite3_bind_null() if the data argument is null.
*/
- private static synchronized native int sqlite3_bind_text(
+ private static native int sqlite3_bind_text(
@NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data, int maxBytes
);
- public static synchronized native int sqlite3_bind_zeroblob(
+ public static native int sqlite3_bind_zeroblob(
@NotNull sqlite3_stmt stmt, int ndx, int n
);
- public static synchronized native int sqlite3_bind_zeroblob64(
+ public static native int sqlite3_bind_zeroblob64(
@NotNull sqlite3_stmt stmt, int ndx, long n
);
to clear the busy handler. Calling this multiple times with the
same object is a no-op on the second and subsequent calls.
*/
- public static synchronized native int sqlite3_busy_handler(
+ public static native int sqlite3_busy_handler(
@NotNull sqlite3 db, @Nullable BusyHandler handler
);
- public static synchronized native int sqlite3_busy_timeout(
+ public static native int sqlite3_busy_timeout(
@NotNull sqlite3 db, int ms
);
effects, if auto extensions are currently running. (The JNI-level
list of extensions cannot be manipulated while it is being traversed.)
*/
- public static synchronized native boolean sqlite3_cancel_auto_extension(
+ public static native boolean sqlite3_cancel_auto_extension(
@NotNull AutoExtension ax
);
- public static synchronized native int sqlite3_changes(
+ public static native int sqlite3_changes(
@NotNull sqlite3 db
);
- public static synchronized native long sqlite3_changes64(
+ public static native long sqlite3_changes64(
@NotNull sqlite3 db
);
- public static synchronized native int sqlite3_clear_bindings(
+ public static native int sqlite3_clear_bindings(
@NotNull sqlite3_stmt stmt
);
- public static synchronized native int sqlite3_close(
+ public static native int sqlite3_close(
@NotNull sqlite3 db
);
- public static synchronized native int sqlite3_close_v2(
+ public static native int sqlite3_close_v2(
@NotNull sqlite3 db
);
- public static synchronized native byte[] sqlite3_column_blob(
+ public static native byte[] sqlite3_column_blob(
@NotNull sqlite3_stmt stmt, int ndx
);
- public static synchronized native int sqlite3_column_bytes(
+ public static native int sqlite3_column_bytes(
@NotNull sqlite3_stmt stmt, int ndx
);
- public static synchronized native int sqlite3_column_bytes16(
+ public static native int sqlite3_column_bytes16(
@NotNull sqlite3_stmt stmt, int ndx
);
- public static synchronized native int sqlite3_column_count(
+ public static native int sqlite3_column_count(
@NotNull sqlite3_stmt stmt
);
- public static synchronized native double sqlite3_column_double(
+ public static native double sqlite3_column_double(
@NotNull sqlite3_stmt stmt, int ndx
);
- public static synchronized native int sqlite3_column_int(
+ public static native int sqlite3_column_int(
@NotNull sqlite3_stmt stmt, int ndx
);
- public static synchronized native long sqlite3_column_int64(
+ public static native long sqlite3_column_int64(
@NotNull sqlite3_stmt stmt, int ndx
);
- public static synchronized native String sqlite3_column_name(
+ public static native String sqlite3_column_name(
@NotNull sqlite3_stmt stmt, int ndx
);
- public static synchronized native String sqlite3_column_database_name(
+ public static native String sqlite3_column_database_name(
@NotNull sqlite3_stmt stmt, int ndx
);
return type.isInstance(o) ? (T)o : null;
}
- public static synchronized native String sqlite3_column_origin_name(
+ public static native String sqlite3_column_origin_name(
@NotNull sqlite3_stmt stmt, int ndx
);
- public static synchronized native String sqlite3_column_table_name(
+ public static native String sqlite3_column_table_name(
@NotNull sqlite3_stmt stmt, int ndx
);
This API includes no functions for working with Java's Modified
UTF-8.
*/
- public static synchronized native String sqlite3_column_text16(
+ public static native String sqlite3_column_text16(
@NotNull sqlite3_stmt stmt, int ndx
);
Returns the given column's contents as UTF-8-encoded (not MUTF-8) text.
Use sqlite3_column_text16() to fetch the text
*/
- public static synchronized native byte[] sqlite3_column_text(
+ public static native byte[] sqlite3_column_text(
@NotNull sqlite3_stmt stmt, int ndx
);
// return rv;
// }
- public static synchronized native int sqlite3_column_type(
+ public static native int sqlite3_column_type(
@NotNull sqlite3_stmt stmt, int ndx
);
- public static synchronized native sqlite3_value sqlite3_column_value(
+ public static native sqlite3_value sqlite3_column_value(
@NotNull sqlite3_stmt stmt, int ndx
);
This functions like C's sqlite3_collation_needed16() because
Java's string type is compatible with that interface.
*/
- public static synchronized native int sqlite3_collation_needed(
+ public static native int sqlite3_collation_needed(
@NotNull sqlite3 db, @Nullable CollationNeeded callback
);
Returns the db handle passed to sqlite3_open() or
sqlite3_open_v2(), as opposed to a new wrapper object.
*/
- public static synchronized native sqlite3 sqlite3_context_db_handle(
+ public static native sqlite3 sqlite3_context_db_handle(
@NotNull sqlite3_context cx
);
- public static synchronized native CommitHook sqlite3_commit_hook(
+ public static native CommitHook sqlite3_commit_hook(
@NotNull sqlite3 db, @Nullable CommitHook hook
);
@NotNull String optName
);
- public static synchronized native int sqlite3_create_collation(
+ public static native int sqlite3_create_collation(
@NotNull sqlite3 db, @NotNull String name, int eTextRep,
@NotNull Collation col
);
SQLFunction's inner classes (Scalar, Aggregate<T>, and Window<T>)
for details.
*/
- public static synchronized native int sqlite3_create_function(
+ public static native int sqlite3_create_function(
@NotNull sqlite3 db, @NotNull String functionName,
int nArg, int eTextRep, @NotNull SQLFunction func
);
- public static synchronized native int sqlite3_data_count(
+ public static native int sqlite3_data_count(
@NotNull sqlite3_stmt stmt
);
- public static synchronized native String sqlite3_db_filename(
+ public static native String sqlite3_db_filename(
@NotNull sqlite3 db, @NotNull String dbName
);
variadic arguments. Returns SQLITE_MISUSE if op is not one of the
SQLITE_DBCONFIG_... options which uses this call form.
*/
- public static synchronized native int sqlite3_db_config(
+ public static native int sqlite3_db_config(
@NotNull sqlite3 db, int op, int onOff, @Nullable OutputPointer.Int32 out
);
SQLITE_DBCONFIG_MAINDBNAME, but that set of options may be
extended in future versions.
*/
- public static synchronized native int sqlite3_db_config(
+ public static native int sqlite3_db_config(
@NotNull sqlite3 db, int op, @NotNull String val
);
- public static synchronized native int sqlite3_db_status(
+ public static native int sqlite3_db_status(
@NotNull sqlite3 db, int op, @NotNull OutputPointer.Int32 pCurrent,
@NotNull OutputPointer.Int32 pHighwater, boolean reset
);
- public static synchronized native int sqlite3_errcode(@NotNull sqlite3 db);
+ public static native int sqlite3_errcode(@NotNull sqlite3 db);
- public static synchronized native String sqlite3_expanded_sql(@NotNull sqlite3_stmt stmt);
+ public static native String sqlite3_expanded_sql(@NotNull sqlite3_stmt stmt);
- public static synchronized native int sqlite3_extended_errcode(@NotNull sqlite3 db);
+ public static native int sqlite3_extended_errcode(@NotNull sqlite3 db);
- public static synchronized native boolean sqlite3_extended_result_codes(
+ public static native boolean sqlite3_extended_result_codes(
@NotNull sqlite3 db, boolean onoff
);
- public static synchronized native String sqlite3_errmsg(@NotNull sqlite3 db);
+ public static native String sqlite3_errmsg(@NotNull sqlite3 db);
- public static synchronized native String sqlite3_errstr(int resultCode);
+ public static native String sqlite3_errstr(int resultCode);
/**
Note that the offset values assume UTF-8-encoded SQL.
*/
- public static synchronized native int sqlite3_error_offset(@NotNull sqlite3 db);
+ public static native int sqlite3_error_offset(@NotNull sqlite3 db);
- public static synchronized native int sqlite3_finalize(@NotNull sqlite3_stmt stmt);
+ public static native int sqlite3_finalize(@NotNull sqlite3_stmt stmt);
- public static synchronized native int sqlite3_initialize();
+ public static native int sqlite3_initialize();
/**
Design note/FIXME: we have a problem vis-a-vis 'synchronized'
//! See sqlite3_interrupt() for threading concerns.
public static native boolean sqlite3_is_interrupted(@NotNull sqlite3 db);
- public static synchronized native long sqlite3_last_insert_rowid(@NotNull sqlite3 db);
+ public static native long sqlite3_last_insert_rowid(@NotNull sqlite3 db);
- public static synchronized native String sqlite3_libversion();
+ public static native String sqlite3_libversion();
- public static synchronized native int sqlite3_libversion_number();
+ public static native int sqlite3_libversion_number();
/**
Works like its C counterpart and makes the native pointer of the
or sqlite3_open_v2() so that they have a predictible object to
pass to, e.g., the sqlite3_collation_needed() callback.
*/
- public static synchronized native int sqlite3_open(
+ public static native int sqlite3_open(
@Nullable String filename, @NotNull OutputPointer.sqlite3 ppDb
);
- public static synchronized native int sqlite3_open_v2(
+ public static native int sqlite3_open_v2(
@Nullable String filename, @NotNull OutputPointer.sqlite3 ppDb,
int flags, @Nullable String zVfs
);
necessary, however, and overloads are provided which gloss over
that.
*/
- private static synchronized native int sqlite3_prepare(
+ private static native int sqlite3_prepare(
@NotNull sqlite3 db, @NotNull byte[] sqlUtf8, int maxBytes,
@NotNull OutputPointer.sqlite3_stmt outStmt,
@Nullable OutputPointer.Int32 pTailOffset
return sqlite3_prepare(db, utf8, utf8.length, outStmt, null);
}
- private static synchronized native int sqlite3_prepare_v2(
+ private static native int sqlite3_prepare_v2(
@NotNull sqlite3 db, @NotNull byte[] sqlUtf8, int maxBytes,
@NotNull OutputPointer.sqlite3_stmt outStmt,
@Nullable OutputPointer.Int32 pTailOffset
return sqlite3_prepare_v2(db, utf8, utf8.length, outStmt, null);
}
- private static synchronized native int sqlite3_prepare_v3(
+ private static native int sqlite3_prepare_v3(
@NotNull sqlite3 db, @NotNull byte[] sqlUtf8, int maxBytes,
int prepFlags, @NotNull OutputPointer.sqlite3_stmt outStmt,
@Nullable OutputPointer.Int32 pTailOffset
return sqlite3_prepare_v3(db, utf8, utf8.length, prepFlags, outStmt, null);
}
- public static synchronized native void sqlite3_progress_handler(
+ public static native void sqlite3_progress_handler(
@NotNull sqlite3 db, int n, @Nullable ProgressHandler h
);
//TODO??? void *sqlite3_preupdate_hook(...) and friends
- public static synchronized native int sqlite3_reset(@NotNull sqlite3_stmt stmt);
+ public static native int sqlite3_reset(@NotNull sqlite3_stmt stmt);
/**
Works like the C API except that it has no side effects if auto
extensions are currently running. (The JNI-level list of
extensions cannot be manipulated while it is being traversed.)
*/
- public static synchronized native void sqlite3_reset_auto_extension();
+ public static native void sqlite3_reset_auto_extension();
- public static synchronized native void sqlite3_result_double(
+ public static native void sqlite3_result_double(
@NotNull sqlite3_context cx, double v
);
results in the C-level sqlite3_result_error() being called with
a complaint about the invalid argument.
*/
- private static synchronized native void sqlite3_result_error(
+ private static native void sqlite3_result_error(
@NotNull sqlite3_context cx, @Nullable byte[] msg,
int eTextRep
);
sqlite3_result_error16(cx, e.getMessage());
}
- public static synchronized native void sqlite3_result_error_toobig(
+ public static native void sqlite3_result_error_toobig(
@NotNull sqlite3_context cx
);
- public static synchronized native void sqlite3_result_error_nomem(
+ public static native void sqlite3_result_error_nomem(
@NotNull sqlite3_context cx
);
- public static synchronized native void sqlite3_result_error_code(
+ public static native void sqlite3_result_error_code(
@NotNull sqlite3_context cx, int c
);
- public static synchronized native void sqlite3_result_null(
+ public static native void sqlite3_result_null(
@NotNull sqlite3_context cx
);
- public static synchronized native void sqlite3_result_int(
+ public static native void sqlite3_result_int(
@NotNull sqlite3_context cx, int v
);
- public static synchronized native void sqlite3_result_int64(
+ public static native void sqlite3_result_int64(
@NotNull sqlite3_context cx, long v
);
Note that there is no sqlite3_bind_java_object() counterpart.
*/
- public static synchronized native void sqlite3_result_java_object(
+ public static native void sqlite3_result_java_object(
@NotNull sqlite3_context cx, @NotNull Object o
);
sqlite3_result_text(cx, v);
}
- public static synchronized native void sqlite3_result_value(
+ public static native void sqlite3_result_value(
@NotNull sqlite3_context cx, @NotNull sqlite3_value v
);
- public static synchronized native void sqlite3_result_zeroblob(
+ public static native void sqlite3_result_zeroblob(
@NotNull sqlite3_context cx, int n
);
- public static synchronized native int sqlite3_result_zeroblob64(
+ public static native int sqlite3_result_zeroblob64(
@NotNull sqlite3_context cx, long n
);
- private static synchronized native void sqlite3_result_blob(
+ private static native void sqlite3_result_blob(
@NotNull sqlite3_context cx, @Nullable byte[] blob, int maxLen
);
If maxLen is larger than blob.length, it is truncated to that
value. If it is negative, results are undefined.
*/
- private static synchronized native void sqlite3_result_blob64(
+ private static native void sqlite3_result_blob64(
@NotNull sqlite3_context cx, @Nullable byte[] blob, long maxLen
);
sqlite3_result_blob64(cx, blob, (long)(null==blob ? 0 : blob.length));
}
- private static synchronized native void sqlite3_result_text(
+ private static native void sqlite3_result_text(
@NotNull sqlite3_context cx, @Nullable byte[] text, int maxLen
);
text.length, it is silently truncated to text.length. If it is
negative, results are undefined.
*/
- private static synchronized native void sqlite3_result_text64(
+ private static native void sqlite3_result_text64(
@NotNull sqlite3_context cx, @Nullable byte[] text,
long maxLength, int encoding
);
- public static synchronized native int sqlite3_status(
+ /**
+ Cleans up all per-JNIEnv and per-db state managed by the library
+ then calls the C-native sqlite3_shutdown().
+ */
+ public static synchronized native int sqlite3_shutdown();
+
+ public static native int sqlite3_status(
int op, @NotNull OutputPointer.Int32 pCurrent,
@NotNull OutputPointer.Int32 pHighwater, boolean reset
);
- public static synchronized native int sqlite3_status64(
+ public static native int sqlite3_status64(
int op, @NotNull OutputPointer.Int64 pCurrent,
@NotNull OutputPointer.Int64 pHighwater, boolean reset
);
sqlite3_result_text64(cx, b, b.length, SQLITE_UTF16BE);
}
- public static synchronized native RollbackHook sqlite3_rollback_hook(
+ 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 synchronized native int sqlite3_set_authorizer(
+ public static native int sqlite3_set_authorizer(
@NotNull sqlite3 db, @Nullable Authorizer auth
);
- public static synchronized native void sqlite3_set_last_insert_rowid(
+ public static native void sqlite3_set_last_insert_rowid(
@NotNull sqlite3 db, long rowid
);
- public static synchronized native int sqlite3_sleep(int ms);
+ public static native int sqlite3_sleep(int ms);
- public static synchronized native String sqlite3_sourceid();
+ public static native String sqlite3_sourceid();
- public static synchronized native String sqlite3_sql(@NotNull sqlite3_stmt stmt);
+ public static native String sqlite3_sql(@NotNull sqlite3_stmt stmt);
- public static synchronized native int sqlite3_step(@NotNull sqlite3_stmt stmt);
+ public static native int sqlite3_step(@NotNull sqlite3_stmt stmt);
/**
Internal impl of the public sqlite3_strglob() method. Neither argument
may be NULL and both _MUST_ be NUL-terminated.
*/
- private static synchronized native int sqlite3_strglob(
+ private static native int sqlite3_strglob(
@NotNull byte[] glob, @NotNull byte[] txt
);
Internal impl of the public sqlite3_strlike() method. Neither
argument may be NULL and both _MUST_ be NUL-terminated.
*/
- private static synchronized native int sqlite3_strlike(
+ private static native int sqlite3_strlike(
@NotNull byte[] glob, @NotNull byte[] txt, int escChar
);
);
}
- public static synchronized native int sqlite3_threadsafe();
+ public static native int sqlite3_threadsafe();
- public static synchronized native int sqlite3_total_changes(@NotNull sqlite3 db);
+ public static native int sqlite3_total_changes(@NotNull sqlite3 db);
- public static synchronized native long sqlite3_total_changes64(@NotNull sqlite3 db);
+ public static native long sqlite3_total_changes64(@NotNull sqlite3 db);
/**
Works like C's sqlite3_trace_v2() except that the 3rd argument to that
mapping state fails and SQLITE_ERROR if the given callback object
cannot be processed propertly (i.e. an internal error).
*/
- public static synchronized native int sqlite3_trace_v2(
+ public static native int sqlite3_trace_v2(
@NotNull sqlite3 db, int traceMask, @Nullable Tracer tracer
);
- public static synchronized native UpdateHook sqlite3_update_hook(
+ public static native UpdateHook sqlite3_update_hook(
sqlite3 db, UpdateHook hook
);
- public static synchronized native byte[] sqlite3_value_blob(@NotNull sqlite3_value v);
+ public static native byte[] sqlite3_value_blob(@NotNull sqlite3_value v);
- public static synchronized native int sqlite3_value_bytes(@NotNull sqlite3_value v);
+ public static native int sqlite3_value_bytes(@NotNull sqlite3_value v);
- public static synchronized native int sqlite3_value_bytes16(@NotNull sqlite3_value v);
+ public static native int sqlite3_value_bytes16(@NotNull sqlite3_value v);
- public static synchronized native double sqlite3_value_double(@NotNull sqlite3_value v);
+ public static native double sqlite3_value_double(@NotNull sqlite3_value v);
- public static synchronized native sqlite3_value sqlite3_value_dupe(
+ public static native sqlite3_value sqlite3_value_dupe(
@NotNull sqlite3_value v
);
- public static synchronized native int sqlite3_value_encoding(@NotNull sqlite3_value v);
+ public static native int sqlite3_value_encoding(@NotNull sqlite3_value v);
- public static synchronized native void sqlite3_value_free(@Nullable sqlite3_value v);
+ public static native void sqlite3_value_free(@Nullable sqlite3_value v);
- public static synchronized native int sqlite3_value_int(@NotNull sqlite3_value v);
+ public static native int sqlite3_value_int(@NotNull sqlite3_value v);
- public static synchronized native long sqlite3_value_int64(@NotNull sqlite3_value v);
+ public static native long sqlite3_value_int64(@NotNull sqlite3_value v);
/**
If the given value was set using sqlite3_result_java_value() then
It is up to the caller to inspect the object to determine its
type, and cast it if necessary.
*/
- public static synchronized native Object sqlite3_value_java_object(
+ public static native Object sqlite3_value_java_object(
@NotNull sqlite3_value v
);
See sqlite3_value_text_utf8() for how to extract text in standard
UTF-8.
*/
- public static synchronized native String sqlite3_value_text(@NotNull sqlite3_value v);
+ public static native String sqlite3_value_text(@NotNull sqlite3_value v);
/**
The sqlite3_value counterpart of sqlite3_column_text_utf8().
*/
- public static synchronized native byte[] sqlite3_value_text_utf8(@NotNull sqlite3_value v);
+ public static native byte[] sqlite3_value_text_utf8(@NotNull sqlite3_value v);
- public static synchronized native byte[] sqlite3_value_text16(@NotNull sqlite3_value v);
+ public static native byte[] sqlite3_value_text16(@NotNull sqlite3_value v);
- public static synchronized native byte[] sqlite3_value_text16le(@NotNull sqlite3_value v);
+ public static native byte[] sqlite3_value_text16le(@NotNull sqlite3_value v);
- public static synchronized native byte[] sqlite3_value_text16be(@NotNull sqlite3_value v);
+ public static native byte[] sqlite3_value_text16be(@NotNull sqlite3_value v);
- public static synchronized native int sqlite3_value_type(@NotNull sqlite3_value v);
+ public static native int sqlite3_value_type(@NotNull sqlite3_value v);
- public static synchronized native int sqlite3_value_numeric_type(@NotNull sqlite3_value v);
+ public static native int sqlite3_value_numeric_type(@NotNull sqlite3_value v);
- public static synchronized native int sqlite3_value_nochange(@NotNull sqlite3_value v);
+ public static native int sqlite3_value_nochange(@NotNull sqlite3_value v);
- public static synchronized native int sqlite3_value_frombind(@NotNull sqlite3_value v);
+ public static native int sqlite3_value_frombind(@NotNull sqlite3_value v);
- public static synchronized native int sqlite3_value_subtype(@NotNull sqlite3_value v);
-
- /**
- Cleans up all per-JNIEnv and per-db state managed by the library
- then calls the C-native sqlite3_shutdown().
- */
- public static synchronized native int sqlite3_shutdown();
+ public static native int sqlite3_value_subtype(@NotNull sqlite3_value v);
/**
This is NOT part of the public API. It exists solely as a place
to hook in arbitrary C-side code during development and testing
of this library.
*/
- public static synchronized native void sqlite3_do_something_for_developer();
+ public static native void sqlite3_do_something_for_developer();
//////////////////////////////////////////////////////////////////////
// SQLITE_... constants follow...