4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 *************************************************************************
12 ** This file implements the JNI bindings declared in
13 ** org.sqlite.jni.SQLiteJni (from which sqlite3-jni.h is generated).
17 ** If you found this comment by searching the code for
18 ** CallStaticObjectMethod then you're the victim of an OpenJDK bug:
20 ** https://bugs.openjdk.org/browse/JDK-8130659
22 ** It's known to happen with OpenJDK v8 but not with v19.
24 ** This code does not use JNI's CallStaticObjectMethod().
28 ** Define any SQLITE_... config defaults we want if they aren't
29 ** overridden by the builder. Please keep these alphabetized.
32 /**********************************************************************/
34 #ifndef SQLITE_DEFAULT_CACHE_SIZE
35 # define SQLITE_DEFAULT_CACHE_SIZE -16384
37 #if !defined(SQLITE_DEFAULT_PAGE_SIZE)
38 # define SQLITE_DEFAULT_PAGE_SIZE 8192
44 /**********************************************************************/
45 /* SQLITE_ENABLE_... */
46 #ifndef SQLITE_ENABLE_BYTECODE_VTAB
47 # define SQLITE_ENABLE_BYTECODE_VTAB 1
49 #ifndef SQLITE_ENABLE_DBPAGE_VTAB
50 # define SQLITE_ENABLE_DBPAGE_VTAB 1
52 #ifndef SQLITE_ENABLE_DBSTAT_VTAB
53 # define SQLITE_ENABLE_DBSTAT_VTAB 1
55 #ifndef SQLITE_ENABLE_EXPLAIN_COMMENTS
56 # define SQLITE_ENABLE_EXPLAIN_COMMENTS 1
58 #ifndef SQLITE_ENABLE_MATH_FUNCTIONS
59 # define SQLITE_ENABLE_MATH_FUNCTIONS 1
61 #ifndef SQLITE_ENABLE_OFFSET_SQL_FUNC
62 # define SQLITE_ENABLE_OFFSET_SQL_FUNC 1
64 #ifndef SQLITE_ENABLE_RTREE
65 # define SQLITE_ENABLE_RTREE 1
67 //#ifndef SQLITE_ENABLE_SESSION
68 //# define SQLITE_ENABLE_SESSION 1
70 #ifndef SQLITE_ENABLE_STMTVTAB
71 # define SQLITE_ENABLE_STMTVTAB 1
73 //#ifndef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
74 //# define SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
77 /**********************************************************************/
79 #ifdef SQLITE_JNI_FATAL_OOM
80 #if !SQLITE_JNI_FATAL_OOM
81 #undef SQLITE_JNI_FATAL_OOM
85 /**********************************************************************/
87 #ifndef SQLITE_MAX_ALLOCATION_SIZE
88 # define SQLITE_MAX_ALLOCATION_SIZE 0x1fffffff
91 /**********************************************************************/
93 #ifndef SQLITE_OMIT_DEPRECATED
94 # define SQLITE_OMIT_DEPRECATED 1
96 #ifndef SQLITE_OMIT_LOAD_EXTENSION
97 # define SQLITE_OMIT_LOAD_EXTENSION 1
99 #ifndef SQLITE_OMIT_SHARED_CACHE
100 # define SQLITE_OMIT_SHARED_CACHE 1
102 #ifdef SQLITE_OMIT_UTF16
103 /* UTF16 is required for java */
104 # undef SQLITE_OMIT_UTF16 1
107 /**********************************************************************/
109 #ifndef SQLITE_TEMP_STORE
110 # define SQLITE_TEMP_STORE 2
112 #ifndef SQLITE_THREADSAFE
113 # define SQLITE_THREADSAFE 1
116 /**********************************************************************/
118 #ifndef SQLITE_USE_URI
119 # define SQLITE_USE_URI 1
124 ** Which sqlite3.c we're using needs to be configurable to enable
125 ** building against a custom copy, e.g. the SEE variant. We have to
126 ** include sqlite3.c, as opposed to sqlite3.h, in order to get access
127 ** to some interal details like SQLITE_MAX_... and friends. This
128 ** increases the rebuild time considerably but we need this in order
129 ** to access some internal functionality and keep the to-Java-exported
130 ** values of SQLITE_MAX_... and SQLITE_LIMIT_... in sync with the C
134 # define SQLITE_C sqlite3.c
136 #define INC__STRINGIFY_(f) #f
137 #define INC__STRINGIFY(f) INC__STRINGIFY_(f)
138 #include INC__STRINGIFY(SQLITE_C)
139 #undef INC__STRINGIFY_
140 #undef INC__STRINGIFY
144 ** End of the sqlite3 lib setup. What follows is JNI-specific.
147 #include "sqlite3-jni.h"
149 #include <stdio.h> /* only for testing/debugging */
151 /* Only for debugging */
152 #define MARKER(pfexp) \
153 do{ printf("MARKER: %s:%d:%s():\t",__FILE__,__LINE__,__func__); \
158 ** Creates a verbose JNI function name. Suffix must be
159 ** the JNI-mangled form of the function's name, minus the
160 ** prefix seen in this macro.
162 #define JniFuncName(Suffix) \
163 Java_org_sqlite_jni_SQLite3Jni_sqlite3_ ## Suffix
165 /* Prologue for JNI function declarations and definitions. */
166 #define JniDecl(ReturnType,Suffix) \
167 JNIEXPORT ReturnType JNICALL JniFuncName(Suffix)
170 ** S3JniApi's intent is that CFunc be the C API func(s) the
171 ** being-declared JNI function is wrapping, making it easier to find
172 ** that function's JNI-side entry point. The other args are for JniDecl.
174 #define S3JniApi(CFunc,ReturnType,Suffix) JniDecl(ReturnType,Suffix)
177 ** Shortcuts for the first 2 parameters to all JNI bindings.
179 ** The type of the jSelf arg differs, but no docs seem to mention
180 ** this: for static methods it's of type jclass and for non-static
181 ** it's jobject. jobject actually works for all funcs, in the sense
182 ** that it compiles and runs so long as we don't use jSelf (which is
183 ** only rarely needed in this code), but to be pedantically correct we
184 ** need the proper type in the signature.
186 ** https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#jni_interface_functions_and_pointers
188 #define JniArgsEnvObj JNIEnv * const env, jobject jSelf
189 #define JniArgsEnvClass JNIEnv * const env, jclass jKlazz
191 ** Helpers to account for -Xcheck:jni warnings about not having
192 ** checked for exceptions.
194 #define S3JniIfThrew if( (*env)->ExceptionCheck(env) )
195 #define S3JniExceptionClear (*env)->ExceptionClear(env)
196 #define S3JniExceptionReport (*env)->ExceptionDescribe(env)
197 #define S3JniExceptionIgnore S3JniIfThrew S3JniExceptionClear
198 #define S3JniExceptionWarnIgnore \
199 S3JniIfThrew {S3JniExceptionReport; S3JniExceptionClear;}(void)0
200 #define S3JniExceptionWarnCallbackThrew(STR) \
201 MARKER(("WARNING: " STR " MUST NOT THROW.\n")); \
202 (*env)->ExceptionDescribe(env)
204 /** To be used for cases where we're _really_ not expecting an
205 exception, e.g. looking up well-defined Java class members. */
206 #define S3JniExceptionIsFatal(MSG) S3JniIfThrew {\
207 S3JniExceptionReport; S3JniExceptionClear; \
208 (*env)->FatalError(env, MSG); \
212 ** Declares local var env = s3jni_env(). All JNI calls involve a
213 ** JNIEnv somewhere, always named env, and many of our macros assume
214 ** env is in scope. Where it's not, but should be, use this to make it
217 #define S3JniDeclLocal_env JNIEnv * const env = s3jni_env()
219 /* Fail fatally with an OOM message. */
220 static inline void s3jni_oom(JNIEnv
* const env
){
221 (*env
)->FatalError(env
, "SQLite3 JNI is out of memory.") /* does not return */;
225 ** sqlite3_malloc() proxy which fails fatally on OOM. This should
226 ** only be used for routines which manage global state and have no
227 ** recovery strategy for OOM. For sqlite3 API which can reasonably
228 ** return SQLITE_NOMEM, s3jni_malloc() should be used instead.
230 static void * s3jni_malloc_or_die(JNIEnv
* const env
, size_t n
){
231 void * const rv
= sqlite3_malloc(n
);
232 if( n
&& !rv
) s3jni_oom(env
);
237 ** Works like sqlite3_malloc() unless built with SQLITE_JNI_FATAL_OOM,
238 ** in which case it calls s3jni_oom() on OOM.
240 #ifdef SQLITE_JNI_FATAL_OOM
241 #define s3jni_malloc(SIZE) s3jni_malloc_or_die(env, SIZE)
243 #define s3jni_malloc(SIZE) sqlite3_malloc(((void)env,(SIZE)))
247 ** Works like sqlite3_realloc() unless built with SQLITE_JNI_FATAL_OOM,
248 ** in which case it calls s3jni_oom() on OOM.
250 #ifdef SQLITE_JNI_FATAL_OOM
251 static void * s3jni_realloc_or_die(JNIEnv
* const env
, void * p
, size_t n
){
252 void * const rv
= sqlite3_realloc(p
, (int)n
);
253 if( n
&& !rv
) s3jni_oom(env
);
256 #define s3jni_realloc(MEM,SIZE) s3jni_realloc_or_die(env, (MEM), (SIZE))
258 #define s3jni_realloc(MEM,SIZE) sqlite3_realloc((MEM), ((void)env, (SIZE)))
261 /* Fail fatally if !EXPR. */
262 #define s3jni_oom_fatal(EXPR) if( !(EXPR) ) s3jni_oom(env)
263 /* Maybe fail fatally if !EXPR. */
264 #ifdef SQLITE_JNI_FATAL_OOM
265 #define s3jni_oom_check s3jni_oom_fatal
267 #define s3jni_oom_check(EXPR)
269 //#define S3JniDb_oom(pDb,EXPR) ((EXPR) ? sqlite3OomFault(pDb) : 0)
271 /* Helpers for Java value reference management. */
272 static jobject
s3jni_ref_global(JNIEnv
* const env
, jobject
const v
){
273 jobject
const rv
= v
? (*env
)->NewGlobalRef(env
, v
) : NULL
;
274 s3jni_oom_fatal( v
? !!rv
: 1 );
277 static jobject
s3jni_ref_local(JNIEnv
* const env
, jobject
const v
){
278 jobject
const rv
= v
? (*env
)->NewLocalRef(env
, v
) : NULL
;
279 s3jni_oom_fatal( v
? !!rv
: 1 );
282 static inline void s3jni_unref_global(JNIEnv
* const env
, jobject
const v
){
283 if( v
) (*env
)->DeleteGlobalRef(env
, v
);
285 static inline void s3jni_unref_local(JNIEnv
* const env
, jobject
const v
){
286 if( v
) (*env
)->DeleteLocalRef(env
, v
);
288 #define S3JniRefGlobal(VAR) s3jni_ref_global(env, (VAR))
289 #define S3JniRefLocal(VAR) s3jni_ref_local(env, (VAR))
290 #define S3JniUnrefGlobal(VAR) s3jni_unref_global(env, (VAR))
291 #define S3JniUnrefLocal(VAR) s3jni_unref_local(env, (VAR))
294 ** Lookup key type for use with s3jni_nph().
296 typedef struct S3JniNphRef S3JniNphRef
;
298 const int index
/* index into S3JniGlobal.nph[] */;
299 const char * const zName
/* Full Java name of the class */;
300 const char * const zMember
/* Name of member property */;
301 const char * const zTypeSig
/* JNI type signature of zMember */;
305 ** Cache keys for each concrete NativePointerHolder subclass and
306 ** OutputPointer.T type. The members are to be used with
307 ** s3jni_nph() and friends, and each one's member->index
308 ** corresponds to its index in the S3JniGlobal.nph[] array.
310 static const struct {
311 const S3JniNphRef sqlite3
;
312 const S3JniNphRef sqlite3_stmt
;
313 const S3JniNphRef sqlite3_context
;
314 const S3JniNphRef sqlite3_value
;
315 const S3JniNphRef OutputPointer_Bool
;
316 const S3JniNphRef OutputPointer_Int32
;
317 const S3JniNphRef OutputPointer_Int64
;
318 const S3JniNphRef OutputPointer_sqlite3
;
319 const S3JniNphRef OutputPointer_sqlite3_stmt
;
320 const S3JniNphRef OutputPointer_sqlite3_value
;
321 const S3JniNphRef OutputPointer_String
;
322 #ifdef SQLITE_ENABLE_FTS5
323 const S3JniNphRef OutputPointer_ByteArray
;
324 const S3JniNphRef Fts5Context
;
325 const S3JniNphRef Fts5ExtensionApi
;
326 const S3JniNphRef fts5_api
;
327 const S3JniNphRef fts5_tokenizer
;
328 const S3JniNphRef Fts5Tokenizer
;
331 #define MkRef(INDEX, KLAZZ, MEMBER, SIG) \
332 { INDEX, "org/sqlite/jni/" KLAZZ, MEMBER, SIG }
333 /* NativePointerHolder ref */
334 #define RefN(INDEX, KLAZZ) MkRef(INDEX, KLAZZ, "nativePointer", "J")
335 /* OutputPointer.T ref */
336 #define RefO(INDEX, KLAZZ, SIG) MkRef(INDEX, KLAZZ, "value", SIG)
338 RefN(1, "sqlite3_stmt"),
339 RefN(2, "sqlite3_context"),
340 RefN(3, "sqlite3_value"),
341 RefO(4, "OutputPointer$Bool", "Z"),
342 RefO(5, "OutputPointer$Int32", "I"),
343 RefO(6, "OutputPointer$Int64", "J"),
344 RefO(7, "OutputPointer$sqlite3",
345 "Lorg/sqlite/jni/sqlite3;"),
346 RefO(8, "OutputPointer$sqlite3_stmt",
347 "Lorg/sqlite/jni/sqlite3_stmt;"),
348 RefO(9, "OutputPointer$sqlite3_value",
349 "Lorg/sqlite/jni/sqlite3_value;"),
350 RefO(10, "OutputPointer$String", "Ljava/lang/String;"),
351 #ifdef SQLITE_ENABLE_FTS5
352 RefO(11, "OutputPointer$ByteArray", "[B"),
353 RefN(12, "Fts5Context"),
354 RefN(13, "Fts5ExtensionApi"),
355 RefN(14, "fts5_api"),
356 RefN(15, "fts5_tokenizer"),
357 RefN(16, "Fts5Tokenizer")
366 ** Size of the NativePointerHolder cache. Need enough space for
367 ** (only) the library's NativePointerHolder and OutputPointer types,
368 ** a fixed count known at build-time. This value needs to be
369 ** exactly the number of S3JniNphRef entries in the S3JniNphRefs
372 S3Jni_NphCache_size
= sizeof(S3JniNphRefs
) / sizeof(S3JniNphRef
)
376 ** Cache entry for NativePointerHolder subclasses and OutputPointer
377 ** types. The pRef and klazz fields are set up the first time the
378 ** entry is fetched using s3jni_nph(). The other fields are
379 ** populated as needed by the routines which use them.
381 typedef struct S3JniNphClass S3JniNphClass
;
382 struct S3JniNphClass
{
383 volatile const S3JniNphRef
* pRef
/* Entry from S3JniNphRefs. */;
384 jclass klazz
/* global ref to the concrete
385 ** NativePointerHolder subclass
386 ** represented by zClassName */;
387 volatile jmethodID midCtor
/* klazz's no-arg constructor. Used by
388 ** new_NativePointerHolder_object(). */;
389 volatile jfieldID fidValue
/* NativePointerHolder.nativePointer or
390 ** OutputPointer.T.value */;
391 volatile jfieldID fidAggCtx
/* sqlite3_context.aggregateContext, used only
392 ** by the sqlite3_context binding. */;
396 ** State for binding C callbacks to Java methods.
398 typedef struct S3JniHook S3JniHook
;
400 jobject jObj
/* global ref to Java instance */;
401 jmethodID midCallback
/* callback method. Signature depends on
403 /* We lookup the jObj.xDestroy() method as-needed for contexts which
404 ** have custom finalizers. */
405 jobject jExtra
/* Global ref to a per-hook-type value */;
406 int doXDestroy
/* If true call jObj->xDestroy() when
407 this object is S3JniHook_unref()'d. */;
408 S3JniHook
* pNext
/* Next entry in S3Global.hooks.aFree */;
410 /* For clean bitwise-copy init of local instances. */
411 static const S3JniHook S3JniHook_empty
= {0,0,0,0,0};
414 ** Per-(sqlite3*) state for various JNI bindings. This state is
415 ** allocated as needed, cleaned up in sqlite3_close(_v2)(), and
416 ** recycled when possible.
418 ** Trivia: vars and parameters of this type are often named "ps"
419 ** because this class used to have a name for which that abbreviation
422 typedef struct S3JniDb S3JniDb
;
424 sqlite3
*pDb
/* The associated db handle */;
425 jobject jDb
/* A global ref of the output object which gets
426 returned from sqlite3_open(_v2)(). We need this in
427 order to have an object to pass to routines like
428 sqlite3_collation_needed()'s callback, or else we
429 have to dynamically create one for that purpose,
430 which would be fine except that it would be a
431 different instance (and maybe even a different
432 class) than the one the user may expect to
434 char * zMainDbName
/* Holds the string allocated on behalf of
435 SQLITE_DBCONFIG_MAINDBNAME. */;
437 S3JniHook busyHandler
;
438 S3JniHook collationNeeded
;
445 #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
449 #ifdef SQLITE_ENABLE_FTS5
450 jobject jFtsApi
/* global ref to s3jni_fts5_api_from_db() */;
452 S3JniDb
* pNext
/* Next entry in SJG.perDb.aFree */;
455 static const char * const S3JniDb_clientdata_key
= "S3JniDb";
456 #define S3JniDb_from_clientdata(pDb) \
457 (pDb ? sqlite3_get_clientdata(pDb, S3JniDb_clientdata_key) : 0)
460 ** Cache for per-JNIEnv (i.e. per-thread) data.
462 ** Trivia: vars and parameters of this type are often named "jc"
463 ** because this class used to have a name for which that abbreviation
466 typedef struct S3JniEnv S3JniEnv
;
468 JNIEnv
*env
/* env in which this cache entry was created */;
470 ** pdbOpening is used to coordinate the Java/DB connection of a
471 ** being-open()'d db in the face of auto-extensions.
472 ** Auto-extensions run before we can bind the C db to its Java
473 ** representation, but auto-extensions require that binding to pass
474 ** on to their Java-side callbacks. We handle this as follows:
476 ** - In the JNI side of sqlite3_open(), allocate the Java side of
477 ** that connection and set pdbOpening to point to that
480 ** - Call sqlite3_open(), which triggers the auto-extension
481 ** handler. That handler uses pdbOpening to connect the native
482 ** db handle which it receives with pdbOpening.
484 ** - When sqlite3_open() returns, check whether pdbOpening->pDb is
485 ** NULL. If it isn't, auto-extension handling set it up. If it
486 ** is, complete the Java/C binding unless sqlite3_open() returns
487 ** a NULL db, in which case free pdbOpening.
489 S3JniDb
* pdbOpening
;
490 S3JniEnv
* pNext
/* Next entry in SJG.envCache.aHead or
491 SJG.envCache.aFree */;
495 ** State for proxying sqlite3_auto_extension() in Java. This was
496 ** initially a separate class from S3JniHook and now the older name is
497 ** retained for readability in the APIs which use this, as well as for
498 ** its better code-searchability.
500 typedef S3JniHook S3JniAutoExtension
;
503 ** Type IDs for SQL function categories.
506 UDF_UNKNOWN_TYPE
= 0/*for error propagation*/,
513 ** State for binding Java-side UDFs.
515 typedef struct S3JniUdf S3JniUdf
;
517 jobject jObj
/* SQLFunction instance */;
518 char * zFuncName
/* Only for error reporting and debug logging */;
519 enum UDFType type
/* UDF type */;
520 /** Method IDs for the various UDF methods. */
521 jmethodID jmidxFunc
/* xFunc method (scalar) */;
522 jmethodID jmidxStep
/* xStep method (aggregate/window) */;
523 jmethodID jmidxFinal
/* xFinal method (aggregate/window) */;
524 jmethodID jmidxValue
/* xValue method (window) */;
525 jmethodID jmidxInverse
/* xInverse method (window) */;
526 S3JniUdf
* pNext
/* Next entry in SJG.udf.aFree. */;
529 #if !defined(SQLITE_JNI_OMIT_METRICS) && !defined(SQLITE_JNI_ENABLE_METRICS)
531 # define SQLITE_JNI_ENABLE_METRICS
536 ** If true, modifying S3JniGlobal.metrics is protected by a mutex,
540 # define S3JNI_METRICS_MUTEX SQLITE_THREADSAFE
542 # define S3JNI_METRICS_MUTEX 0
544 #ifndef SQLITE_JNI_ENABLE_METRICS
545 # undef S3JNI_METRICS_MUTEX
546 # define S3JNI_METRICS_MUTEX 0
550 ** Global state, e.g. caches and metrics.
552 typedef struct S3JniGlobalType S3JniGlobalType
;
553 struct S3JniGlobalType
{
555 ** According to: https://developer.ibm.com/articles/j-jni/
557 ** > A thread can get a JNIEnv by calling GetEnv() using the JNI
558 ** invocation interface through a JavaVM object. The JavaVM object
559 ** itself can be obtained by calling the JNI GetJavaVM() method
560 ** using a JNIEnv object and can be cached and shared across
561 ** threads. Caching a copy of the JavaVM object enables any thread
562 ** with access to the cached object to get access to its own
563 ** JNIEnv when necessary.
568 sqlite3_mutex
* mutex
;
570 ** Cache of Java refs and method IDs for NativePointerHolder
571 ** subclasses and OutputPointer.T types.
573 S3JniNphClass nph
[S3Jni_NphCache_size
];
575 ** Cache of per-thread state.
578 S3JniEnv
* aHead
/* Linked list of in-use instances */;
579 S3JniEnv
* aFree
/* Linked list of free instances */;
580 sqlite3_mutex
* mutex
/* mutex for aHead and aFree, first-time
581 inits of nph[] entries, and
582 NativePointerHolder_get/set(). */;
583 void const * locker
/* env mutex is held on this object's behalf.
584 Used only for sanity checking. */;
587 ** Per-db state. This can move into the core library once we can tie
588 ** client-defined state to db handles there.
591 S3JniDb
* aFree
/* Linked list of free instances */;
592 sqlite3_mutex
* mutex
/* mutex for aHead and aFree */;
593 void const * locker
/* perDb mutex is held on this object's
594 behalf. Used only for sanity checking. */;
597 S3JniUdf
* aFree
/* Head of the free-item list. Guarded by global
601 ** Refs to global classes and methods. Obtained during static init
602 ** and never released.
605 jclass cLong
/* global ref to java.lang.Long */;
606 jclass cString
/* global ref to java.lang.String */;
607 jobject oCharsetUtf8
/* global ref to StandardCharset.UTF_8 */;
608 jmethodID ctorLong1
/* the Long(long) constructor */;
609 jmethodID ctorStringBA
/* the String(byte[],Charset) constructor */;
610 jmethodID stringGetBytes
/* the String.getBytes(Charset) method */;
613 ** The list of Java-side auto-extensions
614 ** (org.sqlite.jni.AutoExtensionCallback objects).
617 S3JniAutoExtension
*aExt
/* The auto-extension list. It is
618 maintained such that all active
619 entries are in the first contiguous
620 nExt array elements. */;
621 int nAlloc
/* number of entries allocated for aExt,
622 as distinct from the number of active
624 int nExt
/* number of active entries in aExt, all in the
625 first nExt'th array elements. */;
626 sqlite3_mutex
* mutex
/* mutex for manipulation/traversal of aExt */;
627 const void * locker
/* object on whose behalf the mutex is held.
628 Only for sanity checking in debug builds. */;
630 #ifdef SQLITE_ENABLE_FTS5
632 volatile jobject jFtsExt
/* Global ref to Java singleton for the
633 Fts5ExtensionApi instance. */;
635 jfieldID fidA
/* Fts5Phrase::a member */;
636 jfieldID fidB
/* Fts5Phrase::b member */;
640 #ifdef SQLITE_ENABLE_SQLLOG
642 S3JniHook sqllog
/* sqlite3_config(SQLITE_CONFIG_SQLLOG) callback */;
643 S3JniHook
* aFree
/* free-item list, for recycling. Guarded by
644 the global mutex. */;
647 #ifdef SQLITE_JNI_ENABLE_METRICS
648 /* Internal metrics. */
650 volatile unsigned nEnvHit
;
651 volatile unsigned nEnvMiss
;
652 volatile unsigned nEnvAlloc
;
653 volatile unsigned nMutexEnv
/* number of times envCache.mutex was entered for
654 a S3JniEnv operation. */;
655 volatile unsigned nMutexEnv2
/* number of times envCache.mutex was entered */;
656 volatile unsigned nMutexPerDb
/* number of times perDb.mutex was entered */;
657 volatile unsigned nMutexAutoExt
/* number of times autoExt.mutex was entered */;
658 volatile unsigned nMutexGlobal
/* number of times global mutex was entered. */;
659 volatile unsigned nMutexUdf
/* number of times global mutex was entered
661 volatile unsigned nDestroy
/* xDestroy() calls across all types */;
662 volatile unsigned nPdbAlloc
/* Number of S3JniDb alloced. */;
663 volatile unsigned nPdbRecycled
/* Number of S3JniDb reused. */;
664 volatile unsigned nUdfAlloc
/* Number of S3JniUdf alloced. */;
665 volatile unsigned nUdfRecycled
/* Number of S3JniUdf reused. */;
666 volatile unsigned nHookAlloc
/* Number of S3JniHook alloced. */;
667 volatile unsigned nHookRecycled
/* Number of S3JniHook reused. */;
669 /* Number of calls for each type of UDF callback. */
670 volatile unsigned nFunc
;
671 volatile unsigned nStep
;
672 volatile unsigned nFinal
;
673 volatile unsigned nValue
;
674 volatile unsigned nInverse
;
676 unsigned nMetrics
/* Total number of mutex-locked
677 metrics increments. */;
678 #if S3JNI_METRICS_MUTEX
679 sqlite3_mutex
* mutex
;
682 #endif /* SQLITE_JNI_ENABLE_METRICS */
684 static S3JniGlobalType S3JniGlobal
= {};
685 #define SJG S3JniGlobal
687 /* Increments *p, possibly protected by a mutex. */
688 #ifndef SQLITE_JNI_ENABLE_METRICS
689 #define s3jni_incr(PTR)
690 #elif S3JNI_METRICS_MUTEX
691 static void s3jni_incr( volatile unsigned int * const p
){
692 sqlite3_mutex_enter(SJG
.metrics
.mutex
);
693 ++SJG
.metrics
.nMetrics
;
695 sqlite3_mutex_leave(SJG
.metrics
.mutex
);
698 #define s3jni_incr(PTR) ++(*(PTR))
701 /* Helpers for working with specific mutexes. */
702 #if SQLITE_THREADSAFE
703 #define S3JniEnv_mutex_assertLocked \
704 assert( 0 != SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" )
705 #define S3JniEnv_mutex_assertLocker \
706 assert( (env) == SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" )
707 #define S3JniEnv_mutex_assertNotLocker \
708 assert( (env) != SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" )
710 #define S3JniEnv_mutex_enter \
711 S3JniEnv_mutex_assertNotLocker; \
712 sqlite3_mutex_enter( SJG.envCache.mutex ); \
713 s3jni_incr(&SJG.metrics.nMutexEnv); \
714 SJG.envCache.locker = env
715 #define S3JniEnv_mutex_leave \
716 S3JniEnv_mutex_assertLocker; \
717 SJG.envCache.locker = 0; \
718 sqlite3_mutex_leave( SJG.envCache.mutex )
720 #define S3JniAutoExt_mutex_enter \
721 sqlite3_mutex_enter( SJG.autoExt.mutex ); \
722 SJG.autoExt.locker = env; \
723 s3jni_incr( &SJG.metrics.nMutexAutoExt )
724 #define S3JniAutoExt_mutex_leave \
725 assert( env == SJG.autoExt.locker && "Misuse of S3JniGlobal.autoExt.mutex" ); \
726 sqlite3_mutex_leave( SJG.autoExt.mutex )
727 #define S3JniAutoExt_mutex_assertLocker \
728 assert( env == SJG.autoExt.locker && "Misuse of S3JniGlobal.autoExt.mutex" )
730 #define S3JniGlobal_mutex_enter \
731 sqlite3_mutex_enter( SJG.mutex ); \
732 s3jni_incr(&SJG.metrics.nMutexGlobal);
733 #define S3JniGlobal_mutex_leave \
734 sqlite3_mutex_leave( SJG.mutex )
736 #define S3JniNph_mutex_enter \
737 S3JniEnv_mutex_assertNotLocker; \
738 sqlite3_mutex_enter( SJG.envCache.mutex ); \
739 s3jni_incr( &SJG.metrics.nMutexEnv2 ); \
740 SJG.envCache.locker = env
741 #define S3JniNph_mutex_leave \
742 S3JniEnv_mutex_assertLocker; \
743 SJG.envCache.locker = 0; \
744 sqlite3_mutex_leave( SJG.envCache.mutex )
746 #define S3JniDb_mutex_assertLocker \
747 assert( (env) == SJG.perDb.locker && "Misuse of S3JniGlobal.perDb.mutex" )
748 #define S3JniDb_mutex_enter \
749 sqlite3_mutex_enter( SJG.perDb.mutex ); \
750 assert( 0==SJG.perDb.locker && "Misuse of S3JniGlobal.perDb.mutex" ); \
751 s3jni_incr( &SJG.metrics.nMutexPerDb ); \
752 SJG.perDb.locker = env;
753 #define S3JniDb_mutex_leave \
754 assert( env == SJG.perDb.locker && "Misuse of S3JniGlobal.perDb.mutex" ); \
755 SJG.perDb.locker = 0; \
756 sqlite3_mutex_leave( SJG.perDb.mutex )
758 #else /* SQLITE_THREADSAFE==0 */
759 #define S3JniEnv_mutex_assertLocked
760 #define S3JniEnv_mutex_assertLocker
761 #define S3JniEnv_mutex_assertNotLocker
762 #define S3JniEnv_mutex_enter
763 #define S3JniEnv_mutex_leave
764 #define S3JniAutoExt_mutex_assertLocker
765 #define S3JniAutoExt_mutex_enter
766 #define S3JniAutoExt_mutex_leave
767 #define S3JniGlobal_mutex_enter
768 #define S3JniGlobal_mutex_leave
769 #define S3JniNph_mutex_enter
770 #define S3JniNph_mutex_leave
771 #define S3JniDb_mutex_assertLocker
772 #define S3JniDb_mutex_enter
773 #define S3JniDb_mutex_leave
776 /* Helpers for jstring and jbyteArray. */
777 static const char * s3jni__jstring_to_mutf8_bytes(JNIEnv
* const env
, jstring v
){
778 const char *z
= v
? (*env
)->GetStringUTFChars(env
, v
, NULL
) : 0;
779 s3jni_oom_check( v
? !!z
: !z
);
783 #define s3jni_jstring_to_mutf8(ARG) s3jni__jstring_to_mutf8_bytes(env, (ARG))
784 #define s3jni_mutf8_release(ARG,VAR) if( VAR ) (*env)->ReleaseStringUTFChars(env, ARG, VAR)
786 static jbyte
* s3jni__jbytearray_bytes(JNIEnv
* const env
, jbyteArray jBA
){
787 jbyte
* const rv
= jBA
? (*env
)->GetByteArrayElements(env
, jBA
, NULL
) : 0;
788 s3jni_oom_check( jBA
? !!rv
: 1 );
792 #define s3jni_jbytearray_bytes(jByteArray) s3jni__jbytearray_bytes(env, (jByteArray))
793 #define s3jni_jbytearray_release(jByteArray,jBytes) \
794 if( jBytes ) (*env)->ReleaseByteArrayElements(env, jByteArray, jBytes, JNI_ABORT)
797 ** Returns the current JNIEnv object. Fails fatally if it cannot find
800 static JNIEnv
* s3jni_env(void){
802 if( (*SJG
.jvm
)->GetEnv(SJG
.jvm
, (void **)&env
,
804 fprintf(stderr
, "Fatal error: cannot get current JNIEnv.\n");
811 ** Fetches the S3JniGlobal.envCache row for the given env, allocing a
812 ** row if needed. When a row is allocated, its state is initialized
813 ** insofar as possible. Calls (*env)->FatalError() if allocation of an
814 ** entry fails. That's hypothetically possible but "shouldn't happen."
816 static S3JniEnv
* S3JniEnv__get(JNIEnv
* const env
){
817 struct S3JniEnv
* row
;
818 S3JniEnv_mutex_enter
;
819 row
= SJG
.envCache
.aHead
;
820 for( ; row
; row
= row
->pNext
){
821 if( row
->env
== env
){
822 s3jni_incr( &SJG
.metrics
.nEnvHit
);
823 S3JniEnv_mutex_leave
;
827 s3jni_incr( &SJG
.metrics
.nEnvMiss
);
828 row
= SJG
.envCache
.aFree
;
830 SJG
.envCache
.aFree
= row
->pNext
;
832 row
= s3jni_malloc_or_die(env
, sizeof(*row
));
833 s3jni_incr( &SJG
.metrics
.nEnvAlloc
);
835 memset(row
, 0, sizeof(*row
));
836 row
->pNext
= SJG
.envCache
.aHead
;
837 SJG
.envCache
.aHead
= row
;
840 S3JniEnv_mutex_leave
;
844 #define S3JniEnv_get() S3JniEnv__get(env)
847 ** This function is NOT part of the sqlite3 public API. It is strictly
848 ** for use by the sqlite project's own Java/JNI bindings.
850 ** For purposes of certain hand-crafted JNI function bindings, we
851 ** need a way of reporting errors which is consistent with the rest of
852 ** the C API, as opposed to throwing JS exceptions. To that end, this
853 ** internal-use-only function is a thin proxy around
854 ** sqlite3ErrorWithMessage(). The intent is that it only be used from
855 ** JNI bindings such as sqlite3_prepare_v2/v3(), and definitely not
860 static int s3jni_db_error(sqlite3
* const db
, int err_code
,
861 const char * const zMsg
){
864 sqlite3Error(db
, err_code
);
866 const int nMsg
= sqlite3Strlen30(zMsg
);
867 sqlite3_mutex_enter(sqlite3_db_mutex(db
));
868 sqlite3ErrorWithMsg(db
, err_code
, "%.*s", nMsg
, zMsg
);
869 sqlite3_mutex_leave(sqlite3_db_mutex(db
));
876 ** Creates a new jByteArray of length nP, copies p's contents into it,
877 ** and returns that byte array (NULL on OOM unless fail-fast alloc
878 ** errors are enabled). p may be NULL, in which case the array is
879 ** created but no bytes are filled.
881 static jbyteArray
s3jni__new_jbyteArray(JNIEnv
* const env
,
882 const void * const p
, int nP
){
883 jbyteArray jba
= (*env
)->NewByteArray(env
, (jint
)nP
);
885 s3jni_oom_check( jba
);
887 (*env
)->SetByteArrayRegion(env
, jba
, 0, (jint
)nP
, (const jbyte
*)p
);
892 #define s3jni_new_jbyteArray(P,n) s3jni__new_jbyteArray(env, P, n)
896 ** Uses the java.lang.String(byte[],Charset) constructor to create a
897 ** new String from UTF-8 string z. n is the number of bytes to
898 ** copy. If n<0 then sqlite3Strlen30() is used to calculate it.
900 ** Returns NULL if z is NULL or on OOM, else returns a new jstring
901 ** owned by the caller.
903 ** Sidebar: this is a painfully inefficient way to convert from
904 ** standard UTF-8 to a Java string, but JNI offers only algorithms for
905 ** working with MUTF-8, not UTF-8.
907 static jstring
s3jni__utf8_to_jstring(JNIEnv
* const env
,
908 const char * const z
, int n
){
910 if( 0==n
|| (n
<0 && z
&& !z
[0]) ){
911 /* Fast-track the empty-string case via the MUTF-8 API. We could
912 hypothetically do this for any strings where n<4 and z is
913 NUL-terminated and none of z[0..3] are NUL bytes. */
914 rv
= (*env
)->NewStringUTF(env
, "");
917 if( n
<0 ) n
= sqlite3Strlen30(z
);
918 jba
= s3jni_new_jbyteArray((unsigned const char *)z
, n
);
920 rv
= (*env
)->NewObject(env
, SJG
.g
.cString
, SJG
.g
.ctorStringBA
,
921 jba
, SJG
.g
.oCharsetUtf8
);
923 S3JniExceptionReport
;
926 S3JniUnrefLocal(jba
);
929 s3jni_oom_check( rv
);
932 #define s3jni_utf8_to_jstring(CStr,n) s3jni__utf8_to_jstring(env, CStr, n)
935 ** Converts the given java.lang.String object into a NUL-terminated
936 ** UTF-8 C-string by calling jstr.getBytes(StandardCharset.UTF_8).
937 ** Returns NULL if jstr is NULL or on allocation error. If jstr is not
938 ** NULL and nLen is not NULL then nLen is set to the length of the
939 ** returned string, not including the terminating NUL. If jstr is not
940 ** NULL and it returns NULL, this indicates an allocation error. In
941 ** that case, if nLen is not NULL then it is either set to 0 (if
942 ** fetching of jstr's bytes fails to allocate) or set to what would
943 ** have been the length of the string had C-string allocation
946 ** The returned memory is allocated from sqlite3_malloc() and
947 ** ownership is transferred to the caller.
949 static char * s3jni__jstring_to_utf8(JNIEnv
* const env
,
950 jstring jstr
, int *nLen
){
955 if( !jstr
) return 0;
956 jba
= (*env
)->CallObjectMethod(env
, jstr
, SJG
.g
.stringGetBytes
,
959 if( (*env
)->ExceptionCheck(env
) || !jba
960 /* order of these checks is significant for -Xlint:jni */ ) {
961 S3JniExceptionReport
;
962 s3jni_oom_check( jba
);
963 if( nLen
) *nLen
= 0;
966 nBa
= (*env
)->GetArrayLength(env
, jba
);
967 if( nLen
) *nLen
= (int)nBa
;
968 rv
= s3jni_malloc( nBa
+ 1 );
970 (*env
)->GetByteArrayRegion(env
, jba
, 0, nBa
, (jbyte
*)rv
);
973 S3JniUnrefLocal(jba
);
976 #define s3jni_jstring_to_utf8(JStr,n) s3jni__jstring_to_utf8(env, JStr, n)
979 ** Expects to be passed a pointer from sqlite3_column_text16() or
980 ** sqlite3_value_text16() and a byte-length value from
981 ** sqlite3_column_bytes16() or sqlite3_value_bytes16(). It creates a
982 ** Java String of exactly half that character length, returning NULL
983 ** if !p or (*env)->NewString() fails.
985 static jstring
s3jni_text16_to_jstring(JNIEnv
* const env
, const void * const p
, int nP
){
987 ? (*env
)->NewString(env
, (const jchar
*)p
, (jsize
)(nP
/2))
989 s3jni_oom_check( p
? !!rv
: 1 );
994 ** Requires jx to be a Throwable. Calls its toString() method and
995 ** returns its value converted to a UTF-8 string. The caller owns the
996 ** returned string and must eventually sqlite3_free() it. Returns 0
997 ** if there is a problem fetching the info or on OOM.
999 ** Design note: we use toString() instead of getMessage() because the
1000 ** former includes the exception type's name:
1002 ** Exception e = new RuntimeException("Hi");
1003 ** System.out.println(e.toString()); // java.lang.RuntimeException: Hi
1004 ** System.out.println(e.getMessage()); // Hi
1006 static char * s3jni_exception_error_msg(JNIEnv
* const env
, jthrowable jx
){
1010 jclass
const klazz
= (*env
)->GetObjectClass(env
, jx
);
1011 mid
= (*env
)->GetMethodID(env
, klazz
, "toString", "()Ljava/lang/String;");
1012 S3JniUnrefLocal(klazz
);
1014 S3JniExceptionReport
;
1015 S3JniExceptionClear
;
1018 msg
= (*env
)->CallObjectMethod(env
, jx
, mid
);
1020 S3JniExceptionReport
;
1021 S3JniExceptionClear
;
1024 zMsg
= s3jni_jstring_to_utf8( msg
, 0);
1025 S3JniUnrefLocal(msg
);
1030 ** Extracts env's current exception, sets ps->pDb's error message to
1031 ** its message string, and clears the exception. If errCode is non-0,
1032 ** it is used as-is, else SQLITE_ERROR is assumed. If there's a
1033 ** problem extracting the exception's message, it's treated as
1034 ** non-fatal and zDfltMsg is used in its place.
1036 ** Locks the global S3JniDb mutex.
1038 ** This must only be called if a JNI exception is pending.
1040 ** Returns errCode unless it is 0, in which case SQLITE_ERROR is
1043 static int s3jni__db_exception(JNIEnv
* const env
, S3JniDb
* const ps
,
1044 int errCode
, const char *zDfltMsg
){
1045 jthrowable
const ex
= (*env
)->ExceptionOccurred(env
);
1047 if( 0==errCode
) errCode
= SQLITE_ERROR
;
1050 S3JniExceptionClear
;
1051 S3JniDb_mutex_enter
;
1052 zMsg
= s3jni_exception_error_msg(env
, ex
);
1053 s3jni_db_error(ps
->pDb
, errCode
, zMsg
? zMsg
: zDfltMsg
);
1055 S3JniUnrefLocal(ex
);
1056 S3JniDb_mutex_leave
;
1060 #define s3jni_db_exception(JniDb,ERRCODE,DFLTMSG) \
1061 s3jni__db_exception(env, (JniDb), (ERRCODE), (DFLTMSG) )
1064 ** Extracts the (void xDestroy()) method from jObj and applies it to
1065 ** jObj. If jObj is NULL, this is a no-op. The lack of an xDestroy()
1066 ** method is silently ignored. Any exceptions thrown by xDestroy()
1067 ** trigger a warning to stdout or stderr and then the exception is
1070 static void s3jni__call_xDestroy(JNIEnv
* const env
, jobject jObj
){
1072 jclass
const klazz
= (*env
)->GetObjectClass(env
, jObj
);
1073 jmethodID method
= (*env
)->GetMethodID(env
, klazz
, "xDestroy", "()V");
1075 S3JniUnrefLocal(klazz
);
1077 s3jni_incr( &SJG
.metrics
.nDestroy
);
1078 (*env
)->CallVoidMethod(env
, jObj
, method
);
1080 S3JniExceptionWarnCallbackThrew("xDestroy() callback");
1081 S3JniExceptionClear
;
1085 S3JniExceptionClear
;
1089 #define s3jni_call_xDestroy(JOBJ) s3jni__call_xDestroy(env, (JOBJ))
1092 ** Internal helper for many hook callback impls. Locks the S3JniDb
1093 ** mutex, makes a copy of src into dest, with a some differences: (1) if
1094 ** src->jObj or src->jExtra are not NULL then dest will be a new LOCAL
1095 ** ref to it instead of a copy of the prior GLOBAL ref. (2) dest->doXDestroy
1098 ** If dest->jObj is not NULL when this returns then the caller is
1099 ** obligated to eventually free the new ref by passing *dest to
1100 ** S3JniHook_localundup(). The dest pointer must NOT be passed to
1101 ** S3JniHook_unref(), as that routine assumes that dest->jObj/jExtra
1102 ** are GLOBAL refs (it's illegal to try to unref the wrong ref type).
1104 ** Background: when running a hook we need a call-local copy lest
1105 ** another thread modify the hook while we're running it. That copy
1106 ** has to have its own Java reference, but it need only be call-local.
1108 static void S3JniHook__localdup( JNIEnv
* const env
, S3JniHook
const * const src
,
1109 S3JniHook
* const dest
){
1110 S3JniDb_mutex_enter
;
1112 if(src
->jObj
) dest
->jObj
= S3JniRefLocal(src
->jObj
);
1113 if(src
->jExtra
) dest
->jExtra
= S3JniRefLocal(src
->jExtra
);
1114 dest
->doXDestroy
= 0;
1115 S3JniDb_mutex_leave
;
1117 #define S3JniHook_localdup(src,dest) S3JniHook__localdup(env,src,dest)
1119 static void S3JniHook__localundup( JNIEnv
* const env
, S3JniHook
* const h
){
1120 S3JniUnrefLocal(h
->jObj
);
1121 S3JniUnrefLocal(h
->jExtra
);
1122 *h
= S3JniHook_empty
;
1124 #define S3JniHook_localundup(HOOK) S3JniHook__localundup(env, &(HOOK))
1127 ** Removes any Java references from s and clears its state. If
1128 ** doXDestroy is true and s->jObj is not NULL, s->jObj
1129 ** is passed to s3jni_call_xDestroy() before any references are
1130 ** cleared. It is legal to call this when the object has no Java
1131 ** references. s must not be NULL.
1133 static void S3JniHook__unref(JNIEnv
* const env
, S3JniHook
* const s
){
1135 if( s
->doXDestroy
){
1136 s3jni_call_xDestroy(s
->jObj
);
1138 S3JniUnrefGlobal(s
->jObj
);
1139 S3JniUnrefGlobal(s
->jExtra
);
1141 *s
= S3JniHook_empty
;
1143 #define S3JniHook_unref(hook) \
1144 S3JniHook__unref(env, (hook))
1147 ** Allocates one blank S3JniHook object from the recycling bin, if
1148 ** available, else from the heap. Returns NULL or dies on OOM. Locks
1149 ** the global mutex.
1151 static S3JniHook
*S3JniHook__alloc(JNIEnv
* const env
){
1153 S3JniGlobal_mutex_enter
;
1154 if( SJG
.hooks
.aFree
){
1155 p
= SJG
.hooks
.aFree
;
1156 SJG
.hooks
.aFree
= p
->pNext
;
1158 s3jni_incr(&SJG
.metrics
.nHookRecycled
);
1160 S3JniGlobal_mutex_leave
;
1162 p
= s3jni_malloc(sizeof(S3JniHook
));
1164 s3jni_incr(&SJG
.metrics
.nHookAlloc
);
1168 *p
= S3JniHook_empty
;
1172 #define S3JniHook_alloc() S3JniHook__alloc(env)
1175 ** The rightful fate of all results from S3JniHook_alloc(). doXDestroy
1176 ** is passed on as-is to S3JniHook_unref(). Locks the global mutex.
1178 static void S3JniHook__free(JNIEnv
* const env
, S3JniHook
* const p
){
1180 assert( !p
->pNext
);
1182 S3JniGlobal_mutex_enter
;
1183 p
->pNext
= SJG
.hooks
.aFree
;
1184 SJG
.hooks
.aFree
= p
;
1185 S3JniGlobal_mutex_leave
;
1188 #define S3JniHook_free(hook) S3JniHook__free(env, hook)
1191 /* S3JniHook__free() without the lock: caller must hold the global mutex */
1192 static void S3JniHook__free_unlocked(JNIEnv
* const env
, S3JniHook
* const p
){
1194 assert( !p
->pNext
);
1195 assert( p
->pNext
!= SJG
.hooks
.aFree
);
1197 p
->pNext
= SJG
.hooks
.aFree
;
1198 SJG
.hooks
.aFree
= p
;
1201 #define S3JniHook_free_unlocked(hook) S3JniHook__free_unlocked(env, hook)
1205 ** Clears all of s's state. Requires that that the caller has locked
1206 ** S3JniGlobal.perDb.mutex. Make sure to do anything needed with
1207 ** s->pNext and s->pPrev before calling this, as this clears them.
1209 static void S3JniDb_clear(JNIEnv
* const env
, S3JniDb
* const s
){
1210 S3JniDb_mutex_assertLocker
;
1211 sqlite3_free( s
->zMainDbName
);
1212 #define UNHOOK(MEMBER) \
1213 S3JniHook_unref(&s->hooks.MEMBER)
1215 UNHOOK(busyHandler
);
1216 UNHOOK(collationNeeded
);
1222 #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
1226 S3JniUnrefGlobal(s
->jDb
);
1227 memset(s
, 0, sizeof(S3JniDb
));
1231 ** Clears s's state and moves it to the free-list. Requires that
1232 ** S3JniGlobal.perDb.mutex is locked.
1234 static void S3JniDb__set_aside_unlocked(JNIEnv
* const env
, S3JniDb
* const s
){
1236 S3JniDb_mutex_assertLocker
;
1238 S3JniDb_clear(env
, s
);
1239 s
->pNext
= SJG
.perDb
.aFree
;
1240 SJG
.perDb
.aFree
= s
;
1243 #define S3JniDb_set_aside_unlocked(JniDb) S3JniDb__set_aside_unlocked(env, JniDb)
1245 static void S3JniDb__set_aside(JNIEnv
* const env
, S3JniDb
* const s
){
1246 S3JniDb_mutex_enter
;
1247 S3JniDb_set_aside_unlocked(s
);
1248 S3JniDb_mutex_leave
;
1250 #define S3JniDb_set_aside(JNIDB) S3JniDb__set_aside(env, JNIDB)
1253 ** Uncache any state for the given JNIEnv, clearing all Java
1254 ** references the cache owns. Returns true if env was cached and false
1255 ** if it was not found in the cache. Ownership of the given object is
1256 ** passed over to this function, which makes it free for re-use.
1258 ** Requires that the Env mutex be locked.
1260 static int S3JniEnv_uncache(JNIEnv
* const env
){
1261 struct S3JniEnv
* row
;
1262 struct S3JniEnv
* pPrev
= 0;
1263 S3JniEnv_mutex_assertLocked
;
1264 row
= SJG
.envCache
.aHead
;
1265 for( ; row
; pPrev
= row
, row
= row
->pNext
){
1266 if( row
->env
== env
){
1273 if( pPrev
) pPrev
->pNext
= row
->pNext
;
1275 assert( SJG
.envCache
.aHead
== row
);
1276 SJG
.envCache
.aHead
= row
->pNext
;
1278 memset(row
, 0, sizeof(S3JniEnv
));
1279 row
->pNext
= SJG
.envCache
.aFree
;
1280 SJG
.envCache
.aFree
= row
;
1285 ** Fetches the given nph-ref from cache the cache and returns the
1286 ** object with its klazz member set. This is an O(1) operation except
1287 ** on the first call for a given pRef, during which pRef->klazz and
1288 ** pRef->pRef are initialized thread-safely. In the latter case it's
1289 ** still effectively O(1), but with a much longer 1.
1291 ** It is up to the caller to populate the other members of the
1292 ** returned object if needed, taking care to lock the modification
1293 ** with S3JniNph_mutex_enter/leave.
1295 ** This simple cache catches >99% of searches in the current
1296 ** (2023-07-31) tests.
1298 static S3JniNphClass
* s3jni__nph(JNIEnv
* const env
, S3JniNphRef
const* pRef
){
1302 https://developer.ibm.com/articles/j-jni/
1304 > ... the IDs returned for a given class don't change for the
1305 lifetime of the JVM process. But the call to get the field or
1306 method can require significant work in the JVM, because
1307 fields and methods might have been inherited from
1308 superclasses, making the JVM walk up the class hierarchy to
1309 find them. Because the IDs are the same for a given class,
1310 you should look them up once and then reuse them. Similarly,
1311 looking up class objects can be expensive, so they should be
1314 S3JniNphClass
* const pNC
= &SJG
.nph
[pRef
->index
];
1315 assert( (void*)pRef
>=(void*)&S3JniNphRefs
&& (void*)pRef
<(void*)(&S3JniNphRefs
+ 1)
1316 && "pRef is out of range." );
1317 assert( pRef
->index
>=0
1318 && (pRef
->index
< (sizeof(S3JniNphRefs
) / sizeof(S3JniNphRef
))) );
1320 S3JniNph_mutex_enter
;
1322 jclass
const klazz
= (*env
)->FindClass(env
, pRef
->zName
);
1323 S3JniExceptionIsFatal("FindClass() unexpectedly threw");
1324 pNC
->klazz
= S3JniRefGlobal(klazz
);
1326 /* Must come last to avoid a race condition where pNC->klass
1327 can be NULL after this function returns. */;
1329 S3JniNph_mutex_leave
;
1331 assert( pNC
->klazz
);
1335 #define s3jni_nph(PRef) s3jni__nph(env, PRef)
1338 ** Common code for accessor functions for NativePointerHolder and
1339 ** OutputPointer types. pRef must be a pointer from S3JniNphRefs. jOut
1340 ** must be an instance of that class (Java's type safety takes care of
1341 ** that requirement). If necessary, this fetches the jfieldID for
1342 ** jOut's pRef->zMember, which must be of the type represented by the
1343 ** JNI type signature pRef->zTypeSig, and stores it in
1344 ** S3JniGlobal.nph[pRef->index]. Fails fatally if the pRef->zMember
1345 ** property is not found, as that presents a serious internal misuse.
1347 ** Property lookups are cached on a per-pRef basis.
1349 static jfieldID
s3jni_nphop_field(JNIEnv
* const env
, S3JniNphRef
const* pRef
){
1350 S3JniNphClass
* const pNC
= s3jni_nph(pRef
);
1352 if( !pNC
->fidValue
){
1353 S3JniNph_mutex_enter
;
1354 if( !pNC
->fidValue
){
1355 pNC
->fidValue
= (*env
)->GetFieldID(env
, pNC
->klazz
,
1356 pRef
->zMember
, pRef
->zTypeSig
);
1357 S3JniExceptionIsFatal("Code maintenance required: missing "
1358 "required S3JniNphClass::fidValue.");
1360 S3JniNph_mutex_leave
;
1362 assert( pNC
->fidValue
);
1363 return pNC
->fidValue
;
1367 ** Sets a native ptr value in NativePointerHolder object ppOut.
1368 ** zClassName must be a static string so we can use its address
1371 static void NativePointerHolder__set(JNIEnv
* const env
, S3JniNphRef
const* pRef
,
1372 jobject ppOut
, const void * p
){
1374 (*env
)->SetLongField(env
, ppOut
, s3jni_nphop_field(env
, pRef
), (jlong
)p
);
1375 S3JniExceptionIsFatal("Could not set NativePointerHolder.nativePointer.");
1378 #define NativePointerHolder_set(PREF,PPOUT,P) \
1379 NativePointerHolder__set(env, PREF, PPOUT, P)
1382 ** Fetches a native ptr value from NativePointerHolder object pObj,
1383 ** which must be of the native type described by pRef. This is a
1384 ** no-op if pObj is NULL.
1386 static void * NativePointerHolder__get(JNIEnv
* env
, jobject pObj
,
1387 S3JniNphRef
const* pRef
){
1390 rv
= (void*)(*env
)->GetLongField(env
, pObj
, s3jni_nphop_field(env
, pRef
));
1391 S3JniExceptionIsFatal("Cannot fetch NativePointerHolder.nativePointer.");
1396 #define NativePointerHolder_get(JOBJ,NPHREF) \
1397 NativePointerHolder__get(env, (JOBJ), (NPHREF))
1400 ** Helpers for extracting pointers from jobjects, noting that we rely
1401 ** on the corresponding Java interfaces having already done the
1402 ** type-checking. OBJ must be a jobject referring to a
1403 ** NativePointerHolder<T>, where T matches PtrGet_T. Don't use these
1404 ** in contexts where that's not the case. Note that these aren't
1405 ** type-safe in the strictest sense:
1407 ** sqlite3 * s = PtrGet_sqlite3_stmt(...)
1409 ** will work, despite the incorrect macro name, so long as the
1410 ** argument is a Java sqlite3 object, as this operation only has void
1411 ** pointers to work with.
1413 #define PtrGet_T(T,OBJ) NativePointerHolder_get(OBJ, &S3JniNphRefs.T)
1414 #define PtrGet_sqlite3(OBJ) PtrGet_T(sqlite3, OBJ)
1415 #define PtrGet_sqlite3_stmt(OBJ) PtrGet_T(sqlite3_stmt, OBJ)
1416 #define PtrGet_sqlite3_value(OBJ) PtrGet_T(sqlite3_value, OBJ)
1417 #define PtrGet_sqlite3_context(OBJ) PtrGet_T(sqlite3_context, OBJ)
1421 ** Enters the S3JniDb mutex and PtrGet_sqlite3()'s jObj. If that's
1422 ** NULL then it leaves the mutex, else the mutex is still entered
1423 ** when this returns and the caller is obligated to leave it.
1425 static sqlite3
* PtrGet__sqlite3_lock(JNIEnv
* const env
, jobject jObj
){
1427 S3JniDb_mutex_enter
;
1428 rv
= PtrGet_sqlite3(jObj
);
1429 if( !rv
){ S3JniDb_mutex_leave
; }
1432 #undef PtrGet_sqlite3
1433 #define PtrGet_sqlite3(JOBJ) PtrGet__sqlite3_lock(env, (JOBJ))
1437 ** Extracts the new S3JniDb instance from the free-list, or allocates
1438 ** one if needed, associats it with pDb, and returns. Returns NULL on
1439 ** OOM. pDb MUST, on success of the calling operation, subsequently be
1440 ** associated with jDb via NativePointerHolder_set().
1442 static S3JniDb
* S3JniDb_alloc(JNIEnv
* const env
, jobject jDb
){
1444 S3JniDb_mutex_enter
;
1445 if( SJG
.perDb
.aFree
){
1446 rv
= SJG
.perDb
.aFree
;
1447 SJG
.perDb
.aFree
= rv
->pNext
;
1449 s3jni_incr( &SJG
.metrics
.nPdbRecycled
);
1451 S3JniDb_mutex_leave
;
1453 rv
= s3jni_malloc( sizeof(S3JniDb
));
1455 s3jni_incr( &SJG
.metrics
.nPdbAlloc
);
1459 memset(rv
, 0, sizeof(S3JniDb
));
1460 rv
->jDb
= S3JniRefGlobal(jDb
);
1466 ** Returns the S3JniDb object for the given org.sqlite.jni.sqlite3
1467 ** object, or NULL if jDb is NULL, no pointer can be extracted
1468 ** from it, or no matching entry can be found.
1470 static S3JniDb
* S3JniDb__from_java(JNIEnv
* const env
, jobject jDb
){
1471 sqlite3
* const pDb
= jDb
? PtrGet_sqlite3(jDb
) : 0;
1472 return pDb
? S3JniDb_from_clientdata(pDb
) : 0;
1474 #define S3JniDb_from_java(jObject) S3JniDb__from_java(env,(jObject))
1477 ** S3JniDb finalizer for use with sqlite3_set_clientdata().
1479 static void S3JniDb_xDestroy(void *p
){
1481 S3JniDb
* const ps
= p
;
1482 assert( !ps
->pNext
&& "Else ps is already in the free-list.");
1483 S3JniDb_set_aside(ps
);
1487 ** Evaluates to the S3JniDb object for the given sqlite3 object, or
1488 ** NULL if pDb is NULL or was not initialized via the JNI interfaces.
1490 #define S3JniDb_from_c(sqlite3Ptr) \
1491 ((sqlite3Ptr) ? S3JniDb_from_clientdata(sqlite3Ptr) : 0)
1494 ** Unref any Java-side state in (S3JniAutoExtension*) AX and zero out
1497 #define S3JniAutoExtension_clear(AX) S3JniHook_unref(AX);
1500 ** Initializes a pre-allocated S3JniAutoExtension object. Returns
1501 ** non-0 if there is an error collecting the required state from
1502 ** jAutoExt (which must be an AutoExtensionCallback object). On error,
1503 ** it passes ax to S3JniAutoExtension_clear().
1505 static int S3JniAutoExtension_init(JNIEnv
*const env
,
1506 S3JniAutoExtension
* const ax
,
1507 jobject
const jAutoExt
){
1508 jclass
const klazz
= (*env
)->GetObjectClass(env
, jAutoExt
);
1510 S3JniAutoExt_mutex_assertLocker
;
1511 *ax
= S3JniHook_empty
;
1512 ax
->midCallback
= (*env
)->GetMethodID(env
, klazz
, "call",
1513 "(Lorg/sqlite/jni/sqlite3;)I");
1514 S3JniUnrefLocal(klazz
);
1515 S3JniExceptionWarnIgnore
;
1516 if( !ax
->midCallback
){
1517 S3JniAutoExtension_clear(ax
);
1518 return SQLITE_ERROR
;
1520 ax
->jObj
= S3JniRefGlobal(jAutoExt
);
1525 ** Sets the value property of the OutputPointer.Bool jOut object to
1528 static void OutputPointer_set_Bool(JNIEnv
* const env
, jobject
const jOut
,
1530 (*env
)->SetBooleanField(env
, jOut
, s3jni_nphop_field(
1531 env
, &S3JniNphRefs
.OutputPointer_Bool
1532 ), v
? JNI_TRUE
: JNI_FALSE
);
1533 S3JniExceptionIsFatal("Cannot set OutputPointer.Bool.value");
1537 ** Sets the value property of the OutputPointer.Int32 jOut object to
1540 static void OutputPointer_set_Int32(JNIEnv
* const env
, jobject
const jOut
,
1542 (*env
)->SetIntField(env
, jOut
, s3jni_nphop_field(
1543 env
, &S3JniNphRefs
.OutputPointer_Int32
1545 S3JniExceptionIsFatal("Cannot set OutputPointer.Int32.value");
1549 ** Sets the value property of the OutputPointer.Int64 jOut object to
1552 static void OutputPointer_set_Int64(JNIEnv
* const env
, jobject
const jOut
,
1554 (*env
)->SetLongField(env
, jOut
, s3jni_nphop_field(
1555 env
, &S3JniNphRefs
.OutputPointer_Int64
1557 S3JniExceptionIsFatal("Cannot set OutputPointer.Int64.value");
1561 ** Internal helper for OutputPointer_set_TYPE() where TYPE is an
1564 static void OutputPointer_set_obj(JNIEnv
* const env
,
1565 S3JniNphRef
const * const pRef
,
1568 (*env
)->SetObjectField(env
, jOut
, s3jni_nphop_field(env
, pRef
), v
);
1569 S3JniExceptionIsFatal("Cannot set OutputPointer.T.value");
1573 ** Sets the value property of the OutputPointer.sqlite3 jOut object to
1576 static void OutputPointer_set_sqlite3(JNIEnv
* const env
, jobject
const jOut
,
1578 OutputPointer_set_obj(env
, &S3JniNphRefs
.OutputPointer_sqlite3
, jOut
, jDb
);
1582 ** Sets the value property of the OutputPointer.sqlite3_stmt jOut object to
1585 static void OutputPointer_set_sqlite3_stmt(JNIEnv
* const env
, jobject
const jOut
,
1587 OutputPointer_set_obj(env
, &S3JniNphRefs
.OutputPointer_sqlite3_stmt
, jOut
, jStmt
);
1590 #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
1592 ** Sets the value property of the OutputPointer.sqlite3_value jOut object to
1595 static void OutputPointer_set_sqlite3_value(JNIEnv
* const env
, jobject
const jOut
,
1597 OutputPointer_set_obj(env
, &S3JniNphRefs
.OutputPointer_sqlite3_value
, jOut
, jValue
);
1599 #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
1601 #ifdef SQLITE_ENABLE_FTS5
1604 ** Sets the value property of the OutputPointer.ByteArray jOut object
1607 static void OutputPointer_set_ByteArray(JNIEnv
* const env
, jobject
const jOut
,
1608 jbyteArray
const v
){
1609 OutputPointer_set_obj(env
, &S3JniNphRefs
.OutputPointer_ByteArray
, jOut
, v
);
1612 #endif /* SQLITE_ENABLE_FTS5 */
1615 ** Sets the value property of the OutputPointer.String jOut object to
1618 static void OutputPointer_set_String(JNIEnv
* const env
, jobject
const jOut
,
1620 OutputPointer_set_obj(env
, &S3JniNphRefs
.OutputPointer_String
, jOut
, v
);
1624 ** Returns true if eTextRep is a valid sqlite3 encoding constant, else
1627 static int encodingTypeIsValid(int eTextRep
){
1629 case SQLITE_UTF8
: case SQLITE_UTF16
:
1630 case SQLITE_UTF16LE
: case SQLITE_UTF16BE
:
1637 /* For use with sqlite3_result/value_pointer() */
1638 #define ResultJavaValuePtrStr "org.sqlite.jni.ResultJavaVal"
1641 ** If v is not NULL, it must be a jobject global reference. Its
1642 ** reference is relinquished and v is freed.
1644 static void ResultJavaValue_finalizer(void *v
){
1647 S3JniUnrefGlobal((jobject
)v
);
1654 ** Returns a new Java instance of the class named by zClassName, which
1655 ** MUST be interface-compatible with NativePointerHolder and MUST have
1656 ** a no-arg constructor. The NativePointerHolder_set() method is
1657 ** passed the new Java object and pNative. Hypothetically returns NULL
1658 ** if Java fails to allocate, but the JNI docs are not entirely clear
1661 ** Always use a static pointer from the S3JniNphRefs struct for the 2nd
1662 ** argument so that we can use pRef->index as an O(1) cache key.
1664 static jobject
new_NativePointerHolder_object(JNIEnv
* const env
, S3JniNphRef
const * pRef
,
1665 const void * pNative
){
1667 S3JniNphClass
* const pNC
= s3jni_nph(pRef
);
1668 if( !pNC
->midCtor
){
1669 S3JniNph_mutex_enter
;
1670 if( !pNC
->midCtor
){
1671 pNC
->midCtor
= (*env
)->GetMethodID(env
, pNC
->klazz
, "<init>", "()V");
1672 S3JniExceptionIsFatal("Cannot find constructor for class.");
1674 S3JniNph_mutex_leave
;
1676 rv
= (*env
)->NewObject(env
, pNC
->klazz
, pNC
->midCtor
);
1677 S3JniExceptionIsFatal("No-arg constructor threw.");
1678 s3jni_oom_check(rv
);
1679 if( rv
) NativePointerHolder_set(pRef
, rv
, pNative
);
1683 static inline jobject
new_sqlite3_wrapper(JNIEnv
* const env
, sqlite3
*sv
){
1684 return new_NativePointerHolder_object(env
, &S3JniNphRefs
.sqlite3
, sv
);
1686 static inline jobject
new_sqlite3_context_wrapper(JNIEnv
* const env
, sqlite3_context
*sv
){
1687 return new_NativePointerHolder_object(env
, &S3JniNphRefs
.sqlite3_context
, sv
);
1689 static inline jobject
new_sqlite3_stmt_wrapper(JNIEnv
* const env
, sqlite3_stmt
*sv
){
1690 return new_NativePointerHolder_object(env
, &S3JniNphRefs
.sqlite3_stmt
, sv
);
1692 static inline jobject
new_sqlite3_value_wrapper(JNIEnv
* const env
, sqlite3_value
*sv
){
1693 return new_NativePointerHolder_object(env
, &S3JniNphRefs
.sqlite3_value
, sv
);
1696 /* Helper typedefs for UDF callback types. */
1697 typedef void (*udf_xFunc_f
)(sqlite3_context
*,int,sqlite3_value
**);
1698 typedef void (*udf_xStep_f
)(sqlite3_context
*,int,sqlite3_value
**);
1699 typedef void (*udf_xFinal_f
)(sqlite3_context
*);
1700 /*typedef void (*udf_xValue_f)(sqlite3_context*);*/
1701 /*typedef void (*udf_xInverse_f)(sqlite3_context*,int,sqlite3_value**);*/
1704 ** Allocate a new S3JniUdf (User-defined Function) and associate it
1705 ** with the SQLFunction-type jObj. Returns NULL on OOM. If the
1706 ** returned object's type==UDF_UNKNOWN_TYPE then the type of UDF was
1707 ** not unambiguously detected based on which callback members it has,
1708 ** which falls into the category of user error.
1710 ** The caller must arrange for the returned object to eventually be
1711 ** passed to S3JniUdf_free().
1713 static S3JniUdf
* S3JniUdf_alloc(JNIEnv
* const env
, jobject jObj
){
1716 S3JniGlobal_mutex_enter
;
1717 s3jni_incr(&SJG
.metrics
.nMutexUdf
);
1718 if( SJG
.udf
.aFree
){
1720 SJG
.udf
.aFree
= s
->pNext
;
1722 s3jni_incr(&SJG
.metrics
.nUdfRecycled
);
1724 S3JniGlobal_mutex_leave
;
1726 s
= s3jni_malloc( sizeof(*s
));
1727 s3jni_incr(&SJG
.metrics
.nUdfAlloc
);
1730 const char * zFSI
= /* signature for xFunc, xStep, xInverse */
1731 "(Lorg/sqlite/jni/sqlite3_context;[Lorg/sqlite/jni/sqlite3_value;)V";
1732 const char * zFV
= /* signature for xFinal, xValue */
1733 "(Lorg/sqlite/jni/sqlite3_context;)V";
1734 jclass
const klazz
= (*env
)->GetObjectClass(env
, jObj
);
1736 memset(s
, 0, sizeof(*s
));
1737 s
->jObj
= S3JniRefGlobal(jObj
);
1739 #define FGET(FuncName,FuncSig,Field) \
1740 s->Field = (*env)->GetMethodID(env, klazz, FuncName, FuncSig); \
1741 if( !s->Field ) (*env)->ExceptionClear(env)
1743 FGET("xFunc", zFSI
, jmidxFunc
);
1744 FGET("xStep", zFSI
, jmidxStep
);
1745 FGET("xFinal", zFV
, jmidxFinal
);
1746 FGET("xValue", zFV
, jmidxValue
);
1747 FGET("xInverse", zFSI
, jmidxInverse
);
1750 S3JniUnrefLocal(klazz
);
1751 if( s
->jmidxFunc
) s
->type
= UDF_SCALAR
;
1752 else if( s
->jmidxStep
&& s
->jmidxFinal
){
1753 s
->type
= s
->jmidxValue
? UDF_WINDOW
: UDF_AGGREGATE
;
1755 s
->type
= UDF_UNKNOWN_TYPE
;
1762 ** Frees up all resources owned by s, clears its state, then either
1763 ** caches it for reuse (if cacheIt is true) or frees it. The former
1764 ** requires locking the global mutex, so it must not be held when this
1767 static void S3JniUdf_free(JNIEnv
* const env
, S3JniUdf
* const s
,
1769 assert( !s
->pNext
);
1771 s3jni_call_xDestroy(s
->jObj
);
1772 S3JniUnrefGlobal(s
->jObj
);
1773 sqlite3_free(s
->zFuncName
);
1774 assert( !s
->pNext
);
1775 memset(s
, 0, sizeof(*s
));
1778 S3JniGlobal_mutex_enter
;
1779 s
->pNext
= S3JniGlobal
.udf
.aFree
;
1780 S3JniGlobal
.udf
.aFree
= s
;
1781 S3JniGlobal_mutex_leave
;
1787 /* Finalizer for sqlite3_create_function() and friends. */
1788 static void S3JniUdf_finalizer(void * s
){
1789 S3JniUdf_free(s3jni_env(), (S3JniUdf
*)s
, 1);
1793 ** Helper for processing args to UDF handlers with signature
1794 ** (sqlite3_context*,int,sqlite3_value**).
1797 jobject jcx
/* sqlite3_context */;
1798 jobjectArray jargv
/* sqlite3_value[] */;
1802 ** Converts the given (cx, argc, argv) into arguments for the given
1803 ** UDF, writing the result (Java wrappers for cx and argv) in the
1804 ** final 2 arguments. Returns 0 on success, SQLITE_NOMEM on allocation
1805 ** error. On error *jCx and *jArgv will be set to 0.
1807 static int udf_args(JNIEnv
*env
,
1808 sqlite3_context
* const cx
,
1809 int argc
, sqlite3_value
**argv
,
1810 jobject
* jCx
, jobjectArray
*jArgv
){
1811 jobjectArray ja
= 0;
1812 jobject jcx
= new_sqlite3_context_wrapper(env
, cx
);
1816 if( !jcx
) goto error_oom
;
1817 ja
= (*env
)->NewObjectArray(
1818 env
, argc
, s3jni_nph(&S3JniNphRefs
.sqlite3_value
)->klazz
,
1820 s3jni_oom_check( ja
);
1821 if( !ja
) goto error_oom
;
1822 for(i
= 0; i
< argc
; ++i
){
1823 jobject jsv
= new_sqlite3_value_wrapper(env
, argv
[i
]);
1824 if( !jsv
) goto error_oom
;
1825 (*env
)->SetObjectArrayElement(env
, ja
, i
, jsv
);
1826 S3JniUnrefLocal(jsv
)/*ja has a ref*/;
1832 S3JniUnrefLocal(jcx
);
1833 S3JniUnrefLocal(ja
);
1834 return SQLITE_NOMEM
;
1838 ** Must be called immediately after a Java-side UDF callback throws.
1839 ** If translateToErr is true then it sets the exception's message in
1840 ** the result error using sqlite3_result_error(). If translateToErr is
1841 ** false then it emits a warning that the function threw but should
1842 ** not do so. In either case, it clears the exception state.
1844 ** Returns SQLITE_NOMEM if an allocation fails, else SQLITE_ERROR. In
1845 ** the former case it calls sqlite3_result_error_nomem().
1847 static int udf_report_exception(JNIEnv
* const env
, int translateToErr
,
1848 sqlite3_context
* cx
,
1849 const char *zFuncName
, const char *zFuncType
){
1850 jthrowable
const ex
= (*env
)->ExceptionOccurred(env
);
1851 int rc
= SQLITE_ERROR
;
1853 assert(ex
&& "This must only be called when a Java exception is pending.");
1854 if( translateToErr
){
1858 S3JniExceptionClear
;
1859 zMsg
= s3jni_exception_error_msg(env
, ex
);
1860 z
= sqlite3_mprintf("Client-defined SQL function %s.%s() threw: %s",
1861 zFuncName
? zFuncName
: "<unnamed>", zFuncType
,
1862 zMsg
? zMsg
: "Unknown exception" );
1865 sqlite3_result_error(cx
, z
, -1);
1868 sqlite3_result_error_nomem(cx
);
1872 S3JniExceptionWarnCallbackThrew("client-defined SQL function");
1873 S3JniExceptionClear
;
1875 S3JniUnrefLocal(ex
);
1880 ** Sets up the state for calling a Java-side xFunc/xStep/xInverse()
1881 ** UDF, calls it, and returns 0 on success.
1883 static int udf_xFSI(sqlite3_context
* const pCx
, int argc
,
1884 sqlite3_value
** const argv
, S3JniUdf
* const s
,
1885 jmethodID xMethodID
, const char * const zFuncType
){
1887 udf_jargs args
= {0,0};
1888 int rc
= udf_args(env
, pCx
, argc
, argv
, &args
.jcx
, &args
.jargv
);
1891 (*env
)->CallVoidMethod(env
, s
->jObj
, xMethodID
, args
.jcx
, args
.jargv
);
1893 rc
= udf_report_exception(env
, 'F'==zFuncType
[1]/*xFunc*/, pCx
,
1894 s
->zFuncName
, zFuncType
);
1897 S3JniUnrefLocal(args
.jcx
);
1898 S3JniUnrefLocal(args
.jargv
);
1903 ** Sets up the state for calling a Java-side xFinal/xValue() UDF,
1904 ** calls it, and returns 0 on success.
1906 static int udf_xFV(sqlite3_context
* cx
, S3JniUdf
* s
,
1907 jmethodID xMethodID
,
1908 const char *zFuncType
){
1910 jobject jcx
= new_sqlite3_context_wrapper(env
, cx
);
1912 int const isFinal
= 'F'==zFuncType
[1]/*xFinal*/;
1915 (*env
)->CallVoidMethod(env
, s
->jObj
, xMethodID
, jcx
);
1917 rc
= udf_report_exception(env
, isFinal
, cx
, s
->zFuncName
,
1920 S3JniUnrefLocal(jcx
);
1922 if( isFinal
) sqlite3_result_error_nomem(cx
);
1928 /* Proxy for C-to-Java xFunc. */
1929 static void udf_xFunc(sqlite3_context
* cx
, int argc
,
1930 sqlite3_value
** argv
){
1931 S3JniUdf
* const s
= (S3JniUdf
*)sqlite3_user_data(cx
);
1932 s3jni_incr( &SJG
.metrics
.udf
.nFunc
);
1933 udf_xFSI(cx
, argc
, argv
, s
, s
->jmidxFunc
, "xFunc");
1935 /* Proxy for C-to-Java xStep. */
1936 static void udf_xStep(sqlite3_context
* cx
, int argc
,
1937 sqlite3_value
** argv
){
1938 S3JniUdf
* const s
= (S3JniUdf
*)sqlite3_user_data(cx
);
1939 s3jni_incr( &SJG
.metrics
.udf
.nStep
);
1940 udf_xFSI(cx
, argc
, argv
, s
, s
->jmidxStep
, "xStep");
1942 /* Proxy for C-to-Java xFinal. */
1943 static void udf_xFinal(sqlite3_context
* cx
){
1944 S3JniUdf
* const s
= (S3JniUdf
*)sqlite3_user_data(cx
);
1945 s3jni_incr( &SJG
.metrics
.udf
.nFinal
);
1946 udf_xFV(cx
, s
, s
->jmidxFinal
, "xFinal");
1948 /* Proxy for C-to-Java xValue. */
1949 static void udf_xValue(sqlite3_context
* cx
){
1950 S3JniUdf
* const s
= (S3JniUdf
*)sqlite3_user_data(cx
);
1951 s3jni_incr( &SJG
.metrics
.udf
.nValue
);
1952 udf_xFV(cx
, s
, s
->jmidxValue
, "xValue");
1954 /* Proxy for C-to-Java xInverse. */
1955 static void udf_xInverse(sqlite3_context
* cx
, int argc
,
1956 sqlite3_value
** argv
){
1957 S3JniUdf
* const s
= (S3JniUdf
*)sqlite3_user_data(cx
);
1958 s3jni_incr( &SJG
.metrics
.udf
.nInverse
);
1959 udf_xFSI(cx
, argc
, argv
, s
, s
->jmidxInverse
, "xInverse");
1963 ////////////////////////////////////////////////////////////////////////
1964 // What follows is the JNI/C bindings. They are in alphabetical order
1965 // except for this macro-generated subset which are kept together
1966 // (alphabetized) here at the front...
1967 ////////////////////////////////////////////////////////////////////////
1969 /** Create a trivial JNI wrapper for (int CName(void)). */
1970 #define WRAP_INT_VOID(JniNameSuffix,CName) \
1971 JniDecl(jint,JniNameSuffix)(JniArgsEnvClass){ \
1972 return (jint)CName(); \
1974 /** Create a trivial JNI wrapper for (int CName(int)). */
1975 #define WRAP_INT_INT(JniNameSuffix,CName) \
1976 JniDecl(jint,JniNameSuffix)(JniArgsEnvClass, jint arg){ \
1977 return (jint)CName((int)arg); \
1980 ** Create a trivial JNI wrapper for (const mutf8_string *
1981 ** CName(void)). This is only valid for functions which are known to
1982 ** return ASCII or text which is equivalent in UTF-8 and MUTF-8.
1984 #define WRAP_MUTF8_VOID(JniNameSuffix,CName) \
1985 JniDecl(jstring,JniNameSuffix)(JniArgsEnvClass){ \
1986 jstring const rv = (*env)->NewStringUTF( env, CName() ); \
1987 s3jni_oom_check(rv); \
1990 /** Create a trivial JNI wrapper for (int CName(sqlite3_stmt*)). */
1991 #define WRAP_INT_STMT(JniNameSuffix,CName) \
1992 JniDecl(jint,JniNameSuffix)(JniArgsEnvClass, jobject jpStmt){ \
1993 jint const rc = (jint)CName(PtrGet_sqlite3_stmt(jpStmt)); \
1994 S3JniExceptionIgnore /* squelch -Xcheck:jni */; \
1997 /** Create a trivial JNI wrapper for (int CName(sqlite3_stmt*,int)). */
1998 #define WRAP_INT_STMT_INT(JniNameSuffix,CName) \
1999 JniDecl(jint,JniNameSuffix)(JniArgsEnvClass, jobject pStmt, jint n){ \
2000 return (jint)CName(PtrGet_sqlite3_stmt(pStmt), (int)n); \
2002 /** Create a trivial JNI wrapper for (boolish-int CName(sqlite3_stmt*)). */
2003 #define WRAP_BOOL_STMT(JniNameSuffix,CName) \
2004 JniDecl(jboolean,JniNameSuffix)(JniArgsEnvClass, jobject pStmt){ \
2005 return CName(PtrGet_sqlite3_stmt(pStmt)) ? JNI_TRUE : JNI_FALSE; \
2007 /** Create a trivial JNI wrapper for (jstring CName(sqlite3_stmt*,int)). */
2008 #define WRAP_STR_STMT_INT(JniNameSuffix,CName) \
2009 JniDecl(jstring,JniNameSuffix)(JniArgsEnvClass, jobject pStmt, jint ndx){ \
2010 return s3jni_utf8_to_jstring( \
2011 CName(PtrGet_sqlite3_stmt(pStmt), (int)ndx), \
2014 /** Create a trivial JNI wrapper for (int CName(sqlite3*)). */
2015 #define WRAP_INT_DB(JniNameSuffix,CName) \
2016 JniDecl(jint,JniNameSuffix)(JniArgsEnvClass, jobject pDb){ \
2017 return (jint)CName(PtrGet_sqlite3(pDb)); \
2019 /** Create a trivial JNI wrapper for (int64 CName(sqlite3*)). */
2020 #define WRAP_INT64_DB(JniNameSuffix,CName) \
2021 JniDecl(jlong,JniNameSuffix)(JniArgsEnvClass, jobject pDb){ \
2022 return (jlong)CName(PtrGet_sqlite3(pDb)); \
2024 /** Create a trivial JNI wrapper for (int CName(sqlite3_value*)). */
2025 #define WRAP_INT_SVALUE(JniNameSuffix,CName) \
2026 JniDecl(jint,JniNameSuffix)(JniArgsEnvClass, jobject jpSValue){ \
2027 return (jint)CName(PtrGet_sqlite3_value(jpSValue)); \
2030 WRAP_INT_STMT(1bind_1parameter_1count
, sqlite3_bind_parameter_count
)
2031 WRAP_INT_DB(1changes
, sqlite3_changes
)
2032 WRAP_INT64_DB(1changes64
, sqlite3_changes64
)
2033 WRAP_INT_STMT(1clear_1bindings
, sqlite3_clear_bindings
)
2034 WRAP_INT_STMT_INT(1column_1bytes
, sqlite3_column_bytes
)
2035 WRAP_INT_STMT_INT(1column_1bytes16
, sqlite3_column_bytes16
)
2036 WRAP_INT_STMT(1column_1count
, sqlite3_column_count
)
2037 WRAP_STR_STMT_INT(1column_1decltype
, sqlite3_column_decltype
)
2038 WRAP_STR_STMT_INT(1column_1name
, sqlite3_column_name
)
2039 WRAP_STR_STMT_INT(1column_1database_1name
, sqlite3_column_database_name
)
2040 WRAP_STR_STMT_INT(1column_1origin_1name
, sqlite3_column_origin_name
)
2041 WRAP_STR_STMT_INT(1column_1table_1name
, sqlite3_column_table_name
)
2042 WRAP_INT_STMT_INT(1column_1type
, sqlite3_column_type
)
2043 WRAP_INT_STMT(1data_1count
, sqlite3_data_count
)
2044 WRAP_INT_DB(1error_1offset
, sqlite3_error_offset
)
2045 WRAP_INT_DB(1extended_1errcode
, sqlite3_extended_errcode
)
2046 WRAP_MUTF8_VOID(1libversion
, sqlite3_libversion
)
2047 WRAP_INT_VOID(1libversion_
1number
, sqlite3_libversion_number
)
2048 #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
2049 WRAP_INT_DB(1preupdate_1blobwrite
, sqlite3_preupdate_blobwrite
)
2050 WRAP_INT_DB(1preupdate_1count
, sqlite3_preupdate_count
)
2051 WRAP_INT_DB(1preupdate_1depth
, sqlite3_preupdate_depth
)
2053 WRAP_INT_INT(1release_1memory
, sqlite3_release_memory
)
2054 WRAP_INT_INT(1sleep
, sqlite3_sleep
)
2055 WRAP_MUTF8_VOID(1sourceid
, sqlite3_sourceid
)
2056 WRAP_INT_STMT_INT(1stmt_1explain
, sqlite3_stmt_explain
)
2057 WRAP_INT_STMT(1stmt_1isexplain
, sqlite3_stmt_isexplain
)
2058 WRAP_BOOL_STMT(1stmt_1readonly
, sqlite3_stmt_readonly
)
2059 WRAP_INT_VOID(1threadsafe
, sqlite3_threadsafe
)
2060 WRAP_INT_DB(1total_1changes
, sqlite3_total_changes
)
2061 WRAP_INT64_DB(1total_1changes64
, sqlite3_total_changes64
)
2062 WRAP_INT_SVALUE(1value_1bytes
, sqlite3_value_bytes
)
2063 WRAP_INT_SVALUE(1value_1bytes16
, sqlite3_value_bytes16
)
2064 WRAP_INT_SVALUE(1value_1encoding
, sqlite3_value_encoding
)
2065 WRAP_INT_SVALUE(1value_1frombind
, sqlite3_value_frombind
)
2066 WRAP_INT_SVALUE(1value_1nochange
, sqlite3_value_nochange
)
2067 WRAP_INT_SVALUE(1value_1numeric_1type
, sqlite3_value_numeric_type
)
2068 WRAP_INT_SVALUE(1value_1subtype
, sqlite3_value_subtype
)
2069 WRAP_INT_SVALUE(1value_1type
, sqlite3_value_type
)
2071 #undef WRAP_INT64_DB
2074 #undef WRAP_INT_STMT
2075 #undef WRAP_INT_STMT_INT
2076 #undef WRAP_INT_SVALUE
2077 #undef WRAP_INT_VOID
2078 #undef WRAP_MUTF8_VOID
2079 #undef WRAP_STR_STMT_INT
2081 S3JniApi(sqlite3_aggregate_context(),jlong
,1aggregate_1context
)(
2082 JniArgsEnvClass
, jobject jCx
, jboolean initialize
2084 sqlite3_context
* const pCx
= PtrGet_sqlite3_context(jCx
);
2085 void * const p
= pCx
2086 ? sqlite3_aggregate_context(pCx
, (int)(initialize
2087 ? (int)sizeof(void*)
2093 /* Central auto-extension handler. */
2094 static int s3jni_run_java_auto_extensions(sqlite3
*pDb
, const char **pzErr
,
2095 const struct sqlite3_api_routines
*ignored
){
2102 if( 0==SJG
.autoExt
.nExt
) return 0;
2104 jc
= S3JniEnv_get();
2105 ps
= jc
->pdbOpening
;
2107 *pzErr
= sqlite3_mprintf("Unexpected arrival of null S3JniDb in "
2108 "auto-extension runner.");
2109 return SQLITE_ERROR
;
2112 assert( !ps
->pDb
&& "it's still being opened" );
2114 rc
= sqlite3_set_clientdata(pDb
, S3JniDb_clientdata_key
,
2115 ps
, 0/* we'll re-set this after open()
2120 NativePointerHolder_set(&S3JniNphRefs
.sqlite3
, ps
->jDb
, pDb
)
2121 /* As of here, the Java/C connection is complete except for the
2122 (temporary) lack of finalizer for the ps object. */;
2124 for( i
= 0; go
&& 0==rc
; ++i
){
2125 S3JniAutoExtension ax
= S3JniHook_empty
2126 /* We need a copy of the auto-extension object, with our own
2127 ** local reference to it, to avoid a race condition with another
2128 ** thread manipulating the list during the call and invaliding
2129 ** what ax references. */;
2130 S3JniAutoExt_mutex_enter
;
2131 if( i
>= SJG
.autoExt
.nExt
){
2134 S3JniHook_localdup(&SJG
.autoExt
.aExt
[i
], &ax
);
2136 S3JniAutoExt_mutex_leave
;
2138 rc
= (*env
)->CallIntMethod(env
, ax
.jObj
, ax
.midCallback
, ps
->jDb
);
2139 S3JniHook_localundup(ax
);
2141 jthrowable
const ex
= (*env
)->ExceptionOccurred(env
);
2143 S3JniExceptionClear
;
2144 zMsg
= s3jni_exception_error_msg(env
, ex
);
2145 S3JniUnrefLocal(ex
);
2146 *pzErr
= sqlite3_mprintf("auto-extension threw: %s", zMsg
);
2155 S3JniApi(sqlite3_auto_extension(),jint
,1auto_1extension
)(
2156 JniArgsEnvClass
, jobject jAutoExt
2159 S3JniAutoExtension
* ax
;
2162 if( !jAutoExt
) return SQLITE_MISUSE
;
2163 S3JniAutoExt_mutex_enter
;
2164 for( i
= 0; i
< SJG
.autoExt
.nExt
; ++i
){
2165 /* Look for a match. */
2166 ax
= &SJG
.autoExt
.aExt
[i
];
2167 if( ax
->jObj
&& (*env
)->IsSameObject(env
, ax
->jObj
, jAutoExt
) ){
2168 /* same object, so this is a no-op. */
2169 S3JniAutoExt_mutex_leave
;
2173 if( i
== SJG
.autoExt
.nExt
){
2174 assert( SJG
.autoExt
.nExt
<= SJG
.autoExt
.nAlloc
);
2175 if( SJG
.autoExt
.nExt
== SJG
.autoExt
.nAlloc
){
2176 /* Allocate another slot. */
2177 unsigned n
= 1 + SJG
.autoExt
.nAlloc
;
2178 S3JniAutoExtension
* const aNew
=
2179 s3jni_realloc( SJG
.autoExt
.aExt
, n
* sizeof(*ax
) );
2183 SJG
.autoExt
.aExt
= aNew
;
2184 ++SJG
.autoExt
.nAlloc
;
2188 ax
= &SJG
.autoExt
.aExt
[SJG
.autoExt
.nExt
];
2189 rc
= S3JniAutoExtension_init(env
, ax
, jAutoExt
);
2190 assert( rc
? (0==ax
->jObj
&& 0==ax
->midCallback
)
2191 : (0!=ax
->jObj
&& 0!=ax
->midCallback
) );
2195 static int once
= 0;
2196 if( 0==once
&& ++once
){
2197 rc
= sqlite3_auto_extension(
2198 (void(*)(void))s3jni_run_java_auto_extensions
2199 /* Reminder: the JNI binding of sqlite3_reset_auto_extension()
2200 ** does not call the core-lib impl. It only clears Java-side
2201 ** auto-extensions. */
2205 S3JniAutoExtension_clear(ax
);
2212 S3JniAutoExt_mutex_leave
;
2216 S3JniApi(sqlite3_bind_blob(),jint
,1bind_1blob
)(
2217 JniArgsEnvClass
, jobject jpStmt
, jint ndx
, jbyteArray baData
, jint nMax
2219 jbyte
* const pBuf
= baData
? s3jni_jbytearray_bytes(baData
) : 0;
2222 rc
= sqlite3_bind_blob(PtrGet_sqlite3_stmt(jpStmt
), (int)ndx
,
2223 pBuf
, (int)nMax
, SQLITE_TRANSIENT
);
2224 s3jni_jbytearray_release(baData
, pBuf
);
2228 : sqlite3_bind_null( PtrGet_sqlite3_stmt(jpStmt
), ndx
);
2233 S3JniApi(sqlite3_bind_double(),jint
,1bind_1double
)(
2234 JniArgsEnvClass
, jobject jpStmt
, jint ndx
, jdouble val
2236 return (jint
)sqlite3_bind_double(PtrGet_sqlite3_stmt(jpStmt
), (int)ndx
, (double)val
);
2239 S3JniApi(sqlite3_bind_int(),jint
,1bind_1int
)(
2240 JniArgsEnvClass
, jobject jpStmt
, jint ndx
, jint val
2242 return (jint
)sqlite3_bind_int(PtrGet_sqlite3_stmt(jpStmt
), (int)ndx
, (int)val
);
2245 S3JniApi(sqlite3_bind_int64(),jint
,1bind_1int64
)(
2246 JniArgsEnvClass
, jobject jpStmt
, jint ndx
, jlong val
2248 return (jint
)sqlite3_bind_int64(PtrGet_sqlite3_stmt(jpStmt
), (int)ndx
, (sqlite3_int64
)val
);
2252 ** Bind a new global ref to Object `val` using sqlite3_bind_pointer().
2254 S3JniApi(sqlite3_bind_java_object(),jint
,1bind_1java_1object
)(
2255 JniArgsEnvClass
, jobject jpStmt
, jint ndx
, jobject val
2257 sqlite3_stmt
* const pStmt
= PtrGet_sqlite3_stmt(jpStmt
);
2261 jobject
const rv
= val
? S3JniRefGlobal(val
) : 0;
2263 rc
= sqlite3_bind_pointer(pStmt
, ndx
, rv
, ResultJavaValuePtrStr
,
2264 ResultJavaValue_finalizer
);
2274 S3JniApi(sqlite3_bind_null(),jint
,1bind_1null
)(
2275 JniArgsEnvClass
, jobject jpStmt
, jint ndx
2277 return (jint
)sqlite3_bind_null(PtrGet_sqlite3_stmt(jpStmt
), (int)ndx
);
2280 S3JniApi(sqlite3_bind_parameter_index(),jint
,1bind_1parameter_1index
)(
2281 JniArgsEnvClass
, jobject jpStmt
, jbyteArray jName
2284 jbyte
* const pBuf
= s3jni_jbytearray_bytes(jName
);
2286 rc
= sqlite3_bind_parameter_index(PtrGet_sqlite3_stmt(jpStmt
),
2287 (const char *)pBuf
);
2288 s3jni_jbytearray_release(jName
, pBuf
);
2293 S3JniApi(sqlite3_bind_text(),jint
,1bind_1text
)(
2294 JniArgsEnvClass
, jobject jpStmt
, jint ndx
, jbyteArray baData
, jint nMax
2296 jbyte
* const pBuf
= baData
? s3jni_jbytearray_bytes(baData
) : 0;
2297 int const rc
= sqlite3_bind_text(PtrGet_sqlite3_stmt(jpStmt
), (int)ndx
,
2299 (int)nMax
, SQLITE_TRANSIENT
);
2300 s3jni_jbytearray_release(baData
, pBuf
);
2304 S3JniApi(sqlite3_text16(),jint
,1bind_1text16
)(
2305 JniArgsEnvClass
, jobject jpStmt
, jint ndx
, jbyteArray baData
, jint nMax
2307 jbyte
* const pBuf
= baData
? s3jni_jbytearray_bytes(baData
) : 0;
2308 int const rc
= sqlite3_bind_text16(PtrGet_sqlite3_stmt(jpStmt
), (int)ndx
,
2309 pBuf
, (int)nMax
, SQLITE_TRANSIENT
);
2310 s3jni_jbytearray_release(baData
, pBuf
);
2314 S3JniApi(sqlite3_bind_zeroblob(),jint
,1bind_1zeroblob
)(
2315 JniArgsEnvClass
, jobject jpStmt
, jint ndx
, jint n
2317 return (jint
)sqlite3_bind_zeroblob(PtrGet_sqlite3_stmt(jpStmt
), (int)ndx
, (int)n
);
2320 S3JniApi(sqlite3_bind_zeroblob(),jint
,1bind_1zeroblob64
)(
2321 JniArgsEnvClass
, jobject jpStmt
, jint ndx
, jlong n
2323 return (jint
)sqlite3_bind_zeroblob(PtrGet_sqlite3_stmt(jpStmt
), (int)ndx
, (sqlite3_uint64
)n
);
2326 /* Central C-to-Java busy handler proxy. */
2327 static int s3jni_busy_handler(void* pState
, int n
){
2328 S3JniDb
* const ps
= (S3JniDb
*)pState
;
2333 S3JniHook_localdup(&ps
->hooks
.busyHandler
, &hook
);
2335 rc
= (*env
)->CallIntMethod(env
, hook
.jObj
,
2336 hook
.midCallback
, (jint
)n
);
2338 S3JniExceptionWarnCallbackThrew("sqlite3_busy_handler() callback");
2339 rc
= s3jni_db_exception(ps
, SQLITE_ERROR
,
2340 "sqlite3_busy_handler() callback threw.");
2342 S3JniHook_localundup(hook
);
2347 S3JniApi(sqlite3_busy_handler(),jint
,1busy_1handler
)(
2348 JniArgsEnvClass
, jobject jDb
, jobject jBusy
2350 S3JniDb
* const ps
= S3JniDb_from_java(jDb
);
2351 S3JniHook
* const pHook
= ps
? &ps
->hooks
.busyHandler
: 0;
2352 S3JniHook hook
= S3JniHook_empty
;
2355 if( !ps
) return (jint
)SQLITE_MISUSE
;
2356 S3JniDb_mutex_enter
;
2358 if( pHook
->jObj
&& (*env
)->IsSameObject(env
, pHook
->jObj
, jBusy
) ){
2359 /* Same object - this is a no-op. */
2361 jclass
const klazz
= (*env
)->GetObjectClass(env
, jBusy
);
2362 hook
.jObj
= S3JniRefGlobal(jBusy
);
2363 hook
.midCallback
= (*env
)->GetMethodID(env
, klazz
, "call", "(I)I");
2364 S3JniUnrefLocal(klazz
);
2372 if( hook
.jObj
){ /* Replace handler */
2373 rc
= sqlite3_busy_handler(ps
->pDb
, s3jni_busy_handler
, ps
);
2375 S3JniHook_unref(pHook
);
2377 hook
= S3JniHook_empty
;
2380 }else{ /* Clear handler */
2381 rc
= sqlite3_busy_handler(ps
->pDb
, 0, 0);
2383 S3JniHook_unref(pHook
);
2387 S3JniHook_unref(&hook
);
2388 S3JniDb_mutex_leave
;
2392 S3JniApi(sqlite3_busy_timeout(),jint
,1busy_1timeout
)(
2393 JniArgsEnvClass
, jobject jDb
, jint ms
2395 S3JniDb
* const ps
= S3JniDb_from_java(jDb
);
2396 int rc
= SQLITE_MISUSE
;
2398 S3JniDb_mutex_enter
;
2399 S3JniHook_unref(&ps
->hooks
.busyHandler
);
2400 rc
= sqlite3_busy_timeout(ps
->pDb
, (int)ms
);
2401 S3JniDb_mutex_leave
;
2406 S3JniApi(sqlite3_cancel_auto_extension(),jboolean
,1cancel_1auto_1extension
)(
2407 JniArgsEnvClass
, jobject jAutoExt
2409 S3JniAutoExtension
* ax
;
2410 jboolean rc
= JNI_FALSE
;
2412 S3JniAutoExt_mutex_enter
;
2413 /* This algo mirrors the one in the core. */
2414 for( i
= SJG
.autoExt
.nExt
-1; i
>= 0; --i
){
2415 ax
= &SJG
.autoExt
.aExt
[i
];
2416 if( ax
->jObj
&& (*env
)->IsSameObject(env
, ax
->jObj
, jAutoExt
) ){
2417 S3JniAutoExtension_clear(ax
);
2418 /* Move final entry into this slot. */
2420 *ax
= SJG
.autoExt
.aExt
[SJG
.autoExt
.nExt
];
2421 SJG
.autoExt
.aExt
[SJG
.autoExt
.nExt
] = S3JniHook_empty
;
2422 assert( !SJG
.autoExt
.aExt
[SJG
.autoExt
.nExt
].jObj
);
2427 S3JniAutoExt_mutex_leave
;
2432 /* Wrapper for sqlite3_close(_v2)(). */
2433 static jint
s3jni_close_db(JNIEnv
* const env
, jobject jDb
, int version
){
2435 S3JniDb
* const ps
= S3JniDb_from_java(jDb
);
2437 assert(version
== 1 || version
== 2);
2440 ? (jint
)sqlite3_close(ps
->pDb
)
2441 : (jint
)sqlite3_close_v2(ps
->pDb
);
2443 NativePointerHolder_set(&S3JniNphRefs
.sqlite3
, jDb
, 0);
2449 S3JniApi(sqlite3_close_v2(),jint
,1close_1v2
)(
2450 JniArgsEnvClass
, jobject pDb
2452 return s3jni_close_db(env
, pDb
, 2);
2455 S3JniApi(sqlite3_close(),jint
,1close
)(
2456 JniArgsEnvClass
, jobject pDb
2458 return s3jni_close_db(env
, pDb
, 1);
2462 ** Assumes z is an array of unsigned short and returns the index in
2463 ** that array of the first element with the value 0.
2465 static unsigned int s3jni_utf16_strlen(void const * z
){
2467 const unsigned short * p
= z
;
2472 /* Descriptive alias for use with sqlite3_collation_needed(). */
2473 typedef S3JniHook S3JniCollationNeeded
;
2475 /* Central C-to-Java sqlite3_collation_needed16() hook impl. */
2476 static void s3jni_collation_needed_impl16(void *pState
, sqlite3
*pDb
,
2477 int eTextRep
, const void * z16Name
){
2478 S3JniCollationNeeded
* const pHook
= pState
;
2482 S3JniHook_localdup(pHook
, &hook
);
2484 unsigned int const nName
= s3jni_utf16_strlen(z16Name
);
2485 jstring jName
= (*env
)->NewString(env
, (jchar
const *)z16Name
, nName
);
2487 s3jni_oom_check( jName
);
2488 assert( hook
.jExtra
);
2490 S3JniExceptionClear
;
2491 }else if( hook
.jExtra
){
2492 (*env
)->CallVoidMethod(env
, hook
.jObj
, hook
.midCallback
,
2493 hook
.jExtra
, (jint
)eTextRep
, jName
);
2495 S3JniExceptionWarnCallbackThrew("sqlite3_collation_needed() callback");
2498 S3JniUnrefLocal(jName
);
2499 S3JniHook_localundup(hook
);
2503 S3JniApi(sqlite3_collation_needed(),jint
,1collation_1needed
)(
2504 JniArgsEnvClass
, jobject jDb
, jobject jHook
2507 S3JniCollationNeeded
* pHook
;
2510 S3JniDb_mutex_enter
;
2511 ps
= S3JniDb_from_java(jDb
);
2513 S3JniDb_mutex_leave
;
2514 return SQLITE_MISUSE
;
2516 pHook
= &ps
->hooks
.collationNeeded
;
2517 if( pHook
->jObj
&& jHook
&&
2518 (*env
)->IsSameObject(env
, pHook
->jObj
, jHook
) ){
2521 rc
= sqlite3_collation_needed(ps
->pDb
, 0, 0);
2523 S3JniHook_unref(pHook
);
2526 jclass
const klazz
= (*env
)->GetObjectClass(env
, jHook
);
2527 jmethodID
const xCallback
= (*env
)->GetMethodID(
2528 env
, klazz
, "call", "(Lorg/sqlite/jni/sqlite3;ILjava/lang/String;)I"
2530 S3JniUnrefLocal(klazz
);
2532 rc
= s3jni_db_exception(ps
, SQLITE_MISUSE
,
2533 "Cannot not find matching call() in "
2534 "CollationNeededCallback object.");
2536 rc
= sqlite3_collation_needed16(ps
->pDb
, pHook
, s3jni_collation_needed_impl16
);
2538 S3JniHook_unref(pHook
);
2539 pHook
->midCallback
= xCallback
;
2540 pHook
->jObj
= S3JniRefGlobal(jHook
);
2541 pHook
->jExtra
= S3JniRefGlobal(ps
->jDb
);
2545 S3JniDb_mutex_leave
;
2549 S3JniApi(sqlite3_column_blob(),jbyteArray
,1column_1blob
)(
2550 JniArgsEnvClass
, jobject jpStmt
, jint ndx
2552 sqlite3_stmt
* const pStmt
= PtrGet_sqlite3_stmt(jpStmt
);
2553 void const * const p
= sqlite3_column_blob(pStmt
, (int)ndx
);
2554 int const n
= p
? sqlite3_column_bytes(pStmt
, (int)ndx
) : 0;
2556 return p
? s3jni_new_jbyteArray(p
, n
) : 0;
2559 S3JniApi(sqlite3_column_double(),jdouble
,1column_1double
)(
2560 JniArgsEnvClass
, jobject jpStmt
, jint ndx
2562 return (jdouble
)sqlite3_column_double(PtrGet_sqlite3_stmt(jpStmt
), (int)ndx
);
2565 S3JniApi(sqlite3_column_int(),jint
,1column_1int
)(
2566 JniArgsEnvClass
, jobject jpStmt
, jint ndx
2568 return (jint
)sqlite3_column_int(PtrGet_sqlite3_stmt(jpStmt
), (int)ndx
);
2571 S3JniApi(sqlite3_column_int64(),jlong
,1column_1int64
)(
2572 JniArgsEnvClass
, jobject jpStmt
, jint ndx
2574 return (jlong
)sqlite3_column_int64(PtrGet_sqlite3_stmt(jpStmt
), (int)ndx
);
2577 S3JniApi(sqlite3_column_text(),jbyteArray
,1column_1text_1utf8
)(
2578 JniArgsEnvClass
, jobject jpStmt
, jint ndx
2580 sqlite3_stmt
* const stmt
= PtrGet_sqlite3_stmt(jpStmt
);
2581 const int n
= sqlite3_column_bytes(stmt
, (int)ndx
);
2582 const unsigned char * const p
= sqlite3_column_text(stmt
, (int)ndx
);
2583 return p
? s3jni_new_jbyteArray(p
, n
) : NULL
;
2586 S3JniApi(sqlite3_column_text(),jstring
,1column_1text
)(
2587 JniArgsEnvClass
, jobject jpStmt
, jint ndx
2589 sqlite3_stmt
* const stmt
= PtrGet_sqlite3_stmt(jpStmt
);
2590 const int n
= sqlite3_column_bytes(stmt
, (int)ndx
);
2591 const unsigned char * const p
= sqlite3_column_text(stmt
, (int)ndx
);
2592 return p
? s3jni_utf8_to_jstring( (const char *)p
, n
) : 0;
2595 S3JniApi(sqlite3_column_text16(),jstring
,1column_1text16
)(
2596 JniArgsEnvClass
, jobject jpStmt
, jint ndx
2598 sqlite3_stmt
* const stmt
= PtrGet_sqlite3_stmt(jpStmt
);
2599 const int n
= sqlite3_column_bytes16(stmt
, (int)ndx
);
2600 const void * const p
= sqlite3_column_text16(stmt
, (int)ndx
);
2601 return s3jni_text16_to_jstring(env
, p
, n
);
2604 S3JniApi(sqlite3_column_value(),jobject
,1column_1value
)(
2605 JniArgsEnvClass
, jobject jpStmt
, jint ndx
2607 sqlite3_value
* const sv
=
2608 sqlite3_column_value(PtrGet_sqlite3_stmt(jpStmt
), (int)ndx
);
2609 return new_sqlite3_value_wrapper(env
, sv
);
2613 ** Impl for both commit hooks (if isCommit is true) or rollback hooks.
2615 static int s3jni_commit_rollback_hook_impl(int isCommit
, S3JniDb
* const ps
){
2620 S3JniHook_localdup(isCommit
2621 ? &ps
->hooks
.commit
: &ps
->hooks
.rollback
,
2625 ? (int)(*env
)->CallIntMethod(env
, hook
.jObj
, hook
.midCallback
)
2626 : (int)((*env
)->CallVoidMethod(env
, hook
.jObj
, hook
.midCallback
), 0);
2628 S3JniExceptionClear
;
2629 rc
= s3jni_db_error(ps
->pDb
, SQLITE_ERROR
, "hook callback threw.");
2631 S3JniHook_localundup(hook
);
2636 /* C-to-Java commit hook wrapper. */
2637 static int s3jni_commit_hook_impl(void *pP
){
2638 return s3jni_commit_rollback_hook_impl(1, pP
);
2641 /* C-to-Java rollback hook wrapper. */
2642 static void s3jni_rollback_hook_impl(void *pP
){
2643 (void)s3jni_commit_rollback_hook_impl(0, pP
);
2646 static jobject
s3jni_commit_rollback_hook(int isCommit
, JNIEnv
* const env
,
2647 jobject jDb
, jobject jHook
){
2652 S3JniDb_mutex_enter
;
2653 ps
= S3JniDb_from_java(jDb
);
2655 s3jni_db_error(ps
->pDb
, SQLITE_NOMEM
, 0);
2656 S3JniDb_mutex_leave
;
2659 pHook
= isCommit
? &ps
->hooks
.commit
: &ps
->hooks
.rollback
;
2661 if( pOld
&& jHook
&&
2662 (*env
)->IsSameObject(env
, pOld
, jHook
) ){
2666 jobject tmp
= S3JniRefLocal(pOld
);
2667 S3JniUnrefGlobal(pOld
);
2670 *pHook
= S3JniHook_empty
;
2671 if( isCommit
) sqlite3_commit_hook(ps
->pDb
, 0, 0);
2672 else sqlite3_rollback_hook(ps
->pDb
, 0, 0);
2674 jclass
const klazz
= (*env
)->GetObjectClass(env
, jHook
);
2675 jmethodID
const xCallback
= (*env
)->GetMethodID(env
, klazz
, "call",
2676 isCommit
? "()I" : "()V");
2677 S3JniUnrefLocal(klazz
);
2679 S3JniExceptionReport
;
2680 S3JniExceptionClear
;
2681 s3jni_db_error(ps
->pDb
, SQLITE_ERROR
,
2682 "Cannot not find matching call() in"
2685 pHook
->midCallback
= xCallback
;
2686 pHook
->jObj
= S3JniRefGlobal(jHook
);
2687 if( isCommit
) sqlite3_commit_hook(ps
->pDb
, s3jni_commit_hook_impl
, ps
);
2688 else sqlite3_rollback_hook(ps
->pDb
, s3jni_rollback_hook_impl
, ps
);
2690 jobject tmp
= S3JniRefLocal(pOld
);
2691 S3JniUnrefGlobal(pOld
);
2696 S3JniDb_mutex_leave
;
2700 S3JniApi(sqlite3_commit_hook(),jobject
,1commit_1hook
)(
2701 JniArgsEnvClass
,jobject jDb
, jobject jHook
2703 return s3jni_commit_rollback_hook(1, env
, jDb
, jHook
);
2706 S3JniApi(sqlite3_compileoption_get(),jstring
,1compileoption_1get
)(
2707 JniArgsEnvClass
, jint n
2709 jstring
const rv
= (*env
)->NewStringUTF( env
, sqlite3_compileoption_get(n
) )
2710 /* We know these to be ASCII, so MUTF-8 is fine. */;
2711 s3jni_oom_check(rv
);
2715 S3JniApi(sqlite3_compileoption_used(),jboolean
,1compileoption_1used
)(
2716 JniArgsEnvClass
, jstring name
2718 const char *zUtf8
= s3jni_jstring_to_mutf8(name
)
2719 /* We know these to be ASCII, so MUTF-8 is fine. */;
2721 0==sqlite3_compileoption_used(zUtf8
) ? JNI_FALSE
: JNI_TRUE
;
2722 s3jni_mutf8_release(name
, zUtf8
);
2726 S3JniApi(sqlite3_config() /*for a small subset of options.*/,
2727 jint
,1config__I
)(JniArgsEnvClass
, jint n
){
2729 case SQLITE_CONFIG_SINGLETHREAD
:
2730 case SQLITE_CONFIG_MULTITHREAD
:
2731 case SQLITE_CONFIG_SERIALIZED
:
2732 return sqlite3_config( n
);
2734 return SQLITE_MISUSE
;
2738 #ifdef SQLITE_ENABLE_SQLLOG
2739 /* C-to-Java SQLITE_CONFIG_SQLLOG wrapper. */
2740 static void s3jni_config_sqllog(void *ignored
, sqlite3
*pDb
, const char *z
, int op
){
2744 S3JniDb
* const ps
= S3JniDb_from_c(pDb
);
2745 S3JniHook hook
= S3JniHook_empty
;
2748 S3JniHook_localdup(&SJG
.hooks
.sqllog
, &hook
);
2750 if( !hook
.jObj
) return;
2751 jArg0
= S3JniRefLocal(ps
->jDb
);
2753 case 0: /* db opened */
2754 case 1: /* SQL executed */
2755 jArg1
= s3jni_utf8_to_jstring( z
, -1);
2757 case 2: /* db closed */
2760 (*env
)->FatalError(env
, "Unhandled 4th arg to SQLITE_CONFIG_SQLLOG.");
2763 (*env
)->CallVoidMethod(env
, hook
.jObj
, hook
.midCallback
, jArg0
, jArg1
, op
);
2765 S3JniExceptionWarnCallbackThrew("SQLITE_CONFIG_SQLLOG callback");
2766 S3JniExceptionClear
;
2768 S3JniHook_localundup(hook
);
2769 S3JniUnrefLocal(jArg0
);
2770 S3JniUnrefLocal(jArg1
);
2772 //! Requirement of SQLITE_CONFIG_SQLLOG.
2773 void sqlite3_init_sqllog(void){
2774 sqlite3_config( SQLITE_CONFIG_SQLLOG
, s3jni_config_sqllog
, 0 );
2778 S3JniApi(sqlite3_config() /* for SQLLOG */,
2779 jint
, 1config__Lorg_sqlite_jni_ConfigSqllogCallback_2
)(
2780 JniArgsEnvClass
, jobject jLog
2782 #ifndef SQLITE_ENABLE_SQLLOG
2783 return SQLITE_MISUSE
;
2785 S3JniHook
* const pHook
= &SJG
.hooks
.sqllog
;
2788 S3JniGlobal_mutex_enter
;
2790 rc
= sqlite3_config( SQLITE_CONFIG_SQLLOG
, s3jni_config_sqllog
, 0 );
2792 S3JniHook_unref(pHook
);
2794 }else if( pHook
->jObj
&& (*env
)->IsSameObject(env
, jLog
, pHook
->jObj
) ){
2797 jclass
const klazz
= (*env
)->GetObjectClass(env
, jLog
);
2798 jmethodID
const midCallback
= (*env
)->GetMethodID(env
, klazz
, "call",
2799 "(Lorg/sqlite/jni/sqlite3;"
2800 "Ljava/lang/String;"
2802 S3JniUnrefLocal(klazz
);
2804 rc
= sqlite3_config( SQLITE_CONFIG_SQLLOG
, s3jni_config_sqllog
, 0 );
2806 S3JniHook_unref(pHook
);
2807 pHook
->midCallback
= midCallback
;
2808 pHook
->jObj
= S3JniRefGlobal(jLog
);
2811 S3JniExceptionWarnIgnore
;
2815 S3JniGlobal_mutex_leave
;
2820 S3JniApi(sqlite3_context_db_handle(),jobject
,1context_1db_1handle
)(
2821 JniArgsEnvClass
, jobject jpCx
2823 sqlite3_context
* const pCx
= PtrGet_sqlite3_context(jpCx
);
2824 sqlite3
* const pDb
= pCx
? sqlite3_context_db_handle(pCx
) : 0;
2825 S3JniDb
* const ps
= pDb
? S3JniDb_from_c(pDb
) : 0;
2826 return ps
? ps
->jDb
: 0;
2830 State for CollationCallbacks.
2832 typedef S3JniHook S3JniCollationCallback
;
2835 ** Proxy for Java-side CollationCallback.xCompare() callbacks.
2837 static int CollationCallback_xCompare(void *pArg
, int nLhs
, const void *lhs
,
2838 int nRhs
, const void *rhs
){
2839 S3JniCollationCallback
* const pCC
= pArg
;
2843 jbyteArray jbaLhs
= s3jni_new_jbyteArray(lhs
, (jint
)nLhs
);
2844 jbyteArray jbaRhs
= jbaLhs
2845 ? s3jni_new_jbyteArray(rhs
, (jint
)nRhs
) : 0;
2847 S3JniUnrefLocal(jbaLhs
);
2848 /* We have no recovery strategy here. */
2849 s3jni_oom_check( jbaRhs
);
2852 rc
= (*env
)->CallIntMethod(env
, pCC
->jObj
, pCC
->midCallback
,
2854 S3JniExceptionIgnore
;
2855 S3JniUnrefLocal(jbaLhs
);
2856 S3JniUnrefLocal(jbaRhs
);
2861 /* CollationCallback finalizer for use by the sqlite3 internals. */
2862 static void CollationCallback_xDestroy(void *pArg
){
2863 S3JniCollationCallback
* const pCC
= pArg
;
2865 S3JniHook_free(pCC
);
2868 S3JniApi(sqlite3_create_collation() sqlite3_create_collation_v2(),
2869 jint
,1create_1collation
2870 )(JniArgsEnvClass
, jobject jDb
, jstring name
, jint eTextRep
,
2871 jobject oCollation
){
2875 S3JniDb_mutex_enter
;
2876 ps
= S3JniDb_from_java(jDb
);
2880 jclass
const klazz
= (*env
)->GetObjectClass(env
, oCollation
);
2881 jmethodID
const midCallback
=
2882 (*env
)->GetMethodID(env
, klazz
, "call", "([B[B)I");
2883 S3JniUnrefLocal(klazz
);
2885 rc
= s3jni_db_error(ps
->pDb
, SQLITE_ERROR
,
2886 "Could not get call() method from "
2887 "CollationCallback object.");
2889 char * const zName
= s3jni_jstring_to_utf8( name
, 0);
2890 S3JniCollationCallback
* const pCC
=
2891 zName
? S3JniHook_alloc() : 0;
2893 rc
= sqlite3_create_collation_v2(ps
->pDb
, zName
, (int)eTextRep
,
2894 pCC
, CollationCallback_xCompare
,
2895 CollationCallback_xDestroy
);
2897 pCC
->midCallback
= midCallback
;
2898 pCC
->jObj
= S3JniRefGlobal(oCollation
);
2899 pCC
->doXDestroy
= 1;
2901 CollationCallback_xDestroy(pCC
);
2906 sqlite3_free(zName
);
2909 S3JniDb_mutex_leave
;
2913 S3JniApi(sqlite3_create_function() sqlite3_create_function_v2() sqlite3_create_window_function(),
2914 jint
,1create_1function
2915 )(JniArgsEnvClass
, jobject jDb
, jstring jFuncName
, jint nArg
,
2916 jint eTextRep
, jobject jFunctor
){
2919 sqlite3
* const pDb
= PtrGet_sqlite3(jDb
);
2920 char * zFuncName
= 0;
2922 if( !encodingTypeIsValid(eTextRep
) ){
2923 return s3jni_db_error(pDb
, SQLITE_FORMAT
,
2924 "Invalid function encoding option.");
2926 s
= S3JniUdf_alloc(env
, jFunctor
);
2927 if( !s
) return SQLITE_NOMEM
;
2929 if( UDF_UNKNOWN_TYPE
==s
->type
){
2930 rc
= s3jni_db_error(pDb
, SQLITE_MISUSE
,
2931 "Cannot unambiguously determine function type.");
2932 S3JniUdf_free(env
, s
, 1);
2935 zFuncName
= s3jni_jstring_to_utf8(jFuncName
,0);
2938 S3JniUdf_free(env
, s
, 1);
2941 if( UDF_WINDOW
== s
->type
){
2942 rc
= sqlite3_create_window_function(pDb
, zFuncName
, nArg
, eTextRep
, s
,
2943 udf_xStep
, udf_xFinal
, udf_xValue
,
2944 udf_xInverse
, S3JniUdf_finalizer
);
2946 udf_xFunc_f xFunc
= 0;
2947 udf_xStep_f xStep
= 0;
2948 udf_xFinal_f xFinal
= 0;
2949 if( UDF_SCALAR
== s
->type
){
2952 assert( UDF_AGGREGATE
== s
->type
);
2954 xFinal
= udf_xFinal
;
2956 rc
= sqlite3_create_function_v2(pDb
, zFuncName
, nArg
, eTextRep
, s
,
2957 xFunc
, xStep
, xFinal
, S3JniUdf_finalizer
);
2960 /* Reminder: on sqlite3_create_function() error, s will be
2961 ** destroyed via create_function(). */
2962 sqlite3_free(zFuncName
);
2966 S3JniApi(sqlite3_db_filename(),jstring
,1db_1filename
)(
2967 JniArgsEnvClass
, jobject jDb
, jstring jDbName
2969 S3JniDb
* const ps
= S3JniDb_from_java(jDb
);
2974 if( !ps
|| !jDbName
){
2977 zDbName
= s3jni_jstring_to_utf8( jDbName
, &nStr
);
2979 char const * zRv
= sqlite3_db_filename(ps
->pDb
, zDbName
);
2980 sqlite3_free(zDbName
);
2982 jRv
= s3jni_utf8_to_jstring( zRv
, -1);
2988 S3JniApi(sqlite3_db_handle(),jobject
,1db_1handle
)(
2989 JniArgsEnvClass
, jobject jpStmt
2991 sqlite3_stmt
* const pStmt
= PtrGet_sqlite3_stmt(jpStmt
);
2992 sqlite3
* const pDb
= pStmt
? sqlite3_db_handle(pStmt
) : 0;
2993 S3JniDb
* const ps
= pDb
? S3JniDb_from_c(pDb
) : 0;
2994 return ps
? ps
->jDb
: 0;
2997 S3JniApi(sqlite3_db_config() /*for MAINDBNAME*/,
2998 jint
,1db_1config__Lorg_sqlite_jni_sqlite3_2ILjava_lang_String_2
2999 )(JniArgsEnvClass
, jobject jDb
, jint op
, jstring jStr
){
3000 S3JniDb
* const ps
= S3JniDb_from_java(jDb
);
3004 switch( (ps
&& jStr
) ? op
: 0 ){
3005 case SQLITE_DBCONFIG_MAINDBNAME
:
3007 /* Protect against a race in modifying/freeing
3008 ps->zMainDbName. */;
3009 zStr
= s3jni_jstring_to_utf8( jStr
, 0);
3011 rc
= sqlite3_db_config(ps
->pDb
, (int)op
, zStr
);
3013 sqlite3_free( zStr
);
3015 sqlite3_free( ps
->zMainDbName
);
3016 ps
->zMainDbName
= zStr
;
3021 S3JniDb_mutex_leave
;
3030 sqlite3_db_config(),
3031 /* WARNING: openjdk v19 creates a different mangled name for this
3032 ** function than openjdk v8 does. We account for that by exporting
3033 ** both versions of the name. */
3034 jint
,1db_1config__Lorg_sqlite_jni_sqlite3_2IILorg_sqlite_jni_OutputPointer_Int32_2
3036 JniArgsEnvClass
, jobject jDb
, jint op
, jint onOff
, jobject jOut
3038 S3JniDb
* const ps
= S3JniDb_from_java(jDb
);
3040 switch( ps
? op
: 0 ){
3041 case SQLITE_DBCONFIG_ENABLE_FKEY
:
3042 case SQLITE_DBCONFIG_ENABLE_TRIGGER
:
3043 case SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
:
3044 case SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
:
3045 case SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
:
3046 case SQLITE_DBCONFIG_ENABLE_QPSG
:
3047 case SQLITE_DBCONFIG_TRIGGER_EQP
:
3048 case SQLITE_DBCONFIG_RESET_DATABASE
:
3049 case SQLITE_DBCONFIG_DEFENSIVE
:
3050 case SQLITE_DBCONFIG_WRITABLE_SCHEMA
:
3051 case SQLITE_DBCONFIG_LEGACY_ALTER_TABLE
:
3052 case SQLITE_DBCONFIG_DQS_DML
:
3053 case SQLITE_DBCONFIG_DQS_DDL
:
3054 case SQLITE_DBCONFIG_ENABLE_VIEW
:
3055 case SQLITE_DBCONFIG_LEGACY_FILE_FORMAT
:
3056 case SQLITE_DBCONFIG_TRUSTED_SCHEMA
:
3057 case SQLITE_DBCONFIG_STMT_SCANSTATUS
:
3058 case SQLITE_DBCONFIG_REVERSE_SCANORDER
: {
3060 rc
= sqlite3_db_config( ps
->pDb
, (int)op
, onOff
, &pOut
);
3061 if( 0==rc
&& jOut
){
3062 OutputPointer_set_Int32(env
, jOut
, pOut
);
3073 ** This is a workaround for openjdk v19 (and possibly others) encoding
3074 ** this function's name differently than JDK v8 does. If we do not
3075 ** install both names for this function then Java will not be able to
3076 ** find the function in both environments.
3078 JniDecl(jint
,1db_1config__Lorg_sqlite_jni_sqlite3_2IILorg_sqlite_jni_OutputPointer_00024Int32_2
)(
3079 JniArgsEnvClass
, jobject jDb
, jint op
, jint onOff
, jobject jOut
3081 return JniFuncName(1db_1config__Lorg_sqlite_jni_sqlite3_2IILorg_sqlite_jni_OutputPointer_Int32_2
)(
3082 env
, jKlazz
, jDb
, op
, onOff
, jOut
3086 S3JniApi(sqlite3_db_release_memory(),int,1db_1release_1memory
)(
3087 JniArgsEnvClass
, jobject jDb
3089 sqlite3
* const pDb
= PtrGet_sqlite3(jDb
);
3090 return pDb
? sqlite3_db_release_memory(pDb
) : SQLITE_MISUSE
;
3093 S3JniApi(sqlite3_db_status(),jint
,1db_1status
)(
3094 JniArgsEnvClass
, jobject jDb
, jint op
, jobject jOutCurrent
,
3095 jobject jOutHigh
, jboolean reset
3097 int iCur
= 0, iHigh
= 0;
3098 sqlite3
* const pDb
= PtrGet_sqlite3(jDb
);
3099 int rc
= sqlite3_db_status( pDb
, op
, &iCur
, &iHigh
, reset
);
3101 OutputPointer_set_Int32(env
, jOutCurrent
, iCur
);
3102 OutputPointer_set_Int32(env
, jOutHigh
, iHigh
);
3107 S3JniApi(sqlite3_errcode(),jint
,1errcode
)(
3108 JniArgsEnvClass
, jobject jpDb
3110 sqlite3
* const pDb
= PtrGet_sqlite3(jpDb
);
3111 return pDb
? sqlite3_errcode(pDb
) : SQLITE_MISUSE
;
3114 S3JniApi(sqlite3_errmsg(),jstring
,1errmsg
)(
3115 JniArgsEnvClass
, jobject jpDb
3117 sqlite3
* const pDb
= PtrGet_sqlite3(jpDb
);
3118 return pDb
? s3jni_utf8_to_jstring( sqlite3_errmsg(pDb
), -1) : 0;
3121 S3JniApi(sqlite3_errstr(),jstring
,1errstr
)(
3122 JniArgsEnvClass
, jint rcCode
3124 jstring
const rv
= (*env
)->NewStringUTF(env
, sqlite3_errstr((int)rcCode
))
3125 /* We know these values to be plain ASCII, so pose no MUTF-8
3126 ** incompatibility */;
3127 s3jni_oom_check( rv
);
3131 S3JniApi(sqlite3_expanded_sql(),jstring
,1expanded_1sql
)(
3132 JniArgsEnvClass
, jobject jpStmt
3135 sqlite3_stmt
* const pStmt
= PtrGet_sqlite3_stmt(jpStmt
);
3137 char * zSql
= sqlite3_expanded_sql(pStmt
);
3138 s3jni_oom_fatal(zSql
);
3140 rv
= s3jni_utf8_to_jstring( zSql
, -1);
3147 S3JniApi(sqlite3_extended_result_codes(),jboolean
,1extended_1result_1codes
)(
3148 JniArgsEnvClass
, jobject jpDb
, jboolean onoff
3150 sqlite3
* const pDb
= PtrGet_sqlite3(jpDb
);
3151 int const rc
= pDb
? sqlite3_extended_result_codes(pDb
, onoff
? 1 : 0) : 0;
3152 return rc
? JNI_TRUE
: JNI_FALSE
;
3155 S3JniApi(sqlite3_finalize(),jint
,1finalize
)(
3156 JniArgsEnvClass
, jobject jpStmt
3159 sqlite3_stmt
* const pStmt
= PtrGet_sqlite3_stmt(jpStmt
);
3161 rc
= sqlite3_finalize(pStmt
);
3162 NativePointerHolder_set(&S3JniNphRefs
.sqlite3_stmt
, jpStmt
, 0);
3167 S3JniApi(sqlite3_initialize(),jint
,1initialize
)(
3170 return sqlite3_initialize();
3173 S3JniApi(sqlite3_interrupt(),void,1interrupt
)(
3174 JniArgsEnvClass
, jobject jpDb
3176 sqlite3
* const pDb
= PtrGet_sqlite3(jpDb
);
3178 sqlite3_interrupt(pDb
);
3182 S3JniApi(sqlite3_is_interrupted(),jboolean
,1is_1interrupted
)(
3183 JniArgsEnvClass
, jobject jpDb
3186 sqlite3
* const pDb
= PtrGet_sqlite3(jpDb
);
3188 rc
= sqlite3_is_interrupted(pDb
);
3190 return rc
? JNI_TRUE
: JNI_FALSE
;
3194 ** Uncaches the current JNIEnv from the S3JniGlobal state, clearing
3195 ** any resources owned by that cache entry and making that slot
3196 ** available for re-use.
3198 JniDecl(jboolean
,1java_1uncache_1thread
)(JniArgsEnvClass
){
3200 S3JniEnv_mutex_enter
;
3201 rc
= S3JniEnv_uncache(env
);
3202 S3JniEnv_mutex_leave
;
3203 return rc
? JNI_TRUE
: JNI_FALSE
;
3207 S3JniApi(sqlite3_last_insert_rowid(),jlong
,1last_
1insert_
1rowid
)(
3208 JniArgsEnvClass
, jobject jpDb
3211 sqlite3
* const pDb
= PtrGet_sqlite3(jpDb
);
3213 rc
= (jlong
)sqlite3_last_insert_rowid(pDb
);
3218 S3JniApi(sqlite3_limit(),jint
,1limit
)(
3219 JniArgsEnvClass
, jobject jpDb
, jint id
, jint newVal
3222 sqlite3
* const pDb
= PtrGet_sqlite3(jpDb
);
3224 rc
= sqlite3_limit( pDb
, (int)id
, (int)newVal
);
3229 /* Pre-open() code common to sqlite3_open[_v2](). */
3230 static int s3jni_open_pre(JNIEnv
* const env
, S3JniEnv
**jc
,
3231 jstring jDbName
, char **zDbName
,
3235 *jc
= S3JniEnv_get();
3240 *zDbName
= jDbName
? s3jni_jstring_to_utf8( jDbName
, 0) : 0;
3241 if( jDbName
&& !*zDbName
){
3245 jDb
= new_sqlite3_wrapper(env
, 0);
3247 sqlite3_free(*zDbName
);
3252 *ps
= S3JniDb_alloc(env
, jDb
);
3254 (*jc
)->pdbOpening
= *ps
;
3256 S3JniUnrefLocal(jDb
);
3264 ** Post-open() code common to both the sqlite3_open() and
3265 ** sqlite3_open_v2() bindings. ps->jDb must be the
3266 ** org.sqlite.jni.sqlite3 object which will hold the db's native
3267 ** pointer. theRc must be the result code of the open() op. If
3268 ** *ppDb is NULL then ps is set aside and its state cleared,
3269 ** else ps is associated with *ppDb. If *ppDb is not NULL then
3270 ** ps->jDb is stored in jOut (an OutputPointer.sqlite3 instance).
3272 ** Must be called if s3jni_open_pre() succeeds and must not be called
3277 static int s3jni_open_post(JNIEnv
* const env
, S3JniEnv
* const jc
,
3278 S3JniDb
* ps
, sqlite3
**ppDb
,
3279 jobject jOut
, int theRc
){
3286 NativePointerHolder_set(&S3JniNphRefs
.sqlite3
, ps
->jDb
, *ppDb
);
3288 assert( ps
->pDb
==*ppDb
3289 && "Set up via s3jni_run_java_auto_extensions()" );
3291 rc
= sqlite3_set_clientdata(ps
->pDb
, S3JniDb_clientdata_key
,
3292 ps
, S3JniDb_xDestroy
)
3293 /* As of here, the Java/C connection is complete */;
3295 S3JniDb_set_aside(ps
);
3298 OutputPointer_set_sqlite3(env
, jOut
, ps
? ps
->jDb
: 0);
3299 return theRc
? theRc
: rc
;
3302 S3JniApi(sqlite3_open(),jint
,1open
)(
3303 JniArgsEnvClass
, jstring strName
, jobject jOut
3310 rc
= s3jni_open_pre(env
, &jc
, strName
, &zName
, &ps
);
3312 rc
= s3jni_open_post(env
, jc
, ps
, &pOut
, jOut
,
3313 sqlite3_open(zName
, &pOut
));
3314 assert(rc
==0 ? pOut
!=0 : 1);
3315 sqlite3_free(zName
);
3320 S3JniApi(sqlite3_open_v2(),jint
,1open_1v2
)(
3321 JniArgsEnvClass
, jstring strName
,
3322 jobject jOut
, jint flags
, jstring strVfs
3329 int rc
= s3jni_open_pre(env
, &jc
, strName
, &zName
, &ps
);
3332 zVfs
= s3jni_jstring_to_utf8( strVfs
, 0);
3338 rc
= sqlite3_open_v2(zName
, &pOut
, (int)flags
, zVfs
);
3340 rc
= s3jni_open_post(env
, jc
, ps
, &pOut
, jOut
, rc
);
3342 assert(rc
==0 ? pOut
!=0 : 1);
3343 sqlite3_free(zName
);
3348 /* Proxy for the sqlite3_prepare[_v2/3]() family. */
3349 jint
sqlite3_jni_prepare_v123( int prepVersion
, JNIEnv
* const env
, jclass self
,
3350 jobject jDb
, jbyteArray baSql
,
3351 jint nMax
, jint prepFlags
,
3352 jobject jOutStmt
, jobject outTail
){
3353 sqlite3_stmt
* pStmt
= 0;
3355 const char * zTail
= 0;
3356 jbyte
* const pBuf
= s3jni_jbytearray_bytes(baSql
);
3357 int rc
= SQLITE_ERROR
;
3358 assert(prepVersion
==1 || prepVersion
==2 || prepVersion
==3);
3360 rc
= baSql
? SQLITE_NOMEM
: SQLITE_MISUSE
;
3363 jStmt
= new_sqlite3_stmt_wrapper(env
, 0);
3368 switch( prepVersion
){
3369 case 1: rc
= sqlite3_prepare(PtrGet_sqlite3(jDb
), (const char *)pBuf
,
3370 (int)nMax
, &pStmt
, &zTail
);
3372 case 2: rc
= sqlite3_prepare_v2(PtrGet_sqlite3(jDb
), (const char *)pBuf
,
3373 (int)nMax
, &pStmt
, &zTail
);
3375 case 3: rc
= sqlite3_prepare_v3(PtrGet_sqlite3(jDb
), (const char *)pBuf
,
3376 (int)nMax
, (unsigned int)prepFlags
,
3380 assert(0 && "Invalid prepare() version");
3383 s3jni_jbytearray_release(baSql
,pBuf
);
3386 /* Noting that pBuf is deallocated now but its address is all we need for
3387 ** what follows... */
3388 assert(zTail
? ((void*)zTail
>=(void*)pBuf
) : 1);
3389 assert(zTail
? (((int)((void*)zTail
- (void*)pBuf
)) >= 0) : 1);
3390 OutputPointer_set_Int32(env
, outTail
, (int)(zTail
? (zTail
- (const char *)pBuf
) : 0));
3393 NativePointerHolder_set(&S3JniNphRefs
.sqlite3_stmt
, jStmt
, pStmt
);
3395 /* Happens for comments and whitespace. */
3396 S3JniUnrefLocal(jStmt
);
3400 S3JniUnrefLocal(jStmt
);
3403 OutputPointer_set_sqlite3_stmt(env
, jOutStmt
, jStmt
);
3406 S3JniApi(sqlite3_prepare(),jint
,1prepare
)(
3407 JNIEnv
* const env
, jclass self
, jobject jDb
, jbyteArray baSql
,
3408 jint nMax
, jobject jOutStmt
, jobject outTail
3410 return sqlite3_jni_prepare_v123(1, env
, self
, jDb
, baSql
, nMax
, 0,
3413 S3JniApi(sqlite3_prepare_v2(),jint
,1prepare_1v2
)(
3414 JNIEnv
* const env
, jclass self
, jobject jDb
, jbyteArray baSql
,
3415 jint nMax
, jobject jOutStmt
, jobject outTail
3417 return sqlite3_jni_prepare_v123(2, env
, self
, jDb
, baSql
, nMax
, 0,
3420 S3JniApi(sqlite3_prepare_v3(),jint
,1prepare_1v3
)(
3421 JNIEnv
* const env
, jclass self
, jobject jDb
, jbyteArray baSql
,
3422 jint nMax
, jint prepFlags
, jobject jOutStmt
, jobject outTail
3424 return sqlite3_jni_prepare_v123(3, env
, self
, jDb
, baSql
, nMax
,
3425 prepFlags
, jOutStmt
, outTail
);
3429 ** Impl for C-to-Java of the callbacks for both sqlite3_update_hook()
3430 ** and sqlite3_preupdate_hook(). The differences are that for
3434 ** - iKey1 is the row ID
3435 ** - iKey2 is unused
3437 static void s3jni_updatepre_hook_impl(void * pState
, sqlite3
*pDb
, int opId
,
3438 const char *zDb
, const char *zTable
,
3439 sqlite3_int64 iKey1
, sqlite3_int64 iKey2
){
3440 S3JniDb
* const ps
= pState
;
3444 const int isPre
= 0!=pDb
;
3447 S3JniHook_localdup(isPre
?
3448 #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
3449 &ps
->hooks
.preUpdate
3453 : &ps
->hooks
.update
, &hook
);
3457 jDbName
= s3jni_utf8_to_jstring( zDb
, -1);
3458 jTable
= jDbName
? s3jni_utf8_to_jstring( zTable
, -1) : 0;
3460 S3JniExceptionClear
;
3461 s3jni_db_error(ps
->pDb
, SQLITE_NOMEM
, 0);
3463 assert( hook
.jObj
);
3464 assert( hook
.midCallback
);
3466 #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
3467 if( isPre
) (*env
)->CallVoidMethod(env
, hook
.jObj
, hook
.midCallback
,
3468 ps
->jDb
, (jint
)opId
, jDbName
, jTable
,
3469 (jlong
)iKey1
, (jlong
)iKey2
);
3472 (*env
)->CallVoidMethod(env
, hook
.jObj
, hook
.midCallback
,
3473 (jint
)opId
, jDbName
, jTable
, (jlong
)iKey1
);
3475 S3JniExceptionWarnCallbackThrew("sqlite3_(pre)update_hook() callback");
3476 s3jni_db_exception(ps
, 0,
3477 "sqlite3_(pre)update_hook() callback threw");
3480 S3JniUnrefLocal(jDbName
);
3481 S3JniUnrefLocal(jTable
);
3482 S3JniHook_localundup(hook
);
3485 #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
3486 static void s3jni_preupdate_hook_impl(void * pState
, sqlite3
*pDb
, int opId
,
3487 const char *zDb
, const char *zTable
,
3488 sqlite3_int64 iKey1
, sqlite3_int64 iKey2
){
3489 return s3jni_updatepre_hook_impl(pState
, pDb
, opId
, zDb
, zTable
,
3492 #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
3494 static void s3jni_update_hook_impl(void * pState
, int opId
, const char *zDb
,
3495 const char *zTable
, sqlite3_int64 nRowid
){
3496 return s3jni_updatepre_hook_impl(pState
, NULL
, opId
, zDb
, zTable
, nRowid
, 0);
3499 #ifndef SQLITE_ENABLE_PREUPDATE_HOOK
3500 /* We need no-op impls for preupdate_{count,depth,blobwrite}() */
3501 S3JniApi(sqlite3_preupdate_blobwrite(),int,1preupdate_1blobwrite
)(
3502 JniArgsEnvClass
, jobject jDb
){ return SQLITE_MISUSE
; }
3503 S3JniApi(sqlite3_preupdate_count(),int,1preupdate_1count
)(
3504 JniArgsEnvClass
, jobject jDb
){ return SQLITE_MISUSE
; }
3505 S3JniApi(sqlite3_preupdate_depth(),int,1preupdate_1depth
)(
3506 JniArgsEnvClass
, jobject jDb
){ return SQLITE_MISUSE
; }
3507 #endif /* !SQLITE_ENABLE_PREUPDATE_HOOK */
3510 ** JNI wrapper for both sqlite3_update_hook() and
3511 ** sqlite3_preupdate_hook() (if isPre is true).
3513 static jobject
s3jni_updatepre_hook(JNIEnv
* env
, int isPre
, jobject jDb
, jobject jHook
){
3514 S3JniDb
* const ps
= S3JniDb_from_java(jDb
);
3517 jmethodID xCallback
;
3521 S3JniDb_mutex_enter
;
3523 #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
3524 &ps
->hooks
.preUpdate
3528 : &ps
->hooks
.update
;
3533 if( pOld
&& jHook
&& (*env
)->IsSameObject(env
, pOld
, jHook
) ){
3538 jobject tmp
= S3JniRefLocal(pOld
);
3539 S3JniUnrefGlobal(pOld
);
3542 *pHook
= S3JniHook_empty
;
3543 #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
3544 if( isPre
) sqlite3_preupdate_hook(ps
->pDb
, 0, 0);
3547 sqlite3_update_hook(ps
->pDb
, 0, 0);
3550 klazz
= (*env
)->GetObjectClass(env
, jHook
);
3552 ? (*env
)->GetMethodID(env
, klazz
, "call",
3553 "(Lorg/sqlite/jni/sqlite3;"
3555 "Ljava/lang/String;"
3556 "Ljava/lang/String;"
3558 : (*env
)->GetMethodID(env
, klazz
, "call",
3559 "(ILjava/lang/String;Ljava/lang/String;J)V");
3560 S3JniUnrefLocal(klazz
);
3562 S3JniExceptionClear
;
3563 s3jni_db_error(ps
->pDb
, SQLITE_ERROR
,
3564 "Cannot not find matching callback on "
3565 "(pre)update hook object.");
3567 pHook
->midCallback
= xCallback
;
3568 pHook
->jObj
= S3JniRefGlobal(jHook
);
3569 #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
3570 if( isPre
) sqlite3_preupdate_hook(ps
->pDb
, s3jni_preupdate_hook_impl
, ps
);
3573 sqlite3_update_hook(ps
->pDb
, s3jni_update_hook_impl
, ps
);
3575 jobject tmp
= S3JniRefLocal(pOld
);
3576 S3JniUnrefGlobal(pOld
);
3581 S3JniDb_mutex_leave
;
3586 S3JniApi(sqlite3_preupdate_hook(),jobject
,1preupdate_1hook
)(
3587 JniArgsEnvClass
, jobject jDb
, jobject jHook
3589 #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
3590 return s3jni_updatepre_hook(env
, 1, jDb
, jHook
);
3593 #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
3596 /* Impl for sqlite3_preupdate_{new,old}(). */
3597 static int s3jni_preupdate_newold(JNIEnv
* const env
, int isNew
, jobject jDb
,
3598 jint iCol
, jobject jOut
){
3599 #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
3600 sqlite3
* const pDb
= PtrGet_sqlite3(jDb
);
3601 int rc
= SQLITE_MISUSE
;
3603 sqlite3_value
* pOut
= 0;
3604 int (*fOrig
)(sqlite3
*,int,sqlite3_value
**) =
3605 isNew
? sqlite3_preupdate_new
: sqlite3_preupdate_old
;
3606 rc
= fOrig(pDb
, (int)iCol
, &pOut
);
3608 jobject pWrap
= new_sqlite3_value_wrapper(env
, pOut
);
3610 OutputPointer_set_sqlite3_value(env
, jOut
, pWrap
);
3611 S3JniUnrefLocal(pWrap
);
3619 return SQLITE_MISUSE
;
3623 S3JniApi(sqlite3_preupdate_new(),jint
,1preupdate_1new
)(
3624 JniArgsEnvClass
, jobject jDb
, jint iCol
, jobject jOut
3626 return s3jni_preupdate_newold(env
, 1, jDb
, iCol
, jOut
);
3629 S3JniApi(sqlite3_preupdate_old(),jint
,1preupdate_1old
)(
3630 JniArgsEnvClass
, jobject jDb
, jint iCol
, jobject jOut
3632 return s3jni_preupdate_newold(env
, 0, jDb
, iCol
, jOut
);
3636 /* Central C-to-Java sqlite3_progress_handler() proxy. */
3637 static int s3jni_progress_handler_impl(void *pP
){
3638 S3JniDb
* const ps
= (S3JniDb
*)pP
;
3643 S3JniHook_localdup(&ps
->hooks
.progress
, &hook
);
3645 rc
= (int)(*env
)->CallIntMethod(env
, hook
.jObj
, hook
.midCallback
);
3647 rc
= s3jni_db_exception(ps
, rc
,
3648 "sqlite3_progress_handler() callback threw");
3650 S3JniHook_localundup(hook
);
3655 S3JniApi(sqlite3_progress_handler(),void,1progress_1handler
)(
3656 JniArgsEnvClass
,jobject jDb
, jint n
, jobject jProgress
3658 S3JniDb
* const ps
= S3JniDb_from_java(jDb
);
3659 S3JniHook
* const pHook
= ps
? &ps
->hooks
.progress
: 0;
3662 S3JniDb_mutex_enter
;
3663 if( n
<1 || !jProgress
){
3664 S3JniHook_unref(pHook
);
3665 sqlite3_progress_handler(ps
->pDb
, 0, 0, 0);
3667 jclass
const klazz
= (*env
)->GetObjectClass(env
, jProgress
);
3668 jmethodID
const xCallback
= (*env
)->GetMethodID(env
, klazz
, "call", "()I");
3669 S3JniUnrefLocal(klazz
);
3671 S3JniExceptionClear
;
3672 s3jni_db_error(ps
->pDb
, SQLITE_ERROR
,
3673 "Cannot not find matching xCallback() on "
3674 "ProgressHandler object.");
3676 S3JniUnrefGlobal(pHook
->jObj
);
3677 pHook
->midCallback
= xCallback
;
3678 pHook
->jObj
= S3JniRefGlobal(jProgress
);
3679 sqlite3_progress_handler(ps
->pDb
, (int)n
, s3jni_progress_handler_impl
, ps
);
3682 S3JniDb_mutex_leave
;
3685 S3JniApi(sqlite3_reset(),jint
,1reset
)(
3686 JniArgsEnvClass
, jobject jpStmt
3688 sqlite3_stmt
* const pStmt
= PtrGet_sqlite3_stmt(jpStmt
);
3689 return pStmt
? sqlite3_reset(pStmt
) : SQLITE_MISUSE
;
3692 /* Clears all entries from S3JniGlobal.autoExt. */
3693 static void s3jni_reset_auto_extension(JNIEnv
*env
){
3695 S3JniAutoExt_mutex_enter
;
3696 for( i
= 0; i
< SJG
.autoExt
.nExt
; ++i
){
3697 S3JniAutoExtension_clear( &SJG
.autoExt
.aExt
[i
] );
3699 SJG
.autoExt
.nExt
= 0;
3700 S3JniAutoExt_mutex_leave
;
3703 S3JniApi(sqlite3_reset_auto_extension(),void,1reset_1auto_1extension
)(
3706 s3jni_reset_auto_extension(env
);
3709 /* Impl for sqlite3_result_text/blob() and friends. */
3710 static void result_blob_text(int as64
/* true for text64/blob64() mode */,
3711 int eTextRep
/* 0 for blobs, else SQLITE_UTF... */,
3712 JNIEnv
* const env
, sqlite3_context
*pCx
,
3713 jbyteArray jBa
, jlong nMax
){
3714 int const asBlob
= 0==eTextRep
;
3716 jbyte
* const pBuf
= s3jni_jbytearray_bytes(jBa
);
3717 jsize nBa
= (*env
)->GetArrayLength(env
, jBa
);
3718 if( nMax
>=0 && nBa
>(jsize
)nMax
){
3721 From the sqlite docs:
3723 > If the 3rd parameter to any of the sqlite3_result_text*
3724 interfaces other than sqlite3_result_text64() is negative,
3725 then SQLite computes the string length itself by searching
3726 the 2nd parameter for the first zero character.
3728 Note that the text64() interfaces take an unsigned value for
3729 the length, which Java does not support. This binding takes
3730 the approach of passing on negative values to the C API,
3731 which will, in turn fail with SQLITE_TOOBIG at some later
3732 point (recall that the sqlite3_result_xyz() family do not
3733 have result values).
3736 if( as64
){ /* 64-bit... */
3737 static const jsize nLimit64
=
3738 SQLITE_MAX_ALLOCATION_SIZE
/*only _kinda_ arbitrary*/;
3739 if( nBa
> nLimit64
){
3740 sqlite3_result_error_toobig(pCx
);
3742 sqlite3_result_blob64(pCx
, pBuf
, (sqlite3_uint64
)nBa
,
3744 }else{ /* text64... */
3745 if( encodingTypeIsValid(eTextRep
) ){
3746 sqlite3_result_text64(pCx
, (const char *)pBuf
,
3747 (sqlite3_uint64
)nBa
,
3748 SQLITE_TRANSIENT
, eTextRep
);
3750 sqlite3_result_error_code(pCx
, SQLITE_FORMAT
);
3753 }else{ /* 32-bit... */
3754 static const jsize nLimit
= SQLITE_MAX_ALLOCATION_SIZE
;
3756 sqlite3_result_error_toobig(pCx
);
3758 sqlite3_result_blob(pCx
, pBuf
, (int)nBa
,
3763 sqlite3_result_text(pCx
, (const char *)pBuf
, (int)nBa
,
3767 sqlite3_result_text16(pCx
, (const char *)pBuf
, (int)nBa
,
3770 case SQLITE_UTF16LE
:
3771 sqlite3_result_text16le(pCx
, (const char *)pBuf
, (int)nBa
,
3774 case SQLITE_UTF16BE
:
3775 sqlite3_result_text16be(pCx
, (const char *)pBuf
, (int)nBa
,
3780 s3jni_jbytearray_release(jBa
, pBuf
);
3783 sqlite3_result_null(pCx
);
3787 S3JniApi(sqlite3_result_blob(),void,1result_1blob
)(
3788 JniArgsEnvClass
, jobject jpCx
, jbyteArray jBa
, jint nMax
3790 return result_blob_text(0, 0, env
, PtrGet_sqlite3_context(jpCx
), jBa
, nMax
);
3793 S3JniApi(sqlite3_result_blob64(),void,1result_1blob64
)(
3794 JniArgsEnvClass
, jobject jpCx
, jbyteArray jBa
, jlong nMax
3796 return result_blob_text(1, 0, env
, PtrGet_sqlite3_context(jpCx
), jBa
, nMax
);
3799 S3JniApi(sqlite3_result_double(),void,1result_1double
)(
3800 JniArgsEnvClass
, jobject jpCx
, jdouble v
3802 sqlite3_result_double(PtrGet_sqlite3_context(jpCx
), v
);
3805 S3JniApi(sqlite3_result_error(),void,1result_1error
)(
3806 JniArgsEnvClass
, jobject jpCx
, jbyteArray baMsg
, int eTextRep
3808 const char * zUnspecified
= "Unspecified error.";
3809 jsize
const baLen
= (*env
)->GetArrayLength(env
, baMsg
);
3810 jbyte
* const pjBuf
= baMsg
? s3jni_jbytearray_bytes(baMsg
) : NULL
;
3811 switch( pjBuf
? eTextRep
: SQLITE_UTF8
){
3813 const char *zMsg
= pjBuf
? (const char *)pjBuf
: zUnspecified
;
3814 int const n
= pjBuf
? (int)baLen
: (int)sqlite3Strlen30(zMsg
);
3815 sqlite3_result_error(PtrGet_sqlite3_context(jpCx
), zMsg
, n
);
3818 case SQLITE_UTF16
: {
3819 const void *zMsg
= pjBuf
;
3820 sqlite3_result_error16(PtrGet_sqlite3_context(jpCx
), zMsg
, (int)baLen
);
3824 sqlite3_result_error(PtrGet_sqlite3_context(jpCx
),
3825 "Invalid encoding argument passed "
3826 "to sqlite3_result_error().", -1);
3829 s3jni_jbytearray_release(baMsg
,pjBuf
);
3832 S3JniApi(sqlite3_result_error_code(),void,1result_1error_1code
)(
3833 JniArgsEnvClass
, jobject jpCx
, jint v
3835 sqlite3_result_error_code(PtrGet_sqlite3_context(jpCx
), (int)v
);
3838 S3JniApi(sqlite3_result_error_nomem(),void,1result_1error_1nomem
)(
3839 JniArgsEnvClass
, jobject jpCx
3841 sqlite3_result_error_nomem(PtrGet_sqlite3_context(jpCx
));
3844 S3JniApi(sqlite3_result_error_toobig(),void,1result_1error_1toobig
)(
3845 JniArgsEnvClass
, jobject jpCx
3847 sqlite3_result_error_toobig(PtrGet_sqlite3_context(jpCx
));
3850 S3JniApi(sqlite3_result_int(),void,1result_1int
)(
3851 JniArgsEnvClass
, jobject jpCx
, jint v
3853 sqlite3_result_int(PtrGet_sqlite3_context(jpCx
), (int)v
);
3856 S3JniApi(sqlite3_result_int64(),void,1result_1int64
)(
3857 JniArgsEnvClass
, jobject jpCx
, jlong v
3859 sqlite3_result_int64(PtrGet_sqlite3_context(jpCx
), (sqlite3_int64
)v
);
3862 S3JniApi(sqlite3_result_java_object(),void,1result_1java_1object
)(
3863 JniArgsEnvClass
, jobject jpCx
, jobject v
3866 jobject
const rjv
= S3JniRefGlobal(v
);
3868 sqlite3_result_pointer(PtrGet_sqlite3_context(jpCx
), rjv
,
3869 ResultJavaValuePtrStr
, ResultJavaValue_finalizer
);
3871 sqlite3_result_error_nomem(PtrGet_sqlite3_context(jpCx
));
3874 sqlite3_result_null(PtrGet_sqlite3_context(jpCx
));
3878 S3JniApi(sqlite3_result_null(),void,1result_1null
)(
3879 JniArgsEnvClass
, jobject jpCx
3881 sqlite3_result_null(PtrGet_sqlite3_context(jpCx
));
3884 S3JniApi(sqlite3_result_text(),void,1result_1text
)(
3885 JniArgsEnvClass
, jobject jpCx
, jbyteArray jBa
, jint nMax
3887 return result_blob_text(0, SQLITE_UTF8
, env
,
3888 PtrGet_sqlite3_context(jpCx
), jBa
, nMax
);
3891 S3JniApi(sqlite3_result_text64(),void,1result_1text64
)(
3892 JniArgsEnvClass
, jobject jpCx
, jbyteArray jBa
, jlong nMax
,
3895 return result_blob_text(1, eTextRep
, env
,
3896 PtrGet_sqlite3_context(jpCx
), jBa
, nMax
);
3899 S3JniApi(sqlite3_result_value(),void,1result_1value
)(
3900 JniArgsEnvClass
, jobject jpCx
, jobject jpSVal
3902 sqlite3_result_value(PtrGet_sqlite3_context(jpCx
),
3903 PtrGet_sqlite3_value(jpSVal
));
3906 S3JniApi(sqlite3_result_zeroblob(),void,1result_1zeroblob
)(
3907 JniArgsEnvClass
, jobject jpCx
, jint v
3909 sqlite3_result_zeroblob(PtrGet_sqlite3_context(jpCx
), (int)v
);
3912 S3JniApi(sqlite3_result_zeroblob64(),jint
,1result_1zeroblob64
)(
3913 JniArgsEnvClass
, jobject jpCx
, jlong v
3915 return (jint
)sqlite3_result_zeroblob64(PtrGet_sqlite3_context(jpCx
),
3919 S3JniApi(sqlite3_rollback_hook(),jobject
,1rollback_1hook
)(
3920 JniArgsEnvClass
, jobject jDb
, jobject jHook
3922 return s3jni_commit_rollback_hook(0, env
, jDb
, jHook
);
3925 /* Callback for sqlite3_set_authorizer(). */
3926 int s3jni_xAuth(void* pState
, int op
,const char*z0
, const char*z1
,
3927 const char*z2
,const char*z3
){
3928 S3JniDb
* const ps
= pState
;
3933 S3JniHook_localdup(&ps
->hooks
.auth
, &hook
);
3935 jstring
const s0
= z0
? s3jni_utf8_to_jstring( z0
, -1) : 0;
3936 jstring
const s1
= z1
? s3jni_utf8_to_jstring( z1
, -1) : 0;
3937 jstring
const s2
= z2
? s3jni_utf8_to_jstring( z2
, -1) : 0;
3938 jstring
const s3
= z3
? s3jni_utf8_to_jstring( z3
, -1) : 0;
3940 rc
= (*env
)->CallIntMethod(env
, hook
.jObj
, hook
.midCallback
, (jint
)op
,
3943 rc
= s3jni_db_exception(ps
, rc
, "sqlite3_set_authorizer() callback");
3945 S3JniUnrefLocal(s0
);
3946 S3JniUnrefLocal(s1
);
3947 S3JniUnrefLocal(s2
);
3948 S3JniUnrefLocal(s3
);
3949 S3JniHook_localundup(hook
);
3954 S3JniApi(sqlite3_set_authorizer(),jint
,1set_1authorizer
)(
3955 JniArgsEnvClass
,jobject jDb
, jobject jHook
3957 S3JniDb
* const ps
= S3JniDb_from_java(jDb
);
3958 S3JniHook
* const pHook
= ps
? &ps
->hooks
.auth
: 0;
3961 if( !ps
) return SQLITE_MISUSE
;
3962 S3JniDb_mutex_enter
;
3964 S3JniHook_unref(pHook
);
3965 rc
= sqlite3_set_authorizer( ps
->pDb
, 0, 0 );
3969 if( (*env
)->IsSameObject(env
, pHook
->jObj
, jHook
) ){
3970 /* Same object - this is a no-op. */
3971 S3JniDb_mutex_leave
;
3974 S3JniHook_unref(pHook
);
3976 pHook
->jObj
= S3JniRefGlobal(jHook
);
3977 klazz
= (*env
)->GetObjectClass(env
, jHook
);
3978 pHook
->midCallback
= (*env
)->GetMethodID(env
, klazz
,
3981 "Ljava/lang/String;"
3982 "Ljava/lang/String;"
3983 "Ljava/lang/String;"
3984 "Ljava/lang/String;"
3986 S3JniUnrefLocal(klazz
);
3988 rc
= s3jni_db_error(ps
->pDb
, SQLITE_ERROR
,
3989 "Error setting up Java parts of authorizer hook.");
3991 rc
= sqlite3_set_authorizer(ps
->pDb
, s3jni_xAuth
, ps
);
3993 if( rc
) S3JniHook_unref(pHook
);
3995 S3JniDb_mutex_leave
;
4000 S3JniApi(sqlite3_set_last_insert_rowid(),void,1set_1last_1insert_1rowid
)(
4001 JniArgsEnvClass
, jobject jpDb
, jlong rowId
4003 sqlite3_set_last_insert_rowid(PtrGet_sqlite3(jpDb
),
4004 (sqlite3_int64
)rowId
);
4007 S3JniApi(sqlite3_shutdown(),jint
,1shutdown
)(
4010 s3jni_reset_auto_extension(env
);
4011 /* Free up S3JniDb recycling bin. */
4012 S3JniDb_mutex_enter
; {
4013 while( S3JniGlobal
.perDb
.aFree
){
4014 S3JniDb
* const d
= S3JniGlobal
.perDb
.aFree
;
4015 S3JniGlobal
.perDb
.aFree
= d
->pNext
;
4016 S3JniDb_clear(env
, d
);
4019 } S3JniDb_mutex_leave
;
4020 S3JniGlobal_mutex_enter
; {
4021 /* Free up S3JniUdf recycling bin. */
4022 while( S3JniGlobal
.udf
.aFree
){
4023 S3JniUdf
* const u
= S3JniGlobal
.udf
.aFree
;
4024 S3JniGlobal
.udf
.aFree
= u
->pNext
;
4026 S3JniUdf_free(env
, u
, 0);
4028 /* Free up S3JniHook recycling bin. */
4029 while( S3JniGlobal
.hooks
.aFree
){
4030 S3JniHook
* const u
= S3JniGlobal
.hooks
.aFree
;
4031 S3JniGlobal
.hooks
.aFree
= u
->pNext
;
4033 assert( !u
->doXDestroy
);
4035 assert( !u
->jExtra
);
4038 } S3JniGlobal_mutex_leave
;
4039 /* Free up env cache. */
4040 S3JniEnv_mutex_enter
; {
4041 while( SJG
.envCache
.aHead
){
4042 S3JniEnv_uncache( SJG
.envCache
.aHead
->env
);
4044 } S3JniEnv_mutex_leave
;
4047 ** Is automatically closing any still-open dbs a good idea? We will
4048 ** get rid of the perDb list once sqlite3 gets a per-db client
4049 ** state, at which point we won't have a central list of databases
4052 S3JniDb_mutex_enter
;
4053 while( SJG
.perDb
.pHead
){
4054 s3jni_close_db(env
, SJG
.perDb
.pHead
->jDb
, 2);
4056 S3JniDb_mutex_leave
;
4058 /* Do not clear S3JniGlobal.jvm: it's legal to restart the lib. */
4059 return sqlite3_shutdown();
4062 S3JniApi(sqlite3_status(),jint
,1status
)(
4063 JniArgsEnvClass
, jint op
, jobject jOutCurrent
, jobject jOutHigh
,
4066 int iCur
= 0, iHigh
= 0;
4067 int rc
= sqlite3_status( op
, &iCur
, &iHigh
, reset
);
4069 OutputPointer_set_Int32(env
, jOutCurrent
, iCur
);
4070 OutputPointer_set_Int32(env
, jOutHigh
, iHigh
);
4075 S3JniApi(sqlite3_status64(),jint
,1status64
)(
4076 JniArgsEnvClass
, jint op
, jobject jOutCurrent
, jobject jOutHigh
,
4079 sqlite3_int64 iCur
= 0, iHigh
= 0;
4080 int rc
= sqlite3_status64( op
, &iCur
, &iHigh
, reset
);
4082 OutputPointer_set_Int64(env
, jOutCurrent
, iCur
);
4083 OutputPointer_set_Int64(env
, jOutHigh
, iHigh
);
4088 static int s3jni_strlike_glob(int isLike
, JNIEnv
*const env
,
4089 jbyteArray baG
, jbyteArray baT
, jint escLike
){
4091 jbyte
* const pG
= s3jni_jbytearray_bytes(baG
);
4092 jbyte
* const pT
= pG
? s3jni_jbytearray_bytes(baT
) : 0;
4094 s3jni_oom_fatal(pT
);
4095 /* Note that we're relying on the byte arrays having been
4096 NUL-terminated on the Java side. */
4098 ? sqlite3_strlike((const char *)pG
, (const char *)pT
,
4099 (unsigned int)escLike
)
4100 : sqlite3_strglob((const char *)pG
, (const char *)pT
);
4101 s3jni_jbytearray_release(baG
, pG
);
4102 s3jni_jbytearray_release(baT
, pT
);
4106 S3JniApi(sqlite3_strglob(),jint
,1strglob
)(
4107 JniArgsEnvClass
, jbyteArray baG
, jbyteArray baT
4109 return s3jni_strlike_glob(0, env
, baG
, baT
, 0);
4112 S3JniApi(sqlite3_strlike(),jint
,1strlike
)(
4113 JniArgsEnvClass
, jbyteArray baG
, jbyteArray baT
, jint escChar
4115 return s3jni_strlike_glob(1, env
, baG
, baT
, escChar
);
4118 S3JniApi(sqlite3_sql(),jstring
,1sql
)(
4119 JniArgsEnvClass
, jobject jpStmt
4121 sqlite3_stmt
* const pStmt
= PtrGet_sqlite3_stmt(jpStmt
);
4124 const char * zSql
= 0;
4125 zSql
= sqlite3_sql(pStmt
);
4126 rv
= s3jni_utf8_to_jstring( zSql
, -1);
4131 S3JniApi(sqlite3_step(),jint
,1step
)(
4132 JniArgsEnvClass
,jobject jStmt
4134 int rc
= SQLITE_MISUSE
;
4135 sqlite3_stmt
* const pStmt
= PtrGet_sqlite3_stmt(jStmt
);
4137 rc
= sqlite3_step(pStmt
);
4142 S3JniApi(sqlite3_table_column_metadata(),int,1table_1column_1metadata
)(
4143 JniArgsEnvClass
, jobject jDb
, jstring jDbName
, jstring jTableName
,
4144 jstring jColumnName
, jobject jDataType
, jobject jCollSeq
, jobject jNotNull
,
4145 jobject jPrimaryKey
, jobject jAutoinc
4147 sqlite3
* const db
= PtrGet_sqlite3(jDb
);
4148 char * zDbName
= 0, * zTableName
= 0, * zColumnName
= 0;
4149 const char * pzCollSeq
= 0;
4150 const char * pzDataType
= 0;
4151 int pNotNull
= 0, pPrimaryKey
= 0, pAutoinc
= 0;
4154 if( !db
|| !jDbName
|| !jTableName
|| !jColumnName
) return SQLITE_MISUSE
;
4155 zDbName
= s3jni_jstring_to_utf8(jDbName
,0);
4156 zTableName
= zDbName
? s3jni_jstring_to_utf8(jTableName
,0) : 0;
4157 zColumnName
= zTableName
? s3jni_jstring_to_utf8(jColumnName
,0) : 0;
4159 ? sqlite3_table_column_metadata(db
, zDbName
, zTableName
,
4160 zColumnName
, &pzDataType
, &pzCollSeq
,
4161 &pNotNull
, &pPrimaryKey
, &pAutoinc
)
4164 jstring jseq
= jCollSeq
4165 ? (pzCollSeq
? s3jni_utf8_to_jstring(pzCollSeq
, -1) : 0)
4167 jstring jdtype
= jDataType
4168 ? (pzDataType
? s3jni_utf8_to_jstring(pzDataType
, -1) : 0)
4170 if( (jCollSeq
&& pzCollSeq
&& !jseq
)
4171 || (jDataType
&& pzDataType
&& !jdtype
) ){
4174 if( jNotNull
) OutputPointer_set_Bool(env
, jNotNull
, pNotNull
);
4175 if( jPrimaryKey
) OutputPointer_set_Bool(env
, jPrimaryKey
, pPrimaryKey
);
4176 if( jAutoinc
) OutputPointer_set_Bool(env
, jAutoinc
, pAutoinc
);
4177 if( jCollSeq
) OutputPointer_set_String(env
, jCollSeq
, jseq
);
4178 if( jDataType
) OutputPointer_set_String(env
, jDataType
, jdtype
);
4180 S3JniUnrefLocal(jseq
);
4181 S3JniUnrefLocal(jdtype
);
4183 sqlite3_free(zDbName
);
4184 sqlite3_free(zTableName
);
4185 sqlite3_free(zColumnName
);
4189 static int s3jni_trace_impl(unsigned traceflag
, void *pC
, void *pP
, void *pX
){
4190 S3JniDb
* const ps
= (S3JniDb
*)pC
;
4192 jobject jX
= NULL
/* the tracer's X arg */;
4193 jobject jP
= NULL
/* the tracer's P arg */;
4194 jobject jPUnref
= NULL
/* potentially a local ref to jP */;
4198 S3JniHook_localdup(&ps
->hooks
.trace
, &hook
);
4202 switch( traceflag
){
4203 case SQLITE_TRACE_STMT
:
4204 jX
= s3jni_utf8_to_jstring( (const char *)pX
, -1);
4205 if( !jX
) rc
= SQLITE_NOMEM
;
4207 case SQLITE_TRACE_PROFILE
:
4208 jX
= (*env
)->NewObject(env
, SJG
.g
.cLong
, SJG
.g
.ctorLong1
,
4209 (jlong
)*((sqlite3_int64
*)pX
));
4210 // hmm. ^^^ (*pX) really is zero.
4211 // MARKER(("profile time = %llu\n", *((sqlite3_int64*)pX)));
4212 s3jni_oom_check( jX
);
4213 if( !jX
) rc
= SQLITE_NOMEM
;
4215 case SQLITE_TRACE_ROW
:
4217 case SQLITE_TRACE_CLOSE
:
4221 assert(!"cannot happen - unkown trace flag");
4226 /* Create a new temporary sqlite3_stmt wrapper */
4227 jP
= jPUnref
= new_sqlite3_stmt_wrapper(env
, pP
);
4234 rc
= (int)(*env
)->CallIntMethod(env
, hook
.jObj
, hook
.midCallback
,
4235 (jint
)traceflag
, jP
, jX
);
4237 rc
= s3jni_db_exception(ps
, SQLITE_ERROR
,
4238 "sqlite3_trace_v2() callback threw.");
4242 S3JniUnrefLocal(jPUnref
);
4243 S3JniUnrefLocal(jX
);
4244 S3JniHook_localundup(hook
);
4248 S3JniApi(sqlite3_trace_v2(),jint
,1trace_1v2
)(
4249 JniArgsEnvClass
,jobject jDb
, jint traceMask
, jobject jTracer
4251 S3JniDb
* const ps
= S3JniDb_from_java(jDb
);
4254 if( !ps
) return SQLITE_MISUSE
;
4255 if( !traceMask
|| !jTracer
){
4256 S3JniDb_mutex_enter
;
4257 rc
= (jint
)sqlite3_trace_v2(ps
->pDb
, 0, 0, 0);
4258 S3JniHook_unref(&ps
->hooks
.trace
);
4259 S3JniDb_mutex_leave
;
4261 jclass
const klazz
= (*env
)->GetObjectClass(env
, jTracer
);
4262 S3JniHook hook
= S3JniHook_empty
;
4263 hook
.midCallback
= (*env
)->GetMethodID(
4264 env
, klazz
, "call", "(ILjava/lang/Object;Ljava/lang/Object;)I"
4266 S3JniUnrefLocal(klazz
);
4268 S3JniExceptionClear
;
4269 rc
= s3jni_db_error(ps
->pDb
, SQLITE_ERROR
,
4270 "Cannot not find matching call() on "
4271 "TracerCallback object.");
4273 hook
.jObj
= S3JniRefGlobal(jTracer
);
4274 S3JniDb_mutex_enter
;
4275 rc
= sqlite3_trace_v2(ps
->pDb
, (unsigned)traceMask
, s3jni_trace_impl
, ps
);
4277 S3JniHook_unref(&ps
->hooks
.trace
);
4278 ps
->hooks
.trace
= hook
/* transfer ownership of reference */;
4280 S3JniHook_unref(&hook
);
4282 S3JniDb_mutex_leave
;
4288 S3JniApi(sqlite3_txn_state(),jint
,1txn_1state
)(
4289 JniArgsEnvClass
,jobject jDb
, jstring jSchema
4291 sqlite3
* const pDb
= PtrGet_sqlite3(jDb
);
4292 int rc
= SQLITE_MISUSE
;
4294 char * zSchema
= jSchema
4295 ? s3jni_jstring_to_utf8(jSchema
, 0)
4297 if( !jSchema
|| (zSchema
&& jSchema
) ){
4298 rc
= sqlite3_txn_state(pDb
, zSchema
);
4299 sqlite3_free(zSchema
);
4307 S3JniApi(sqlite3_update_hook(),jobject
,1update_
1hook
)(
4308 JniArgsEnvClass
, jobject jDb
, jobject jHook
4310 return s3jni_updatepre_hook(env
, 0, jDb
, jHook
);
4314 S3JniApi(sqlite3_value_blob(),jbyteArray
,1value_1blob
)(
4315 JniArgsEnvClass
, jobject jpSVal
4317 sqlite3_value
* const sv
= PtrGet_sqlite3_value(jpSVal
);
4318 int const nLen
= sqlite3_value_bytes(sv
);
4319 const jbyte
* pBytes
= sqlite3_value_blob(sv
);
4321 s3jni_oom_check( nLen
? !!pBytes
: 1 );
4323 ? s3jni_new_jbyteArray(pBytes
, nLen
)
4328 S3JniApi(sqlite3_value_double(),jdouble
,1value_1double
)(
4329 JniArgsEnvClass
, jobject jpSVal
4331 return (jdouble
) sqlite3_value_double(PtrGet_sqlite3_value(jpSVal
));
4335 S3JniApi(sqlite3_value_dup(),jobject
,1value_1dup
)(
4336 JniArgsEnvClass
, jobject jpSVal
4338 sqlite3_value
* const sv
= sqlite3_value_dup(PtrGet_sqlite3_value(jpSVal
));
4339 return sv
? new_sqlite3_value_wrapper(env
, sv
) : 0;
4342 S3JniApi(sqlite3_value_free(),void,1value_1free
)(
4343 JniArgsEnvClass
, jobject jpSVal
4345 sqlite3_value_free(PtrGet_sqlite3_value(jpSVal
));
4348 S3JniApi(sqlite3_value_int(),jint
,1value_1int
)(
4349 JniArgsEnvClass
, jobject jpSVal
4351 return (jint
) sqlite3_value_int(PtrGet_sqlite3_value(jpSVal
));
4354 S3JniApi(sqlite3_value_int64(),jlong
,1value_1int64
)(
4355 JniArgsEnvClass
, jobject jpSVal
4357 return (jlong
) sqlite3_value_int64(PtrGet_sqlite3_value(jpSVal
));
4360 S3JniApi(sqlite3_value_java_object(),jobject
,1value_1java_1object
)(
4361 JniArgsEnvClass
, jobject jpSVal
4363 return sqlite3_value_pointer(PtrGet_sqlite3_value(jpSVal
),
4364 ResultJavaValuePtrStr
);
4367 S3JniApi(sqlite3_value_text_utf8(),jbyteArray
,1value_1text_1utf8
)(
4368 JniArgsEnvClass
, jobject jpSVal
4370 sqlite3_value
* const sv
= PtrGet_sqlite3_value(jpSVal
);
4371 int const n
= sqlite3_value_bytes(sv
);
4372 const unsigned char * const p
= sqlite3_value_text(sv
);
4373 return p
? s3jni_new_jbyteArray(p
, n
) : 0;
4376 S3JniApi(sqlite3_value_text(),jstring
,1value_1text
)(
4377 JniArgsEnvClass
, jobject jpSVal
4379 sqlite3_value
* const sv
= PtrGet_sqlite3_value(jpSVal
);
4380 int const n
= sqlite3_value_bytes(sv
);
4381 const unsigned char * const p
= sqlite3_value_text(sv
);
4382 return p
? s3jni_utf8_to_jstring( (const char *)p
, n
) : 0;
4385 S3JniApi(sqlite3_value_text16(),jstring
,1value_1text16
)(
4386 JniArgsEnvClass
, jobject jpSVal
4388 sqlite3_value
* const sv
= PtrGet_sqlite3_value(jpSVal
);
4389 const int n
= sqlite3_value_bytes16(sv
);
4390 const void * const p
= sqlite3_value_text16(sv
);
4391 return s3jni_text16_to_jstring(env
, p
, n
);
4394 JniDecl(void,1jni_1internal_1details
)(JniArgsEnvClass
){
4395 MARKER(("\nVarious bits of internal info:\n"));
4397 #ifdef SQLITE_ENABLE_FTS5
4405 #define SO(T) printf("\tsizeof(" #T ") = %u\n", (unsigned)sizeof(T))
4413 printf("\t(^^^ %u NativePointerHolder/OutputPointer.T types)\n",
4414 (unsigned)S3Jni_NphCache_size
);
4416 SO(S3JniAutoExtension
);
4419 #ifdef SQLITE_JNI_ENABLE_METRICS
4420 printf("Cache info:\n");
4421 printf("\tJNIEnv cache: %u allocs, %u misses, %u hits\n",
4422 SJG
.metrics
.nEnvAlloc
, SJG
.metrics
.nEnvMiss
,
4423 SJG
.metrics
.nEnvHit
);
4424 printf("Mutex entry:"
4427 "\n\tnph = %u for S3JniNphClass init"
4429 "\n\tautoExt list = %u"
4430 "\n\tS3JniUdf = %u (free-list)"
4431 "\n\tmetrics = %u\n",
4432 SJG
.metrics
.nMutexGlobal
, SJG
.metrics
.nMutexEnv
,
4433 SJG
.metrics
.nMutexEnv2
, SJG
.metrics
.nMutexPerDb
,
4434 SJG
.metrics
.nMutexAutoExt
, SJG
.metrics
.nMutexUdf
,
4435 SJG
.metrics
.nMetrics
);
4437 printf("\tS3JniDb: %u alloced (*%u = %u bytes), %u recycled\n",
4438 SJG
.metrics
.nPdbAlloc
, (unsigned) sizeof(S3JniDb
),
4439 (unsigned)(SJG
.metrics
.nPdbAlloc
* sizeof(S3JniDb
)),
4440 SJG
.metrics
.nPdbRecycled
);
4441 printf("\tS3JniUdf: %u alloced (*%u = %u bytes), %u recycled\n",
4442 SJG
.metrics
.nUdfAlloc
, (unsigned) sizeof(S3JniUdf
),
4443 (unsigned)(SJG
.metrics
.nUdfAlloc
* sizeof(S3JniUdf
)),
4444 SJG
.metrics
.nUdfRecycled
);
4445 printf("\tS3JniHook: %u alloced (*%u = %u bytes), %u recycled\n",
4446 SJG
.metrics
.nHookAlloc
, (unsigned) sizeof(S3JniHook
),
4447 (unsigned)(SJG
.metrics
.nHookAlloc
* sizeof(S3JniHook
)),
4448 SJG
.metrics
.nHookRecycled
);
4449 printf("\tS3JniEnv: %u alloced (*%u = %u bytes)\n",
4450 SJG
.metrics
.nEnvAlloc
, (unsigned) sizeof(S3JniEnv
),
4451 (unsigned)(SJG
.metrics
.nEnvAlloc
* sizeof(S3JniEnv
)));
4452 puts("Java-side UDF calls:");
4453 #define UDF(T) printf("\t%-8s = %u\n", "x" #T, SJG.metrics.udf.n##T)
4454 UDF(Func
); UDF(Step
); UDF(Final
); UDF(Value
); UDF(Inverse
);
4456 printf("xDestroy calls across all callback types: %u\n",
4457 SJG
.metrics
.nDestroy
);
4459 puts("Built without SQLITE_JNI_ENABLE_METRICS.");
4463 ////////////////////////////////////////////////////////////////////////
4464 // End of the sqlite3_... API bindings. Next up, FTS5...
4465 ////////////////////////////////////////////////////////////////////////
4466 #ifdef SQLITE_ENABLE_FTS5
4468 /* Creates a verbose JNI Fts5 function name. */
4469 #define JniFuncNameFtsXA(Suffix) \
4470 Java_org_sqlite_jni_Fts5ExtensionApi_ ## Suffix
4471 #define JniFuncNameFtsApi(Suffix) \
4472 Java_org_sqlite_jni_fts5_1api_ ## Suffix
4473 #define JniFuncNameFtsTok(Suffix) \
4474 Java_org_sqlite_jni_fts5_tokenizer_ ## Suffix
4476 #define JniDeclFtsXA(ReturnType,Suffix) \
4477 JNIEXPORT ReturnType JNICALL \
4478 JniFuncNameFtsXA(Suffix)
4479 #define JniDeclFtsApi(ReturnType,Suffix) \
4480 JNIEXPORT ReturnType JNICALL \
4481 JniFuncNameFtsApi(Suffix)
4482 #define JniDeclFtsTok(ReturnType,Suffix) \
4483 JNIEXPORT ReturnType JNICALL \
4484 JniFuncNameFtsTok(Suffix)
4486 #define PtrGet_fts5_api(OBJ) NativePointerHolder_get(OBJ,&S3JniNphRefs.fts5_api)
4487 #define PtrGet_fts5_tokenizer(OBJ) NativePointerHolder_get(OBJ,&S3JniNphRefs.fts5_tokenizer)
4488 #define PtrGet_Fts5Context(OBJ) NativePointerHolder_get(OBJ,&S3JniNphRefs.Fts5Context)
4489 #define PtrGet_Fts5Tokenizer(OBJ) NativePointerHolder_get(OBJ,&S3JniNphRefs.Fts5Tokenizer)
4490 #define Fts5ExtDecl Fts5ExtensionApi const * const fext = s3jni_ftsext()
4493 State for binding Java-side FTS5 auxiliary functions.
4496 jobject jObj
/* functor instance */;
4497 jobject jUserData
/* 2nd arg to JNI binding of
4498 xCreateFunction(), ostensibly the 3rd arg
4499 to the lib-level xCreateFunction(), except
4500 that we necessarily use that slot for a
4501 Fts5JniAux instance. */;
4502 char * zFuncName
/* Only for error reporting and debug logging */;
4503 jmethodID jmid
/* callback member's method ID */;
4506 static void Fts5JniAux_free(Fts5JniAux
* const s
){
4509 /*MARKER(("FTS5 aux function cleanup: %s\n", s->zFuncName));*/
4510 s3jni_call_xDestroy(s
->jObj
);
4511 S3JniUnrefGlobal(s
->jObj
);
4512 S3JniUnrefGlobal(s
->jUserData
);
4514 sqlite3_free(s
->zFuncName
);
4518 static void Fts5JniAux_xDestroy(void *p
){
4519 if( p
) Fts5JniAux_free(p
);
4522 static Fts5JniAux
* Fts5JniAux_alloc(JNIEnv
* const env
, jobject jObj
){
4523 Fts5JniAux
* s
= s3jni_malloc( sizeof(Fts5JniAux
));
4527 memset(s
, 0, sizeof(Fts5JniAux
));
4528 s
->jObj
= S3JniRefGlobal(jObj
);
4529 klazz
= (*env
)->GetObjectClass(env
, jObj
);
4530 s
->jmid
= (*env
)->GetMethodID(env
, klazz
, "xFunction",
4531 "(Lorg/sqlite/jni/Fts5ExtensionApi;"
4532 "Lorg/sqlite/jni/Fts5Context;"
4533 "Lorg/sqlite/jni/sqlite3_context;"
4534 "[Lorg/sqlite/jni/sqlite3_value;)V");
4535 S3JniUnrefLocal(klazz
);
4537 S3JniExceptionReport
;
4538 S3JniExceptionClear
;
4546 static inline Fts5ExtensionApi
const * s3jni_ftsext(void){
4547 return &sFts5Api
/*singleton from sqlite3.c*/;
4550 static inline jobject
new_Fts5Context_wrapper(JNIEnv
* const env
, Fts5Context
*sv
){
4551 return new_NativePointerHolder_object(env
, &S3JniNphRefs
.Fts5Context
, sv
);
4553 static inline jobject
new_fts5_api_wrapper(JNIEnv
* const env
, fts5_api
*sv
){
4554 return new_NativePointerHolder_object(env
, &S3JniNphRefs
.fts5_api
, sv
);
4558 ** Returns a per-JNIEnv global ref to the Fts5ExtensionApi singleton
4559 ** instance, or NULL on OOM.
4561 static jobject
s3jni_getFts5ExensionApi(JNIEnv
* const env
){
4562 if( !SJG
.fts5
.jFtsExt
){
4563 jobject pNPH
= new_NativePointerHolder_object(
4564 env
, &S3JniNphRefs
.Fts5ExtensionApi
, s3jni_ftsext()
4566 S3JniEnv_mutex_enter
;
4568 if( !SJG
.fts5
.jFtsExt
){
4569 SJG
.fts5
.jFtsExt
= S3JniRefGlobal(pNPH
);
4571 S3JniUnrefLocal(pNPH
);
4573 S3JniEnv_mutex_leave
;
4575 return SJG
.fts5
.jFtsExt
;
4579 ** Returns a pointer to the fts5_api instance for database connection
4580 ** db. If an error occurs, returns NULL and leaves an error in the
4581 ** database handle (accessible using sqlite3_errcode()/errmsg()).
4583 static fts5_api
*s3jni_fts5_api_from_db(sqlite3
*db
){
4585 sqlite3_stmt
*pStmt
= 0;
4586 if( SQLITE_OK
==sqlite3_prepare(db
, "SELECT fts5(?1)", -1, &pStmt
, 0) ){
4587 sqlite3_bind_pointer(pStmt
, 1, (void*)&pRet
, "fts5_api_ptr", NULL
);
4588 sqlite3_step(pStmt
);
4590 sqlite3_finalize(pStmt
);
4594 JniDeclFtsApi(jobject
,getInstanceForDb
)(JniArgsEnvClass
,jobject jDb
){
4595 S3JniDb
* const ps
= S3JniDb_from_java(jDb
);
4598 else if( ps
->jFtsApi
){
4601 fts5_api
* const pApi
= s3jni_fts5_api_from_db(ps
->pDb
);
4603 rv
= new_fts5_api_wrapper(env
, pApi
);
4604 ps
->jFtsApi
= rv
? S3JniRefGlobal(rv
) : 0;
4611 JniDeclFtsXA(jobject
,getInstance
)(JniArgsEnvClass
){
4612 return s3jni_getFts5ExensionApi(env
);
4615 JniDeclFtsXA(jint
,xColumnCount
)(JniArgsEnvObj
,jobject jCtx
){
4617 return (jint
)fext
->xColumnCount(PtrGet_Fts5Context(jCtx
));
4620 JniDeclFtsXA(jint
,xColumnSize
)(JniArgsEnvObj
,jobject jCtx
, jint iIdx
, jobject jOut32
){
4623 int const rc
= fext
->xColumnSize(PtrGet_Fts5Context(jCtx
), (int)iIdx
, &n1
);
4624 if( 0==rc
) OutputPointer_set_Int32(env
, jOut32
, n1
);
4628 JniDeclFtsXA(jint
,xColumnText
)(JniArgsEnvObj
,jobject jCtx
, jint iCol
,
4633 int rc
= fext
->xColumnText(PtrGet_Fts5Context(jCtx
), (int)iCol
,
4636 jstring jstr
= pz
? s3jni_utf8_to_jstring( pz
, pn
) : 0;
4639 OutputPointer_set_String(env
, jOut
, jstr
);
4640 S3JniUnrefLocal(jstr
)/*jOut has a reference*/;
4649 JniDeclFtsXA(jint
,xColumnTotalSize
)(JniArgsEnvObj
,jobject jCtx
, jint iCol
, jobject jOut64
){
4651 sqlite3_int64 nOut
= 0;
4652 int const rc
= fext
->xColumnTotalSize(PtrGet_Fts5Context(jCtx
), (int)iCol
, &nOut
);
4653 if( 0==rc
&& jOut64
) OutputPointer_set_Int64(env
, jOut64
, (jlong
)nOut
);
4658 ** Proxy for fts5_extension_function instances plugged in via
4659 ** fts5_api::xCreateFunction().
4661 static void s3jni_fts5_extension_function(Fts5ExtensionApi
const *pApi
,
4663 sqlite3_context
*pCx
,
4665 sqlite3_value
**argv
){
4666 Fts5JniAux
* const pAux
= pApi
->xUserData(pFts
);
4668 jobjectArray jArgv
= 0;
4675 jFXA
= s3jni_getFts5ExensionApi(env
);
4676 if( !jFXA
) goto error_oom
;
4677 jpFts
= new_Fts5Context_wrapper(env
, pFts
);
4678 if( !jpFts
) goto error_oom
;
4679 rc
= udf_args(env
, pCx
, argc
, argv
, &jpCx
, &jArgv
);
4680 if( rc
) goto error_oom
;
4681 (*env
)->CallVoidMethod(env
, pAux
->jObj
, pAux
->jmid
,
4682 jFXA
, jpFts
, jpCx
, jArgv
);
4684 udf_report_exception(env
, 1, pCx
, pAux
->zFuncName
, "xFunction");
4686 S3JniUnrefLocal(jpFts
);
4687 S3JniUnrefLocal(jpCx
);
4688 S3JniUnrefLocal(jArgv
);
4693 S3JniUnrefLocal(jpFts
);
4694 sqlite3_result_error_nomem(pCx
);
4698 JniDeclFtsApi(jint
,xCreateFunction
)(JniArgsEnvObj
, jstring jName
,
4699 jobject jUserData
, jobject jFunc
){
4700 fts5_api
* const pApi
= PtrGet_fts5_api(jSelf
);
4706 zName
= s3jni_jstring_to_utf8( jName
, 0);
4707 if(!zName
) return SQLITE_NOMEM
;
4708 pAux
= Fts5JniAux_alloc(env
, jFunc
);
4710 rc
= pApi
->xCreateFunction(pApi
, zName
, pAux
,
4711 s3jni_fts5_extension_function
,
4712 Fts5JniAux_xDestroy
);
4717 pAux
->jUserData
= jUserData
? S3JniRefGlobal(jUserData
) : 0;
4718 pAux
->zFuncName
= zName
;
4720 sqlite3_free(zName
);
4726 typedef struct S3JniFts5AuxData S3JniFts5AuxData
;
4728 ** TODO: this middle-man struct is no longer necessary. Conider
4729 ** removing it and passing around jObj itself instead.
4731 struct S3JniFts5AuxData
{
4735 static void S3JniFts5AuxData_xDestroy(void *x
){
4737 S3JniFts5AuxData
* const p
= x
;
4740 s3jni_call_xDestroy(p
->jObj
);
4741 S3JniUnrefGlobal(p
->jObj
);
4747 JniDeclFtsXA(jobject
,xGetAuxdata
)(JniArgsEnvObj
,jobject jCtx
, jboolean bClear
){
4750 S3JniFts5AuxData
* const pAux
= fext
->xGetAuxdata(PtrGet_Fts5Context(jCtx
), bClear
);
4754 rv
= S3JniRefLocal(pAux
->jObj
);
4755 S3JniUnrefGlobal(pAux
->jObj
);
4757 /* Note that we do not call xDestroy() in this case. */
4766 JniDeclFtsXA(jint
,xInst
)(JniArgsEnvObj
,jobject jCtx
, jint iIdx
, jobject jOutPhrase
,
4767 jobject jOutCol
, jobject jOutOff
){
4769 int n1
= 0, n2
= 2, n3
= 0;
4770 int const rc
= fext
->xInst(PtrGet_Fts5Context(jCtx
), (int)iIdx
, &n1
, &n2
, &n3
);
4772 OutputPointer_set_Int32(env
, jOutPhrase
, n1
);
4773 OutputPointer_set_Int32(env
, jOutCol
, n2
);
4774 OutputPointer_set_Int32(env
, jOutOff
, n3
);
4779 JniDeclFtsXA(jint
,xInstCount
)(JniArgsEnvObj
,jobject jCtx
, jobject jOut32
){
4782 int const rc
= fext
->xInstCount(PtrGet_Fts5Context(jCtx
), &nOut
);
4783 if( 0==rc
&& jOut32
) OutputPointer_set_Int32(env
, jOut32
, nOut
);
4787 JniDeclFtsXA(jint
,xPhraseCount
)(JniArgsEnvObj
,jobject jCtx
){
4789 return (jint
)fext
->xPhraseCount(PtrGet_Fts5Context(jCtx
));
4792 /* Copy the 'a' and 'b' fields from pSrc to Fts5PhraseIter object jIter. */
4793 static void s3jni_phraseIter_NToJ(JNIEnv
*const env
,
4794 Fts5PhraseIter
const * const pSrc
,
4796 S3JniGlobalType
* const g
= &S3JniGlobal
;
4797 assert(g
->fts5
.jPhraseIter
.fidA
);
4798 (*env
)->SetLongField(env
, jIter
, g
->fts5
.jPhraseIter
.fidA
, (jlong
)pSrc
->a
);
4799 S3JniExceptionIsFatal("Cannot set Fts5PhraseIter.a field.");
4800 (*env
)->SetLongField(env
, jIter
, g
->fts5
.jPhraseIter
.fidB
, (jlong
)pSrc
->b
);
4801 S3JniExceptionIsFatal("Cannot set Fts5PhraseIter.b field.");
4804 /* Copy the 'a' and 'b' fields from Fts5PhraseIter object jIter to pDest. */
4805 static void s3jni_phraseIter_JToN(JNIEnv
*const env
, jobject jIter
,
4806 Fts5PhraseIter
* const pDest
){
4807 S3JniGlobalType
* const g
= &S3JniGlobal
;
4808 assert(g
->fts5
.jPhraseIter
.fidA
);
4810 (const unsigned char *)(*env
)->GetLongField(env
, jIter
, g
->fts5
.jPhraseIter
.fidA
);
4811 S3JniExceptionIsFatal("Cannot get Fts5PhraseIter.a field.");
4813 (const unsigned char *)(*env
)->GetLongField(env
, jIter
, g
->fts5
.jPhraseIter
.fidB
);
4814 S3JniExceptionIsFatal("Cannot get Fts5PhraseIter.b field.");
4817 JniDeclFtsXA(jint
,xPhraseFirst
)(JniArgsEnvObj
,jobject jCtx
, jint iPhrase
,
4818 jobject jIter
, jobject jOutCol
,
4821 Fts5PhraseIter iter
;
4822 int rc
, iCol
= 0, iOff
= 0;
4823 rc
= fext
->xPhraseFirst(PtrGet_Fts5Context(jCtx
), (int)iPhrase
,
4824 &iter
, &iCol
, &iOff
);
4826 OutputPointer_set_Int32(env
, jOutCol
, iCol
);
4827 OutputPointer_set_Int32(env
, jOutOff
, iOff
);
4828 s3jni_phraseIter_NToJ(env
, &iter
, jIter
);
4833 JniDeclFtsXA(jint
,xPhraseFirstColumn
)(JniArgsEnvObj
,jobject jCtx
, jint iPhrase
,
4834 jobject jIter
, jobject jOutCol
){
4836 Fts5PhraseIter iter
;
4838 rc
= fext
->xPhraseFirstColumn(PtrGet_Fts5Context(jCtx
), (int)iPhrase
,
4841 OutputPointer_set_Int32(env
, jOutCol
, iCol
);
4842 s3jni_phraseIter_NToJ(env
, &iter
, jIter
);
4847 JniDeclFtsXA(void,xPhraseNext
)(JniArgsEnvObj
,jobject jCtx
, jobject jIter
,
4848 jobject jOutCol
, jobject jOutOff
){
4850 Fts5PhraseIter iter
;
4851 int iCol
= 0, iOff
= 0;
4852 s3jni_phraseIter_JToN(env
, jIter
, &iter
);
4853 fext
->xPhraseNext(PtrGet_Fts5Context(jCtx
), &iter
, &iCol
, &iOff
);
4854 OutputPointer_set_Int32(env
, jOutCol
, iCol
);
4855 OutputPointer_set_Int32(env
, jOutOff
, iOff
);
4856 s3jni_phraseIter_NToJ(env
, &iter
, jIter
);
4859 JniDeclFtsXA(void,xPhraseNextColumn
)(JniArgsEnvObj
,jobject jCtx
, jobject jIter
,
4862 Fts5PhraseIter iter
;
4864 s3jni_phraseIter_JToN(env
, jIter
, &iter
);
4865 fext
->xPhraseNextColumn(PtrGet_Fts5Context(jCtx
), &iter
, &iCol
);
4866 OutputPointer_set_Int32(env
, jOutCol
, iCol
);
4867 s3jni_phraseIter_NToJ(env
, &iter
, jIter
);
4871 JniDeclFtsXA(jint
,xPhraseSize
)(JniArgsEnvObj
,jobject jCtx
, jint iPhrase
){
4873 return (jint
)fext
->xPhraseSize(PtrGet_Fts5Context(jCtx
), (int)iPhrase
);
4876 /* State for use with xQueryPhrase() and xTokenize(). */
4877 struct s3jni_xQueryPhraseState
{
4878 Fts5ExtensionApi
const * fext
;
4879 S3JniEnv
const * jc
;
4880 jmethodID midCallback
;
4883 /* State for xTokenize() */
4891 static int s3jni_xQueryPhrase(const Fts5ExtensionApi
*xapi
,
4892 Fts5Context
* pFcx
, void *pData
){
4893 /* TODO: confirm that the Fts5Context passed to this function is
4894 guaranteed to be the same one passed to xQueryPhrase(). If it's
4895 not, we'll have to create a new wrapper object on every call. */
4896 struct s3jni_xQueryPhraseState
const * s
= pData
;
4898 int rc
= (int)(*env
)->CallIntMethod(env
, s
->jCallback
, s
->midCallback
,
4899 SJG
.fts5
.jFtsExt
, s
->jFcx
);
4901 S3JniExceptionWarnCallbackThrew("xQueryPhrase() callback");
4902 S3JniExceptionClear
;
4908 JniDeclFtsXA(jint
,xQueryPhrase
)(JniArgsEnvObj
,jobject jFcx
, jint iPhrase
,
4911 S3JniEnv
* const jc
= S3JniEnv_get();
4912 struct s3jni_xQueryPhraseState s
;
4913 jclass klazz
= jCallback
? (*env
)->GetObjectClass(env
, jCallback
) : NULL
;
4915 if( !klazz
) return SQLITE_MISUSE
;
4917 s
.jCallback
= jCallback
;
4920 s
.midCallback
= (*env
)->GetMethodID(env
, klazz
, "xCallback",
4921 "(Lorg.sqlite.jni.Fts5ExtensionApi;"
4922 "Lorg.sqlite.jni.Fts5Context;)I");
4923 S3JniUnrefLocal(klazz
);
4924 S3JniExceptionIsFatal("Could not extract xQueryPhraseCallback.xCallback method.");
4925 return (jint
)fext
->xQueryPhrase(PtrGet_Fts5Context(jFcx
), iPhrase
, &s
,
4926 s3jni_xQueryPhrase
);
4930 JniDeclFtsXA(jint
,xRowCount
)(JniArgsEnvObj
,jobject jCtx
, jobject jOut64
){
4932 sqlite3_int64 nOut
= 0;
4933 int const rc
= fext
->xRowCount(PtrGet_Fts5Context(jCtx
), &nOut
);
4934 if( 0==rc
&& jOut64
) OutputPointer_set_Int64(env
, jOut64
, (jlong
)nOut
);
4938 JniDeclFtsXA(jlong
,xRowid
)(JniArgsEnvObj
,jobject jCtx
){
4940 return (jlong
)fext
->xRowid(PtrGet_Fts5Context(jCtx
));
4943 JniDeclFtsXA(int,xSetAuxdata
)(JniArgsEnvObj
,jobject jCtx
, jobject jAux
){
4946 S3JniFts5AuxData
* pAux
;
4948 pAux
= s3jni_malloc( sizeof(*pAux
));
4951 /* Emulate how xSetAuxdata() behaves when it cannot alloc
4952 ** its auxdata wrapper. */
4953 s3jni_call_xDestroy(jAux
);
4955 return SQLITE_NOMEM
;
4957 pAux
->jObj
= S3JniRefGlobal(jAux
);
4958 rc
= fext
->xSetAuxdata(PtrGet_Fts5Context(jCtx
), pAux
,
4959 S3JniFts5AuxData_xDestroy
);
4963 /* xToken() impl for xTokenize(). */
4964 static int s3jni_xTokenize_xToken(void *p
, int tFlags
, const char* z
,
4965 int nZ
, int iStart
, int iEnd
){
4968 struct s3jni_xQueryPhraseState
* const s
= p
;
4971 if( s
->tok
.zPrev
== z
&& s
->tok
.nPrev
== nZ
){
4974 S3JniUnrefLocal(s
->tok
.jba
);
4977 s
->tok
.jba
= s3jni_new_jbyteArray(z
, nZ
);
4978 if( !s
->tok
.jba
) return SQLITE_NOMEM
;
4981 rc
= (int)(*env
)->CallIntMethod(env
, s
->jCallback
, s
->midCallback
,
4982 (jint
)tFlags
, jba
, (jint
)iStart
,
4988 ** Proxy for Fts5ExtensionApi.xTokenize() and
4989 ** fts5_tokenizer.xTokenize()
4991 static jint
s3jni_fts5_xTokenize(JniArgsEnvObj
, S3JniNphRef
const *pRef
,
4992 jint tokFlags
, jobject jFcx
,
4993 jbyteArray jbaText
, jobject jCallback
){
4995 S3JniEnv
* const jc
= S3JniEnv_get();
4996 struct s3jni_xQueryPhraseState s
;
4998 jbyte
* const pText
= jCallback
? s3jni_jbytearray_bytes(jbaText
) : 0;
4999 jsize nText
= pText
? (*env
)->GetArrayLength(env
, jbaText
) : 0;
5000 jclass
const klazz
= jCallback
? (*env
)->GetObjectClass(env
, jCallback
) : NULL
;
5002 if( !klazz
) return SQLITE_MISUSE
;
5003 memset(&s
, 0, sizeof(s
));
5005 s
.jCallback
= jCallback
;
5008 s
.midCallback
= (*env
)->GetMethodID(env
, klazz
, "call", "(I[BII)I");
5009 S3JniUnrefLocal(klazz
);
5011 S3JniExceptionReport
;
5012 S3JniExceptionClear
;
5013 s3jni_jbytearray_release(jbaText
, pText
);
5014 return SQLITE_ERROR
;
5016 s
.tok
.jba
= S3JniRefLocal(jbaText
);
5017 s
.tok
.zPrev
= (const char *)pText
;
5018 s
.tok
.nPrev
= (int)nText
;
5019 if( pRef
== &S3JniNphRefs
.Fts5ExtensionApi
){
5020 rc
= fext
->xTokenize(PtrGet_Fts5Context(jFcx
),
5021 (const char *)pText
, (int)nText
,
5022 &s
, s3jni_xTokenize_xToken
);
5023 }else if( pRef
== &S3JniNphRefs
.fts5_tokenizer
){
5024 fts5_tokenizer
* const pTok
= PtrGet_fts5_tokenizer(jSelf
);
5025 rc
= pTok
->xTokenize(PtrGet_Fts5Tokenizer(jFcx
), &s
, tokFlags
,
5026 (const char *)pText
, (int)nText
,
5027 s3jni_xTokenize_xToken
);
5029 (*env
)->FatalError(env
, "This cannot happen. Maintenance required.");
5032 assert( s
.tok
.zPrev
);
5033 S3JniUnrefLocal(s
.tok
.jba
);
5035 s3jni_jbytearray_release(jbaText
, pText
);
5039 JniDeclFtsXA(jint
,xTokenize
)(JniArgsEnvObj
,jobject jFcx
, jbyteArray jbaText
,
5041 return s3jni_fts5_xTokenize(env
, jSelf
, &S3JniNphRefs
.Fts5ExtensionApi
,
5042 0, jFcx
, jbaText
, jCallback
);
5045 JniDeclFtsTok(jint
,xTokenize
)(JniArgsEnvObj
,jobject jFcx
, jint tokFlags
,
5046 jbyteArray jbaText
, jobject jCallback
){
5047 return s3jni_fts5_xTokenize(env
, jSelf
, &S3JniNphRefs
.Fts5Tokenizer
,
5048 tokFlags
, jFcx
, jbaText
, jCallback
);
5052 JniDeclFtsXA(jobject
,xUserData
)(JniArgsEnvObj
,jobject jFcx
){
5054 Fts5JniAux
* const pAux
= fext
->xUserData(PtrGet_Fts5Context(jFcx
));
5055 return pAux
? pAux
->jUserData
: 0;
5058 #endif /* SQLITE_ENABLE_FTS5 */
5060 ////////////////////////////////////////////////////////////////////////
5061 // End of the main API bindings. Start of SQLTester bits...
5062 ////////////////////////////////////////////////////////////////////////
5064 #ifdef SQLITE_JNI_ENABLE_SQLTester
5065 typedef struct SQLTesterJni SQLTesterJni
;
5066 struct SQLTesterJni
{
5069 static SQLTesterJni SQLTester
= {
5073 static void SQLTester_dup_destructor(void*pToFree
){
5074 u64
*p
= (u64
*)pToFree
;
5077 assert( p
[0]==0x2bbf4b7c );
5084 ** Implementation of
5088 ** This SQL function simply makes a copy of its text argument. But it
5089 ** returns the result using a custom destructor, in order to provide
5090 ** tests for the use of Mem.xDel() in the SQLite VDBE.
5092 static void SQLTester_dup_func(
5093 sqlite3_context
*context
,
5095 sqlite3_value
**argv
5099 int n
= sqlite3_value_bytes(argv
[0]);
5100 SQLTesterJni
* const p
= (SQLTesterJni
*)sqlite3_user_data(context
);
5104 if( n
>0 && (pOut
= s3jni_malloc( (n
+16)&~7 ))!=0 ){
5105 pOut
[0] = 0x2bbf4b7c;
5106 z
= (char*)&pOut
[1];
5107 memcpy(z
, sqlite3_value_text(argv
[0]), n
);
5109 sqlite3_result_text(context
, z
, n
, SQLTester_dup_destructor
);
5115 ** Return the number of calls to the dup() SQL function since the
5116 ** SQLTester context was opened or since the last dup_count() call.
5118 static void SQLTester_dup_count_func(
5119 sqlite3_context
*context
,
5121 sqlite3_value
**argv
5123 SQLTesterJni
* const p
= (SQLTesterJni
*)sqlite3_user_data(context
);
5124 sqlite3_result_int64(context
, p
->nDup
);
5129 ** Return non-zero if string z matches glob pattern zGlob and zero if the
5130 ** pattern does not match.
5135 ** non-zero == match
5139 ** '*' Matches any sequence of zero or more characters.
5141 ** '?' Matches exactly one character.
5143 ** [...] Matches one character from the enclosed list of
5146 ** [^...] Matches one character not in the enclosed list.
5148 ** '#' Matches any sequence of one or more digits with an
5149 ** optional + or - sign in front, or a hexadecimal
5150 ** literal of the form 0x...
5152 static int SQLTester_strnotglob(const char *zGlob
, const char *z
){
5157 while( (c
= (*(zGlob
++)))!=0 ){
5159 while( (c
=(*(zGlob
++))) == '*' || c
=='?' ){
5160 if( c
=='?' && (*(z
++))==0 ) return 0;
5165 while( *z
&& SQLTester_strnotglob(zGlob
-1,z
)==0 ){
5170 while( (c2
= (*(z
++)))!=0 ){
5173 if( c2
==0 ) return 0;
5175 if( SQLTester_strnotglob(zGlob
,z
) ) return 1;
5179 if( (*(z
++))==0 ) return 0;
5185 if( c
==0 ) return 0;
5192 if( c
==']' ) seen
= 1;
5195 while( c2
&& c2
!=']' ){
5196 if( c2
=='-' && zGlob
[0]!=']' && zGlob
[0]!=0 && prior_c
>0 ){
5198 if( c
>=prior_c
&& c
<=c2
) seen
= 1;
5208 if( c2
==0 || (seen
^ invert
)==0 ) return 0;
5211 && (z
[1]=='x' || z
[1]=='X')
5212 && sqlite3Isxdigit(z
[2])
5215 while( sqlite3Isxdigit(z
[0]) ){ z
++; }
5217 if( (z
[0]=='-' || z
[0]=='+') && sqlite3Isdigit(z
[1]) ) z
++;
5218 if( !sqlite3Isdigit(z
[0]) ) return 0;
5220 while( sqlite3Isdigit(z
[0]) ){ z
++; }
5223 if( c
!=(*(z
++)) ) return 0;
5229 JNIEXPORT jint JNICALL
5230 Java_org_sqlite_jni_tester_SQLTester_strglob(
5231 JniArgsEnvClass
, jbyteArray baG
, jbyteArray baT
5234 jbyte
* const pG
= s3jni_jbytearray_bytes(baG
);
5235 jbyte
* const pT
= pG
? s3jni_jbytearray_bytes(baT
) : 0;
5237 s3jni_oom_fatal(pT
);
5238 /* Note that we're relying on the byte arrays having been
5239 NUL-terminated on the Java side. */
5240 rc
= !SQLTester_strnotglob((const char *)pG
, (const char *)pT
);
5241 s3jni_jbytearray_release(baG
, pG
);
5242 s3jni_jbytearray_release(baT
, pT
);
5247 static int SQLTester_auto_extension(sqlite3
*pDb
, const char **pzErr
,
5248 const struct sqlite3_api_routines
*ignored
){
5249 sqlite3_create_function(pDb
, "dup", 1, SQLITE_UTF8
, &SQLTester
,
5250 SQLTester_dup_func
, 0, 0);
5251 sqlite3_create_function(pDb
, "dup_count", 0, SQLITE_UTF8
, &SQLTester
,
5252 SQLTester_dup_count_func
, 0, 0);
5256 JNIEXPORT
void JNICALL
5257 Java_org_sqlite_jni_tester_SQLTester_installCustomExtensions(JniArgsEnvClass
){
5258 sqlite3_auto_extension( (void(*)(void))SQLTester_auto_extension
);
5261 #endif /* SQLITE_JNI_ENABLE_SQLTester */
5262 ////////////////////////////////////////////////////////////////////////
5263 // End of SQLTester bindings. Start of lower-level bits.
5264 ////////////////////////////////////////////////////////////////////////
5267 ** Called during static init of the SQLite3Jni class to sync certain
5268 ** compile-time constants to Java-space.
5270 ** This routine is part of the reason why we have to #include
5271 ** sqlite3.c instead of sqlite3.h.
5273 JNIEXPORT
void JNICALL
5274 Java_org_sqlite_jni_SQLite3Jni_init(JniArgsEnvClass
){
5284 const DefineEntry aLimits
[] = {
5289 const DefineEntry
* pDef
;
5292 if( 0==sqlite3_threadsafe() ){
5293 (*env
)->FatalError(env
, "sqlite3 currently requires SQLITE_THREADSAFE!=0.");
5297 memset(&S3JniGlobal
, 0, sizeof(S3JniGlobal
));
5298 if( (*env
)->GetJavaVM(env
, &SJG
.jvm
) ){
5299 (*env
)->FatalError(env
, "GetJavaVM() failure shouldn't be possible.");
5303 /* Grab references to various global classes and objects... */
5304 SJG
.g
.cLong
= S3JniRefGlobal((*env
)->FindClass(env
,"java/lang/Long"));
5305 S3JniExceptionIsFatal("Error getting reference to Long class.");
5306 SJG
.g
.ctorLong1
= (*env
)->GetMethodID(env
, SJG
.g
.cLong
,
5308 S3JniExceptionIsFatal("Error getting reference to Long constructor.");
5310 SJG
.g
.cString
= S3JniRefGlobal((*env
)->FindClass(env
,"java/lang/String"));
5311 S3JniExceptionIsFatal("Error getting reference to String class.");
5312 SJG
.g
.ctorStringBA
=
5313 (*env
)->GetMethodID(env
, SJG
.g
.cString
,
5314 "<init>", "([BLjava/nio/charset/Charset;)V");
5315 S3JniExceptionIsFatal("Error getting reference to String(byte[],Charset) ctor.");
5316 SJG
.g
.stringGetBytes
=
5317 (*env
)->GetMethodID(env
, SJG
.g
.cString
,
5318 "getBytes", "(Ljava/nio/charset/Charset;)[B");
5319 S3JniExceptionIsFatal("Error getting reference to String.getBytes(Charset).");
5321 { /* StandardCharsets.UTF_8 */
5323 klazz
= (*env
)->FindClass(env
,"java/nio/charset/StandardCharsets");
5324 S3JniExceptionIsFatal("Error getting reference to StandardCharsets class.");
5325 fUtf8
= (*env
)->GetStaticFieldID(env
, klazz
, "UTF_8",
5326 "Ljava/nio/charset/Charset;");
5327 S3JniExceptionIsFatal("Error getting StandardCharsets.UTF_8 field.");
5328 SJG
.g
.oCharsetUtf8
=
5329 S3JniRefGlobal((*env
)->GetStaticObjectField(env
, klazz
, fUtf8
));
5330 S3JniExceptionIsFatal("Error getting reference to StandardCharsets.UTF_8.");
5331 S3JniUnrefLocal(klazz
);
5334 #ifdef SQLITE_ENABLE_FTS5
5335 klazz
= (*env
)->FindClass(env
, "org/sqlite/jni/Fts5PhraseIter");
5336 S3JniExceptionIsFatal("Error getting reference to org.sqlite.jni.Fts5PhraseIter.");
5337 SJG
.fts5
.jPhraseIter
.fidA
= (*env
)->GetFieldID(env
, klazz
, "a", "J");
5338 S3JniExceptionIsFatal("Cannot get Fts5PhraseIter.a field.");
5339 SJG
.fts5
.jPhraseIter
.fidB
= (*env
)->GetFieldID(env
, klazz
, "b", "J");
5340 S3JniExceptionIsFatal("Cannot get Fts5PhraseIter.b field.");
5341 S3JniUnrefLocal(klazz
);
5344 SJG
.mutex
= sqlite3_mutex_alloc(SQLITE_MUTEX_FAST
);
5345 s3jni_oom_fatal( SJG
.mutex
);
5346 SJG
.envCache
.mutex
= sqlite3_mutex_alloc(SQLITE_MUTEX_FAST
);
5347 s3jni_oom_fatal( SJG
.envCache
.mutex
);
5348 SJG
.perDb
.mutex
= sqlite3_mutex_alloc(SQLITE_MUTEX_FAST
);
5349 s3jni_oom_fatal( SJG
.perDb
.mutex
);
5350 SJG
.autoExt
.mutex
= sqlite3_mutex_alloc(SQLITE_MUTEX_FAST
);
5351 s3jni_oom_fatal( SJG
.autoExt
.mutex
);
5353 #if S3JNI_METRICS_MUTEX
5354 SJG
.metrics
.mutex
= sqlite3_mutex_alloc(SQLITE_MUTEX_FAST
);
5355 s3jni_oom_fatal( SJG
.metrics
.mutex
);
5359 /* So that it becomes legal for Java-level code to call
5360 ** sqlite3_config(), if it's ever implemented. */;
5362 /* Set up static "consts" of the SQLite3Jni class. */
5363 for( pDef
= &aLimits
[0]; pDef
->zName
; ++pDef
){
5364 char const * zSig
= (JTYPE_BOOL
== pDef
->jtype
) ? "Z" : "I";
5365 fieldId
= (*env
)->GetStaticFieldID(env
, jKlazz
, pDef
->zName
, zSig
);
5366 S3JniExceptionIsFatal("Missing an expected static member of the SQLite3Jni class.");
5368 switch( pDef
->jtype
){
5370 (*env
)->SetStaticIntField(env
, jKlazz
, fieldId
, (jint
)pDef
->value
);
5373 (*env
)->SetStaticBooleanField(env
, jKlazz
, fieldId
,
5374 pDef
->value
? JNI_TRUE
: JNI_FALSE
);
5377 S3JniExceptionIsFatal("Seting a static member of the SQLite3Jni class failed.");