1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-30 19:03:16 +03:00

JNI-internal cleanups and API renaming. Add a C-side java-string-to-utf8 conversion.

FossilOrigin-Name: 672d85795d04131135b1dc6a02d64eceb8b5084217c17766afeca4af23c07ec4
This commit is contained in:
stephan
2023-08-06 13:02:43 +00:00
parent 6a9364a518
commit 9c4c16c80d
9 changed files with 155 additions and 149 deletions

View File

@ -128,7 +128,6 @@ $(sqlite3.c): $(sqlite3.h)
SQLITE_OPT := \
-DSQLITE_ENABLE_RTREE \
-DSQLITE_ENABLE_EXPLAIN_COMMENTS \
-DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION \
-DSQLITE_ENABLE_STMTVTAB \
-DSQLITE_ENABLE_DBPAGE_VTAB \
-DSQLITE_ENABLE_DBSTAT_VTAB \
@ -137,7 +136,6 @@ SQLITE_OPT := \
-DSQLITE_OMIT_LOAD_EXTENSION \
-DSQLITE_OMIT_DEPRECATED \
-DSQLITE_OMIT_SHARED_CACHE \
-DSQLITE_OMIT_WAL \
-DSQLITE_THREADSAFE=0 \
-DSQLITE_TEMP_STORE=2 \
-DSQLITE_USE_URI=1 \
@ -147,7 +145,7 @@ SQLITE_OPT := \
# for a var which gets set in all builds but only read
# via assert().
SQLITE_OPFS += -g -DDEBUG -UNDEBUG
SQLITE_OPT += -g -DDEBUG -UNDEBUG
ifeq (1,$(enable.fts5))
SQLITE_OPT += -DSQLITE_ENABLE_FTS5

View File

@ -37,11 +37,9 @@
#if !defined(SQLITE_DEFAULT_PAGE_SIZE)
# define SQLITE_DEFAULT_PAGE_SIZE 8192
#endif
#ifndef SQLITE_DEFAULT_UNIX_VFS
# define SQLITE_DEFAULT_UNIX_VFS "unix"
#ifndef SQLITE_DQS
# define SQLITE_DQS 0
#endif
#undef SQLITE_DQS
#define SQLITE_DQS 0
/**********************************************************************/
/* SQLITE_ENABLE_... */
@ -57,11 +55,6 @@
#ifndef SQLITE_ENABLE_EXPLAIN_COMMENTS
# define SQLITE_ENABLE_EXPLAIN_COMMENTS 1
#endif
#ifdef SQLITE_ENABLE_FTS5
# ifndef SQLITE_ENABLE_FTS4
# define SQLITE_ENABLE_FTS4 1
# endif
#endif
#ifndef SQLITE_ENABLE_MATH_FUNCTIONS
# define SQLITE_ENABLE_MATH_FUNCTIONS 1
#endif
@ -74,15 +67,15 @@
#ifndef SQLITE_ENABLE_RTREE
# define SQLITE_ENABLE_RTREE 1
#endif
#ifndef SQLITE_ENABLE_SESSION
# define SQLITE_ENABLE_SESSION 1
#endif
//#ifndef SQLITE_ENABLE_SESSION
//# define SQLITE_ENABLE_SESSION 1
//#endif
#ifndef SQLITE_ENABLE_STMTVTAB
# define SQLITE_ENABLE_STMTVTAB 1
#endif
#ifndef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
# define SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
#endif
//#ifndef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
//# define SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
//#endif
/**********************************************************************/
/* SQLITE_M... */
@ -160,8 +153,8 @@
JFuncName(Suffix)
/* First 2 parameters to all JNI bindings. */
#define JENV_JSELF JNIEnv * const env, jobject jSelf
/* Helpers to squelch -Xcheck:jni warnings about
not having checked for exceptions. */
/* Helpers to account for -Xcheck:jni warnings about not having
checked for exceptions. */
#define IFTHREW if((*env)->ExceptionCheck(env))
#define EXCEPTION_IGNORE (void)((*env)->ExceptionCheck(env))
#define EXCEPTION_CLEAR (*env)->ExceptionClear(env)
@ -337,8 +330,8 @@ struct NphCacheLine {
Whereas we cache new refs for each thread.
*/
typedef struct JNIEnvCacheLine JNIEnvCacheLine;
struct JNIEnvCacheLine {
typedef struct JNIEnvCache JNIEnvCache;
struct JNIEnvCache {
JNIEnv *env /* env in which this cache entry was created */;
//! The various refs to global classes might be cacheable a single
// time globally. Information online seems inconsistent on that
@ -350,17 +343,17 @@ struct JNIEnvCacheLine {
jobject oCharsetUtf8 /* global ref to StandardCharset.UTF_8 */;
jmethodID ctorLong1 /* the Long(long) constructor */;
jmethodID ctorStringBA /* the String(byte[],Charset) constructor */;
jmethodID stringGetBytes /* the String.getBytes(Charset) method */;
} g;
jobject currentStmt /* Current Java sqlite3_stmt object being
prepared, stepped, reset, or
finalized. Needed for tracing, the
alternative being that we create a new
sqlite3_stmt wrapper object for every
tracing call which needs a stmt
object. This approach is rather invasive,
however, requiring code in all stmt
operations which can lead through the
tracing API. */;
sqlite3_stmt wrapper object for every tracing
call which needs a stmt object. This approach
is rather invasive, however, requiring code
in all stmt operations which can lead through
the tracing API. */;
#ifdef SQLITE_ENABLE_FTS5
jobject jFtsExt /* Global ref to Java singleton for the
Fts5ExtensionApi instance. */;
@ -370,8 +363,8 @@ struct JNIEnvCacheLine {
jfieldID fidB;
} jPhraseIter;
#endif
JNIEnvCacheLine * pPrev /* Previous entry in the linked list */;
JNIEnvCacheLine * pNext /* Next entry in the linked list */;
JNIEnvCache * pPrev /* Previous entry in the linked list */;
JNIEnvCache * pNext /* Next entry in the linked list */;
/** TODO: NphCacheLine *pNphHit;
to help fast-track cache lookups, update this to point to the
@ -445,8 +438,8 @@ static struct {
*/
JavaVM * jvm;
struct {
JNIEnvCacheLine * aHead /* Linked list of in-use instances */;
JNIEnvCacheLine * aFree /* Linked list of free instances */;
JNIEnvCache * aHead /* Linked list of in-use instances */;
JNIEnvCache * aFree /* Linked list of free instances */;
} envCache;
struct {
PerDbStateJni * aUsed /* Linked list of in-use instances */;
@ -550,14 +543,14 @@ static void s3jni_call_xDestroy(JNIEnv * const env, jobject jObj, jclass klazz){
standard UTF-8 to a Java string, but JNI offers only algorithms for
working with MUTF-8, not UTF-8.
*/
static jstring s3jni_string_from_utf8(JNIEnvCacheLine * const jc,
static jstring s3jni_utf8_to_jstring(JNIEnvCache * const jc,
const char * const z, int n){
jstring rv = NULL;
JNIEnv * const env = jc->env;
if( 0==n || (z && !z[0]) ){
/* Fast-track the empty-string case. We could hypothetically do
this for any strings where n<4 and z is NUL-terminated and none
of z[0..3] are NUL bytes. */
if( 0==n || (n<0 && z && !z[0]) ){
/* Fast-track the empty-string case via the MUTF-8 API. We could
hypothetically do this for any strings where n<4 and z is
NUL-terminated and none of z[0..3] are NUL bytes. */
rv = (*env)->NewStringUTF(env, "");
}else if( z ){
jbyteArray jba;
@ -573,6 +566,45 @@ static jstring s3jni_string_from_utf8(JNIEnvCacheLine * const jc,
return rv;
}
/**
Converts the given java.lang.String object into a NUL-terminated
UTF-8 C-string by calling jstr.getBytes(StandardCharset.UTF_8).
Returns NULL if jstr is NULL or on allocation error. If jstr is not
NULL and nLen is not NULL then nLen is set to the length of the
returned string, not including the terminating NUL. If jstr is not
NULL and it returns NULL, this indicates an allocation error. In
that case, if nLen is not NULL then it is either set to 0 (if
fetching of jstr's bytes fails to allocate) or set to what would
have been the length of the string had C-string allocation
succeeded.
*/
static char * s3jni_jstring_to_utf8(JNIEnvCache * const jc,
jstring jstr, int *nLen){
JNIEnv * const env = jc->env;
jbyteArray jba;
jsize nBa;
char *rv;
if(!jstr) return 0;
jba = (*env)->CallObjectMethod(env, jstr, jc->g.stringGetBytes,
jc->g.oCharsetUtf8);
if( (*env)->ExceptionCheck(env) || !jba
/* order of these checks is significant for -Xlint:jni */ ) {
EXCEPTION_REPORT;
if( nLen ) *nLen = 0;
return 0;
}
nBa = (*env)->GetArrayLength(env, jba);
if( nLen ) *nLen = (int)nBa;
rv = sqlite3_malloc( nBa + 1 );
if( rv ){
(*env)->GetByteArrayRegion(env, jba, 0, nBa, (jbyte*)rv);
rv[nBa] = 0;
}
UNREF_L(jba);
return rv;
}
/**
Fetches the S3Global.envCache row for the given env, allocing
a row if needed. When a row is allocated, its state is initialized
@ -580,8 +612,8 @@ static jstring s3jni_string_from_utf8(JNIEnvCacheLine * const jc,
an entry fails. That's hypothetically possible but "shouldn't happen."
*/
FIXME_THREADING
static JNIEnvCacheLine * S3Global_JNIEnvCache_cache(JNIEnv * const env){
struct JNIEnvCacheLine * row = S3Global.envCache.aHead;
static JNIEnvCache * S3Global_env_cache(JNIEnv * const env){
struct JNIEnvCache * row = S3Global.envCache.aHead;
for( ; row; row = row->pNext ){
if( row->env == env ){
++S3Global.metrics.envCacheHits;
@ -595,7 +627,7 @@ static JNIEnvCacheLine * S3Global_JNIEnvCache_cache(JNIEnv * const env){
S3Global.envCache.aFree = row->pNext;
if( row->pNext ) row->pNext->pPrev = 0;
}else{
row = sqlite3_malloc(sizeof(JNIEnvCacheLine));
row = sqlite3_malloc(sizeof(JNIEnvCache));
if( !row ){
(*env)->FatalError(env, "Maintenance required: JNIEnvCache is full.")
/* Does not return, but cc doesn't know that */;
@ -624,6 +656,10 @@ static JNIEnvCacheLine * S3Global_JNIEnvCache_cache(JNIEnv * const env){
(*env)->GetMethodID(env, row->g.cString,
"<init>", "([BLjava/nio/charset/Charset;)V");
EXCEPTION_IS_FATAL("Error getting reference to String(byte[],Charset) ctor.");
row->g.stringGetBytes =
(*env)->GetMethodID(env, row->g.cString,
"getBytes", "(Ljava/nio/charset/Charset;)[B");
EXCEPTION_IS_FATAL("Error getting reference to String.getBytes(Charset).");
{ /* StandardCharsets.UTF_8 */
jfieldID fUtf8;
@ -702,7 +738,7 @@ static void PerDbStateJni_set_aside(PerDbStateJni * const s){
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 JNIEnvCacheLine_clear(JNIEnvCacheLine * const p){
static void JNIEnvCache_clear(JNIEnvCache * const p){
JNIEnv * const env = p->env;
if(env){
int i;
@ -718,7 +754,7 @@ static void JNIEnvCacheLine_clear(JNIEnvCacheLine * const p){
for( i = 0; i < NphCache_SIZE; ++i ){
NphCacheLine_clear(env, &p->nph[i]);
}
memset(p, 0, sizeof(JNIEnvCacheLine));
memset(p, 0, sizeof(JNIEnvCache));
}
}
@ -750,8 +786,8 @@ static void PerDbStateJni_free_for_env(JNIEnv *env){
Also passes env to PerDbStateJni_free_for_env() to free up
what would otherwise be stale references.
*/
static int S3Global_JNIEnvCache_uncache(JNIEnv * const env){
struct JNIEnvCacheLine * row = S3Global.envCache.aHead;
static int S3Global_env_uncache(JNIEnv * const env){
struct JNIEnvCache * row = S3Global.envCache.aHead;
for( ; row; row = row->pNext ){
if( row->env == env ){
break;
@ -764,7 +800,7 @@ static int S3Global_JNIEnvCache_uncache(JNIEnv * const env){
assert( !row->pPrev );
S3Global.envCache.aHead = row->pNext;
}
JNIEnvCacheLine_clear(row);
JNIEnvCache_clear(row);
assert( !row->pNext );
assert( !row->pPrev );
row->pNext = S3Global.envCache.aFree;
@ -776,7 +812,7 @@ static int S3Global_JNIEnvCache_uncache(JNIEnv * const env){
static void S3Global_JNIEnvCache_clear(void){
while( S3Global.envCache.aHead ){
S3Global_JNIEnvCache_uncache( S3Global.envCache.aHead->env );
S3Global_env_uncache( S3Global.envCache.aHead->env );
}
}
@ -813,7 +849,7 @@ static struct NphCacheLine * S3Global_nph_cache(JNIEnv * const env, const char *
looking up class objects can be expensive, so they should be
cached as well.
*/
struct JNIEnvCacheLine * const envRow = S3Global_JNIEnvCache_cache(env);
struct JNIEnvCache * const envRow = S3Global_env_cache(env);
struct NphCacheLine * freeSlot = 0;
struct NphCacheLine * cacheLine = 0;
int i;
@ -1413,7 +1449,7 @@ static int udf_args(JNIEnv *env,
*jArgv = 0;
if(!jcx) goto error_oom;
ja = (*env)->NewObjectArray(env, argc,
S3Global_JNIEnvCache_cache(env)->g.cObj,
S3Global_env_cache(env)->g.cObj,
NULL);
if(!ja) goto error_oom;
for(i = 0; i < argc; ++i){
@ -2063,41 +2099,25 @@ JDECL(jint,1create_1function)(JENV_JSELF, jobject jDb, jstring jFuncName,
}
JDECL(jbyteArray,1db_1filename)(JENV_JSELF, jobject jDb, jbyteArray jDbName){
#if 1
JDECL(jstring,1db_1filename)(JENV_JSELF, jobject jDb, jstring jDbName){
PerDbStateJni * const ps = PerDbStateJni_for_db(env, jDb, 0, 0);
jbyte *zFilename = (ps && jDbName) ? JBA_TOC(jDbName) : 0;
const char *zRv;
jbyteArray jRv = 0;
JNIEnvCache * const jc = S3Global_env_cache(env);
char *zDbName;
jstring jRv = 0;
int nStr = 0;
if( !ps || (jDbName && !zFilename) ) return 0;
zRv = sqlite3_db_filename(ps->pDb, (const char *)zFilename);
if( !ps || !jDbName ){
return 0;
}
zDbName = s3jni_jstring_to_utf8(jc, jDbName, &nStr);
if( zDbName ){
char const * zRv = sqlite3_db_filename(ps->pDb, zDbName);
sqlite3_free(zDbName);
if( zRv ){
const int n = sqlite3Strlen30(zRv);
jRv = (*env)->NewByteArray(env, (jint)n);
if( jRv ){
(*env)->SetByteArrayRegion(env, jRv, 0, (jint)n, (const jbyte *)zRv);
jRv = s3jni_utf8_to_jstring(jc, zRv, -1);
}
}
JBA_RELEASE(jDbName, zFilename);
return jRv;
#else
/* For comparison, this impl expects a jstring jDbName and returns a
jstring for significant code savings but it's not
MUTF-8-safe. With this impl, the Java-side byte-array-using
sqlite3_db_filename() impl is unnecessary. */
JDECL(jstring,1db_1filename)(JENV_JSELF, jobject jDb, jstring jDbName){
PerDbStateJni * const ps = PerDbStateJni_for_db(env, jDb, 0, 0);
const char *zFilename = (ps && jDbName) ? JSTR_TOC(jDbName) : 0;
const char *zRv;
if( !ps || (jDbName && !zFilename)) return 0;
zRv = sqlite3_db_filename(ps->pDb, zFilename ? zFilename : "main");
JSTR_RELEASE(jDbName, zFilename);
return zRv ? (*env)->NewStringUTF(env, zRv) : 0;
}
#endif
}
JDECL(jstring,1errmsg)(JENV_JSELF, jobject jpDb){
@ -2127,7 +2147,7 @@ JDECL(jint,1initialize)(JENV_JSELF){
is needed for certain tracing flags. At a minumum those ops are:
step, reset, finalize, prepare.
*/
static jobject stmt_set_current(JNIEnvCacheLine * const jc, jobject jStmt){
static jobject stmt_set_current(JNIEnvCache * const jc, jobject jStmt){
jobject const old = jc->currentStmt;
jc->currentStmt = jStmt;
return old;
@ -2137,7 +2157,7 @@ JDECL(jint,1finalize)(JENV_JSELF, jobject jpStmt){
int rc = 0;
sqlite3_stmt * const pStmt = PtrGet_sqlite3_stmt(jpStmt);
if( pStmt ){
JNIEnvCacheLine * const jc = S3Global_JNIEnvCache_cache(env);
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);
@ -2208,7 +2228,7 @@ static jint sqlite3_jni_prepare_v123(int prepVersion, JNIEnv * const env, jclass
sqlite3_stmt * pStmt = 0;
const char * zTail = 0;
jbyte * const pBuf = JBA_TOC(baSql);
JNIEnvCacheLine * const jc = S3Global_JNIEnvCache_cache(env);
JNIEnvCache * const jc = S3Global_env_cache(env);
jobject const pOldStmt = stmt_set_current(jc, jOutStmt);
int rc = SQLITE_ERROR;
assert(prepVersion==1 || prepVersion==2 || prepVersion==3);
@ -2303,7 +2323,7 @@ JDECL(jint,1reset)(JENV_JSELF, jobject jpStmt){
int rc = 0;
sqlite3_stmt * const pStmt = PtrGet_sqlite3_stmt(jpStmt);
if( pStmt ){
JNIEnvCacheLine * const jc = S3Global_JNIEnvCache_cache(env);
JNIEnvCache * const jc = S3Global_env_cache(env);
jobject const pPrev = stmt_set_current(jc, jpStmt);
rc = sqlite3_reset(pStmt);
(void)stmt_set_current(jc, pPrev);
@ -2571,7 +2591,7 @@ JDECL(jint,1step)(JENV_JSELF,jobject jStmt){
int rc = SQLITE_MISUSE;
sqlite3_stmt * const pStmt = PtrGet_sqlite3_stmt(jStmt);
if(pStmt){
JNIEnvCacheLine * const jc = S3Global_JNIEnvCache_cache(env);
JNIEnvCache * const jc = S3Global_env_cache(env);
jobject const jPrevStmt = stmt_set_current(jc, jStmt);
rc = sqlite3_step(pStmt);
(void)stmt_set_current(jc, jPrevStmt);
@ -2585,11 +2605,11 @@ static int s3jni_trace_impl(unsigned traceflag, void *pC, void *pP, void *pX){
jobject jX = NULL /* the tracer's X arg */;
jobject jP = NULL /* the tracer's P arg */;
jobject jPUnref = NULL /* potentially a local ref to jP */;
JNIEnvCacheLine * const jc = S3Global_JNIEnvCache_cache(env);
JNIEnvCache * const jc = S3Global_env_cache(env);
int rc;
switch(traceflag){
case SQLITE_TRACE_STMT:
jX = s3jni_string_from_utf8(jc, (const char *)pX, -1);
jX = s3jni_utf8_to_jstring(jc, (const char *)pX, -1);
if(!jX) return SQLITE_NOMEM;
jP = jc->currentStmt;
break;
@ -2841,6 +2861,7 @@ JDECL(void,1do_1something_1for_1developer)(JENV_JSELF){
#define SO(T) printf("\tsizeof(" #T ") = %u\n", (unsigned)sizeof(T))
SO(void*);
SO(JniHookState);
SO(JNIEnvCache);
SO(PerDbStateJni);
SO(S3Global);
SO(S3ClassNames);
@ -2964,7 +2985,7 @@ static inline jobject new_fts5_api_wrapper(JNIEnv * const env, fts5_api *sv){
instance, or NULL on OOM.
*/
static jobject s3jni_getFts5ExensionApi(JNIEnv * const env){
JNIEnvCacheLine * const row = S3Global_JNIEnvCache_cache(env);
JNIEnvCache * const row = S3Global_env_cache(env);
if( !row->jFtsExt ){
row->jFtsExt = new_NativePointerHolder_object(env, S3ClassNames.Fts5ExtensionApi,
s3jni_ftsext());
@ -3031,8 +3052,8 @@ JDECLFtsXA(jint,xColumnText)(JENV_JSELF,jobject jCtx, jint iCol,
int rc = fext->xColumnText(PtrGet_Fts5Context(jCtx), (int)iCol,
&pz, &pn);
if( 0==rc ){
JNIEnvCacheLine * const jc = S3Global_JNIEnvCache_cache(env);
jstring jstr = pz ? s3jni_string_from_utf8(jc, pz, pn) : 0;
JNIEnvCache * const jc = S3Global_env_cache(env);
jstring jstr = pz ? s3jni_utf8_to_jstring(jc, pz, pn) : 0;
if( pz ){
if( jstr ){
setOutputString(env, jOut, jstr);
@ -3188,7 +3209,7 @@ JDECLFtsXA(jint,xPhraseCount)(JENV_JSELF,jobject jCtx){
/**
Initializes jc->jPhraseIter if it needed it.
*/
static void s3jni_phraseIter_init(JNIEnv *const env, JNIEnvCacheLine * const jc,
static void s3jni_phraseIter_init(JNIEnv *const env, JNIEnvCache * const jc,
jobject jIter){
if(!jc->jPhraseIter.klazz){
jclass klazz = (*env)->GetObjectClass(env, jIter);
@ -3202,7 +3223,7 @@ static void s3jni_phraseIter_init(JNIEnv *const env, JNIEnvCacheLine * const jc,
}
/* Copy the 'a' and 'b' fields from pSrc to Fts5PhraseIter object jIter. */
static void s3jni_phraseIter_NToJ(JNIEnv *const env, JNIEnvCacheLine const * const jc,
static void s3jni_phraseIter_NToJ(JNIEnv *const env, JNIEnvCache const * const jc,
Fts5PhraseIter const * const pSrc,
jobject jIter){
assert(jc->jPhraseIter.klazz);
@ -3213,7 +3234,7 @@ static void s3jni_phraseIter_NToJ(JNIEnv *const env, JNIEnvCacheLine const * con
}
/* Copy the 'a' and 'b' fields from Fts5PhraseIter object jIter to pDest. */
static void s3jni_phraseIter_JToN(JNIEnv *const env, JNIEnvCacheLine const * const jc,
static void s3jni_phraseIter_JToN(JNIEnv *const env, JNIEnvCache const * const jc,
jobject jIter, Fts5PhraseIter * const pDest){
assert(jc->jPhraseIter.klazz);
pDest->a =
@ -3228,7 +3249,7 @@ JDECLFtsXA(jint,xPhraseFirst)(JENV_JSELF,jobject jCtx, jint iPhrase,
jobject jIter, jobject jOutCol,
jobject jOutOff){
Fts5ExtDecl;
JNIEnvCacheLine * const jc = S3Global_JNIEnvCache_cache(env);
JNIEnvCache * const jc = S3Global_env_cache(env);
Fts5PhraseIter iter;
int rc, iCol = 0, iOff = 0;
s3jni_phraseIter_init(env, jc, jIter);
@ -3245,7 +3266,7 @@ JDECLFtsXA(jint,xPhraseFirst)(JENV_JSELF,jobject jCtx, jint iPhrase,
JDECLFtsXA(jint,xPhraseFirstColumn)(JENV_JSELF,jobject jCtx, jint iPhrase,
jobject jIter, jobject jOutCol){
Fts5ExtDecl;
JNIEnvCacheLine * const jc = S3Global_JNIEnvCache_cache(env);
JNIEnvCache * const jc = S3Global_env_cache(env);
Fts5PhraseIter iter;
int rc, iCol = 0;
s3jni_phraseIter_init(env, jc, jIter);
@ -3261,7 +3282,7 @@ JDECLFtsXA(jint,xPhraseFirstColumn)(JENV_JSELF,jobject jCtx, jint iPhrase,
JDECLFtsXA(void,xPhraseNext)(JENV_JSELF,jobject jCtx, jobject jIter,
jobject jOutCol, jobject jOutOff){
Fts5ExtDecl;
JNIEnvCacheLine * const jc = S3Global_JNIEnvCache_cache(env);
JNIEnvCache * const jc = S3Global_env_cache(env);
Fts5PhraseIter iter;
int iCol = 0, iOff = 0;
if(!jc->jPhraseIter.klazz) return /*SQLITE_MISUSE*/;
@ -3276,7 +3297,7 @@ JDECLFtsXA(void,xPhraseNext)(JENV_JSELF,jobject jCtx, jobject jIter,
JDECLFtsXA(void,xPhraseNextColumn)(JENV_JSELF,jobject jCtx, jobject jIter,
jobject jOutCol){
Fts5ExtDecl;
JNIEnvCacheLine * const jc = S3Global_JNIEnvCache_cache(env);
JNIEnvCache * const jc = S3Global_env_cache(env);
Fts5PhraseIter iter;
int iCol = 0;
if(!jc->jPhraseIter.klazz) return /*SQLITE_MISUSE*/;
@ -3298,7 +3319,7 @@ JDECLFtsXA(jint,xPhraseSize)(JENV_JSELF,jobject jCtx, jint iPhrase){
struct s3jni_xQueryPhraseState {
JNIEnv *env;
Fts5ExtensionApi const * fext;
JNIEnvCacheLine const * jc;
JNIEnvCache const * jc;
jmethodID midCallback;
jobject jCallback;
jobject jFcx;
@ -3330,7 +3351,7 @@ static int s3jni_xQueryPhrase(const Fts5ExtensionApi *xapi,
JDECLFtsXA(jint,xQueryPhrase)(JENV_JSELF,jobject jFcx, jint iPhrase,
jobject jCallback){
Fts5ExtDecl;
JNIEnvCacheLine * const jc = S3Global_JNIEnvCache_cache(env);
JNIEnvCache * const jc = S3Global_env_cache(env);
struct s3jni_xQueryPhraseState s;
jclass klazz = jCallback ? (*env)->GetObjectClass(env, jCallback) : NULL;
if( !klazz ){
@ -3419,7 +3440,7 @@ static jint s3jni_fts5_xTokenize(JENV_JSELF, const char *zClassName,
jint tokFlags, jobject jFcx,
jbyteArray jbaText, jobject jCallback){
Fts5ExtDecl;
JNIEnvCacheLine * const jc = S3Global_JNIEnvCache_cache(env);
JNIEnvCache * const jc = S3Global_env_cache(env);
struct s3jni_xQueryPhraseState s;
int rc = 0;
jbyte * const pText = JBA_TOC(jbaText);
@ -3485,8 +3506,8 @@ JDECLFtsXA(jobject,xUserData)(JENV_JSELF,jobject jFcx){
return pAux ? pAux->jUserData : 0;
}
#endif /* SQLITE_ENABLE_FTS5 */
////////////////////////////////////////////////////////////////////////
// End of the main API bindings. What follows are internal utilities.
////////////////////////////////////////////////////////////////////////
@ -3499,7 +3520,7 @@ JDECLFtsXA(jobject,xUserData)(JENV_JSELF,jobject jFcx){
*/
JNIEXPORT jboolean JNICALL
Java_org_sqlite_jni_SQLite3Jni_uncacheJniEnv(JNIEnv * const env, jclass self){
return S3Global_JNIEnvCache_uncache(env) ? JNI_TRUE : JNI_FALSE;
return S3Global_env_uncache(env) ? JNI_TRUE : JNI_FALSE;
}
@ -3564,7 +3585,7 @@ Java_org_sqlite_jni_SQLite3Jni_init(JNIEnv * const env, jclass self, jclass klaz
(*env)->FatalError(env, "GetJavaVM() failure shouldn't be possible.");
return;
}
(void)S3Global_JNIEnvCache_cache(env);
(void)S3Global_env_cache(env);
if( !S3Global.envCache.aHead ){
(*env)->FatalError(env, "Could not allocate JNIEnv-specific cache.");
return;

View File

@ -1094,10 +1094,10 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1data_1count
/*
* Class: org_sqlite_jni_SQLite3Jni
* Method: sqlite3_db_filename
* Signature: (Lorg/sqlite/jni/sqlite3;[B)[B
* Signature: (Lorg/sqlite/jni/sqlite3;Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jbyteArray JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1db_1filename
(JNIEnv *, jclass, jobject, jbyteArray);
JNIEXPORT jstring JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1db_1filename
(JNIEnv *, jclass, jobject, jstring);
/*
* Class: org_sqlite_jni_SQLite3Jni

View File

@ -34,7 +34,7 @@ public final class Fts5ExtensionApi extends NativePointerHolder<Fts5ExtensionApi
/**
Returns a singleton instance of this class.
*/
public static native Fts5ExtensionApi getInstance();
public static synchronized native Fts5ExtensionApi getInstance();
public native int xColumnCount(@NotNull Fts5Context fcx);
public native int xColumnSize(@NotNull Fts5Context cx, int iCol,

View File

@ -111,6 +111,7 @@ import java.lang.annotation.ElementType;
- https://stackoverflow.com/questions/57419723
- https://stackoverflow.com/questions/7921016
- https://itecnote.com/tecnote/java-getting-true-utf-8-characters-in-java-jni/
- https://docs.oracle.com/javase/8/docs/api/java/lang/Character.html#unicode
- https://docs.oracle.com/javase/8/docs/api/java/io/DataInput.html#modified-utf-8
@ -397,22 +398,8 @@ public final class SQLite3Jni {
public static native int sqlite3_data_count(@NotNull sqlite3_stmt stmt);
/** In order to support the full range of UTF-8 filenames, we
require an extra layer of conversion via a byte[]. */
private static native byte[] sqlite3_db_filename(@NotNull sqlite3 db,
@NotNull byte dbName[]);
/**
As for the C API of the same name except that if dbName is null then
"main" is assumed.
*/
public static String sqlite3_db_filename(@NotNull sqlite3 db,
@Nullable String dbName){
final byte[] bName =
(((null == dbName) ? "main" : dbName)+"\0").getBytes(StandardCharsets.UTF_8);
final byte[] rv = sqlite3_db_filename(db, bName);
return (null == rv) ? null : new String(rv, StandardCharsets.UTF_8);
}
public static native String sqlite3_db_filename(@NotNull sqlite3 db,
@NotNull String dbName);
public static native int sqlite3_errcode(@NotNull sqlite3 db);

View File

@ -740,7 +740,7 @@ public class Tester1 {
rc = sqlite3_open(dbName, db2);
++metrics.dbOpen;
affirm( 0 == rc );
affirm( sqlite3_db_filename(db1, null).endsWith(dbName) );
affirm( sqlite3_db_filename(db1, "main").endsWith(dbName) );
final ValueHolder<Boolean> xDestroyed = new ValueHolder<>(false);
final ValueHolder<Integer> xBusyCalled = new ValueHolder<>(0);

View File

@ -30,7 +30,7 @@ public final class fts5_api extends NativePointerHolder<fts5_api> {
Returns the fts5_api instance associated with the given db, or
null if something goes horribly wrong.
*/
public static native fts5_api getInstanceForDb(@NotNull sqlite3 db);
public static synchronized native fts5_api getInstanceForDb(@NotNull sqlite3 db);
// int (*xCreateTokenizer)(
// fts5_api *pApi,

View File

@ -1,5 +1,5 @@
C Remove\sdoc\soutdated\swarning\sabout\ssqlite3_trace_v2()\sJNI\sbinding\sbeing\sincompatible\swith\sMUTF-8.\sUse\snew\sto-string\scapability\sto\ssimplify\sFts5ExtensionApi::xColumnText()\sJNI\sbinding.
D 2023-08-06T11:05:17.309
C JNI-internal\scleanups\sand\sAPI\srenaming.\sAdd\sa\sC-side\sjava-string-to-utf8\sconversion.
D 2023-08-06T13:02:43.735
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -230,10 +230,10 @@ F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9
F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282
F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
F ext/jni/GNUmakefile bb4cd99bd8da534215cb6d278f05a626283eb5d2e8aebdb4d35e548637d35a9a
F ext/jni/GNUmakefile 9f0b0172903dfdb46ed3a77d431153238b7b96ec66cf40333c07e6dd23a3fabe
F ext/jni/README.md 6ff7e1f4100dee980434a6ee37a199b653bceec62e233a6e2ccde6e7ae0c58bf
F ext/jni/src/c/sqlite3-jni.c 433ac7a2f113cda29ecf89b72711b55eeb97be5305fadd420408d1e538699177
F ext/jni/src/c/sqlite3-jni.h 1bb138aa39a5ae6cc0b2ab6c72de9afe752123b02f3322a8d5b1ca36b9e5a410
F ext/jni/src/c/sqlite3-jni.c 38c251d74f78b54b30e84ed97230eb2fa008e7400e9a460066ef6f1c43c06a2b
F ext/jni/src/c/sqlite3-jni.h 8ddf8a2e044d7880c75c07c9f025f3cdc5d486a42d30d99e0c45d7a8a973a97d
F ext/jni/src/org/sqlite/jni/Authorizer.java 8dde03bbe50896d2f426240a4af4dcb6d98b655af84fe6ed86e637f5d5ac1fc8
F ext/jni/src/org/sqlite/jni/BusyHandler.java 1b1d3e5c86cd796a0580c81b6af6550ad943baa25e47ada0dcca3aff3ebe978c
F ext/jni/src/org/sqlite/jni/Collation.java 8dffbb00938007ad0967b2ab424d3c908413af1bbd3d212b9c9899910f1218d1
@ -241,7 +241,7 @@ F ext/jni/src/org/sqlite/jni/CollationNeeded.java ebc7cd96d46a70daa76016a308e80f
F ext/jni/src/org/sqlite/jni/CommitHook.java 87c6a8e5138c61a8eeff018fe16d23f29219150239746032687f245938baca1a
F ext/jni/src/org/sqlite/jni/Fts5.java 13844685231e8b4840a706db3bed84d5dfcf15be0ae7e809eac40420dba24901
F ext/jni/src/org/sqlite/jni/Fts5Context.java 0a5a02047a6a1dd3e4a38b0e542a8dd2de365033ba30e6ae019a676305959890
F ext/jni/src/org/sqlite/jni/Fts5ExtensionApi.java aaab15f6dd515fa45b99ddb1f2f889657a2939f64f7934114f013c98442032da
F ext/jni/src/org/sqlite/jni/Fts5ExtensionApi.java 5b92cc034ca403936f11e07838699e6cf28afc5dd84020dfe9a6b64739b65065
F ext/jni/src/org/sqlite/jni/Fts5Function.java 65cde7151e441fee012250a5e03277de7babcd11a0c308a832b7940574259bcc
F ext/jni/src/org/sqlite/jni/Fts5PhraseIter.java 6642beda341c0b1b46af4e2d7f6f9ab03a7aede43277b2c92859176d6bce3be9
F ext/jni/src/org/sqlite/jni/Fts5Tokenizer.java 91489893596b6528c0df5cd7180bd5b55809c26e2b797fb321dfcdbc1298c060
@ -250,13 +250,13 @@ F ext/jni/src/org/sqlite/jni/OutputPointer.java fcece068415b804aa7843534addb3905
F ext/jni/src/org/sqlite/jni/ProgressHandler.java 5979450e996416d28543f1d42634d308439565a99332a8bd84e424af667116cc
F ext/jni/src/org/sqlite/jni/RollbackHook.java b04c8abcc6ade44a8a57129e33765793f69df0ba909e49ba18d73f4268d92564
F ext/jni/src/org/sqlite/jni/SQLFunction.java 09ce81c1c637e31c3a830d4c859cce95d65f5e02ff45f8bd1985b3479381bc46
F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 3494bd0eda06b56e137ff71fcdada9c463d40a0bbb02fc0ce96bf3761e6110b7
F ext/jni/src/org/sqlite/jni/Tester1.java ecc72fcba231f5dfd787fd5d62fac685e8cfc349f74d11245d19325643517bfd
F ext/jni/src/org/sqlite/jni/SQLite3Jni.java eb1a0b741654a1c813de4e3f11f354aae87b50f8656e440d95c0fd0509fad2f5
F ext/jni/src/org/sqlite/jni/Tester1.java a57a56717104d6ff50932c9e81edf4a8773ce524d497988c8b044c18bbc963ee
F ext/jni/src/org/sqlite/jni/TesterFts5.java cf2d687baafffdeba219b77cf611fd47a0556248820ea794ae3e8259bfbdc5ee
F ext/jni/src/org/sqlite/jni/Tracer.java a5cece9f947b0af27669b8baec300b6dd7ff859c3e6a6e4a1bd8b50f9714775d
F ext/jni/src/org/sqlite/jni/UpdateHook.java e58645a1727f8a9bbe72dc072ec5b40d9f9362cb0aa24acfe93f49ff56a9016d
F ext/jni/src/org/sqlite/jni/ValueHolder.java f022873abaabf64f3dd71ab0d6037c6e71cece3b8819fa10bf26a5461dc973ee
F ext/jni/src/org/sqlite/jni/fts5_api.java ae52ff7f963976fabb7e87b0b8cdb3f9d2ba1838e7d3b79b0b4cb526202d4709
F ext/jni/src/org/sqlite/jni/fts5_api.java 8c6b32455d7f85ee3f7f3e71c148bb3c2106f1d5484017daddfd560dd69d4f66
F ext/jni/src/org/sqlite/jni/fts5_extension_function.java ac825035d7d83fc7fd960347abfa6803e1614334a21533302041823ad5fc894c
F ext/jni/src/org/sqlite/jni/fts5_tokenizer.java e530b36e6437fcc500e95d5d75fbffe272bdea20d2fac6be2e1336c578fba98b
F ext/jni/src/org/sqlite/jni/sqlite3.java 600c3ddc1ac28ee8f58669fb435fd0d21f2972c652039361fde907d4fe44eb58
@ -2082,8 +2082,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 07dd082c9e371829a18aeb574f842891e545e1fc125760238ede7e7e2b6a4262
R 774991bd316a19b5ee8ab2518b7f41ee
P ebcfc2379be12f76a96f3605b734f406b3354d4c985062cdbfca0cf7e3f31379
R a7badfa2d93b121b26fb8275a69f64a6
U stephan
Z 78a283a26c39161657872bbb379dbda5
Z afedd572770e60de292afd4c7121fd3f
# Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
ebcfc2379be12f76a96f3605b734f406b3354d4c985062cdbfca0cf7e3f31379
672d85795d04131135b1dc6a02d64eceb8b5084217c17766afeca4af23c07ec4