mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Bind the auto-extension APIs to JNI.
FossilOrigin-Name: 746a5fa079ad80b3c59411202ee601e0b5c50e79e5994d5e464fa06d3c276324
This commit is contained in:
@ -397,7 +397,7 @@ static void NphCacheLine_clear(JNIEnv * const env, NphCacheLine * const p){
|
|||||||
memset(p, 0, sizeof(NphCacheLine));
|
memset(p, 0, sizeof(NphCacheLine));
|
||||||
}
|
}
|
||||||
|
|
||||||
#define S3JNI_ENABLE_AUTOEXT 0
|
#define S3JNI_ENABLE_AUTOEXT 1
|
||||||
#if S3JNI_ENABLE_AUTOEXT
|
#if S3JNI_ENABLE_AUTOEXT
|
||||||
/*
|
/*
|
||||||
Whether auto extensions are feasible here is currently unknown due
|
Whether auto extensions are feasible here is currently unknown due
|
||||||
@ -421,7 +421,6 @@ static void NphCacheLine_clear(JNIEnv * const env, NphCacheLine * const p){
|
|||||||
typedef struct S3JniAutoExtension S3JniAutoExtension;
|
typedef struct S3JniAutoExtension S3JniAutoExtension;
|
||||||
typedef void (*S3JniAutoExtension_xEntryPoint)(sqlite3*);
|
typedef void (*S3JniAutoExtension_xEntryPoint)(sqlite3*);
|
||||||
struct S3JniAutoExtension {
|
struct S3JniAutoExtension {
|
||||||
JNIEnv * env;
|
|
||||||
jobject jObj;
|
jobject jObj;
|
||||||
jmethodID midFunc;
|
jmethodID midFunc;
|
||||||
S3JniAutoExtension_xEntryPoint xEntryPoint;
|
S3JniAutoExtension_xEntryPoint xEntryPoint;
|
||||||
@ -515,8 +514,18 @@ static struct {
|
|||||||
} metrics;
|
} metrics;
|
||||||
#if S3JNI_ENABLE_AUTOEXT
|
#if S3JNI_ENABLE_AUTOEXT
|
||||||
struct {
|
struct {
|
||||||
S3JniAutoExtension *pHead;
|
S3JniAutoExtension *pHead /* Head of the auto-extension list */;
|
||||||
int isRunning;
|
PerDbStateJni * 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. */;
|
||||||
} autoExt;
|
} autoExt;
|
||||||
#endif
|
#endif
|
||||||
} S3Global;
|
} S3Global;
|
||||||
@ -738,6 +747,36 @@ static JNIEnvCache * S3Global_env_cache(JNIEnv * const env){
|
|||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Requires jx to be a Throwable. Calls its getMessage() method and
|
||||||
|
returns its value converted to a UTF-8 string. The caller owns the
|
||||||
|
returned string and must eventually sqlite3_free() it. Returns 0
|
||||||
|
if there is a problem fetching the info or on OOM.
|
||||||
|
*/
|
||||||
|
static char * s3jni_exception_error_msg(JNIEnv * const env, jthrowable jx ){
|
||||||
|
JNIEnvCache * const jc = S3Global_env_cache(env);
|
||||||
|
jmethodID mid;
|
||||||
|
jstring msg;
|
||||||
|
char * zMsg;
|
||||||
|
jclass const klazz = (*env)->GetObjectClass(env, jx);
|
||||||
|
EXCEPTION_IS_FATAL("Cannot get class of exception object.");
|
||||||
|
mid = (*env)->GetMethodID(env, klazz, "getMessage", "()Ljava/lang/String;");
|
||||||
|
IFTHREW{
|
||||||
|
EXCEPTION_REPORT;
|
||||||
|
EXCEPTION_CLEAR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
msg = (*env)->CallObjectMethod(env, jx, mid);
|
||||||
|
IFTHREW{
|
||||||
|
EXCEPTION_REPORT;
|
||||||
|
EXCEPTION_CLEAR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
zMsg = s3jni_jstring_to_utf8(jc, msg, 0);
|
||||||
|
UNREF_L(msg);
|
||||||
|
return zMsg;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Removes any Java references from s and clears its state. If
|
Removes any Java references from s and clears its state. If
|
||||||
doXDestroy is true and s->klazz and s->jObj are not NULL, s->jObj's
|
doXDestroy is true and s->klazz and s->jObj are not NULL, s->jObj's
|
||||||
@ -1131,6 +1170,59 @@ static PerDbStateJni * PerDbStateJni_for_db2(sqlite3 *pDb){
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if S3JNI_ENABLE_AUTOEXT
|
||||||
|
/**
|
||||||
|
Unlink ax from S3Global.autoExt and free it.
|
||||||
|
*/
|
||||||
|
static void S3JniAutoExtension_free(JNIEnv * const env,
|
||||||
|
S3JniAutoExtension * const ax){
|
||||||
|
if( ax ){
|
||||||
|
if( ax->pNext ) ax->pNext->pPrev = ax->pPrev;
|
||||||
|
if( ax == S3Global.autoExt.pHead ){
|
||||||
|
assert( !ax->pNext );
|
||||||
|
S3Global.autoExt.pHead = ax->pNext;
|
||||||
|
}else if( ax->pPrev ){
|
||||||
|
ax->pPrev->pNext = ax->pNext;
|
||||||
|
}
|
||||||
|
ax->pNext = ax->pPrev = 0;
|
||||||
|
UNREF_G(ax->jObj);
|
||||||
|
sqlite3_free(ax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Allocates a new auto extension and plugs it in to S3Global.autoExt.
|
||||||
|
Returns 0 on OOM or if there is an error collecting the required
|
||||||
|
state from jAutoExt (which must be an AutoExtension object).
|
||||||
|
*/
|
||||||
|
static S3JniAutoExtension * S3JniAutoExtension_alloc(JNIEnv *const env,
|
||||||
|
jobject const jAutoExt){
|
||||||
|
S3JniAutoExtension * const ax = sqlite3_malloc(sizeof(*ax));
|
||||||
|
if( ax ){
|
||||||
|
jclass klazz;
|
||||||
|
memset(ax, 0, sizeof(*ax));
|
||||||
|
klazz = (*env)->GetObjectClass(env, jAutoExt);
|
||||||
|
EXCEPTION_IS_FATAL("Cannot get class of jAutoExt.");
|
||||||
|
if(!klazz){
|
||||||
|
S3JniAutoExtension_free(env, ax);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ax->midFunc = (*env)->GetMethodID(env, klazz, "xEntryPoint",
|
||||||
|
"(Lorg/sqlite/jni/sqlite3;)I");
|
||||||
|
if(!ax->midFunc){
|
||||||
|
MARKER(("Error getting xEntryPoint(sqlite3) from object."));
|
||||||
|
S3JniAutoExtension_free(env, ax);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ax->jObj = REF_G(jAutoExt);
|
||||||
|
ax->pNext = S3Global.autoExt.pHead;
|
||||||
|
if( ax->pNext ) ax->pNext->pPrev = ax;
|
||||||
|
S3Global.autoExt.pHead = ax;
|
||||||
|
}
|
||||||
|
return ax;
|
||||||
|
}
|
||||||
|
#endif /* S3JNI_ENABLE_AUTOEXT */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Requires that jCx be a Java-side sqlite3_context wrapper for pCx.
|
Requires that jCx be a Java-side sqlite3_context wrapper for pCx.
|
||||||
This function calls sqlite3_aggregate_context() to allocate a tiny
|
This function calls sqlite3_aggregate_context() to allocate a tiny
|
||||||
@ -1683,7 +1775,6 @@ static void udf_xInverse(sqlite3_context* cx, int argc,
|
|||||||
// except for this macro-generated subset which are kept together here
|
// except for this macro-generated subset which are kept together here
|
||||||
// at the front...
|
// at the front...
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
WRAP_INT_DB(1errcode, sqlite3_errcode)
|
|
||||||
WRAP_INT_DB(1error_1offset, sqlite3_error_offset)
|
WRAP_INT_DB(1error_1offset, sqlite3_error_offset)
|
||||||
WRAP_INT_DB(1extended_1errcode, sqlite3_extended_errcode)
|
WRAP_INT_DB(1extended_1errcode, sqlite3_extended_errcode)
|
||||||
WRAP_INT_STMT(1bind_1parameter_1count, sqlite3_bind_parameter_count)
|
WRAP_INT_STMT(1bind_1parameter_1count, sqlite3_bind_parameter_count)
|
||||||
@ -1717,44 +1808,71 @@ WRAP_INT_SVALUE(1value_1subtype, sqlite3_value_subtype)
|
|||||||
WRAP_INT_SVALUE(1value_1type, sqlite3_value_type)
|
WRAP_INT_SVALUE(1value_1type, sqlite3_value_type)
|
||||||
|
|
||||||
#if S3JNI_ENABLE_AUTOEXT
|
#if S3JNI_ENABLE_AUTOEXT
|
||||||
/* auto-extension is very incomplete */
|
/* Central auto-extension handler. */
|
||||||
/*static*/ int s3jni_auto_extension(sqlite3 *pDb, const char **pzErr,
|
static int s3jni_auto_extension(sqlite3 *pDb, const char **pzErr,
|
||||||
const struct sqlite3_api_routines *pThunk){
|
const struct sqlite3_api_routines *ignored){
|
||||||
S3JniAutoExtension const * pAX = S3Global.autoExt.pHead;
|
S3JniAutoExtension const * pAX = S3Global.autoExt.pHead;
|
||||||
jobject jDb;
|
|
||||||
int rc;
|
int rc;
|
||||||
JNIEnv * env = 0;
|
JNIEnv * env = 0;
|
||||||
if(S3Global.autoExt.isRunning){
|
PerDbStateJni * const ps = S3Global.autoExt.psOpening;
|
||||||
|
|
||||||
|
S3Global.autoExt.psOpening = 0;
|
||||||
|
if( !pAX ){
|
||||||
|
assert( 0==S3Global.autoExt.isRunning );
|
||||||
|
return 0;
|
||||||
|
}else if( S3Global.autoExt.isRunning ){
|
||||||
*pzErr = sqlite3_mprintf("Auto-extensions must not be triggered while "
|
*pzErr = sqlite3_mprintf("Auto-extensions must not be triggered while "
|
||||||
"auto-extensions are running.");
|
"auto-extensions are running.");
|
||||||
return SQLITE_MISUSE;
|
return SQLITE_MISUSE;
|
||||||
}
|
}else if(!ps){
|
||||||
if( S3Global.jvm->GetEnv(S3Global.jvm, (void **)&env, JNI_VERSION_1_8) ){
|
MARKER(("Internal error: cannot find PerDbStateJni for auto-extension\n"));
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}else if( (*S3Global.jvm)->GetEnv(S3Global.jvm, (void **)&env, JNI_VERSION_1_8) ){
|
||||||
|
assert(!"Cannot get JNIEnv");
|
||||||
*pzErr = sqlite3_mprintf("Could not get current JNIEnv.");
|
*pzErr = sqlite3_mprintf("Could not get current JNIEnv.");
|
||||||
return SQLITE_ERROR;
|
return SQLITE_ERROR;
|
||||||
}
|
}
|
||||||
|
assert( !ps->pDb /* it's still being opened */ );
|
||||||
|
ps->pDb = pDb;
|
||||||
|
assert( ps->jDb );
|
||||||
|
NativePointerHolder_set(env, ps->jDb, pDb, S3ClassNames.sqlite3);
|
||||||
S3Global.autoExt.isRunning = 1;
|
S3Global.autoExt.isRunning = 1;
|
||||||
jDb = new_sqlite3_wrapper( env, pDb );
|
|
||||||
EXCEPTION_IS_FATAL("Cannot create sqlite3 wrapper object.");
|
|
||||||
// Now we need PerDbStateJni_for_db(env, jDb, pDb, 1)
|
|
||||||
// and rewire sqlite3_open(_v2()) to use OutputPointer.sqlite3
|
|
||||||
// so that they can have this same jobject.
|
|
||||||
for( ; pAX; pAX = pAX->pNext ){
|
for( ; pAX; pAX = pAX->pNext ){
|
||||||
JNIEnv * const env = pAX->env
|
rc = (*env)->CallIntMethod(env, pAX->jObj, pAX->midFunc, ps->jDb);
|
||||||
/* ^^^ is this correct, or must we use the JavaVM::GetEnv()'s env
|
|
||||||
instead? */;
|
|
||||||
rc = (*env)->CallVoidMethod(env, pAX->jObj, pAX->midFunc, jDb);
|
|
||||||
IFTHREW {
|
IFTHREW {
|
||||||
*pzErr = sqlite3_mprintf("auto-extension threw. TODO: extract error message.");
|
jthrowable const ex = (*env)->ExceptionOccurred(env);
|
||||||
rc = SQLITE_ERROR;
|
char * zMsg;
|
||||||
|
EXCEPTION_CLEAR;
|
||||||
|
zMsg = s3jni_exception_error_msg(env, ex);
|
||||||
|
UNREF_L(ex);
|
||||||
|
*pzErr = sqlite3_mprintf("auto-extension threw: %s", zMsg);
|
||||||
|
sqlite3_free(zMsg);
|
||||||
|
rc = rc ? rc : SQLITE_ERROR;
|
||||||
|
break;
|
||||||
|
}else if( rc ){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UNREF_L(jDb);
|
|
||||||
S3Global.autoExt.isRunning = 0;
|
S3Global.autoExt.isRunning = 0;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
JDECL(jint,1auto_1extension)(JENV_OSELF, jobject jAutoExt){}
|
|
||||||
|
JDECL(jint,1auto_1extension)(JENV_OSELF, jobject jAutoExt){
|
||||||
|
static int once = 0;
|
||||||
|
S3JniAutoExtension * ax;
|
||||||
|
|
||||||
|
if( !jAutoExt ) return SQLITE_MISUSE;
|
||||||
|
else if( 0==once && ++once ){
|
||||||
|
sqlite3_auto_extension( (void(*)(void))s3jni_auto_extension );
|
||||||
|
}
|
||||||
|
ax = S3Global.autoExt.pHead;
|
||||||
|
for( ; ax; ax = ax->pNext ){
|
||||||
|
if( (*env)->IsSameObject(env, ax->jObj, jAutoExt) ){
|
||||||
|
return 0 /* C API treats this as a no-op. */;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return S3JniAutoExtension_alloc(env, jAutoExt) ? 0 : SQLITE_NOMEM;
|
||||||
|
}
|
||||||
#endif /* S3JNI_ENABLE_AUTOEXT */
|
#endif /* S3JNI_ENABLE_AUTOEXT */
|
||||||
|
|
||||||
JDECL(jint,1bind_1blob)(JENV_CSELF, jobject jpStmt,
|
JDECL(jint,1bind_1blob)(JENV_CSELF, jobject jpStmt,
|
||||||
@ -1879,6 +1997,21 @@ JDECL(jint,1busy_1timeout)(JENV_CSELF, jobject jDb, jint ms){
|
|||||||
return SQLITE_MISUSE;
|
return SQLITE_MISUSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if S3JNI_ENABLE_AUTOEXT
|
||||||
|
JDECL(jboolean,1cancel_1auto_1extension)(JENV_OSELF, jobject jAutoExt){
|
||||||
|
S3JniAutoExtension * ax;;
|
||||||
|
if( S3Global.autoExt.isRunning ) return JNI_FALSE;
|
||||||
|
for( ax = S3Global.autoExt.pHead; ax; ax = ax->pNext ){
|
||||||
|
if( (*env)->IsSameObject(env, ax->jObj, jAutoExt) ){
|
||||||
|
S3JniAutoExtension_free(env, ax);
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
#endif /* S3JNI_ENABLE_AUTOEXT */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Wrapper for sqlite3_close(_v2)().
|
Wrapper for sqlite3_close(_v2)().
|
||||||
*/
|
*/
|
||||||
@ -2331,12 +2464,21 @@ JDECL(jstring,1db_1filename)(JENV_CSELF, jobject jDb, jstring jDbName){
|
|||||||
return jRv;
|
return jRv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JDECL(jint,1errcode)(JENV_CSELF, jobject jpDb){
|
||||||
|
sqlite3 * const pDb = PtrGet_sqlite3(jpDb);
|
||||||
|
return pDb ? sqlite3_errcode(pDb) : SQLITE_MISUSE;
|
||||||
|
}
|
||||||
|
|
||||||
JDECL(jstring,1errmsg)(JENV_CSELF, jobject jpDb){
|
JDECL(jstring,1errmsg)(JENV_CSELF, jobject jpDb){
|
||||||
return (*env)->NewStringUTF(env, sqlite3_errmsg(PtrGet_sqlite3(jpDb)));
|
sqlite3 * const pDb = PtrGet_sqlite3(jpDb);
|
||||||
|
JNIEnvCache * const jc = pDb ? S3Global_env_cache(env) : 0;
|
||||||
|
return jc ? s3jni_utf8_to_jstring(jc, sqlite3_errmsg(pDb), -1) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
JDECL(jstring,1errstr)(JENV_CSELF, jint rcCode){
|
JDECL(jstring,1errstr)(JENV_CSELF, jint rcCode){
|
||||||
return (*env)->NewStringUTF(env, sqlite3_errstr((int)rcCode));
|
return (*env)->NewStringUTF(env, sqlite3_errstr((int)rcCode))
|
||||||
|
/* We know these values to be plain ASCII, so pose no
|
||||||
|
MUTF-8 incompatibility */;
|
||||||
}
|
}
|
||||||
|
|
||||||
JDECL(jboolean,1extended_1result_1codes)(JENV_CSELF, jobject jpDb,
|
JDECL(jboolean,1extended_1result_1codes)(JENV_CSELF, jobject jpDb,
|
||||||
@ -2397,6 +2539,12 @@ static int s3jni_open_pre(JNIEnv * const env, JNIEnvCache **jc,
|
|||||||
return SQLITE_NOMEM;
|
return SQLITE_NOMEM;
|
||||||
}
|
}
|
||||||
*ps = PerDbStateJni_alloc(env, 0, *jDb);
|
*ps = PerDbStateJni_alloc(env, 0, *jDb);
|
||||||
|
#if S3JNI_ENABLE_AUTOEXT
|
||||||
|
if(*ps){
|
||||||
|
assert(!S3Global.autoExt.psOpening);
|
||||||
|
S3Global.autoExt.psOpening = *ps;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return *ps ? 0 : SQLITE_NOMEM;
|
return *ps ? 0 : SQLITE_NOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2413,8 +2561,15 @@ static int s3jni_open_pre(JNIEnv * const env, JNIEnvCache **jc,
|
|||||||
*/
|
*/
|
||||||
static int s3jni_open_post(JNIEnv * const env, PerDbStateJni * ps,
|
static int s3jni_open_post(JNIEnv * const env, PerDbStateJni * ps,
|
||||||
sqlite3 **ppDb, jobject jOut, int theRc){
|
sqlite3 **ppDb, jobject jOut, int theRc){
|
||||||
|
#if S3JNI_ENABLE_AUTOEXT
|
||||||
|
assert( S3Global.autoExt.pHead ? 0==S3Global.autoExt.psOpening : 1 );
|
||||||
|
S3Global.autoExt.psOpening = 0;
|
||||||
|
#endif
|
||||||
if(*ppDb){
|
if(*ppDb){
|
||||||
assert(ps->jDb);
|
assert(ps->jDb);
|
||||||
|
#if S3JNI_ENABLE_AUTOEXT
|
||||||
|
assert( S3Global.autoExt.pHead ? *ppDb==ps->pDb : 0==ps->pDb );
|
||||||
|
#endif
|
||||||
ps->pDb = *ppDb;
|
ps->pDb = *ppDb;
|
||||||
NativePointerHolder_set(env, ps->jDb, *ppDb, S3ClassNames.sqlite3);
|
NativePointerHolder_set(env, ps->jDb, *ppDb, S3ClassNames.sqlite3);
|
||||||
}else{
|
}else{
|
||||||
@ -2598,6 +2753,16 @@ JDECL(jint,1reset)(JENV_CSELF, jobject jpStmt){
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if S3JNI_ENABLE_AUTOEXT
|
||||||
|
JDECL(void,1reset_1auto_1extension)(JENV_CSELF){
|
||||||
|
if(!S3Global.autoExt.isRunning){
|
||||||
|
while( S3Global.autoExt.pHead ){
|
||||||
|
S3JniAutoExtension_free(env, S3Global.autoExt.pHead);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* S3JNI_ENABLE_AUTOEXT */
|
||||||
|
|
||||||
/* sqlite3_result_text/blob() and friends. */
|
/* sqlite3_result_text/blob() and friends. */
|
||||||
static void result_blob_text(int asBlob, int as64,
|
static void result_blob_text(int asBlob, int as64,
|
||||||
int eTextRep/*only for (asBlob=0)*/,
|
int eTextRep/*only for (asBlob=0)*/,
|
||||||
|
@ -771,6 +771,14 @@ JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_init
|
|||||||
JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_SQLite3Jni_uncacheJniEnv
|
JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_SQLite3Jni_uncacheJniEnv
|
||||||
(JNIEnv *, jclass);
|
(JNIEnv *, jclass);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_sqlite_jni_SQLite3Jni
|
||||||
|
* Method: sqlite3_auto_extension
|
||||||
|
* Signature: (Lorg/sqlite/jni/AutoExtension;)I
|
||||||
|
*/
|
||||||
|
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1auto_1extension
|
||||||
|
(JNIEnv *, jclass, jobject);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: org_sqlite_jni_SQLite3Jni
|
* Class: org_sqlite_jni_SQLite3Jni
|
||||||
* Method: sqlite3_bind_blob
|
* Method: sqlite3_bind_blob
|
||||||
@ -867,6 +875,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1busy_1handler
|
|||||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1busy_1timeout
|
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1busy_1timeout
|
||||||
(JNIEnv *, jclass, jobject, jint);
|
(JNIEnv *, jclass, jobject, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_sqlite_jni_SQLite3Jni
|
||||||
|
* Method: sqlite3_cancel_auto_extension
|
||||||
|
* Signature: (Lorg/sqlite/jni/AutoExtension;)Z
|
||||||
|
*/
|
||||||
|
JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1cancel_1auto_1extension
|
||||||
|
(JNIEnv *, jclass, jobject);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: org_sqlite_jni_SQLite3Jni
|
* Class: org_sqlite_jni_SQLite3Jni
|
||||||
* Method: sqlite3_changes
|
* Method: sqlite3_changes
|
||||||
@ -1259,6 +1275,14 @@ JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1progress_1handler
|
|||||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1reset
|
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1reset
|
||||||
(JNIEnv *, jclass, jobject);
|
(JNIEnv *, jclass, jobject);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_sqlite_jni_SQLite3Jni
|
||||||
|
* Method: sqlite3_reset_auto_extension
|
||||||
|
* Signature: ()V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1reset_1auto_1extension
|
||||||
|
(JNIEnv *, jclass);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: org_sqlite_jni_SQLite3Jni
|
* Class: org_sqlite_jni_SQLite3Jni
|
||||||
* Method: sqlite3_result_double
|
* Method: sqlite3_result_double
|
||||||
|
29
ext/jni/src/org/sqlite/jni/AutoExtension.java
Normal file
29
ext/jni/src/org/sqlite/jni/AutoExtension.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
** 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 callback for use with sqlite3_auto_extension().
|
||||||
|
*/
|
||||||
|
public interface AutoExtension {
|
||||||
|
/**
|
||||||
|
Must function as described for the sqlite3_auto_extension(),
|
||||||
|
with the caveat that the signature is more limited.
|
||||||
|
|
||||||
|
As an exception to the callbacks-must-not-throw rule,
|
||||||
|
AutoExtensions may do so and the exception's error
|
||||||
|
message will be set as the db's error string.
|
||||||
|
*/
|
||||||
|
int xEntryPoint(sqlite3 db);
|
||||||
|
}
|
@ -166,24 +166,24 @@ public final class SQLite3Jni {
|
|||||||
// grouped by category.
|
// grouped by category.
|
||||||
|
|
||||||
|
|
||||||
// Auto-extensions cannot currently work properly in our setup
|
/**
|
||||||
// for reasons explained in sqlite3-jni.c.
|
Functions almost as documented for the C API, with these
|
||||||
//
|
exceptions:
|
||||||
// /**
|
|
||||||
// Functions almost as documented for the C API, with these
|
|
||||||
// exceptions:
|
|
||||||
//
|
|
||||||
// - The callback interface is more limited because of
|
|
||||||
// cross-language differences.
|
|
||||||
//
|
|
||||||
// - All of the auto-extension routines will fail without side
|
|
||||||
// effects if invoked from within the execution of an
|
|
||||||
// auto-extension.
|
|
||||||
//
|
|
||||||
// See the AutoExtension class docs for more information.
|
|
||||||
// */
|
|
||||||
// private static native int sqlite3_auto_extension(@NotNull AutoExtension callback);
|
|
||||||
|
|
||||||
|
- The callback interface is more limited because of
|
||||||
|
cross-language differences.
|
||||||
|
|
||||||
|
- All of the auto extension routines will fail without side
|
||||||
|
effects if invoked from within the execution of an
|
||||||
|
auto-extension. i.e. auto extensions can neither be
|
||||||
|
added, removed, nor cleared while one is running.
|
||||||
|
|
||||||
|
See the AutoExtension class docs for more information.
|
||||||
|
|
||||||
|
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 int sqlite3_bind_blob(@NotNull sqlite3_stmt stmt, int ndx,
|
public static int sqlite3_bind_blob(@NotNull sqlite3_stmt stmt, int ndx,
|
||||||
@Nullable byte[] data){
|
@Nullable byte[] data){
|
||||||
@ -259,6 +259,12 @@ public final class SQLite3Jni {
|
|||||||
|
|
||||||
public static native int sqlite3_busy_timeout(@NotNull sqlite3 db, int ms);
|
public static native int sqlite3_busy_timeout(@NotNull sqlite3 db, int ms);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Works like the C API except that it returns false, without side
|
||||||
|
effects, if auto extensions are currently running.
|
||||||
|
*/
|
||||||
|
public static synchronized native boolean sqlite3_cancel_auto_extension(@NotNull AutoExtension ax);
|
||||||
|
|
||||||
public static native int sqlite3_changes(@NotNull sqlite3 db);
|
public static native int sqlite3_changes(@NotNull sqlite3 db);
|
||||||
|
|
||||||
public static native long sqlite3_changes64(@NotNull sqlite3 db);
|
public static native long sqlite3_changes64(@NotNull sqlite3 db);
|
||||||
@ -584,6 +590,12 @@ public final class SQLite3Jni {
|
|||||||
|
|
||||||
public static 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.
|
||||||
|
*/
|
||||||
|
public static synchronized native void sqlite3_reset_auto_extension();
|
||||||
|
|
||||||
public static native void sqlite3_result_double(@NotNull sqlite3_context cx, double v);
|
public static native void sqlite3_result_double(@NotNull sqlite3_context cx, double v);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -58,8 +58,13 @@ public class Tester1 {
|
|||||||
final OutputPointer.sqlite3 out = new OutputPointer.sqlite3();
|
final OutputPointer.sqlite3 out = new OutputPointer.sqlite3();
|
||||||
int rc = sqlite3_open(":memory:", out);
|
int rc = sqlite3_open(":memory:", out);
|
||||||
++metrics.dbOpen;
|
++metrics.dbOpen;
|
||||||
affirm(0 == rc);
|
|
||||||
sqlite3 db = out.getValue();
|
sqlite3 db = out.getValue();
|
||||||
|
if( 0!=rc ){
|
||||||
|
final String msg = db.getNativePointer()==0
|
||||||
|
? sqlite3_errstr(rc)
|
||||||
|
: sqlite3_errmsg(db);
|
||||||
|
throw new RuntimeException("Opening db failed: "+msg);
|
||||||
|
}
|
||||||
affirm(0 != db.getNativePointer());
|
affirm(0 != db.getNativePointer());
|
||||||
rc = sqlite3_busy_timeout(db, 2000);
|
rc = sqlite3_busy_timeout(db, 2000);
|
||||||
affirm( 0 == rc );
|
affirm( 0 == rc );
|
||||||
@ -979,6 +984,52 @@ public class Tester1 {
|
|||||||
sqlite3_close(db);
|
sqlite3_close(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void testAutoExtension(){
|
||||||
|
final ValueHolder<Integer> val = new ValueHolder<>(0);
|
||||||
|
final ValueHolder<String> toss = new ValueHolder<>(null);
|
||||||
|
final AutoExtension ax = new AutoExtension(){
|
||||||
|
public synchronized int xEntryPoint(sqlite3 db){
|
||||||
|
++val.value;
|
||||||
|
if( null!=toss.value ){
|
||||||
|
throw new RuntimeException(toss.value);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
int rc = sqlite3_auto_extension( ax );
|
||||||
|
affirm( 0==rc );
|
||||||
|
sqlite3_close(createNewDb());
|
||||||
|
affirm( 1==val.value );
|
||||||
|
sqlite3_close(createNewDb());
|
||||||
|
affirm( 2==val.value );
|
||||||
|
sqlite3_reset_auto_extension();
|
||||||
|
sqlite3_close(createNewDb());
|
||||||
|
affirm( 2==val.value );
|
||||||
|
rc = sqlite3_auto_extension( ax );
|
||||||
|
affirm( 0==rc );
|
||||||
|
// Must not add a new entry
|
||||||
|
rc = sqlite3_auto_extension( ax );
|
||||||
|
affirm( 0==rc );
|
||||||
|
sqlite3_close( createNewDb() );
|
||||||
|
affirm( 3==val.value );
|
||||||
|
affirm( sqlite3_cancel_auto_extension(ax) );
|
||||||
|
affirm( !sqlite3_cancel_auto_extension(ax) );
|
||||||
|
sqlite3_close(createNewDb());
|
||||||
|
affirm( 3==val.value );
|
||||||
|
rc = sqlite3_auto_extension( ax );
|
||||||
|
affirm( 0==rc );
|
||||||
|
Exception err = null;
|
||||||
|
toss.value = "Throwing from AutoExtension.";
|
||||||
|
try{
|
||||||
|
createNewDb();
|
||||||
|
}catch(Exception e){
|
||||||
|
err = e;
|
||||||
|
}
|
||||||
|
affirm( err!=null );
|
||||||
|
affirm( err.getMessage().indexOf(toss.value)>0 );
|
||||||
|
affirm( sqlite3_cancel_auto_extension(ax) );
|
||||||
|
}
|
||||||
|
|
||||||
private static void testSleep(){
|
private static void testSleep(){
|
||||||
out("Sleeping briefly... ");
|
out("Sleeping briefly... ");
|
||||||
sqlite3_sleep(600);
|
sqlite3_sleep(600);
|
||||||
@ -1013,6 +1064,7 @@ public class Tester1 {
|
|||||||
testUpdateHook();
|
testUpdateHook();
|
||||||
testAuthorizer();
|
testAuthorizer();
|
||||||
testFts5();
|
testFts5();
|
||||||
|
testAutoExtension();
|
||||||
//testSleep();
|
//testSleep();
|
||||||
if(liArgs.indexOf("-v")>0){
|
if(liArgs.indexOf("-v")>0){
|
||||||
sqlite3_do_something_for_developer();
|
sqlite3_do_something_for_developer();
|
||||||
|
19
manifest
19
manifest
@ -1,5 +1,5 @@
|
|||||||
C Rework\sthe\ssqlite3_open(_v2)()\sorder\sof\soperations\sso\sthat\spending\sauto-extension\ssupport\scan\sget\sahold\sof\sthe\sopen-time\sJava\sstate\sdespite\sthe\sJava/C\s(sqlite3*)\sbinding\snot\shaving\syet\sbeen\sestablished.
|
C Bind\sthe\sauto-extension\sAPIs\sto\sJNI.
|
||||||
D 2023-08-06T22:09:09.175
|
D 2023-08-07T00:06:31.250
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||||
@ -232,9 +232,10 @@ F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282
|
|||||||
F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
|
F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
|
||||||
F ext/jni/GNUmakefile 61d9bbc179a49523a142928455b3297779b9c40f25783ecf1538279e426cbc99
|
F ext/jni/GNUmakefile 61d9bbc179a49523a142928455b3297779b9c40f25783ecf1538279e426cbc99
|
||||||
F ext/jni/README.md e965674505e105626127ad45e628e4d19fcd379cdafc4d23c814c1ac2c55681d
|
F ext/jni/README.md e965674505e105626127ad45e628e4d19fcd379cdafc4d23c814c1ac2c55681d
|
||||||
F ext/jni/src/c/sqlite3-jni.c 21177d7c3492f84aad0666c43ea6d9bc0ebd544f66dcb41219f966b137e86c1b
|
F ext/jni/src/c/sqlite3-jni.c 406f3fe36661b3628d108a912246b48cafd7fcc1f8b30a563ce6806addb30d71
|
||||||
F ext/jni/src/c/sqlite3-jni.h 2108bb9434fe873e08d6388bce102a474b5c6b00c2ea47d8aee257aca2de2a67
|
F ext/jni/src/c/sqlite3-jni.h 68d219dd351676e819deb38926ebcee0fda141403ce4efa60c3d8bd77993d220
|
||||||
F ext/jni/src/org/sqlite/jni/Authorizer.java 1308988f7f40579ea0e4deeaec3c6be971630566bd021c31367fe3f5140db892
|
F ext/jni/src/org/sqlite/jni/Authorizer.java 1308988f7f40579ea0e4deeaec3c6be971630566bd021c31367fe3f5140db892
|
||||||
|
F ext/jni/src/org/sqlite/jni/AutoExtension.java aac84ec21c93306ff5c6ff3b0130de5b76f265dfbc8f7cd158d62cfb8384ff57
|
||||||
F ext/jni/src/org/sqlite/jni/BusyHandler.java 1b1d3e5c86cd796a0580c81b6af6550ad943baa25e47ada0dcca3aff3ebe978c
|
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/Collation.java 8dffbb00938007ad0967b2ab424d3c908413af1bbd3d212b9c9899910f1218d1
|
||||||
F ext/jni/src/org/sqlite/jni/CollationNeeded.java ebc7cd96d46a70daa76016a308e80f70a3f21d3282787c8d139aa840fdcb1bd7
|
F ext/jni/src/org/sqlite/jni/CollationNeeded.java ebc7cd96d46a70daa76016a308e80f70a3f21d3282787c8d139aa840fdcb1bd7
|
||||||
@ -250,8 +251,8 @@ F ext/jni/src/org/sqlite/jni/OutputPointer.java 053ea7dbc1234dd70b8948009a52a3f1
|
|||||||
F ext/jni/src/org/sqlite/jni/ProgressHandler.java 5979450e996416d28543f1d42634d308439565a99332a8bd84e424af667116cc
|
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/RollbackHook.java b04c8abcc6ade44a8a57129e33765793f69df0ba909e49ba18d73f4268d92564
|
||||||
F ext/jni/src/org/sqlite/jni/SQLFunction.java 09ce81c1c637e31c3a830d4c859cce95d65f5e02ff45f8bd1985b3479381bc46
|
F ext/jni/src/org/sqlite/jni/SQLFunction.java 09ce81c1c637e31c3a830d4c859cce95d65f5e02ff45f8bd1985b3479381bc46
|
||||||
F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 3edf79fb7a3cb5eaeeaaa074f51521d6d9a962b0dd1ca88074be4fd075258fd8
|
F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 9af0e0ea79db59d5c4dac13f70031dd5069223d8198f7324f8c1c25e60451e8c
|
||||||
F ext/jni/src/org/sqlite/jni/Tester1.java 7ea111e9d52042889f2360e7addfefed4174c1a17dfe6efccf64aaa9a65749cf
|
F ext/jni/src/org/sqlite/jni/Tester1.java 63fc2f58b3a5abdad8bd41ff4a1b2572c24fa9246c17a3fcab07dc6adf06ff35
|
||||||
F ext/jni/src/org/sqlite/jni/TesterFts5.java cf2d687baafffdeba219b77cf611fd47a0556248820ea794ae3e8259bfbdc5ee
|
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/Tracer.java a5cece9f947b0af27669b8baec300b6dd7ff859c3e6a6e4a1bd8b50f9714775d
|
||||||
F ext/jni/src/org/sqlite/jni/UpdateHook.java e58645a1727f8a9bbe72dc072ec5b40d9f9362cb0aa24acfe93f49ff56a9016d
|
F ext/jni/src/org/sqlite/jni/UpdateHook.java e58645a1727f8a9bbe72dc072ec5b40d9f9362cb0aa24acfe93f49ff56a9016d
|
||||||
@ -2082,8 +2083,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 644999caff9db79562d45520d94aaa24ee88c65e397b6fb9c20a4f0e7f84e1a5
|
P 34da294ab558880e81eebd7d261bc590551d5a7d2855e844695cef6394647ea7
|
||||||
R c4d749cda5fec61bfb97a76dd1b71afd
|
R 8af70828073a693d0f965376a6f73a57
|
||||||
U stephan
|
U stephan
|
||||||
Z cb93209a7d6706bee6dfc5cbdd5b5747
|
Z 18db46b387e0d752e217b2db93c72ada
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
@ -1 +1 @@
|
|||||||
34da294ab558880e81eebd7d261bc590551d5a7d2855e844695cef6394647ea7
|
746a5fa079ad80b3c59411202ee601e0b5c50e79e5994d5e464fa06d3c276324
|
Reference in New Issue
Block a user