struct {
S3JniEnv * aHead /* Linked list of in-use instances */;
S3JniEnv * aFree /* Linked list of free instances */;
- sqlite3_mutex * mutex /* mutex for aHead and aFree as well for
- first-time inits of nph[] entries. */;
+ sqlite3_mutex * mutex /* mutex for aHead and aFree, first-time
+ inits of nph[] entries, and
+ NativePointerHolder_get/set(). */;
void const * locker /* env mutex is held on this object's behalf.
Used only for sanity checking. */;
} envCache;
** argument is a Java sqlite3 object, as this operation only has void
** pointers to work with.
*/
-#define PtrGet_T(T,OBJ) NativePointerHolder_get(env, OBJ, &S3NphRefs.T)
+#define PtrGet_T(T,OBJ) NativePointerHolder_get(OBJ, &S3NphRefs.T)
#define PtrGet_sqlite3(OBJ) PtrGet_T(sqlite3, OBJ)
#define PtrGet_sqlite3_stmt(OBJ) PtrGet_T(sqlite3_stmt, OBJ)
#define PtrGet_sqlite3_value(OBJ) PtrGet_T(sqlite3_value, OBJ)
** insofar as possible. Calls (*env)->FatalError() if allocation of an
** entry fails. That's hypothetically possible but "shouldn't happen."
*/
-static S3JniEnv * S3JniEnv_get(JNIEnv * const env){
+static S3JniEnv * S3JniEnv__get(JNIEnv * const env){
struct S3JniEnv * row;
S3JniMutex_Env_enter;
row = SJG.envCache.aHead;
return row;
}
+#define S3JniEnv_get() S3JniEnv__get(env)
+
/*
** This function is NOT part of the sqlite3 public API. It is strictly
** for use by the sqlite project's own Java/JNI bindings.
}
/*
-** Clears s's state and moves it to the free-list. Requires that that the
-** caller has locked S3JniGlobal.perDb.mutex.
+** Clears s's state and moves it to the free-list. Requires that
+** S3JniGlobal.perDb.mutex is locked.
*/
-static void S3JniDb_set_aside(JNIEnv * const env, S3JniDb * const s){
+static void S3JniDb__set_aside_unlocked(JNIEnv * const env, S3JniDb * const s){
+ assert( s );
if( s ){
- S3JniMutex_S3JniDb_enter;
+ S3JniMutex_S3JniDb_assertLocker;
assert(s->pPrev != s);
assert(s->pNext != s);
assert(s->pPrev ? (s->pPrev!=s->pNext) : 1);
s->pNext = SJG.perDb.aFree;
if(s->pNext) s->pNext->pPrev = s;
SJG.perDb.aFree = s;
- S3JniMutex_S3JniDb_leave;
}
}
+static void S3JniDb__set_aside(JNIEnv * const env, S3JniDb * const s){
+ S3JniMutex_S3JniDb_enter;
+ S3JniDb__set_aside_unlocked(env, s);
+ S3JniMutex_S3JniDb_leave;
+}
+#define S3JniDb_set_aside(JNIDB) S3JniDb__set_aside(env, JNIDB)
+
/*
** Uncache any state for the given JNIEnv, clearing all Java
** references the cache owns. Returns true if env was cached and false
/*
** Searches the NativePointerHolder cache for the given combination of
-** args. It returns a cache entry with its klazz member set.
+** args. It returns a cache entry with its klazz member set. This is
+** an O(1) operation except on the first call for a given pRef, during
+** which pRef->klazz and pRef->pRef are initialized thread-safely. In
+** the latter case it's still effectively O(1), but with a much longer
+** 1.
**
** It is up to the caller to populate the other members of the
-** returned object if needed, taking care to lock the population with
-** S3JniMutex_Nph_enter/LEAVE.
+** returned object if needed, taking care to lock the modification
+** with S3JniMutex_Nph_enter/leave.
**
** This simple cache catches >99% of searches in the current
** (2023-07-31) tests.
*/
-static S3JniNphClass * S3JniGlobal_nph(JNIEnv * const env, S3NphRef const* pRef){
+static S3JniNphClass * S3JniGlobal__nph(JNIEnv * const env, S3NphRef const* pRef){
/**
According to:
return pNC;
}
+#define S3JniGlobal_nph(PREF) S3JniGlobal__nph(env, PREF)
+
/*
** Returns the ID of the "nativePointer" field from the given
** NativePointerHolder<T> class.
*/
static jfieldID NativePointerHolder_field(JNIEnv * const env,
S3NphRef const* pRef){
- S3JniNphClass * const pNC = S3JniGlobal_nph(env, pRef);
+ S3JniNphClass * const pNC = S3JniGlobal_nph(pRef);
if( !pNC->fidValue ){
S3JniMutex_Nph_enter;
if( !pNC->fidValue ){
** zClassName must be a static string so we can use its address
** as a cache key.
*/
-static void NativePointerHolder_set(JNIEnv * env, S3NphRef const* pRef,
+static void NativePointerHolder__set(JNIEnv * env, S3NphRef const* pRef,
jobject ppOut, const void * p){
- (*env)->SetLongField(env, ppOut, NativePointerHolder_field(env, pRef),
- (jlong)p);
+ jfieldID const fid = NativePointerHolder_field(env, pRef);
+ S3JniMutex_Nph_enter;
+ (*env)->SetLongField(env, ppOut, fid, (jlong)p);
+ S3JniMutex_Nph_leave;
S3JniExceptionIsFatal("Could not set NativePointerHolder.nativePointer.");
}
+#define NativePointerHolder_set(PREF,PPOUT,P) \
+ NativePointerHolder__set(env, PREF, PPOUT, P)
+
/*
** Fetches a native ptr value from NativePointerHolder object ppOut.
** zClassName must be a static string so we can use its address as a
** cache key. This is a no-op if pObj is NULL.
*/
-static void * NativePointerHolder_get(JNIEnv * env, jobject pObj,
- S3NphRef const* pRef){
+static void * NativePointerHolder__get(JNIEnv * env, jobject pObj,
+ S3NphRef const* pRef){
if( pObj ){
- void * const rv = (void*)(*env)->GetLongField(
- env, pObj, NativePointerHolder_field(env, pRef)
- );
+ jfieldID const fid = NativePointerHolder_field(env, pRef);
+ void * rv;
+ S3JniMutex_Nph_enter;
+ rv = (void*)(*env)->GetLongField(env, pObj, fid);
+ S3JniMutex_Nph_leave;
S3JniExceptionIsFatal("Cannot fetch NativePointerHolder.nativePointer.");
return rv;
}else{
}
}
+#define NativePointerHolder_get(JOBJ,NPHREF) \
+ NativePointerHolder__get(env, (JOBJ), (NPHREF))
+
/*
** Extracts the new S3JniDb instance from the free-list, or allocates
** one if needed, associats it with pDb, and returns. Returns NULL on
return rv;
}
+/* Short-lived code consolidator. */
+#define S3JniDb_search \
+ s = SJG.perDb.aHead; \
+ for( ; pDb && s; s = s->pNext){ \
+ if( s->pDb == pDb ) break; \
+ }
+
/*
** Returns the S3JniDb object for the given org.sqlite.jni.sqlite3
** object, or NULL if jDb is NULL, no pointer can be extracted
static S3JniDb * S3JniDb__from_java(JNIEnv * const env, jobject jDb){
S3JniDb * s = 0;
sqlite3 * pDb = 0;
+
S3JniMutex_S3JniDb_enter;
- if( jDb ){
- pDb = PtrGet_sqlite3(jDb);
- }
- s = SJG.perDb.aHead;
- for( ; pDb && s; s = s->pNext){
- if( s->pDb == pDb ){
- break;
- }
- }
+ if( jDb ) pDb = PtrGet_sqlite3(jDb);
+ S3JniDb_search;
S3JniMutex_S3JniDb_leave;
return s;
}
+/* An experiment */
+//#define CLOSE_DB_LOCKED
+#if defined(CLOSE_DB_LOCKED)
+static S3JniDb * S3JniDb__from_java_unlocked(JNIEnv * const env, jobject jDb){
+ S3JniDb * s = 0;
+ sqlite3 * pDb = 0;
+
+ S3JniMutex_S3JniDb_assertLocker;
+ if( jDb ) pDb = PtrGet_sqlite3(jDb);
+ S3JniDb_search;
+ return s;
+}
+#endif
+
/*
** Returns the S3JniDb object for the sqlite3 object, or NULL if pDb
** is NULL, or no matching entry
*/
static S3JniDb * S3JniDb__from_c(JNIEnv * const env, sqlite3 *pDb){
S3JniDb * s = 0;
+
S3JniMutex_S3JniDb_enter;
- s = SJG.perDb.aHead;
- for( ; pDb && s; s = s->pNext){
- if( s->pDb == pDb ){
- break;
- }
- }
+ S3JniDb_search;
S3JniMutex_S3JniDb_leave;
return s;
}
** misbehave.
*/
static jfieldID OutputPointer_field(JNIEnv * const env, S3NphRef const * pRef){
- S3JniNphClass * const pNC = S3JniGlobal_nph(env, pRef);
+ S3JniNphClass * const pNC = S3JniGlobal_nph(pRef);
+
+ assert( pNC->klazz );
if( !pNC->fidValue ){
S3JniMutex_Nph_enter;
if( !pNC->fidValue ){
static jobject new_NativePointerHolder_object(JNIEnv * const env, S3NphRef const * pRef,
const void * pNative){
jobject rv = 0;
- S3JniNphClass * const pNC = S3JniGlobal_nph(env, pRef);
+ S3JniNphClass * const pNC = S3JniGlobal_nph(pRef);
if( !pNC->midCtor ){
S3JniMutex_Nph_enter;
if( !pNC->midCtor ){
rv = (*env)->NewObject(env, pNC->klazz, pNC->midCtor);
S3JniExceptionIsFatal("No-arg constructor threw.");
s3jni_oom_check(rv);
- if( rv ) NativePointerHolder_set(env, pRef, rv, pNative);
+ if( rv ) NativePointerHolder_set(pRef, rv, pNative);
return rv;
}
if( !jcx ) goto error_oom;
ja = (*env)->NewObjectArray(
env, argc, SJG.g.cObj
- /* S3JniGlobal_nph(env,&S3NphRefs.sqlite3_value)->klazz would be
+ /* S3JniGlobal_nph(&S3NphRefs.sqlite3_value)->klazz would be
more correct, but it unpredictably triggers an assert in the
JVM. */, NULL);
s3jni_oom_check( ja );
if( 0==SJG.autoExt.nExt ) return 0;
env = s3jni_env();
- jc = S3JniEnv_get(env);
+ jc = S3JniEnv_get();
ps = jc->pdbOpening;
if( !ps ){
*pzErr = sqlite3_mprintf("Unexpected arrival of null S3JniDb in "
assert( !ps->pDb && "it's still being opened" );
assert( ps->jDb );
ps->pDb = pDb;
- NativePointerHolder_set(env, &S3NphRefs.sqlite3, ps->jDb, pDb)
+ NativePointerHolder_set(&S3NphRefs.sqlite3, ps->jDb, pDb)
/* As of here, the Java/C connection is complete */;
for( i = 0; go && 0==rc; ++i ){
S3JniAutoExtension ax = {0,0}
/* Wrapper for sqlite3_close(_v2)(). */
static jint s3jni_close_db(JNIEnv * const env, jobject jDb, int version){
int rc = 0;
+
+#ifndef CLOSE_DB_LOCKED
S3JniDb * const ps = S3JniDb_from_java(jDb);
assert(version == 1 || version == 2);
if( ps ){
? (jint)sqlite3_close(ps->pDb)
: (jint)sqlite3_close_v2(ps->pDb);
if( 0==rc ){
- S3JniDb_set_aside(env, ps)
+ S3JniDb_set_aside(ps)
/* MUST come after close() because of ps->trace. */;
- NativePointerHolder_set(env, &S3NphRefs.sqlite3, jDb, 0);
+ NativePointerHolder_set(&S3NphRefs.sqlite3, jDb, 0);
}
}
+#else
+ /* This impl leads to an assertion in sqlite3_close[_v2]()
+
+ pthreadMutexEnter: Assertion `p->id==SQLITE_MUTEX_RECURSIVE
+ || pthreadMutexNotheld(p)' failed.
+
+ For reasons not yet fully understood.
+ */
+ assert(version == 1 || version == 2);
+ if( 0!=jDb ){
+ S3JniDb * ps;
+ S3JniMutex_S3JniDb_enter;
+ ps = S3JniDb__from_java_unlocked(env, jDb);
+ if( ps && ps->pDb ){
+ rc = 1==version
+ ? (jint)sqlite3_close(ps->pDb)
+ : (jint)sqlite3_close_v2(ps->pDb);
+ if( 0==rc ){
+ S3JniDb__set_aside_unlocked(env,ps)
+ /* MUST come after close() because of ps->trace. */;
+ NativePointerHolder_set(&S3NphRefs.sqlite3, jDb, 0);
+ }
+ }else{
+ /* ps is from S3Global.perDb.aFree. */
+ }
+ S3JniMutex_S3JniDb_leave;
+ }
+#endif
return (jint)rc;
}
sqlite3_stmt * const pStmt = PtrGet_sqlite3_stmt(jpStmt);
if( pStmt ){
rc = sqlite3_finalize(pStmt);
- NativePointerHolder_set(env, &S3NphRefs.sqlite3_stmt, jpStmt, 0);
+ NativePointerHolder_set(&S3NphRefs.sqlite3_stmt, jpStmt, 0);
}
return rc;
}
S3JniDb ** ps){
int rc = 0;
jobject jDb = 0;
- *jc = S3JniEnv_get(env);
+ *jc = S3JniEnv_get();
if( !*jc ){
rc = SQLITE_NOMEM;
goto end;
assert(ps->jDb);
if( 0==ps->pDb ){
ps->pDb = *ppDb;
- NativePointerHolder_set(env, &S3NphRefs.sqlite3, ps->jDb, *ppDb)
+ NativePointerHolder_set(&S3NphRefs.sqlite3, ps->jDb, *ppDb)
/* As of here, the Java/C connection is complete */;
}else{
assert( ps->pDb==*ppDb
&& "Set up via s3jni_run_java_auto_extensions()" );
}
}else{
- S3JniDb_set_aside(env, ps);
+ S3JniDb_set_aside(ps);
ps = 0;
}
OutputPointer_set_sqlite3(env, jOut, ps ? ps->jDb : 0);
OutputPointer_set_Int32(env, outTail, (int)(zTail ? (zTail - (const char *)pBuf) : 0));
}
if( pStmt ){
- NativePointerHolder_set(env, &S3NphRefs.sqlite3_stmt, jStmt, pStmt);
+ NativePointerHolder_set(&S3NphRefs.sqlite3_stmt, jStmt, pStmt);
}else{
/* Happens for comments and whitespace. */
S3JniUnrefLocal(jStmt);
printf("Mutex entry:"
"\n\tglobal = %u"
"\n\tenv = %u"
- "\n\tnph inits = %u"
+ "\n\tnph = %u"
"\n\tperDb = %u"
"\n\tautoExt list = %u"
"\n\tS3JniUdf free-list = %u"
SJG.metrics.nMutexEnv2, SJG.metrics.nMutexPerDb,
SJG.metrics.nMutexAutoExt, SJG.metrics.nMutexUdf,
SJG.metrics.nMetrics);
- printf("S3JniDb: %u alloced (*%u = %u bytes), %u recycled\n",
+ puts("Allocs:");
+ printf("\tS3JniDb: %u alloced (*%u = %u bytes), %u recycled\n",
SJG.metrics.nPdbAlloc, (unsigned) sizeof(S3JniDb),
(unsigned)(SJG.metrics.nPdbAlloc * sizeof(S3JniDb)),
SJG.metrics.nPdbRecycled);
- printf("S3JniUdf: %u alloced (*%u = %u bytes), %u recycled\n",
+ printf("\tS3JniUdf: %u alloced (*%u = %u bytes), %u recycled\n",
SJG.metrics.nUdfAlloc, (unsigned) sizeof(S3JniUdf),
(unsigned)(SJG.metrics.nUdfAlloc * sizeof(S3JniUdf)),
SJG.metrics.nUdfRecycled);
JNIEXPORT ReturnType JNICALL \
JniFuncNameFtsTok(Suffix)
-#define PtrGet_fts5_api(OBJ) NativePointerHolder_get(env,OBJ,&S3NphRefs.fts5_api)
-#define PtrGet_fts5_tokenizer(OBJ) NativePointerHolder_get(env,OBJ,&S3NphRefs.fts5_tokenizer)
-#define PtrGet_Fts5Context(OBJ) NativePointerHolder_get(env,OBJ,&S3NphRefs.Fts5Context)
-#define PtrGet_Fts5Tokenizer(OBJ) NativePointerHolder_get(env,OBJ,&S3NphRefs.Fts5Tokenizer)
+#define PtrGet_fts5_api(OBJ) NativePointerHolder_get(OBJ,&S3NphRefs.fts5_api)
+#define PtrGet_fts5_tokenizer(OBJ) NativePointerHolder_get(OBJ,&S3NphRefs.fts5_tokenizer)
+#define PtrGet_Fts5Context(OBJ) NativePointerHolder_get(OBJ,&S3NphRefs.Fts5Context)
+#define PtrGet_Fts5Tokenizer(OBJ) NativePointerHolder_get(OBJ,&S3NphRefs.Fts5Tokenizer)
#define Fts5ExtDecl Fts5ExtensionApi const * const fext = s3jni_ftsext()
/**
JniDeclFtsXA(jint,xQueryPhrase)(JniArgsEnvObj,jobject jFcx, jint iPhrase,
jobject jCallback){
Fts5ExtDecl;
- S3JniEnv * const jc = S3JniEnv_get(env);
+ S3JniEnv * const jc = S3JniEnv_get();
struct s3jni_xQueryPhraseState s;
jclass klazz = jCallback ? (*env)->GetObjectClass(env, jCallback) : NULL;
jint tokFlags, jobject jFcx,
jbyteArray jbaText, jobject jCallback){
Fts5ExtDecl;
- S3JniEnv * const jc = S3JniEnv_get(env);
+ S3JniEnv * const jc = S3JniEnv_get();
struct s3jni_xQueryPhraseState s;
int rc = 0;
jbyte * const pText = jCallback ? s3jni_jbytearray_bytes(jbaText) : 0;
<p><a href="https://sqlite.org/c3ref/intro.html">https://sqlite.org/c3ref/intro.html</a>
- <p>A handful of Java-specific APIs have been added which are documented
- here.
+ <p>A handful of Java-specific APIs have been added which are
+ documented here. A number of convenience overloads are provided
+ which are not documented but whose semantics map 1-to-1 in an
+ intuitive manner. e.g. {@link
+ #sqlite3_result_set(sqlite3_context,int)} is equivalent to {@link
+ #sqlite3_result_int}, and sqlite3_result_set() has many
+ type-specific overloads.
<p>Though most of the {@code SQLITE_abc...} C macros represented by
this class are defined as final, a few are necessarily non-final
/**
Works like the C-level sqlite3_bind_text() but assumes
- SQLITE_TRANSIENT for the final C API parameter.
+ SQLITE_TRANSIENT for the final C API parameter. The byte array is
+ assumed to be in UTF-8 encoding.
<p>Results are undefined if data is not null and
- maxBytes>=data.length. If maxBytes is negative then results are
+ maxBytes>=utf8.length. If maxBytes is negative then results are
undefined if data is not null and does not contain a NUL byte.
*/
@Canonical
- private static native int sqlite3_bind_text(
- @NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data, int maxBytes
+ public static native int sqlite3_bind_text(
+ @NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] utf8, int maxBytes
);
/**
}
/**
- Requires that data be null or in UTF-8 encoding.
+ Requires that utf8 be null or in UTF-8 encoding.
*/
public static int sqlite3_bind_text(
- @NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data
+ @NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] utf8
){
- return (null == data)
+ return (null == utf8)
? sqlite3_bind_null(stmt, ndx)
- : sqlite3_bind_text(stmt, ndx, data, data.length);
+ : sqlite3_bind_text(stmt, ndx, utf8, utf8.length);
}
/**
platform byte order.
*/
@Canonical
- private static native int sqlite3_bind_text16(
+ public static native int sqlite3_bind_text16(
@NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data, int maxBytes
);
class.) For that vast majority of uses, that capability is not
necessary, however, and overloads are provided which gloss over
that.
+
+ <p>Results are undefined if maxBytes>=sqlUtf8.length.
+
+ <p>This routine is private because its maxBytes value is not
+ strictly necessary in the Java interface, as sqlUtf8.length tells
+ us the information we need. Making this public would give clients
+ more ways to shoot themselves in the foot without providing any
+ real utility.
*/
@Canonical
private static native int sqlite3_prepare(
@Nullable OutputPointer.Int32 pTailOffset
);
+ /**
+ Works like the canonical sqlite3_prepare() but its "tail" output
+ argument is returned as the index offset into the given
+ UTF-8-encoded byte array at which SQL parsing stopped. The
+ semantics are otherwise identical to the C API counterpart.
+
+ <p>Several overloads provided simplified call signatures.
+ */
public static int sqlite3_prepare(
@NotNull sqlite3 db, @NotNull byte[] sqlUtf8,
@NotNull OutputPointer.sqlite3_stmt outStmt,
}
/**
- See sqlite3_prepare() for details about the slight API differences
- from the C API.
+ @see #sqlite3_prepare
*/
@Canonical
private static native int sqlite3_prepare_v2(
@Nullable OutputPointer.Int32 pTailOffset
);
+ /**
+ Works like the canonical sqlite3_prepare_v2() but its "tail"
+ output paramter is returned as the index offset into the given
+ byte array at which SQL parsing stopped.
+ */
public static int sqlite3_prepare_v2(
@NotNull sqlite3 db, @NotNull byte[] sqlUtf8,
@NotNull OutputPointer.sqlite3_stmt outStmt,
return out.take();
}
+ /**
+ @see #sqlite3_prepare
+ */
@Canonical
private static native int sqlite3_prepare_v3(
@NotNull sqlite3 db, @NotNull byte[] sqlUtf8, int maxBytes,
@Nullable OutputPointer.Int32 pTailOffset
);
+ /**
+ Works like the canonical sqlite3_prepare_v2() but its "tail"
+ output paramter is returned as the index offset into the given
+ byte array at which SQL parsing stopped.
+ */
public static int sqlite3_prepare_v3(
@NotNull sqlite3 db, @NotNull byte[] sqlUtf8, int prepFlags,
@NotNull OutputPointer.sqlite3_stmt outStmt,
}
/**
- Equivalent to passing e.getMessage() to
- sqlite3_result_error(db,String).
+ Equivalent to passing e.toString() to {@link
+ #sqlite3_result_error(sqlite3_context,String)}. Note that
+ toString() is used instead of getMessage() because the former
+ prepends the exception type name to the message.
*/
public static void sqlite3_result_error(
@NotNull sqlite3_context cx, @NotNull Exception e
){
- sqlite3_result_error(cx, e.getMessage());
+ sqlite3_result_error(cx, e.toString());
}
@Canonical
);
/**
- Binds the SQL result to the given object, or
- {@link #sqlite3_result_null} if {@code o} is null. Use
- {@link #sqlite3_value_java_object(sqlite3_value) sqlite3_value_java_object()} to
- fetch it.
+ Binds the SQL result to the given object, or {@link
+ #sqlite3_result_null} if {@code o} is null. Use {@link
+ #sqlite3_value_java_object} to fetch it.
<p>This is implemented in terms of C's sqlite3_result_pointer(),
- but that function is not exposed to JNI because its 3rd argument
- must be a constant string (the library does not copy it), and
- those semantics are cumbersome to bridge cross-language. Java
- doesn't need that argument for type safety, in any case: the
- object can, after extraction on the other end of the API, be
- inspected with {@code instanceof}.
+ but that function is not exposed to JNI because (A)
+ cross-language semantic mismatch and (B) Java doesn't need that
+ argument for its intended purpose (type safety).
<p>Note that there is no sqlite3_column_java_object(), as the
C-level API has no sqlite3_column_pointer() to proxy.
);
public static void sqlite3_result_set(
- @NotNull sqlite3_context cx, @NotNull Integer v
+ @NotNull sqlite3_context cx, @NotNull Boolean v
){
- sqlite3_result_int(cx, v);
+ sqlite3_result_int(cx, v ? 1 : 0);
}
public static void sqlite3_result_set(
- @NotNull sqlite3_context cx, int v
+ @NotNull sqlite3_context cx, boolean v
){
- sqlite3_result_int(cx, v);
+ sqlite3_result_int(cx, v ? 1 : 0);
}
public static void sqlite3_result_set(
- @NotNull sqlite3_context cx, @NotNull Boolean v
+ @NotNull sqlite3_context cx, @NotNull Double v
){
- sqlite3_result_int(cx, v ? 1 : 0);
+ sqlite3_result_double(cx, v);
}
public static void sqlite3_result_set(
- @NotNull sqlite3_context cx, boolean v
+ @NotNull sqlite3_context cx, double v
){
- sqlite3_result_int(cx, v ? 1 : 0);
+ sqlite3_result_double(cx, v);
}
public static void sqlite3_result_set(
- @NotNull sqlite3_context cx, @NotNull Long v
+ @NotNull sqlite3_context cx, @NotNull Integer v
){
- sqlite3_result_int64(cx, v);
+ sqlite3_result_int(cx, v);
+ }
+
+ public static void sqlite3_result_set(@NotNull sqlite3_context cx, int v){
+ sqlite3_result_int(cx, v);
}
public static void sqlite3_result_set(
- @NotNull sqlite3_context cx, long v
+ @NotNull sqlite3_context cx, @NotNull Long v
){
sqlite3_result_int64(cx, v);
}
public static void sqlite3_result_set(
- @NotNull sqlite3_context cx, @NotNull Double v
+ @NotNull sqlite3_context cx, long v
){
- sqlite3_result_double(cx, v);
+ sqlite3_result_int64(cx, v);
}
public static void sqlite3_result_set(
- @NotNull sqlite3_context cx, double v
+ @NotNull sqlite3_context cx, @Nullable String v
){
- sqlite3_result_double(cx, v);
+ if( null==v ) sqlite3_result_null(cx);
+ else sqlite3_result_text(cx, v);
}
public static void sqlite3_result_set(
- @NotNull sqlite3_context cx, @Nullable String v
+ @NotNull sqlite3_context cx, @Nullable byte[] blob
){
- sqlite3_result_text(cx, v);
+ if( null==blob ) sqlite3_result_null(cx);
+ else sqlite3_result_blob(cx, blob, blob.length);
}
@Canonical