mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Completely rework how the JNI sqlite3_open(_v2) and sqlite3_prepare(_vN)() bindings deal with output pointers to give the JNI side full control over the origin of db and stmt handles (necessary for solving chicken/egg situations in auto-extensions and prepare-time trace). Lots of adjacent internal API renaming.
FossilOrigin-Name: 644999caff9db79562d45520d94aaa24ee88c65e397b6fb9c20a4f0e7f84e1a5
This commit is contained in:
@ -189,10 +189,10 @@
|
||||
/** Helpers for extracting pointers from jobjects, noting that the
|
||||
corresponding Java interfaces have already done the type-checking.
|
||||
*/
|
||||
#define PtrGet_sqlite3(OBJ) getNativePointer(env,OBJ,S3ClassNames.sqlite3)
|
||||
#define PtrGet_sqlite3_stmt(OBJ) getNativePointer(env,OBJ,S3ClassNames.sqlite3_stmt)
|
||||
#define PtrGet_sqlite3_value(OBJ) getNativePointer(env,OBJ,S3ClassNames.sqlite3_value)
|
||||
#define PtrGet_sqlite3_context(OBJ) getNativePointer(env,OBJ,S3ClassNames.sqlite3_context)
|
||||
#define PtrGet_sqlite3(OBJ) NativePointerHolder_get(env,OBJ,S3ClassNames.sqlite3)
|
||||
#define PtrGet_sqlite3_stmt(OBJ) NativePointerHolder_get(env,OBJ,S3ClassNames.sqlite3_stmt)
|
||||
#define PtrGet_sqlite3_value(OBJ) NativePointerHolder_get(env,OBJ,S3ClassNames.sqlite3_value)
|
||||
#define PtrGet_sqlite3_context(OBJ) NativePointerHolder_get(env,OBJ,S3ClassNames.sqlite3_context)
|
||||
/* Helpers for Java value reference management. */
|
||||
static inline jobject new_global_ref(JNIEnv *env, jobject v){
|
||||
return v ? (*env)->NewGlobalRef(env, v) : NULL;
|
||||
@ -215,6 +215,8 @@ static const struct {
|
||||
const char * const OutputPointer_Int64;
|
||||
const char * const OutputPointer_String;
|
||||
const char * const OutputPointer_ByteArray;
|
||||
const char * const OutputPointer_sqlite3;
|
||||
const char * const OutputPointer_sqlite3_stmt;
|
||||
#ifdef SQLITE_ENABLE_FTS5
|
||||
const char * const Fts5Context;
|
||||
const char * const Fts5ExtensionApi;
|
||||
@ -231,6 +233,8 @@ static const struct {
|
||||
"org/sqlite/jni/OutputPointer$Int64",
|
||||
"org/sqlite/jni/OutputPointer$String",
|
||||
"org/sqlite/jni/OutputPointer$ByteArray",
|
||||
"org/sqlite/jni/OutputPointer$sqlite3",
|
||||
"org/sqlite/jni/OutputPointer$sqlite3_stmt",
|
||||
#ifdef SQLITE_ENABLE_FTS5
|
||||
"org/sqlite/jni/Fts5Context",
|
||||
"org/sqlite/jni/Fts5ExtensionApi",
|
||||
@ -296,7 +300,7 @@ static const struct {
|
||||
#define JSTR_TOC(ARG) (*env)->GetStringUTFChars(env, ARG, NULL)
|
||||
#define JSTR_RELEASE(ARG,VAR) if(VAR) (*env)->ReleaseStringUTFChars(env, ARG, VAR)
|
||||
#define JBA_TOC(ARG) (*env)->GetByteArrayElements(env,ARG, NULL)
|
||||
#define JBA_RELEASE(ARG,VAR) if(ARG) (*env)->ReleaseByteArrayElements(env, ARG, VAR, JNI_ABORT)
|
||||
#define JBA_RELEASE(ARG,VAR) if(VAR) (*env)->ReleaseByteArrayElements(env, ARG, VAR, JNI_ABORT)
|
||||
|
||||
/* Marker for code which needs(?) to be made thread-safe. */
|
||||
#define FIXME_THREADING
|
||||
@ -948,7 +952,11 @@ static struct NphCacheLine * S3Global_nph_cache(JNIEnv * const env, const char *
|
||||
return freeSlot;
|
||||
}
|
||||
|
||||
static jfieldID getNativePointerField(JNIEnv * const env, jclass klazz){
|
||||
/**
|
||||
Returns the ID of the "nativePointer" field from the given
|
||||
NativePointerHolder<T> class.
|
||||
*/
|
||||
static jfieldID NativePointerHolder_getField(JNIEnv * const env, jclass klazz){
|
||||
jfieldID rv = (*env)->GetFieldID(env, klazz, "nativePointer", "J");
|
||||
EXCEPTION_IS_FATAL("Code maintenance required: missing nativePointer field.");
|
||||
return rv;
|
||||
@ -959,7 +967,7 @@ static jfieldID getNativePointerField(JNIEnv * const env, jclass klazz){
|
||||
zClassName must be a static string so we can use its address
|
||||
as a cache key.
|
||||
*/
|
||||
static void setNativePointer(JNIEnv * env, jobject ppOut, const void * p,
|
||||
static void NativePointerHolder_set(JNIEnv * env, jobject ppOut, const void * p,
|
||||
const char *zClassName){
|
||||
jfieldID setter = 0;
|
||||
struct NphCacheLine * const cacheLine = S3Global_nph_cache(env, zClassName);
|
||||
@ -970,7 +978,7 @@ static void setNativePointer(JNIEnv * env, jobject ppOut, const void * p,
|
||||
}else{
|
||||
jclass const klazz =
|
||||
cacheLine ? cacheLine->klazz : (*env)->GetObjectClass(env, ppOut);
|
||||
setter = getNativePointerField(env, klazz);
|
||||
setter = NativePointerHolder_getField(env, klazz);
|
||||
if(cacheLine){
|
||||
assert(cacheLine->klazz);
|
||||
assert(!cacheLine->fidValue);
|
||||
@ -987,9 +995,8 @@ static void setNativePointer(JNIEnv * env, jobject ppOut, const void * p,
|
||||
zClassName must be a static string so we can use its address as a
|
||||
cache key.
|
||||
*/
|
||||
static void * getNativePointer(JNIEnv * env, jobject pObj, const char *zClassName){
|
||||
if( 0==pObj ) return 0;
|
||||
else{
|
||||
static void * NativePointerHolder_get(JNIEnv * env, jobject pObj, const char *zClassName){
|
||||
if( pObj ){
|
||||
jfieldID getter = 0;
|
||||
void * rv = 0;
|
||||
struct NphCacheLine * const cacheLine = S3Global_nph_cache(env, zClassName);
|
||||
@ -998,7 +1005,7 @@ static void * getNativePointer(JNIEnv * env, jobject pObj, const char *zClassNam
|
||||
}else{
|
||||
jclass const klazz =
|
||||
cacheLine ? cacheLine->klazz : (*env)->GetObjectClass(env, pObj);
|
||||
getter = getNativePointerField(env, klazz);
|
||||
getter = NativePointerHolder_getField(env, klazz);
|
||||
if(cacheLine){
|
||||
assert(cacheLine->klazz);
|
||||
assert(zClassName == cacheLine->zClassName);
|
||||
@ -1008,6 +1015,8 @@ static void * getNativePointer(JNIEnv * env, jobject pObj, const char *zClassNam
|
||||
rv = (void*)(*env)->GetLongField(env, pObj, getter);
|
||||
IFTHREW_REPORT;
|
||||
return rv;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1015,7 +1024,7 @@ static void * getNativePointer(JNIEnv * env, jobject pObj, const char *zClassNam
|
||||
Extracts the new PerDbStateJni 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
|
||||
setNativePointer().
|
||||
NativePointerHolder_set().
|
||||
*/
|
||||
static PerDbStateJni * PerDbStateJni_alloc(JNIEnv * const env, sqlite3 *pDb, jobject jDb){
|
||||
PerDbStateJni * rv;
|
||||
@ -1179,7 +1188,7 @@ static int udf_setAggregateContext(JNIEnv * env, jobject jCx,
|
||||
}
|
||||
|
||||
/**
|
||||
Common init for setOutputInt32() and friends. zClassName must be a
|
||||
Common init for OutputPointer_set_Int32() and friends. zClassName must be a
|
||||
pointer from S3ClassNames. jOut must be an instance of that
|
||||
class. Fetches the jfieldID for jOut's [value] property, which must
|
||||
be of the type represented by the JNI type signature zTypeSig, and
|
||||
@ -1213,17 +1222,35 @@ static void setupOutputPointer(JNIEnv * const env, const char *zClassName,
|
||||
|
||||
/* Sets the value property of the OutputPointer.Int32 jOut object
|
||||
to v. */
|
||||
static void setOutputInt32(JNIEnv * const env, jobject const jOut, int v){
|
||||
static void OutputPointer_set_Int32(JNIEnv * const env, jobject const jOut, int v){
|
||||
jfieldID setter = 0;
|
||||
setupOutputPointer(env, S3ClassNames.OutputPointer_Int32, "I", jOut, &setter);
|
||||
(*env)->SetIntField(env, jOut, setter, (jint)v);
|
||||
EXCEPTION_IS_FATAL("Cannot set OutputPointer.Int32.value");
|
||||
}
|
||||
|
||||
static void OutputPointer_set_sqlite3(JNIEnv * const env, jobject const jOut,
|
||||
jobject jDb){
|
||||
jfieldID setter = 0;
|
||||
setupOutputPointer(env, S3ClassNames.OutputPointer_sqlite3,
|
||||
"Lorg/sqlite/jni/sqlite3;", jOut, &setter);
|
||||
(*env)->SetObjectField(env, jOut, setter, jDb);
|
||||
EXCEPTION_IS_FATAL("Cannot set OutputPointer.sqlite3.value");
|
||||
}
|
||||
|
||||
static void OutputPointer_set_sqlite3_stmt(JNIEnv * const env, jobject const jOut,
|
||||
jobject jStmt){
|
||||
jfieldID setter = 0;
|
||||
setupOutputPointer(env, S3ClassNames.OutputPointer_sqlite3_stmt,
|
||||
"Lorg/sqlite/jni/sqlite3_stmt;", jOut, &setter);
|
||||
(*env)->SetObjectField(env, jOut, setter, jStmt);
|
||||
EXCEPTION_IS_FATAL("Cannot set OutputPointer.sqlite3_stmt.value");
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_FTS5
|
||||
/* Sets the value property of the OutputPointer.Int64 jOut object
|
||||
to v. */
|
||||
static void setOutputInt64(JNIEnv * const env, jobject const jOut, jlong v){
|
||||
static void OutputPointer_set_Int64(JNIEnv * const env, jobject const jOut, jlong v){
|
||||
jfieldID setter = 0;
|
||||
setupOutputPointer(env, S3ClassNames.OutputPointer_Int64, "J", jOut, &setter);
|
||||
(*env)->SetLongField(env, jOut, setter, v);
|
||||
@ -1232,7 +1259,7 @@ static void setOutputInt64(JNIEnv * const env, jobject const jOut, jlong v){
|
||||
#if 0
|
||||
/* Sets the value property of the OutputPointer.ByteArray jOut object
|
||||
to v. */
|
||||
static void setOutputByteArray(JNIEnv * const env, jobject const jOut,
|
||||
static void OutputPointer_set_ByteArray(JNIEnv * const env, jobject const jOut,
|
||||
jbyteArray const v){
|
||||
jfieldID setter = 0;
|
||||
setupOutputPointer(env, S3ClassNames.OutputPointer_ByteArray, "[B",
|
||||
@ -1243,7 +1270,7 @@ static void setOutputByteArray(JNIEnv * const env, jobject const jOut,
|
||||
#endif
|
||||
/* Sets the value property of the OutputPointer.String jOut object
|
||||
to v. */
|
||||
static void setOutputString(JNIEnv * const env, jobject const jOut,
|
||||
static void OutputPointer_set_String(JNIEnv * const env, jobject const jOut,
|
||||
jstring const v){
|
||||
jfieldID setter = 0;
|
||||
setupOutputPointer(env, S3ClassNames.OutputPointer_String,
|
||||
@ -1367,7 +1394,7 @@ static void ResultJavaVal_finalizer(void *v){
|
||||
/**
|
||||
Returns a new Java instance of the class named by zClassName, which
|
||||
MUST be interface-compatible with NativePointerHolder and MUST have
|
||||
a no-arg constructor. Its setNativePointer() method is passed
|
||||
a no-arg constructor. Its NativePointerHolder_set() method is passed
|
||||
pNative. Hypothetically returns NULL if Java fails to allocate, but
|
||||
the JNI docs are not entirely clear on that detail.
|
||||
|
||||
@ -1402,21 +1429,22 @@ static jobject new_NativePointerHolder_object(JNIEnv * const env, const char *zC
|
||||
assert(ctor);
|
||||
rv = (*env)->NewObject(env, klazz, ctor);
|
||||
EXCEPTION_IS_FATAL("No-arg constructor threw.");
|
||||
if(rv) setNativePointer(env, rv, pNative, zClassName);
|
||||
if(rv) NativePointerHolder_set(env, rv, pNative, zClassName);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static inline jobject new_sqlite3_value_wrapper(JNIEnv * const env, sqlite3_value *sv){
|
||||
return new_NativePointerHolder_object(env, S3ClassNames.sqlite3_value, sv);
|
||||
static inline jobject new_sqlite3_wrapper(JNIEnv * const env, sqlite3 *sv){
|
||||
return new_NativePointerHolder_object(env, S3ClassNames.sqlite3, sv);
|
||||
}
|
||||
|
||||
static inline jobject new_sqlite3_context_wrapper(JNIEnv * const env, sqlite3_context *sv){
|
||||
return new_NativePointerHolder_object(env, S3ClassNames.sqlite3_context, sv);
|
||||
}
|
||||
|
||||
static inline jobject new_sqlite3_stmt_wrapper(JNIEnv * const env, sqlite3_stmt *sv){
|
||||
return new_NativePointerHolder_object(env, S3ClassNames.sqlite3_stmt, sv);
|
||||
}
|
||||
static inline jobject new_sqlite3_value_wrapper(JNIEnv * const env, sqlite3_value *sv){
|
||||
return new_NativePointerHolder_object(env, S3ClassNames.sqlite3_value, sv);
|
||||
}
|
||||
|
||||
enum UDFType {
|
||||
UDF_SCALAR = 1,
|
||||
@ -1690,9 +1718,6 @@ WRAP_INT_SVALUE(1value_1type, sqlite3_value_type)
|
||||
|
||||
#if S3JNI_ENABLE_AUTOEXT
|
||||
/* auto-extension is very incomplete */
|
||||
static inline jobject new_sqlite3_wrapper(JNIEnv * const env, sqlite3 *sv){
|
||||
return new_NativePointerHolder_object(env, S3ClassNames.sqlite3, sv);
|
||||
}
|
||||
/*static*/ int s3jni_auto_extension(sqlite3 *pDb, const char **pzErr,
|
||||
const struct sqlite3_api_routines *pThunk){
|
||||
S3JniAutoExtension const * pAX = S3Global.autoExt.pHead;
|
||||
@ -1872,7 +1897,7 @@ static jint s3jni_close_db(JNIEnv * const env, jobject jDb, int version){
|
||||
rc = 1==version ? (jint)sqlite3_close(ps->pDb) : (jint)sqlite3_close_v2(ps->pDb);
|
||||
if(ps) PerDbStateJni_set_aside(ps)
|
||||
/* MUST come after close() because of ps->trace. */;
|
||||
setNativePointer(env, jDb, 0, S3ClassNames.sqlite3);
|
||||
NativePointerHolder_set(env, jDb, 0, S3ClassNames.sqlite3);
|
||||
return (jint)rc;
|
||||
}
|
||||
|
||||
@ -2177,7 +2202,7 @@ JDECL(jint,1db_1config__Lorg_sqlite_jni_sqlite3_2ILorg_sqlite_jni_OutputPointer_
|
||||
int pOut = 0;
|
||||
rc = sqlite3_db_config( ps->pDb, (int)op, &pOut );
|
||||
if( 0==rc && jOut ){
|
||||
setOutputInt32(env, jOut, pOut);
|
||||
OutputPointer_set_Int32(env, jOut, pOut);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -2346,7 +2371,7 @@ JDECL(jint,1finalize)(JENV_CSELF, jobject jpStmt){
|
||||
JNIEnvCache * const jc = S3Global_env_cache(env);
|
||||
jobject const pPrev = stmt_set_current(jc, jpStmt);
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
setNativePointer(env, jpStmt, 0, S3ClassNames.sqlite3_stmt);
|
||||
NativePointerHolder_set(env, jpStmt, 0, S3ClassNames.sqlite3_stmt);
|
||||
(void)stmt_set_current(jc, pPrev);
|
||||
}
|
||||
return rc;
|
||||
@ -2367,16 +2392,19 @@ JDECL(jlong,1last_1insert_1rowid)(JENV_CSELF, jobject jpDb){
|
||||
is returned, else theRc is returned. In in case, *ppDb is stored in
|
||||
jDb's native pointer property (even if it's NULL).
|
||||
*/
|
||||
static int s3jni_open_post(JNIEnv * const env, sqlite3 **ppDb, jobject jDb, int theRc){
|
||||
static int s3jni_open_post(JNIEnv * const env, sqlite3 **ppDb, jobject jOut, int theRc){
|
||||
jobject jDb = 0;
|
||||
if(*ppDb){
|
||||
PerDbStateJni * const s = PerDbStateJni_for_db(env, jDb, *ppDb, 1);
|
||||
jDb = new_sqlite3_wrapper(env, *ppDb);
|
||||
PerDbStateJni * const s = jDb ? PerDbStateJni_for_db(env, jDb, *ppDb, 1) : 0;
|
||||
if(!s && 0==theRc){
|
||||
UNREF_L(jDb);
|
||||
sqlite3_close(*ppDb);
|
||||
*ppDb = 0;
|
||||
theRc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
setNativePointer(env, jDb, *ppDb, S3ClassNames.sqlite3);
|
||||
OutputPointer_set_sqlite3(env, jOut, jDb);
|
||||
return theRc;
|
||||
}
|
||||
|
||||
@ -2408,53 +2436,72 @@ JDECL(jint,1open_1v2)(JENV_CSELF, jstring strName,
|
||||
|
||||
/* Proxy for the sqlite3_prepare[_v2/3]() family. */
|
||||
static jint sqlite3_jni_prepare_v123(int prepVersion, JNIEnv * const env, jclass self,
|
||||
jobject jpDb, jbyteArray baSql,
|
||||
jobject jDb, jbyteArray baSql,
|
||||
jint nMax, jint prepFlags,
|
||||
jobject jOutStmt, jobject outTail){
|
||||
sqlite3_stmt * pStmt = 0;
|
||||
jobject jStmt = 0;
|
||||
const char * zTail = 0;
|
||||
jbyte * const pBuf = JBA_TOC(baSql);
|
||||
JNIEnvCache * const jc = S3Global_env_cache(env);
|
||||
jobject const pOldStmt = stmt_set_current(jc, jOutStmt);
|
||||
jobject const pOldStmt = stmt_set_current(jc, 0);
|
||||
int rc = SQLITE_ERROR;
|
||||
assert(prepVersion==1 || prepVersion==2 || prepVersion==3);
|
||||
if( !pBuf ){
|
||||
rc = baSql ? SQLITE_MISUSE : SQLITE_NOMEM;
|
||||
goto end;
|
||||
}
|
||||
jStmt = new_sqlite3_stmt_wrapper(env, 0);
|
||||
if( !jStmt ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto end;
|
||||
}
|
||||
switch( prepVersion ){
|
||||
case 1: rc = sqlite3_prepare(PtrGet_sqlite3(jpDb), (const char *)pBuf,
|
||||
case 1: rc = sqlite3_prepare(PtrGet_sqlite3(jDb), (const char *)pBuf,
|
||||
(int)nMax, &pStmt, &zTail);
|
||||
break;
|
||||
case 2: rc = sqlite3_prepare_v2(PtrGet_sqlite3(jpDb), (const char *)pBuf,
|
||||
case 2: rc = sqlite3_prepare_v2(PtrGet_sqlite3(jDb), (const char *)pBuf,
|
||||
(int)nMax, &pStmt, &zTail);
|
||||
break;
|
||||
case 3: rc = sqlite3_prepare_v3(PtrGet_sqlite3(jpDb), (const char *)pBuf,
|
||||
case 3: rc = sqlite3_prepare_v3(PtrGet_sqlite3(jDb), (const char *)pBuf,
|
||||
(int)nMax, (unsigned int)prepFlags,
|
||||
&pStmt, &zTail);
|
||||
break;
|
||||
default:
|
||||
assert(0 && "Invalid prepare() version");
|
||||
}
|
||||
end:
|
||||
JBA_RELEASE(baSql,pBuf);
|
||||
if( 0!=outTail ){
|
||||
assert(zTail ? ((void*)zTail>=(void*)pBuf) : 1);
|
||||
assert(zTail ? (((int)((void*)zTail - (void*)pBuf)) >= 0) : 1);
|
||||
setOutputInt32(env, outTail, (int)(zTail ? (zTail - (const char *)pBuf) : 0));
|
||||
if( 0==rc ){
|
||||
if( 0!=outTail ){
|
||||
/* Noting that pBuf is deallocated now but its address is all we need. */
|
||||
assert(zTail ? ((void*)zTail>=(void*)pBuf) : 1);
|
||||
assert(zTail ? (((int)((void*)zTail - (void*)pBuf)) >= 0) : 1);
|
||||
OutputPointer_set_Int32(env, outTail, (int)(zTail ? (zTail - (const char *)pBuf) : 0));
|
||||
}
|
||||
NativePointerHolder_set(env, jStmt, pStmt, S3ClassNames.sqlite3_stmt);
|
||||
}else{
|
||||
UNREF_L(jStmt);
|
||||
jStmt = 0;
|
||||
}
|
||||
setNativePointer(env, jOutStmt, pStmt, S3ClassNames.sqlite3_stmt);
|
||||
OutputPointer_set_sqlite3_stmt(env, jOutStmt, jStmt);
|
||||
//NativePointerHolder_set(env, jOutStmt, pStmt, S3ClassNames.sqlite3_stmt);
|
||||
(void)stmt_set_current(jc, pOldStmt);
|
||||
return (jint)rc;
|
||||
}
|
||||
JDECL(jint,1prepare)(JNIEnv * const env, jclass self, jobject jpDb, jbyteArray baSql,
|
||||
JDECL(jint,1prepare)(JNIEnv * const env, jclass self, jobject jDb, jbyteArray baSql,
|
||||
jint nMax, jobject jOutStmt, jobject outTail){
|
||||
return sqlite3_jni_prepare_v123(1, env, self, jpDb, baSql, nMax, 0,
|
||||
return sqlite3_jni_prepare_v123(1, env, self, jDb, baSql, nMax, 0,
|
||||
jOutStmt, outTail);
|
||||
}
|
||||
JDECL(jint,1prepare_1v2)(JNIEnv * const env, jclass self, jobject jpDb, jbyteArray baSql,
|
||||
JDECL(jint,1prepare_1v2)(JNIEnv * const env, jclass self, jobject jDb, jbyteArray baSql,
|
||||
jint nMax, jobject jOutStmt, jobject outTail){
|
||||
return sqlite3_jni_prepare_v123(2, env, self, jpDb, baSql, nMax, 0,
|
||||
return sqlite3_jni_prepare_v123(2, env, self, jDb, baSql, nMax, 0,
|
||||
jOutStmt, outTail);
|
||||
}
|
||||
JDECL(jint,1prepare_1v3)(JNIEnv * const env, jclass self, jobject jpDb, jbyteArray baSql,
|
||||
JDECL(jint,1prepare_1v3)(JNIEnv * const env, jclass self, jobject jDb, jbyteArray baSql,
|
||||
jint nMax, jint prepFlags, jobject jOutStmt, jobject outTail){
|
||||
return sqlite3_jni_prepare_v123(3, env, self, jpDb, baSql, nMax,
|
||||
return sqlite3_jni_prepare_v123(3, env, self, jDb, baSql, nMax,
|
||||
prepFlags, jOutStmt, outTail);
|
||||
}
|
||||
|
||||
@ -2797,6 +2844,7 @@ static int s3jni_trace_impl(unsigned traceflag, void *pC, void *pP, void *pX){
|
||||
case SQLITE_TRACE_STMT:
|
||||
jX = s3jni_utf8_to_jstring(jc, (const char *)pX, -1);
|
||||
if(!jX) return SQLITE_NOMEM;
|
||||
/*MARKER(("TRACE_STMT@%p SQL=%p / %s\n", pP, jX, (const char *)pX));*/
|
||||
jP = jc->currentStmt;
|
||||
break;
|
||||
case SQLITE_TRACE_PROFILE:
|
||||
@ -2806,15 +2854,13 @@ static int s3jni_trace_impl(unsigned traceflag, void *pC, void *pP, void *pX){
|
||||
// MARKER(("profile time = %llu\n", *((sqlite3_int64*)pX)));
|
||||
jP = jc->currentStmt;
|
||||
if(!jP){
|
||||
// This will be the case during prepare() b/c we don't have the
|
||||
// pointer in time to wrap it before tracing is triggered.
|
||||
jP = jPUnref = new_sqlite3_stmt_wrapper(env, pP);
|
||||
if(!jP){
|
||||
UNREF_L(jX);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
MARKER(("WARNING: created new sqlite3_stmt wrapper for TRACE_PROFILE. stmt@%p\n"
|
||||
"This means we have missed a route into the tracing API and it "
|
||||
"needs the stmt_set_current() treatment which is littered around "
|
||||
"a handful of other functions in this file.\n", pP));
|
||||
}
|
||||
break;
|
||||
case SQLITE_TRACE_ROW:
|
||||
@ -3092,10 +3138,10 @@ JDECL(void,1do_1something_1for_1developer)(JENV_CSELF){
|
||||
JNIEXPORT ReturnType JNICALL \
|
||||
JFuncNameFtsTok(Suffix)
|
||||
|
||||
#define PtrGet_fts5_api(OBJ) getNativePointer(env,OBJ,S3ClassNames.fts5_api)
|
||||
#define PtrGet_fts5_tokenizer(OBJ) getNativePointer(env,OBJ,S3ClassNames.fts5_tokenizer)
|
||||
#define PtrGet_Fts5Context(OBJ) getNativePointer(env,OBJ,S3ClassNames.Fts5Context)
|
||||
#define PtrGet_Fts5Tokenizer(OBJ) getNativePointer(env,OBJ,S3ClassNames.Fts5Tokenizer)
|
||||
#define PtrGet_fts5_api(OBJ) NativePointerHolder_get(env,OBJ,S3ClassNames.fts5_api)
|
||||
#define PtrGet_fts5_tokenizer(OBJ) NativePointerHolder_get(env,OBJ,S3ClassNames.fts5_tokenizer)
|
||||
#define PtrGet_Fts5Context(OBJ) NativePointerHolder_get(env,OBJ,S3ClassNames.Fts5Context)
|
||||
#define PtrGet_Fts5Tokenizer(OBJ) NativePointerHolder_get(env,OBJ,S3ClassNames.Fts5Tokenizer)
|
||||
#define Fts5ExtDecl Fts5ExtensionApi const * const fext = s3jni_ftsext()
|
||||
|
||||
/**
|
||||
@ -3226,7 +3272,7 @@ JDECLFtsXA(jint,xColumnSize)(JENV_OSELF,jobject jCtx, jint iIdx, jobject jOut32)
|
||||
Fts5ExtDecl;
|
||||
int n1 = 0;
|
||||
int const rc = fext->xColumnSize(PtrGet_Fts5Context(jCtx), (int)iIdx, &n1);
|
||||
if( 0==rc ) setOutputInt32(env, jOut32, n1);
|
||||
if( 0==rc ) OutputPointer_set_Int32(env, jOut32, n1);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -3242,7 +3288,7 @@ JDECLFtsXA(jint,xColumnText)(JENV_OSELF,jobject jCtx, jint iCol,
|
||||
jstring jstr = pz ? s3jni_utf8_to_jstring(jc, pz, pn) : 0;
|
||||
if( pz ){
|
||||
if( jstr ){
|
||||
setOutputString(env, jOut, jstr);
|
||||
OutputPointer_set_String(env, jOut, jstr);
|
||||
UNREF_L(jstr)/*jOut has a reference*/;
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
@ -3256,7 +3302,7 @@ JDECLFtsXA(jint,xColumnTotalSize)(JENV_OSELF,jobject jCtx, jint iCol, jobject jO
|
||||
Fts5ExtDecl;
|
||||
sqlite3_int64 nOut = 0;
|
||||
int const rc = fext->xColumnTotalSize(PtrGet_Fts5Context(jCtx), (int)iCol, &nOut);
|
||||
if( 0==rc && jOut64 ) setOutputInt64(env, jOut64, (jlong)nOut);
|
||||
if( 0==rc && jOut64 ) OutputPointer_set_Int64(env, jOut64, (jlong)nOut);
|
||||
return (jint)rc;
|
||||
}
|
||||
|
||||
@ -3372,9 +3418,9 @@ JDECLFtsXA(jint,xInst)(JENV_OSELF,jobject jCtx, jint iIdx, jobject jOutPhrase,
|
||||
int n1 = 0, n2 = 2, n3 = 0;
|
||||
int const rc = fext->xInst(PtrGet_Fts5Context(jCtx), (int)iIdx, &n1, &n2, &n3);
|
||||
if( 0==rc ){
|
||||
setOutputInt32(env, jOutPhrase, n1);
|
||||
setOutputInt32(env, jOutCol, n2);
|
||||
setOutputInt32(env, jOutOff, n3);
|
||||
OutputPointer_set_Int32(env, jOutPhrase, n1);
|
||||
OutputPointer_set_Int32(env, jOutCol, n2);
|
||||
OutputPointer_set_Int32(env, jOutOff, n3);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@ -3383,7 +3429,7 @@ JDECLFtsXA(jint,xInstCount)(JENV_OSELF,jobject jCtx, jobject jOut32){
|
||||
Fts5ExtDecl;
|
||||
int nOut = 0;
|
||||
int const rc = fext->xInstCount(PtrGet_Fts5Context(jCtx), &nOut);
|
||||
if( 0==rc && jOut32 ) setOutputInt32(env, jOut32, nOut);
|
||||
if( 0==rc && jOut32 ) OutputPointer_set_Int32(env, jOut32, nOut);
|
||||
return (jint)rc;
|
||||
}
|
||||
|
||||
@ -3442,8 +3488,8 @@ JDECLFtsXA(jint,xPhraseFirst)(JENV_OSELF,jobject jCtx, jint iPhrase,
|
||||
rc = fext->xPhraseFirst(PtrGet_Fts5Context(jCtx), (int)iPhrase,
|
||||
&iter, &iCol, &iOff);
|
||||
if( 0==rc ){
|
||||
setOutputInt32(env, jOutCol, iCol);
|
||||
setOutputInt32(env, jOutOff, iOff);
|
||||
OutputPointer_set_Int32(env, jOutCol, iCol);
|
||||
OutputPointer_set_Int32(env, jOutOff, iOff);
|
||||
s3jni_phraseIter_NToJ(env, jc, &iter, jIter);
|
||||
}
|
||||
return rc;
|
||||
@ -3459,7 +3505,7 @@ JDECLFtsXA(jint,xPhraseFirstColumn)(JENV_OSELF,jobject jCtx, jint iPhrase,
|
||||
rc = fext->xPhraseFirstColumn(PtrGet_Fts5Context(jCtx), (int)iPhrase,
|
||||
&iter, &iCol);
|
||||
if( 0==rc ){
|
||||
setOutputInt32(env, jOutCol, iCol);
|
||||
OutputPointer_set_Int32(env, jOutCol, iCol);
|
||||
s3jni_phraseIter_NToJ(env, jc, &iter, jIter);
|
||||
}
|
||||
return rc;
|
||||
@ -3475,8 +3521,8 @@ JDECLFtsXA(void,xPhraseNext)(JENV_OSELF,jobject jCtx, jobject jIter,
|
||||
s3jni_phraseIter_JToN(env, jc, jIter, &iter);
|
||||
fext->xPhraseNext(PtrGet_Fts5Context(jCtx),
|
||||
&iter, &iCol, &iOff);
|
||||
setOutputInt32(env, jOutCol, iCol);
|
||||
setOutputInt32(env, jOutOff, iOff);
|
||||
OutputPointer_set_Int32(env, jOutCol, iCol);
|
||||
OutputPointer_set_Int32(env, jOutOff, iOff);
|
||||
s3jni_phraseIter_NToJ(env, jc, &iter, jIter);
|
||||
}
|
||||
|
||||
@ -3489,7 +3535,7 @@ JDECLFtsXA(void,xPhraseNextColumn)(JENV_OSELF,jobject jCtx, jobject jIter,
|
||||
if(!jc->jPhraseIter.klazz) return /*SQLITE_MISUSE*/;
|
||||
s3jni_phraseIter_JToN(env, jc, jIter, &iter);
|
||||
fext->xPhraseNextColumn(PtrGet_Fts5Context(jCtx), &iter, &iCol);
|
||||
setOutputInt32(env, jOutCol, iCol);
|
||||
OutputPointer_set_Int32(env, jOutCol, iCol);
|
||||
s3jni_phraseIter_NToJ(env, jc, &iter, jIter);
|
||||
}
|
||||
|
||||
@ -3562,7 +3608,7 @@ JDECLFtsXA(jint,xRowCount)(JENV_OSELF,jobject jCtx, jobject jOut64){
|
||||
Fts5ExtDecl;
|
||||
sqlite3_int64 nOut = 0;
|
||||
int const rc = fext->xRowCount(PtrGet_Fts5Context(jCtx), &nOut);
|
||||
if( 0==rc && jOut64 ) setOutputInt64(env, jOut64, (jlong)nOut);
|
||||
if( 0==rc && jOut64 ) OutputPointer_set_Int64(env, jOut64, (jlong)nOut);
|
||||
return (jint)rc;
|
||||
}
|
||||
|
||||
|
@ -1104,7 +1104,7 @@ JNIEXPORT jstring JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1db_1filename
|
||||
* Method: sqlite3_db_config
|
||||
* Signature: (Lorg/sqlite/jni/sqlite3;ILorg/sqlite/jni/OutputPointer/Int32;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1db_1config__Lorg_sqlite_jni_sqlite3_2ILorg_sqlite_jni_OutputPointer_00024Int32_2
|
||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1db_1config__Lorg_sqlite_jni_sqlite3_2ILorg_sqlite_jni_OutputPointer_Int32_2
|
||||
(JNIEnv *, jclass, jobject, jint, jobject);
|
||||
|
||||
/*
|
||||
@ -1206,7 +1206,7 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1libversion_1numbe
|
||||
/*
|
||||
* Class: org_sqlite_jni_SQLite3Jni
|
||||
* Method: sqlite3_open
|
||||
* Signature: (Ljava/lang/String;Lorg/sqlite/jni/sqlite3;)I
|
||||
* Signature: (Ljava/lang/String;Lorg/sqlite/jni/OutputPointer/sqlite3;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1open
|
||||
(JNIEnv *, jclass, jstring, jobject);
|
||||
@ -1214,7 +1214,7 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1open
|
||||
/*
|
||||
* Class: org_sqlite_jni_SQLite3Jni
|
||||
* Method: sqlite3_open_v2
|
||||
* Signature: (Ljava/lang/String;Lorg/sqlite/jni/sqlite3;ILjava/lang/String;)I
|
||||
* Signature: (Ljava/lang/String;Lorg/sqlite/jni/OutputPointer/sqlite3;ILjava/lang/String;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1open_1v2
|
||||
(JNIEnv *, jclass, jstring, jobject, jint, jstring);
|
||||
@ -1222,7 +1222,7 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1open_1v2
|
||||
/*
|
||||
* Class: org_sqlite_jni_SQLite3Jni
|
||||
* Method: sqlite3_prepare
|
||||
* Signature: (Lorg/sqlite/jni/sqlite3;[BILorg/sqlite/jni/sqlite3_stmt;Lorg/sqlite/jni/OutputPointer/Int32;)I
|
||||
* Signature: (Lorg/sqlite/jni/sqlite3;[BILorg/sqlite/jni/OutputPointer/sqlite3_stmt;Lorg/sqlite/jni/OutputPointer/Int32;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1prepare
|
||||
(JNIEnv *, jclass, jobject, jbyteArray, jint, jobject, jobject);
|
||||
@ -1230,7 +1230,7 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1prepare
|
||||
/*
|
||||
* Class: org_sqlite_jni_SQLite3Jni
|
||||
* Method: sqlite3_prepare_v2
|
||||
* Signature: (Lorg/sqlite/jni/sqlite3;[BILorg/sqlite/jni/sqlite3_stmt;Lorg/sqlite/jni/OutputPointer/Int32;)I
|
||||
* Signature: (Lorg/sqlite/jni/sqlite3;[BILorg/sqlite/jni/OutputPointer/sqlite3_stmt;Lorg/sqlite/jni/OutputPointer/Int32;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1prepare_1v2
|
||||
(JNIEnv *, jclass, jobject, jbyteArray, jint, jobject, jobject);
|
||||
@ -1238,7 +1238,7 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1prepare_1v2
|
||||
/*
|
||||
* Class: org_sqlite_jni_SQLite3Jni
|
||||
* Method: sqlite3_prepare_v3
|
||||
* Signature: (Lorg/sqlite/jni/sqlite3;[BIILorg/sqlite/jni/sqlite3_stmt;Lorg/sqlite/jni/OutputPointer/Int32;)I
|
||||
* Signature: (Lorg/sqlite/jni/sqlite3;[BIILorg/sqlite/jni/OutputPointer/sqlite3_stmt;Lorg/sqlite/jni/OutputPointer/Int32;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1prepare_1v3
|
||||
(JNIEnv *, jclass, jobject, jbyteArray, jint, jint, jobject, jobject);
|
||||
|
@ -22,6 +22,20 @@ package org.sqlite.jni;
|
||||
autoboxing at that level.
|
||||
*/
|
||||
public final class OutputPointer {
|
||||
public static final class sqlite3 {
|
||||
private org.sqlite.jni.sqlite3 value;
|
||||
public sqlite3(){value = null;}
|
||||
public void clear(){value = null;}
|
||||
public final org.sqlite.jni.sqlite3 getValue(){return value;}
|
||||
}
|
||||
|
||||
public static final class sqlite3_stmt {
|
||||
private org.sqlite.jni.sqlite3_stmt value;
|
||||
public sqlite3_stmt(){value = null;}
|
||||
public void clear(){value = null;}
|
||||
public final org.sqlite.jni.sqlite3_stmt getValue(){return value;}
|
||||
}
|
||||
|
||||
public static final class Int32 {
|
||||
private int value;
|
||||
public Int32(){this(0);}
|
||||
|
@ -476,10 +476,10 @@ public final class SQLite3Jni {
|
||||
pass to, e.g., the sqlite3_collation_needed() callback.
|
||||
*/
|
||||
public static native int sqlite3_open(@Nullable String filename,
|
||||
@NotNull sqlite3 ppDb);
|
||||
@NotNull OutputPointer.sqlite3 ppDb);
|
||||
|
||||
public static native int sqlite3_open_v2(@Nullable String filename,
|
||||
@NotNull sqlite3 ppDb,
|
||||
@NotNull OutputPointer.sqlite3 ppDb,
|
||||
int flags, @Nullable String zVfs);
|
||||
|
||||
/**
|
||||
@ -503,24 +503,24 @@ public final class SQLite3Jni {
|
||||
*/
|
||||
private static native int sqlite3_prepare(@NotNull sqlite3 db,
|
||||
@NotNull byte[] sqlUtf8, int maxBytes,
|
||||
@NotNull sqlite3_stmt outStmt,
|
||||
@NotNull OutputPointer.sqlite3_stmt outStmt,
|
||||
@Nullable OutputPointer.Int32 pTailOffset);
|
||||
|
||||
public static int sqlite3_prepare(@NotNull sqlite3 db,
|
||||
@NotNull byte[] sqlUtf8,
|
||||
@NotNull sqlite3_stmt outStmt,
|
||||
@NotNull OutputPointer.sqlite3_stmt outStmt,
|
||||
@Nullable OutputPointer.Int32 pTailOffset){
|
||||
return sqlite3_prepare(db, sqlUtf8, sqlUtf8.length, outStmt, pTailOffset);
|
||||
}
|
||||
|
||||
public static int sqlite3_prepare(@NotNull sqlite3 db,
|
||||
@NotNull byte[] sqlUtf8,
|
||||
@NotNull sqlite3_stmt outStmt){
|
||||
@NotNull OutputPointer.sqlite3_stmt outStmt){
|
||||
return sqlite3_prepare(db, sqlUtf8, sqlUtf8.length, outStmt, null);
|
||||
}
|
||||
|
||||
public static int sqlite3_prepare(@NotNull sqlite3 db, @NotNull String sql,
|
||||
@NotNull sqlite3_stmt outStmt){
|
||||
@NotNull OutputPointer.sqlite3_stmt outStmt){
|
||||
final byte[] utf8 = sql.getBytes(StandardCharsets.UTF_8);
|
||||
return sqlite3_prepare(db, utf8, utf8.length, outStmt, null);
|
||||
}
|
||||
@ -528,24 +528,24 @@ public final class SQLite3Jni {
|
||||
private static native int sqlite3_prepare_v2(@NotNull sqlite3 db,
|
||||
@NotNull byte[] sqlUtf8,
|
||||
int maxBytes,
|
||||
@NotNull sqlite3_stmt outStmt,
|
||||
@NotNull OutputPointer.sqlite3_stmt outStmt,
|
||||
@Nullable OutputPointer.Int32 pTailOffset);
|
||||
|
||||
public static int sqlite3_prepare_v2(@NotNull sqlite3 db, @NotNull byte[] sqlUtf8,
|
||||
@NotNull sqlite3_stmt outStmt,
|
||||
@NotNull OutputPointer.sqlite3_stmt outStmt,
|
||||
@Nullable OutputPointer.Int32 pTailOffset){
|
||||
return sqlite3_prepare_v2(db, sqlUtf8, sqlUtf8.length, outStmt, pTailOffset);
|
||||
}
|
||||
|
||||
public static int sqlite3_prepare_v2(@NotNull sqlite3 db,
|
||||
@NotNull byte[] sqlUtf8,
|
||||
@NotNull sqlite3_stmt outStmt){
|
||||
@NotNull OutputPointer.sqlite3_stmt outStmt){
|
||||
return sqlite3_prepare_v2(db, sqlUtf8, sqlUtf8.length, outStmt, null);
|
||||
}
|
||||
|
||||
public static int sqlite3_prepare_v2(@NotNull sqlite3 db,
|
||||
@NotNull String sql,
|
||||
@NotNull sqlite3_stmt outStmt){
|
||||
@NotNull OutputPointer.sqlite3_stmt outStmt){
|
||||
final byte[] utf8 = sql.getBytes(StandardCharsets.UTF_8);
|
||||
return sqlite3_prepare_v2(db, utf8, utf8.length, outStmt, null);
|
||||
}
|
||||
@ -553,12 +553,12 @@ public final class SQLite3Jni {
|
||||
private static native int sqlite3_prepare_v3(@NotNull sqlite3 db,
|
||||
@NotNull byte[] sqlUtf8,
|
||||
int maxBytes, int prepFlags,
|
||||
@NotNull sqlite3_stmt outStmt,
|
||||
@NotNull OutputPointer.sqlite3_stmt outStmt,
|
||||
@Nullable OutputPointer.Int32 pTailOffset);
|
||||
|
||||
public static int sqlite3_prepare_v3(@NotNull sqlite3 db, @NotNull byte[] sqlUtf8,
|
||||
int prepFlags,
|
||||
@NotNull sqlite3_stmt outStmt,
|
||||
@NotNull OutputPointer.sqlite3_stmt outStmt,
|
||||
@Nullable OutputPointer.Int32 pTailOffset){
|
||||
return sqlite3_prepare_v3(db, sqlUtf8, sqlUtf8.length, prepFlags, outStmt, pTailOffset);
|
||||
}
|
||||
@ -566,12 +566,13 @@ public final class SQLite3Jni {
|
||||
public static int sqlite3_prepare_v3(@NotNull sqlite3 db,
|
||||
@NotNull byte[] sqlUtf8,
|
||||
int prepFlags,
|
||||
@NotNull sqlite3_stmt outStmt){
|
||||
@NotNull OutputPointer.sqlite3_stmt outStmt){
|
||||
return sqlite3_prepare_v3(db, sqlUtf8, sqlUtf8.length, prepFlags, outStmt, null);
|
||||
}
|
||||
|
||||
public static int sqlite3_prepare_v3(@NotNull sqlite3 db, @NotNull String sql,
|
||||
int prepFlags, @NotNull sqlite3_stmt outStmt){
|
||||
int prepFlags,
|
||||
@NotNull OutputPointer.sqlite3_stmt outStmt){
|
||||
final byte[] utf8 = sql.getBytes(StandardCharsets.UTF_8);
|
||||
return sqlite3_prepare_v3(db, utf8, utf8.length, prepFlags, outStmt, null);
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ public class Tester1 {
|
||||
}
|
||||
|
||||
static final Metrics metrics = new Metrics();
|
||||
private static final OutputPointer.sqlite3_stmt outStmt
|
||||
= new OutputPointer.sqlite3_stmt();
|
||||
|
||||
public static <T> void out(T val){
|
||||
System.out.print(val);
|
||||
@ -53,11 +55,11 @@ public class Tester1 {
|
||||
}
|
||||
|
||||
public static sqlite3 createNewDb(){
|
||||
sqlite3 db = new sqlite3();
|
||||
affirm(0 == db.getNativePointer());
|
||||
int rc = sqlite3_open(":memory:", db);
|
||||
final OutputPointer.sqlite3 out = new OutputPointer.sqlite3();
|
||||
int rc = sqlite3_open(":memory:", out);
|
||||
++metrics.dbOpen;
|
||||
affirm(0 == rc);
|
||||
sqlite3 db = out.getValue();
|
||||
affirm(0 != db.getNativePointer());
|
||||
rc = sqlite3_busy_timeout(db, 2000);
|
||||
affirm( 0 == rc );
|
||||
@ -69,52 +71,63 @@ public class Tester1 {
|
||||
}
|
||||
|
||||
public static int execSql(sqlite3 db, boolean throwOnError, String sql){
|
||||
OutputPointer.Int32 oTail = new OutputPointer.Int32();
|
||||
final byte[] sqlUtf8 = sql.getBytes(StandardCharsets.UTF_8);
|
||||
int pos = 0, n = 1;
|
||||
byte[] sqlChunk = sqlUtf8;
|
||||
sqlite3_stmt stmt = new sqlite3_stmt();
|
||||
int rc = 0;
|
||||
while(pos < sqlChunk.length){
|
||||
if(pos > 0){
|
||||
sqlChunk = Arrays.copyOfRange(sqlChunk, pos,
|
||||
sqlChunk.length);
|
||||
}
|
||||
if( 0==sqlChunk.length ) break;
|
||||
rc = sqlite3_prepare_v2(db, sqlChunk, stmt, oTail);
|
||||
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);
|
||||
affirm(0 == stmt.getNativePointer());
|
||||
if(0!=rc && SQLITE_ROW!=rc && SQLITE_DONE!=rc){
|
||||
if(throwOnError){
|
||||
throw new RuntimeException("db op failed with rc="+rc);
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
OutputPointer.Int32 oTail = new OutputPointer.Int32();
|
||||
final byte[] sqlUtf8 = sql.getBytes(StandardCharsets.UTF_8);
|
||||
int pos = 0, n = 1;
|
||||
byte[] sqlChunk = sqlUtf8;
|
||||
int rc = 0;
|
||||
sqlite3_stmt stmt = null;
|
||||
while(pos < sqlChunk.length){
|
||||
if(pos > 0){
|
||||
sqlChunk = Arrays.copyOfRange(sqlChunk, pos,
|
||||
sqlChunk.length);
|
||||
}
|
||||
if( 0==sqlChunk.length ) break;
|
||||
rc = sqlite3_prepare_v2(db, sqlChunk, outStmt, oTail);
|
||||
if(throwOnError) affirm(0 == rc);
|
||||
else if( 0!=rc ) break;
|
||||
stmt = outStmt.getValue();
|
||||
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;
|
||||
affirm(0 == stmt.getNativePointer());
|
||||
if(0!=rc && SQLITE_ROW!=rc && SQLITE_DONE!=rc){
|
||||
if(throwOnError){
|
||||
throw new RuntimeException("db op failed with rc="+rc);
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
if(SQLITE_ROW==rc || SQLITE_DONE==rc) rc = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
public static void execSql(sqlite3 db, String sql){
|
||||
execSql(db, true, sql);
|
||||
}
|
||||
|
||||
public static sqlite3_stmt prepare(sqlite3 db, String sql){
|
||||
outStmt.clear();
|
||||
int rc = sqlite3_prepare(db, sql, outStmt);
|
||||
affirm( 0 == rc );
|
||||
final sqlite3_stmt rv = outStmt.getValue();
|
||||
outStmt.clear();
|
||||
affirm( 0 != rv.getNativePointer() );
|
||||
return rv;
|
||||
}
|
||||
|
||||
private static void testOpenDb1(){
|
||||
sqlite3 db = new sqlite3();
|
||||
affirm(0 == db.getNativePointer());
|
||||
int rc = sqlite3_open(":memory:", db);
|
||||
++metrics.dbOpen;
|
||||
affirm(0 == rc);
|
||||
affirm(0 < db.getNativePointer());
|
||||
sqlite3_close_v2(db);
|
||||
final OutputPointer.sqlite3 out = new OutputPointer.sqlite3();
|
||||
int rc = sqlite3_open(":memory:", out);
|
||||
++metrics.dbOpen;
|
||||
sqlite3 db = out.getValue();
|
||||
affirm(0 == rc);
|
||||
affirm(0 < db.getNativePointer());
|
||||
sqlite3_close_v2(db);
|
||||
affirm(0 == db.getNativePointer());
|
||||
}
|
||||
|
||||
@ -130,13 +143,13 @@ public class Tester1 {
|
||||
}
|
||||
|
||||
private static void testOpenDb2(){
|
||||
sqlite3 db = new sqlite3();
|
||||
affirm(0 == db.getNativePointer());
|
||||
int rc = sqlite3_open_v2(":memory:", db,
|
||||
final OutputPointer.sqlite3 out = new OutputPointer.sqlite3();
|
||||
int rc = sqlite3_open_v2(":memory:", out,
|
||||
SQLITE_OPEN_READWRITE
|
||||
| SQLITE_OPEN_CREATE, null);
|
||||
++metrics.dbOpen;
|
||||
affirm(0 == rc);
|
||||
sqlite3 db = out.getValue();
|
||||
affirm(0 < db.getNativePointer());
|
||||
sqlite3_close_v2(db);
|
||||
affirm(0 == db.getNativePointer());
|
||||
@ -145,10 +158,9 @@ public class Tester1 {
|
||||
private static void testPrepare123(){
|
||||
sqlite3 db = createNewDb();
|
||||
int rc;
|
||||
sqlite3_stmt stmt = new sqlite3_stmt();
|
||||
affirm(0 == stmt.getNativePointer());
|
||||
rc = sqlite3_prepare(db, "CREATE TABLE t1(a);", stmt);
|
||||
rc = sqlite3_prepare(db, "CREATE TABLE t1(a);", outStmt);
|
||||
affirm(0 == rc);
|
||||
sqlite3_stmt stmt = outStmt.getValue();
|
||||
affirm(0 != stmt.getNativePointer());
|
||||
rc = sqlite3_step(stmt);
|
||||
affirm(SQLITE_DONE == rc);
|
||||
@ -169,8 +181,9 @@ public class Tester1 {
|
||||
}
|
||||
//outln("SQL chunk #"+n+" length = "+sqlChunk.length+", pos = "+pos);
|
||||
if( 0==sqlChunk.length ) break;
|
||||
rc = sqlite3_prepare_v2(db, sqlChunk, stmt, oTail);
|
||||
rc = sqlite3_prepare_v2(db, sqlChunk, outStmt, oTail);
|
||||
affirm(0 == rc);
|
||||
stmt = outStmt.getValue();
|
||||
pos = oTail.getValue();
|
||||
/*outln("SQL tail pos = "+pos+". Chunk = "+
|
||||
(new String(Arrays.copyOfRange(sqlChunk,0,pos),
|
||||
@ -192,8 +205,9 @@ public class Tester1 {
|
||||
|
||||
|
||||
rc = sqlite3_prepare_v3(db, "INSERT INTO t2(a) VALUES(1),(2),(3)",
|
||||
SQLITE_PREPARE_NORMALIZE, stmt);
|
||||
SQLITE_PREPARE_NORMALIZE, outStmt);
|
||||
affirm(0 == rc);
|
||||
stmt = outStmt.getValue();
|
||||
affirm(0 != stmt.getNativePointer());
|
||||
sqlite3_finalize(stmt);
|
||||
affirm(0 == stmt.getNativePointer() );
|
||||
@ -204,9 +218,7 @@ public class Tester1 {
|
||||
sqlite3 db = createNewDb();
|
||||
execSql(db, "CREATE TABLE t(a)");
|
||||
|
||||
sqlite3_stmt stmt = new sqlite3_stmt();
|
||||
int rc = sqlite3_prepare(db, "INSERT INTO t(a) VALUES(:a);", stmt);
|
||||
affirm(0 == rc);
|
||||
sqlite3_stmt stmt = prepare(db, "INSERT INTO t(a) VALUES(:a);");
|
||||
affirm(1 == sqlite3_bind_parameter_count(stmt));
|
||||
final int paramNdx = sqlite3_bind_parameter_index(stmt, ":a");
|
||||
affirm(1 == paramNdx);
|
||||
@ -216,6 +228,7 @@ public class Tester1 {
|
||||
int changesT = sqlite3_total_changes(db);
|
||||
long changes64 = sqlite3_changes64(db);
|
||||
long changesT64 = sqlite3_total_changes64(db);
|
||||
int rc;
|
||||
for(int i = 99; i < 102; ++i ){
|
||||
total1 += i;
|
||||
rc = sqlite3_bind_int(stmt, paramNdx, i);
|
||||
@ -233,8 +246,7 @@ public class Tester1 {
|
||||
affirm(sqlite3_total_changes(db) > changesT);
|
||||
affirm(sqlite3_changes64(db) > changes64);
|
||||
affirm(sqlite3_total_changes64(db) > changesT64);
|
||||
rc = sqlite3_prepare(db, "SELECT a FROM t ORDER BY a DESC;", stmt);
|
||||
affirm(0 == rc);
|
||||
stmt = prepare(db, "SELECT a FROM t ORDER BY a DESC;");
|
||||
int total2 = 0;
|
||||
while( SQLITE_ROW == sqlite3_step(stmt) ){
|
||||
total2 += sqlite3_column_int(stmt, 0);
|
||||
@ -252,8 +264,7 @@ public class Tester1 {
|
||||
private static void testBindFetchInt64(){
|
||||
sqlite3 db = createNewDb();
|
||||
execSql(db, "CREATE TABLE t(a)");
|
||||
sqlite3_stmt stmt = new sqlite3_stmt();
|
||||
int rc = sqlite3_prepare(db, "INSERT INTO t(a) VALUES(?);", stmt);
|
||||
sqlite3_stmt stmt = prepare(db, "INSERT INTO t(a) VALUES(?);");
|
||||
long total1 = 0;
|
||||
for(long i = 0xffffffff; i < 0xffffffff + 3; ++i ){
|
||||
total1 += i;
|
||||
@ -262,8 +273,7 @@ public class Tester1 {
|
||||
sqlite3_reset(stmt);
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
rc = sqlite3_prepare(db, "SELECT a FROM t ORDER BY a DESC;", stmt);
|
||||
affirm(0 == rc);
|
||||
stmt = prepare(db, "SELECT a FROM t ORDER BY a DESC;");
|
||||
long total2 = 0;
|
||||
while( SQLITE_ROW == sqlite3_step(stmt) ){
|
||||
total2 += sqlite3_column_int64(stmt, 0);
|
||||
@ -276,8 +286,7 @@ public class Tester1 {
|
||||
private static void testBindFetchDouble(){
|
||||
sqlite3 db = createNewDb();
|
||||
execSql(db, "CREATE TABLE t(a)");
|
||||
sqlite3_stmt stmt = new sqlite3_stmt();
|
||||
int rc = sqlite3_prepare(db, "INSERT INTO t(a) VALUES(?);", stmt);
|
||||
sqlite3_stmt stmt = prepare(db, "INSERT INTO t(a) VALUES(?);");
|
||||
double total1 = 0;
|
||||
for(double i = 1.5; i < 5.0; i = i + 1.0 ){
|
||||
total1 += i;
|
||||
@ -286,8 +295,7 @@ public class Tester1 {
|
||||
sqlite3_reset(stmt);
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
rc = sqlite3_prepare(db, "SELECT a FROM t ORDER BY a DESC;", stmt);
|
||||
affirm(0 == rc);
|
||||
stmt = prepare(db, "SELECT a FROM t ORDER BY a DESC;");
|
||||
double total2 = 0;
|
||||
int counter = 0;
|
||||
while( SQLITE_ROW == sqlite3_step(stmt) ){
|
||||
@ -303,9 +311,9 @@ public class Tester1 {
|
||||
private static void testBindFetchText(){
|
||||
sqlite3 db = createNewDb();
|
||||
execSql(db, "CREATE TABLE t(a)");
|
||||
sqlite3_stmt stmt = new sqlite3_stmt();
|
||||
int rc = sqlite3_prepare(db, "INSERT INTO t(a) VALUES(?);", stmt);
|
||||
sqlite3_stmt stmt = prepare(db, "INSERT INTO t(a) VALUES(?);");
|
||||
String[] list1 = { "hell🤩", "w😃rld", "!" };
|
||||
int rc;
|
||||
for( String e : list1 ){
|
||||
rc = sqlite3_bind_text(stmt, 1, e);
|
||||
affirm(0 == rc);
|
||||
@ -314,8 +322,7 @@ public class Tester1 {
|
||||
sqlite3_reset(stmt);
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
rc = sqlite3_prepare(db, "SELECT a FROM t ORDER BY a DESC;", stmt);
|
||||
affirm(0 == rc);
|
||||
stmt = prepare(db, "SELECT a FROM t ORDER BY a DESC;");
|
||||
StringBuilder sbuf = new StringBuilder();
|
||||
int n = 0;
|
||||
while( SQLITE_ROW == sqlite3_step(stmt) ){
|
||||
@ -333,15 +340,14 @@ public class Tester1 {
|
||||
private static void testBindFetchBlob(){
|
||||
sqlite3 db = createNewDb();
|
||||
execSql(db, "CREATE TABLE t(a)");
|
||||
sqlite3_stmt stmt = new sqlite3_stmt();
|
||||
int rc = sqlite3_prepare(db, "INSERT INTO t(a) VALUES(?);", stmt);
|
||||
sqlite3_stmt stmt = prepare(db, "INSERT INTO t(a) VALUES(?);");
|
||||
byte[] list1 = { 0x32, 0x33, 0x34 };
|
||||
rc = sqlite3_bind_blob(stmt, 1, list1);
|
||||
int rc = sqlite3_bind_blob(stmt, 1, list1);
|
||||
affirm( 0==rc );
|
||||
rc = sqlite3_step(stmt);
|
||||
affirm(SQLITE_DONE == rc);
|
||||
sqlite3_finalize(stmt);
|
||||
rc = sqlite3_prepare(db, "SELECT a FROM t ORDER BY a DESC;", stmt);
|
||||
affirm(0 == rc);
|
||||
stmt = prepare(db, "SELECT a FROM t ORDER BY a DESC;");
|
||||
int n = 0;
|
||||
int total = 0;
|
||||
while( SQLITE_ROW == sqlite3_step(stmt) ){
|
||||
@ -398,9 +404,7 @@ public class Tester1 {
|
||||
affirm( 0 == rc );
|
||||
rc = sqlite3_collation_needed(db, collLoader);
|
||||
affirm( 0 == rc /* Installing the same object again is a no-op */);
|
||||
sqlite3_stmt stmt = new sqlite3_stmt();
|
||||
rc = sqlite3_prepare(db, "SELECT a FROM t ORDER BY a COLLATE reversi", stmt);
|
||||
affirm( 0 == rc );
|
||||
sqlite3_stmt stmt = prepare(db, "SELECT a FROM t ORDER BY a COLLATE reversi");
|
||||
int counter = 0;
|
||||
while( SQLITE_ROW == sqlite3_step(stmt) ){
|
||||
final String val = sqlite3_column_text(stmt, 0);
|
||||
@ -414,7 +418,7 @@ public class Tester1 {
|
||||
}
|
||||
affirm(3 == counter);
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_prepare(db, "SELECT a FROM t ORDER BY a", stmt);
|
||||
stmt = prepare(db, "SELECT a FROM t ORDER BY a");
|
||||
counter = 0;
|
||||
while( SQLITE_ROW == sqlite3_step(stmt) ){
|
||||
final String val = sqlite3_column_text(stmt, 0);
|
||||
@ -479,9 +483,7 @@ public class Tester1 {
|
||||
int rc = sqlite3_create_function(db, "myfunc", -1, SQLITE_UTF8, func);
|
||||
affirm(0 == rc);
|
||||
affirm(0 == xFuncAccum.value);
|
||||
final sqlite3_stmt stmt = new sqlite3_stmt();
|
||||
rc = sqlite3_prepare(db, "SELECT myfunc(1,2,3)", stmt);
|
||||
affirm( 0==rc );
|
||||
final sqlite3_stmt stmt = prepare(db, "SELECT myfunc(1,2,3)");
|
||||
int n = 0;
|
||||
while( SQLITE_ROW == sqlite3_step(stmt) ){
|
||||
affirm( 6 == sqlite3_column_int(stmt, 0) );
|
||||
@ -498,15 +500,14 @@ public class Tester1 {
|
||||
private static void testUdfJavaObject(){
|
||||
final sqlite3 db = createNewDb();
|
||||
final ValueHolder<sqlite3> testResult = new ValueHolder<>(db);
|
||||
SQLFunction func = new SQLFunction.Scalar(){
|
||||
final SQLFunction func = new SQLFunction.Scalar(){
|
||||
public void xFunc(sqlite3_context cx, sqlite3_value args[]){
|
||||
sqlite3_result_java_object(cx, testResult.value);
|
||||
}
|
||||
};
|
||||
int rc = sqlite3_create_function(db, "myfunc", -1, SQLITE_UTF8, func);
|
||||
affirm(0 == rc);
|
||||
sqlite3_stmt stmt = new sqlite3_stmt();
|
||||
sqlite3_prepare(db, "select myfunc()", stmt);
|
||||
final sqlite3_stmt stmt = prepare(db, "select myfunc()");
|
||||
affirm( 0 != stmt.getNativePointer() );
|
||||
affirm( testResult.value == db );
|
||||
int n = 0;
|
||||
@ -550,9 +551,7 @@ public class Tester1 {
|
||||
execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES(1),(2),(3)");
|
||||
int rc = sqlite3_create_function(db, "myfunc", 1, SQLITE_UTF8, func);
|
||||
affirm(0 == rc);
|
||||
sqlite3_stmt stmt = new sqlite3_stmt();
|
||||
sqlite3_prepare(db, "select myfunc(a), myfunc(a+10) from t", stmt);
|
||||
affirm( 0 != stmt.getNativePointer() );
|
||||
sqlite3_stmt stmt = prepare(db, "select myfunc(a), myfunc(a+10) from t");
|
||||
int n = 0;
|
||||
if( SQLITE_ROW == sqlite3_step(stmt) ){
|
||||
final int v = sqlite3_column_int(stmt, 0);
|
||||
@ -571,9 +570,7 @@ public class Tester1 {
|
||||
sqlite3_finalize(stmt);
|
||||
affirm( 1==n );
|
||||
|
||||
rc = sqlite3_prepare(db, "select myfunc(a), myfunc(a+a) from t order by a",
|
||||
stmt);
|
||||
affirm( 0 == rc );
|
||||
stmt = prepare(db, "select myfunc(a), myfunc(a+a) from t order by a");
|
||||
n = 0;
|
||||
while( SQLITE_ROW == sqlite3_step(stmt) ){
|
||||
final int c0 = sqlite3_column_int(stmt, 0);
|
||||
@ -624,12 +621,11 @@ public class Tester1 {
|
||||
"CREATE TEMP TABLE twin(x, y); INSERT INTO twin VALUES",
|
||||
"('a', 4),('b', 5),('c', 3),('d', 8),('e', 1)"
|
||||
});
|
||||
sqlite3_stmt stmt = new sqlite3_stmt();
|
||||
rc = sqlite3_prepare(db,
|
||||
final sqlite3_stmt stmt = prepare(db,
|
||||
"SELECT x, winsumint(y) OVER ("+
|
||||
"ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING"+
|
||||
") AS sum_y "+
|
||||
"FROM twin ORDER BY x;", stmt);
|
||||
"FROM twin ORDER BY x;");
|
||||
affirm( 0 == rc );
|
||||
int n = 0;
|
||||
while( SQLITE_ROW == sqlite3_step(stmt) ){
|
||||
@ -693,11 +689,12 @@ public class Tester1 {
|
||||
new Tracer(){
|
||||
public int xCallback(int traceFlag, Object pNative, Object x){
|
||||
++counter.value;
|
||||
//outln("TRACE "+traceFlag+" pNative = "+pNative.getClass().getName());
|
||||
switch(traceFlag){
|
||||
case SQLITE_TRACE_STMT:
|
||||
affirm(pNative instanceof sqlite3_stmt);
|
||||
affirm(x instanceof String);
|
||||
//outln("TRACE_STMT sql = "+x);
|
||||
affirm(x instanceof String);
|
||||
affirm( ((String)x).indexOf(nonBmpChar) > 0 );
|
||||
break;
|
||||
case SQLITE_TRACE_PROFILE:
|
||||
@ -730,16 +727,18 @@ public class Tester1 {
|
||||
|
||||
private static void testBusy(){
|
||||
final String dbName = "_busy-handler.db";
|
||||
final sqlite3 db1 = new sqlite3();
|
||||
final sqlite3 db2 = new sqlite3();
|
||||
final OutputPointer.sqlite3 outDb = new OutputPointer.sqlite3();
|
||||
|
||||
int rc = sqlite3_open(dbName, db1);
|
||||
int rc = sqlite3_open(dbName, outDb);
|
||||
++metrics.dbOpen;
|
||||
affirm( 0 == rc );
|
||||
final sqlite3 db1 = outDb.getValue();
|
||||
execSql(db1, "CREATE TABLE IF NOT EXISTS t(a)");
|
||||
rc = sqlite3_open(dbName, db2);
|
||||
rc = sqlite3_open(dbName, outDb);
|
||||
++metrics.dbOpen;
|
||||
affirm( 0 == rc );
|
||||
affirm( outDb.getValue() != db1 );
|
||||
final sqlite3 db2 = outDb.getValue();
|
||||
rc = sqlite3_db_config(db1, SQLITE_DBCONFIG_MAINDBNAME, "foo");
|
||||
affirm( sqlite3_db_filename(db1, "foo").endsWith(dbName) );
|
||||
|
||||
@ -760,11 +759,10 @@ public class Tester1 {
|
||||
// Force a locked condition...
|
||||
execSql(db1, "BEGIN EXCLUSIVE");
|
||||
affirm(!xDestroyed.value);
|
||||
sqlite3_stmt stmt = new sqlite3_stmt();
|
||||
rc = sqlite3_prepare(db2, "SELECT * from t", stmt);
|
||||
rc = sqlite3_prepare_v2(db2, "SELECT * from t", outStmt);
|
||||
affirm( SQLITE_BUSY == rc);
|
||||
assert( null == outStmt.getValue() );
|
||||
affirm( 3 == xBusyCalled.value );
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_close_v2(db1);
|
||||
affirm(!xDestroyed.value);
|
||||
sqlite3_close_v2(db2);
|
||||
|
@ -20,4 +20,6 @@ package org.sqlite.jni;
|
||||
and C via JNI.
|
||||
*/
|
||||
public final class sqlite3 extends NativePointerHolder<sqlite3> {
|
||||
// Only invoked from JNI
|
||||
private sqlite3(){}
|
||||
}
|
||||
|
@ -14,4 +14,6 @@
|
||||
package org.sqlite.jni;
|
||||
|
||||
public final class sqlite3_value extends NativePointerHolder<sqlite3_value> {
|
||||
//! Invoked only from JNI.
|
||||
private sqlite3_value(){}
|
||||
}
|
||||
|
Reference in New Issue
Block a user