** S3JniApi's intent is that CFunc be the C API func(s) the
** being-declared JNI function is wrapping, making it easier to find
** that function's JNI-side entry point. The other args are for JniDecl.
- */
+** See the many examples in this file.
+*/
#define S3JniApi(CFunc,ReturnType,Suffix) JniDecl(ReturnType,Suffix)
/*
};
/*
-** Cache keys for each concrete NativePointerHolder subclass and
-** OutputPointer.T type. The members are to be used with
-** s3jni_nph() and friends, and each one's member->index
-** corresponds to its index in the S3JniGlobal.nph[] array.
+** Cache keys for each concrete NativePointerHolder subclasses and
+** OutputPointer.T types. The members are to be used with s3jni_nph()
+** and friends, and each one's member->index corresponds to its index
+** in the S3JniGlobal.nph[] array.
*/
static const struct {
const S3JniNphRef sqlite3;
#undef RefO
};
+#define S3JniNph(T) &S3JniNphRefs.T
+
enum {
/*
** Size of the NativePointerHolder cache. Need enough space for
*/
typedef struct S3JniNphClass S3JniNphClass;
struct S3JniNphClass {
- volatile const S3JniNphRef * pRef /* Entry from S3JniNphRefs. */;
- jclass klazz /* global ref to the concrete
- ** NativePointerHolder subclass
- ** represented by zClassName */;
+ volatile const S3JniNphRef * pRef /* Entry from S3JniNphRefs */;
+ /*
+ ** klazz is a global ref to the class represented by pRef.
+ **
+ ** According to:
+ **
+ ** https://developer.ibm.com/articles/j-jni/
+ **
+ ** > ... the IDs returned for a given class don't change for the
+ ** lifetime of the JVM process. But the call to get the field or
+ ** method can require significant work in the JVM, because fields
+ ** and methods might have been inherited from superclasses, making
+ ** the JVM walk up the class hierarchy to find them. Because the
+ ** IDs are the same for a given class, you should look them up
+ ** once and then reuse them. Similarly, looking up class objects
+ ** can be expensive, so they should be cached as well.
+ */
+ jclass klazz;
volatile jmethodID midCtor /* klazz's no-arg constructor. Used by
** new_NativePointerHolder_object(). */;
volatile jfieldID fidValue /* NativePointerHolder.nativePointer or
*/
typedef struct S3JniEnv S3JniEnv;
struct S3JniEnv {
- JNIEnv *env /* env in which this cache entry was created */;
+ JNIEnv *env /* JNIEnv in which this cache entry was created */;
/*
** pdbOpening is used to coordinate the Java/DB connection of a
** being-open()'d db in the face of auto-extensions.
** threads. Caching a copy of the JavaVM object enables any thread
** with access to the cached object to get access to its own
** JNIEnv when necessary.
- **
*/
JavaVM * jvm;
/* Global mutex. */
struct {
S3JniEnv * aHead /* Linked list of in-use instances */;
S3JniEnv * aFree /* Linked list of free instances */;
- sqlite3_mutex * mutex /* mutex for aHead and aFree, first-time
- inits of nph[] entries, and
- NativePointerHolder_get/set(). */;
+ sqlite3_mutex * mutex /* mutex for aHead and aFree, and first-time
+ inits of nph[] entries. */;
void const * locker /* env mutex is held on this object's behalf.
Used only for sanity checking. */;
} envCache;
** Returns errCode unless it is 0, in which case SQLITE_ERROR is
** returned.
*/
-static int s3jni__db_exception(JNIEnv * const env, S3JniDb * const ps,
+static int s3jni__db_exception(JNIEnv * const env, sqlite3 * const pDb,
int errCode, const char *zDfltMsg){
jthrowable const ex = (*env)->ExceptionOccurred(env);
if( ex ){
char * zMsg;
S3JniExceptionClear;
- S3JniDb_mutex_enter;
zMsg = s3jni_exception_error_msg(env, ex);
- s3jni_db_error(ps->pDb, errCode, zMsg ? zMsg : zDfltMsg);
+ s3jni_db_error(pDb, errCode, zMsg ? zMsg : zDfltMsg);
sqlite3_free(zMsg);
S3JniUnrefLocal(ex);
- S3JniDb_mutex_leave;
+ }else if( zDfltMsg ){
+ s3jni_db_error(pDb, errCode, zDfltMsg);
}
return errCode;
}
-#define s3jni_db_exception(JniDb,ERRCODE,DFLTMSG) \
- s3jni__db_exception(env, (JniDb), (ERRCODE), (DFLTMSG) )
+#define s3jni_db_exception(pDb,ERRCODE,DFLTMSG) \
+ s3jni__db_exception(env, (pDb), (ERRCODE), (DFLTMSG) )
/*
** Extracts the (void xDestroy()) method from jObj and applies it to
}
*s = S3JniHook_empty;
}
-#define S3JniHook_unref(hook) \
- S3JniHook__unref(env, (hook))
+#define S3JniHook_unref(hook) S3JniHook__unref(env, (hook))
/*
** Allocates one blank S3JniHook object from the recycling bin, if
static int S3JniEnv_uncache(JNIEnv * const env){
struct S3JniEnv * row;
struct S3JniEnv * pPrev = 0;
+
S3JniEnv_mutex_assertLocked;
row = SJG.envCache.aHead;
for( ; row; pPrev = row, row = row->pNext ){
** (2023-07-31) tests.
*/
static S3JniNphClass * s3jni__nph(JNIEnv * const env, S3JniNphRef const* pRef){
- /**
- According to:
-
- https://developer.ibm.com/articles/j-jni/
-
- > ... the IDs returned for a given class don't change for the
- lifetime of the JVM process. But the call to get the field or
- method can require significant work in the JVM, because
- fields and methods might have been inherited from
- superclasses, making the JVM walk up the class hierarchy to
- find them. Because the IDs are the same for a given class,
- you should look them up once and then reuse them. Similarly,
- looking up class objects can be expensive, so they should be
- cached as well.
- */
S3JniNphClass * const pNC = &SJG.nph[pRef->index];
+
assert( (void*)pRef>=(void*)&S3JniNphRefs && (void*)pRef<(void*)(&S3JniNphRefs + 1)
- && "pRef is out of range." );
+ && "pRef is out of range" );
assert( pRef->index>=0
- && (pRef->index < (sizeof(S3JniNphRefs) / sizeof(S3JniNphRef))) );
+ && (pRef->index < (sizeof(S3JniNphRefs) / sizeof(S3JniNphRef)))
+ && "pRef->index is out of range" );
if( !pNC->pRef ){
S3JniNph_mutex_enter;
if( !pNC->pRef ){
** argument is a Java sqlite3 object, as this operation only has void
** pointers to work with.
*/
-#define PtrGet_T(T,OBJ) NativePointerHolder_get(OBJ, &S3JniNphRefs.T)
+#define PtrGet_T(T,OBJ) NativePointerHolder_get(OBJ, S3JniNph(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)
static void OutputPointer_set_Bool(JNIEnv * const env, jobject const jOut,
int v){
(*env)->SetBooleanField(env, jOut, s3jni_nphop_field(
- env, &S3JniNphRefs.OutputPointer_Bool
+ env, S3JniNph(OutputPointer_Bool)
), v ? JNI_TRUE : JNI_FALSE );
S3JniExceptionIsFatal("Cannot set OutputPointer.Bool.value");
}
static void OutputPointer_set_Int32(JNIEnv * const env, jobject const jOut,
int v){
(*env)->SetIntField(env, jOut, s3jni_nphop_field(
- env, &S3JniNphRefs.OutputPointer_Int32
+ env, S3JniNph(OutputPointer_Int32)
), (jint)v);
S3JniExceptionIsFatal("Cannot set OutputPointer.Int32.value");
}
static void OutputPointer_set_Int64(JNIEnv * const env, jobject const jOut,
jlong v){
(*env)->SetLongField(env, jOut, s3jni_nphop_field(
- env, &S3JniNphRefs.OutputPointer_Int64
+ env, S3JniNph(OutputPointer_Int64)
), v);
S3JniExceptionIsFatal("Cannot set OutputPointer.Int64.value");
}
*/
static void OutputPointer_set_sqlite3(JNIEnv * const env, jobject const jOut,
jobject jDb){
- OutputPointer_set_obj(env, &S3JniNphRefs.OutputPointer_sqlite3, jOut, jDb);
+ OutputPointer_set_obj(env, S3JniNph(OutputPointer_sqlite3), jOut, jDb);
}
/*
*/
static void OutputPointer_set_sqlite3_stmt(JNIEnv * const env, jobject const jOut,
jobject jStmt){
- OutputPointer_set_obj(env, &S3JniNphRefs.OutputPointer_sqlite3_stmt, jOut, jStmt);
+ OutputPointer_set_obj(env, S3JniNph(OutputPointer_sqlite3_stmt), jOut, jStmt);
}
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
*/
static void OutputPointer_set_sqlite3_value(JNIEnv * const env, jobject const jOut,
jobject jValue){
- OutputPointer_set_obj(env, &S3JniNphRefs.OutputPointer_sqlite3_value, jOut, jValue);
+ OutputPointer_set_obj(env, S3JniNph(OutputPointer_sqlite3_value), jOut, jValue);
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
*/
static void OutputPointer_set_ByteArray(JNIEnv * const env, jobject const jOut,
jbyteArray const v){
- OutputPointer_set_obj(env, &S3JniNphRefs.OutputPointer_ByteArray, jOut, v);
+ OutputPointer_set_obj(env, S3JniNph(OutputPointer_ByteArray), jOut, v);
}
#endif
#endif /* SQLITE_ENABLE_FTS5 */
*/
static void OutputPointer_set_String(JNIEnv * const env, jobject const jOut,
jstring const v){
- OutputPointer_set_obj(env, &S3JniNphRefs.OutputPointer_String, jOut, v);
+ OutputPointer_set_obj(env, S3JniNph(OutputPointer_String), jOut, v);
}
/*
/*
-** Returns a new Java instance of the class named by zClassName, which
+** Returns a new Java instance of the class referred to by pRef, which
** MUST be interface-compatible with NativePointerHolder and MUST have
** a no-arg constructor. The NativePointerHolder_set() method is
** passed the new Java object and pNative. Hypothetically returns NULL
** if Java fails to allocate, but the JNI docs are not entirely clear
** on that detail.
**
-** Always use a static pointer from the S3JniNphRefs struct for the 2nd
-** argument so that we can use pRef->index as an O(1) cache key.
+** Always use a static pointer from the S3JniNphRefs struct for the
+** 2nd argument.
*/
static jobject new_NativePointerHolder_object(JNIEnv * const env, S3JniNphRef const * pRef,
const void * pNative){
}
static inline jobject new_sqlite3_wrapper(JNIEnv * const env, sqlite3 *sv){
- return new_NativePointerHolder_object(env, &S3JniNphRefs.sqlite3, sv);
+ return new_NativePointerHolder_object(env, S3JniNph(sqlite3), sv);
}
static inline jobject new_sqlite3_context_wrapper(JNIEnv * const env, sqlite3_context *sv){
- return new_NativePointerHolder_object(env, &S3JniNphRefs.sqlite3_context, sv);
+ return new_NativePointerHolder_object(env, S3JniNph(sqlite3_context), sv);
}
static inline jobject new_sqlite3_stmt_wrapper(JNIEnv * const env, sqlite3_stmt *sv){
- return new_NativePointerHolder_object(env, &S3JniNphRefs.sqlite3_stmt, sv);
+ return new_NativePointerHolder_object(env, S3JniNph(sqlite3_stmt), sv);
}
static inline jobject new_sqlite3_value_wrapper(JNIEnv * const env, sqlite3_value *sv){
- return new_NativePointerHolder_object(env, &S3JniNphRefs.sqlite3_value, sv);
+ return new_NativePointerHolder_object(env, S3JniNph(sqlite3_value), sv);
}
/* Helper typedefs for UDF callback types. */
*jArgv = 0;
if( !jcx ) goto error_oom;
ja = (*env)->NewObjectArray(
- env, argc, s3jni_nph(&S3JniNphRefs.sqlite3_value)->klazz,
+ env, argc, s3jni_nph(S3JniNph(sqlite3_value))->klazz,
NULL);
s3jni_oom_check( ja );
if( !ja ) goto error_oom;
if( rc ){
return rc;
}
- NativePointerHolder_set(&S3JniNphRefs.sqlite3, ps->jDb, pDb)
+ NativePointerHolder_set(S3JniNph(sqlite3), ps->jDb, pDb)
/* As of here, the Java/C connection is complete except for the
(temporary) lack of finalizer for the ps object. */;
ps->pDb = pDb;
JniArgsEnvClass, jobject jAutoExt
){
int i;
- S3JniAutoExtension * ax;
+ S3JniAutoExtension * ax = 0;
int rc = 0;
if( !jAutoExt ) return SQLITE_MISUSE;
hook.midCallback, (jint)n);
S3JniIfThrew{
S3JniExceptionWarnCallbackThrew("sqlite3_busy_handler() callback");
- rc = s3jni_db_exception(ps, SQLITE_ERROR,
+ rc = s3jni_db_exception(ps->pDb, SQLITE_ERROR,
"sqlite3_busy_handler() callback threw.");
}
S3JniHook_localundup(hook);
? (jint)sqlite3_close(ps->pDb)
: (jint)sqlite3_close_v2(ps->pDb);
if( 0==rc ){
- NativePointerHolder_set(&S3JniNphRefs.sqlite3, jDb, 0);
+ NativePointerHolder_set(S3JniNph(sqlite3), jDb, 0);
}
}
return (jint)rc;
);
S3JniUnrefLocal(klazz);
S3JniIfThrew {
- rc = s3jni_db_exception(ps, SQLITE_MISUSE,
+ rc = s3jni_db_exception(ps->pDb, SQLITE_MISUSE,
"Cannot not find matching call() in "
"CollationNeededCallback object.");
}else{
return (jlong)sqlite3_column_int64(PtrGet_sqlite3_stmt(jpStmt), (int)ndx);
}
-S3JniApi(sqlite3_column_text(),jbyteArray,1column_1text_1utf8)(
+S3JniApi(sqlite3_column_text(),jbyteArray,1column_1text)(
JniArgsEnvClass, jobject jpStmt, jint ndx
){
sqlite3_stmt * const stmt = PtrGet_sqlite3_stmt(jpStmt);
return p ? s3jni_new_jbyteArray(p, n) : NULL;
}
+#if 0
+// this impl might prove useful, but we'd need to publish the
+// bytearray-returning impl with a different name.
S3JniApi(sqlite3_column_text(),jstring,1column_1text)(
JniArgsEnvClass, jobject jpStmt, jint ndx
){
const unsigned char * const p = sqlite3_column_text(stmt, (int)ndx);
return p ? s3jni_utf8_to_jstring( (const char *)p, n) : 0;
}
+#endif
S3JniApi(sqlite3_column_text16(),jstring,1column_1text16)(
JniArgsEnvClass, jobject jpStmt, jint ndx
}
/*
-** Impl for both commit hooks (if isCommit is true) or rollback hooks.
+** Impl for commit hooks (if isCommit is true) or rollback hooks.
*/
static int s3jni_commit_rollback_hook_impl(int isCommit, S3JniDb * const ps){
S3JniDeclLocal_env;
? (int)(*env)->CallIntMethod(env, hook.jObj, hook.midCallback)
: (int)((*env)->CallVoidMethod(env, hook.jObj, hook.midCallback), 0);
S3JniIfThrew{
- S3JniExceptionClear;
- rc = s3jni_db_error(ps->pDb, SQLITE_ERROR, "hook callback threw.");
+ rc = s3jni_db_exception(ps->pDb, SQLITE_ERROR, "hook callback threw");
}
S3JniHook_localundup(hook);
}
sqlite3_stmt * const pStmt = PtrGet_sqlite3_stmt(jpStmt);
if( pStmt ){
rc = sqlite3_finalize(pStmt);
- NativePointerHolder_set(&S3JniNphRefs.sqlite3_stmt, jpStmt, 0);
+ NativePointerHolder_set(S3JniNph(sqlite3_stmt), jpStmt, 0);
}
return rc;
}
assert(ps->jDb);
if( 0==ps->pDb ){
ps->pDb = *ppDb;
- NativePointerHolder_set(&S3JniNphRefs.sqlite3, ps->jDb, *ppDb);
+ NativePointerHolder_set(S3JniNph(sqlite3), ps->jDb, *ppDb);
}else{
assert( ps->pDb==*ppDb
&& "Set up via s3jni_run_java_auto_extensions()" );
OutputPointer_set_Int32(env, outTail, (int)(zTail ? (zTail - (const char *)pBuf) : 0));
}
if( pStmt ){
- NativePointerHolder_set(&S3JniNphRefs.sqlite3_stmt, jStmt, pStmt);
+ NativePointerHolder_set(S3JniNph(sqlite3_stmt), jStmt, pStmt);
}else{
/* Happens for comments and whitespace. */
S3JniUnrefLocal(jStmt);
(jint)opId, jDbName, jTable, (jlong)iKey1);
S3JniIfThrew{
S3JniExceptionWarnCallbackThrew("sqlite3_(pre)update_hook() callback");
- s3jni_db_exception(ps, 0,
+ s3jni_db_exception(ps->pDb, 0,
"sqlite3_(pre)update_hook() callback threw");
}
}
if( hook.jObj ){
rc = (int)(*env)->CallIntMethod(env, hook.jObj, hook.midCallback);
S3JniIfThrew{
- rc = s3jni_db_exception(ps, rc,
+ rc = s3jni_db_exception(ps->pDb, rc,
"sqlite3_progress_handler() callback threw");
}
S3JniHook_localundup(hook);
rc = (*env)->CallIntMethod(env, hook.jObj, hook.midCallback, (jint)op,
s0, s1, s3, s3);
S3JniIfThrew{
- rc = s3jni_db_exception(ps, rc, "sqlite3_set_authorizer() callback");
+ rc = s3jni_db_exception(ps->pDb, rc, "sqlite3_set_authorizer() callback");
}
S3JniUnrefLocal(s0);
S3JniUnrefLocal(s1);
case SQLITE_TRACE_ROW:
break;
case SQLITE_TRACE_CLOSE:
- jP = ps->jDb;
+ jP = jPUnref = S3JniRefLocal(ps->jDb);
break;
default:
assert(!"cannot happen - unkown trace flag");
rc = (int)(*env)->CallIntMethod(env, hook.jObj, hook.midCallback,
(jint)traceflag, jP, jX);
S3JniIfThrew{
- rc = s3jni_db_exception(ps, SQLITE_ERROR,
+ rc = s3jni_db_exception(ps->pDb, SQLITE_ERROR,
"sqlite3_trace_v2() callback threw.");
}
}
ResultJavaValuePtrStr);
}
-S3JniApi(sqlite3_value_text_utf8(),jbyteArray,1value_1text_1utf8)(
+S3JniApi(sqlite3_value_text(),jbyteArray,1value_1text)(
JniArgsEnvClass, jobject jpSVal
){
sqlite3_value * const sv = PtrGet_sqlite3_value(jpSVal);
return p ? s3jni_new_jbyteArray(p, n) : 0;
}
+#if 0
+// this impl might prove useful, but we'd need to publish the
+// bytearray-returning impl with a different name.
S3JniApi(sqlite3_value_text(),jstring,1value_1text)(
JniArgsEnvClass, jobject jpSVal
){
const unsigned char * const p = sqlite3_value_text(sv);
return p ? s3jni_utf8_to_jstring( (const char *)p, n) : 0;
}
+#endif
S3JniApi(sqlite3_value_text16(),jstring,1value_1text16)(
JniArgsEnvClass, jobject jpSVal
JNIEXPORT ReturnType JNICALL \
JniFuncNameFtsTok(Suffix)
-#define PtrGet_fts5_api(OBJ) NativePointerHolder_get(OBJ,&S3JniNphRefs.fts5_api)
-#define PtrGet_fts5_tokenizer(OBJ) NativePointerHolder_get(OBJ,&S3JniNphRefs.fts5_tokenizer)
-#define PtrGet_Fts5Context(OBJ) NativePointerHolder_get(OBJ,&S3JniNphRefs.Fts5Context)
-#define PtrGet_Fts5Tokenizer(OBJ) NativePointerHolder_get(OBJ,&S3JniNphRefs.Fts5Tokenizer)
+#define PtrGet_fts5_api(OBJ) NativePointerHolder_get(OBJ,S3JniNph(fts5_api))
+#define PtrGet_fts5_tokenizer(OBJ) NativePointerHolder_get(OBJ,S3JniNph(fts5_tokenizer))
+#define PtrGet_Fts5Context(OBJ) NativePointerHolder_get(OBJ,S3JniNph(Fts5Context))
+#define PtrGet_Fts5Tokenizer(OBJ) NativePointerHolder_get(OBJ,S3JniNph(Fts5Tokenizer))
#define Fts5ExtDecl Fts5ExtensionApi const * const fext = s3jni_ftsext()
/**
}
static inline jobject new_Fts5Context_wrapper(JNIEnv * const env, Fts5Context *sv){
- return new_NativePointerHolder_object(env, &S3JniNphRefs.Fts5Context, sv);
+ return new_NativePointerHolder_object(env, S3JniNph(Fts5Context), sv);
}
static inline jobject new_fts5_api_wrapper(JNIEnv * const env, fts5_api *sv){
- return new_NativePointerHolder_object(env, &S3JniNphRefs.fts5_api, sv);
+ return new_NativePointerHolder_object(env, S3JniNph(fts5_api), sv);
}
/*
static jobject s3jni_getFts5ExensionApi(JNIEnv * const env){
if( !SJG.fts5.jFtsExt ){
jobject pNPH = new_NativePointerHolder_object(
- env, &S3JniNphRefs.Fts5ExtensionApi, s3jni_ftsext()
+ env, S3JniNph(Fts5ExtensionApi), s3jni_ftsext()
);
S3JniEnv_mutex_enter;
if( pNPH ){
s.tok.jba = S3JniRefLocal(jbaText);
s.tok.zPrev = (const char *)pText;
s.tok.nPrev = (int)nText;
- if( pRef == &S3JniNphRefs.Fts5ExtensionApi ){
+ if( pRef == S3JniNph(Fts5ExtensionApi) ){
rc = fext->xTokenize(PtrGet_Fts5Context(jFcx),
(const char *)pText, (int)nText,
&s, s3jni_xTokenize_xToken);
- }else if( pRef == &S3JniNphRefs.fts5_tokenizer ){
+ }else if( pRef == S3JniNph(fts5_tokenizer) ){
fts5_tokenizer * const pTok = PtrGet_fts5_tokenizer(jSelf);
rc = pTok->xTokenize(PtrGet_Fts5Tokenizer(jFcx), &s, tokFlags,
(const char *)pText, (int)nText,
JniDeclFtsXA(jint,xTokenize)(JniArgsEnvObj,jobject jFcx, jbyteArray jbaText,
jobject jCallback){
- return s3jni_fts5_xTokenize(env, jSelf, &S3JniNphRefs.Fts5ExtensionApi,
+ return s3jni_fts5_xTokenize(env, jSelf, S3JniNph(Fts5ExtensionApi),
0, jFcx, jbaText, jCallback);
}
JniDeclFtsTok(jint,xTokenize)(JniArgsEnvObj,jobject jFcx, jint tokFlags,
jbyteArray jbaText, jobject jCallback){
- return s3jni_fts5_xTokenize(env, jSelf, &S3JniNphRefs.Fts5Tokenizer,
+ return s3jni_fts5_xTokenize(env, jSelf, S3JniNph(Fts5Tokenizer),
tokFlags, jFcx, jbaText, jCallback);
}
sqlite3_shutdown()
/* So that it becomes legal for Java-level code to call
- ** sqlite3_config(), if it's ever implemented. */;
+ ** sqlite3_config(). */;
}
);
/**
- Returns the given column's contents as UTF-8-encoded (not MUTF-8)
- text. Returns null if the C-level sqlite3_column_text() returns
- NULL.
-
- @see #sqlite3_column_text
- */
- @Canonical(cname="sqlite3_column_text")
- public static native byte[] sqlite3_column_text_utf8(
- @NotNull sqlite3_stmt stmt, int ndx
- );
-
- /**
- Provides the same feature as the same-named C API but returns the
- text in Java-native encoding rather than the C API's UTF-8.
-
- @see #sqlite3_column_text16
+ Functions identially to the C API, and this note is just to
+ stress that the returned bytes are encoded as UTF-8. It returns
+ null if the underlying C-level sqlite3_column_text() returns NULL
+ or on allocation error.
*/
- public static native String sqlite3_column_text(
+ @Canonical
+ public static native byte[] sqlite3_column_text(
@NotNull sqlite3_stmt stmt, int ndx
);
// }
// case SQLITE_FLOAT: rv = new Double(sqlite3_value_double(v)); break;
// case SQLITE_BLOB: rv = sqlite3_value_blob(v); break;
- // case SQLITE_TEXT: rv = sqlite3_value_text(v); break;
+ // case SQLITE_TEXT: rv = sqlite3_value_text16(v); break;
// default: break;
// }
// }
@NotNull sqlite3_context cx, long n
);
+ /**
+ This overload is private because its final parameter is arguably
+ unnecessary in Java.
+ */
@Canonical
private static native void sqlite3_result_blob(
@NotNull sqlite3_context cx, @Nullable byte[] blob, int maxLen
</ul>
- If @param maxLen is larger than blob.length, it is truncated to
- that value. If it is negative, results are undefined.
+ <p>If @param maxLen is larger than blob.length, it is truncated
+ to that value. If it is negative, results are undefined.</p>
+
+ <p>This overload is private because its final parameter is
+ arguably unnecessary in Java.</p>
*/
@Canonical
private static native void sqlite3_result_blob64(
sqlite3_result_blob64(cx, blob, (long)(null==blob ? 0 : blob.length));
}
+ /**
+ This overload is private because its final parameter is
+ arguably unnecessary in Java.
+ */
@Canonical
private static native void sqlite3_result_text(
@NotNull sqlite3_context cx, @Nullable byte[] utf8, int maxLen
text.length, it is silently truncated to text.length. If it is
negative, results are undefined. If text is null, the subsequent
arguments are ignored.
+
+ This overload is private because its maxLength parameter is
+ arguably unnecessary in Java.
*/
@Canonical
private static native void sqlite3_result_text64(
/**
Internal impl of the public sqlite3_strglob() method. Neither
argument may be NULL and both MUST be NUL-terminated UTF-8.
+
+ This overload is private because: (A) to keep users from
+ inadvertently passing non-NUL-terminated byte arrays (an easy
+ thing to do). (B) it is cheaper to NUL-terminate the
+ String-to-byte-array conversion in the Java implementation
+ (sqlite3_strglob(String,String)) than to do that in C, so that
+ signature is the public-facing one.
*/
@Canonical
private static native int sqlite3_strglob(
}
/**
- Internal impl of the public sqlite3_strlike() method. Neither
- argument may be NULL and both MUST be NUL-terminated UTF-8.
+ The LIKE counterpart of the private sqlite3_strglob() method.
*/
@Canonical
private static native int sqlite3_strlike(
}
/**
- Returns the given value as UTF-8-encoded bytes, or null if the
- underlying C-level sqlite3_value_text() returns NULL.
+ Functions identially to the C API, and this note is just to
+ stress that the returned bytes are encoded as UTF-8. It returns
+ null if the underlying C-level sqlite3_value_text() returns NULL
+ or on allocation error.
*/
- @Canonical(cname="sqlite3_value_text",
- comment="Renamed because its String-returning overload would "+
- "otherwise be ambiguous.")
- public static native byte[] sqlite3_value_text_utf8(@NotNull sqlite3_value v);
-
- /**
- Provides the same feature as the same-named C API but returns the
- text in Java-native encoding rather than the C API's UTF-8.
-
- @see #sqlite3_value_text16
- */
- public static native String sqlite3_value_text(@NotNull sqlite3_value v);
+ @Canonical
+ public static native byte[] sqlite3_value_text(@NotNull sqlite3_value v);
- /**
- In the Java layer, sqlite3_value_text() and
- sqlite3_value_text16() are functionally equivalent, the
- difference being only where the encoding to UTF-16 (if necessary)
- takes place. This function does it via SQLite and
- sqlite3_value_text() fetches UTF-8 (SQLite's default encoding)
- and converts it to UTF-16 in Java.
- */
@Canonical
public static native String sqlite3_value_text16(@NotNull sqlite3_value v);