mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Whether or not OOM is always fatal in JNI is now a compile-time option.
FossilOrigin-Name: 320a34c080d8bc1feae1578697923dfa7c4144b78de36f704c24cc4a4ce9d535
This commit is contained in:
@ -74,6 +74,14 @@
|
||||
//# define SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||
//#endif
|
||||
|
||||
/**********************************************************************/
|
||||
/* SQLITE_J... */
|
||||
#ifdef SQLITE_JNI_FATAL_OOM
|
||||
#if !SQLITE_JNI_FATAL_OOM
|
||||
#undef SQLITE_JNI_FATAL_OOM
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
/* SQLITE_M... */
|
||||
#ifndef SQLITE_MAX_ALLOCATION_SIZE
|
||||
@ -717,14 +725,39 @@ static inline void s3jni_oom(JNIEnv * const env){
|
||||
** sqlite3_malloc() proxy which fails fatally on OOM. This should
|
||||
** only be used for routines which manage global state and have no
|
||||
** recovery strategy for OOM. For sqlite3 API which can reasonably
|
||||
** return SQLITE_NOMEM, sqlite3_malloc() should be used instead.
|
||||
** return SQLITE_NOMEM, s3jni_malloc() should be used instead.
|
||||
*/
|
||||
static void * s3jni_malloc(JNIEnv * const env, size_t n){
|
||||
static void * s3jni_malloc_or_die(JNIEnv * const env, size_t n){
|
||||
void * const rv = sqlite3_malloc(n);
|
||||
if( n && !rv ) s3jni_oom(env);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
** Works like sqlite3_malloc() unless built with SQLITE_JNI_FATAL_OOM,
|
||||
** in which case it calls s3jni_oom() on OOM.
|
||||
*/
|
||||
static void * s3jni_malloc(JNIEnv * const env, size_t n){
|
||||
void * const rv = sqlite3_malloc(n);
|
||||
#ifdef SQLITE_JNI_FATAL_OOM
|
||||
if( n && !rv ) s3jni_oom(env);
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
** Works like sqlite3_realloc() unless built with SQLITE_JNI_FATAL_OOM,
|
||||
** in which case it calls s3jni_oom() on OOM.
|
||||
*/
|
||||
static void * s3jni_realloc(JNIEnv * const env, void * p, size_t n){
|
||||
void * const rv = sqlite3_realloc(p, (int)n);
|
||||
#ifdef SQLITE_JNI_FATAL_OOM
|
||||
if( n && !rv ) s3jni_oom(env);
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Returns the current JNIEnv object. Fails fatally if it cannot find
|
||||
** the object.
|
||||
@ -765,7 +798,7 @@ static S3JniEnv * S3JniEnv_get(JNIEnv * const env){
|
||||
SJG.envCache.aFree = row->pNext;
|
||||
if( row->pNext ) row->pNext->pPrev = 0;
|
||||
}else{
|
||||
row = s3jni_malloc(env, sizeof(S3JniEnv));
|
||||
row = s3jni_malloc_or_die(env, sizeof(*row));
|
||||
s3jni_incr( &SJG.metrics.envCacheAllocs );
|
||||
}
|
||||
memset(row, 0, sizeof(*row));
|
||||
@ -885,7 +918,7 @@ static char * s3jni_jstring_to_utf8(JNIEnv * const env,
|
||||
}
|
||||
nBa = (*env)->GetArrayLength(env, jba);
|
||||
if( nLen ) *nLen = (int)nBa;
|
||||
rv = sqlite3_malloc( nBa + 1 );
|
||||
rv = s3jni_malloc( env, nBa + 1 );
|
||||
if( rv ){
|
||||
(*env)->GetByteArrayRegion(env, jba, 0, nBa, (jbyte*)rv);
|
||||
rv[nBa] = 0;
|
||||
@ -1506,7 +1539,7 @@ typedef struct {
|
||||
** to ResultJavaVal_finalizer().
|
||||
*/
|
||||
static ResultJavaVal * ResultJavaVal_alloc(JNIEnv * const env, jobject jObj){
|
||||
ResultJavaVal * rv = sqlite3_malloc(sizeof(ResultJavaVal));
|
||||
ResultJavaVal * const rv = s3jni_malloc(env, sizeof(ResultJavaVal));
|
||||
if( rv ){
|
||||
rv->jObj = jObj ? S3JniRefGlobal(jObj) : 0;
|
||||
}
|
||||
@ -1590,7 +1623,7 @@ static S3JniUdf * S3JniUdf_alloc(JNIEnv * const env, jobject jObj){
|
||||
}
|
||||
S3JniMutex_Global_leave;
|
||||
if( !s ){
|
||||
s = sqlite3_malloc(sizeof(*s));
|
||||
s = s3jni_malloc(env, sizeof(*s));
|
||||
s3jni_incr(&SJG.metrics.nUdfAlloc);
|
||||
}
|
||||
if( s ){
|
||||
@ -2012,8 +2045,7 @@ S3JniApi(sqlite3_auto_extension(),jint,1auto_1extension)(
|
||||
if( SJG.autoExt.nExt == SJG.autoExt.nAlloc ){
|
||||
unsigned n = 1 + SJG.autoExt.nAlloc;
|
||||
S3JniAutoExtension * const aNew =
|
||||
sqlite3_realloc( SJG.autoExt.pExt,
|
||||
n * sizeof(S3JniAutoExtension) );
|
||||
s3jni_realloc( env, SJG.autoExt.pExt, n * sizeof(*ax) );
|
||||
if( !aNew ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@ -3397,8 +3429,8 @@ S3JniApi(sqlite3_reset_auto_extension(),void,1reset_1auto_1extension)(
|
||||
}
|
||||
|
||||
/* Impl for sqlite3_result_text/blob() and friends. */
|
||||
static void result_blob_text(int as64,
|
||||
int eTextRep/*only for (asBlob=0)*/,
|
||||
static void result_blob_text(int as64 /* true for text64/blob64() mode */,
|
||||
int eTextRep /* 0 for blobs, else SQLITE_UTF... */,
|
||||
JNIEnv * const env, sqlite3_context *pCx,
|
||||
jbyteArray jBa, jlong nMax){
|
||||
int const asBlob = 0==eTextRep;
|
||||
@ -3425,8 +3457,7 @@ static void result_blob_text(int as64,
|
||||
}
|
||||
if( as64 ){ /* 64-bit... */
|
||||
static const jsize nLimit64 =
|
||||
SQLITE_MAX_ALLOCATION_SIZE/*only _kinda_ arbitrary!*/
|
||||
/* jsize is int32, not int64! */;
|
||||
SQLITE_MAX_ALLOCATION_SIZE/*only _kinda_ arbitrary*/;
|
||||
if( nBa > nLimit64 ){
|
||||
sqlite3_result_error_toobig(pCx);
|
||||
}else if( asBlob ){
|
||||
@ -3739,18 +3770,6 @@ static int s3jni_strlike_glob(int isLike, JNIEnv *const env,
|
||||
return rc;
|
||||
}
|
||||
|
||||
S3JniApi(sqlite3_strglob(),jint,1strglob)(
|
||||
JniArgsEnvClass, jbyteArray baG, jbyteArray baT
|
||||
){
|
||||
return s3jni_strlike_glob(0, env, baG, baT, 0);
|
||||
}
|
||||
|
||||
S3JniApi(sqlite3_strlike(),jint,1strlike)(
|
||||
JniArgsEnvClass, jbyteArray baG, jbyteArray baT, jint escChar
|
||||
){
|
||||
return s3jni_strlike_glob(1, env, baG, baT, escChar);
|
||||
}
|
||||
|
||||
S3JniApi(sqlite3_shutdown(),jint,1shutdown)(
|
||||
JniArgsEnvClass
|
||||
){
|
||||
@ -3776,6 +3795,18 @@ S3JniApi(sqlite3_shutdown(),jint,1shutdown)(
|
||||
return sqlite3_shutdown();
|
||||
}
|
||||
|
||||
S3JniApi(sqlite3_strglob(),jint,1strglob)(
|
||||
JniArgsEnvClass, jbyteArray baG, jbyteArray baT
|
||||
){
|
||||
return s3jni_strlike_glob(0, env, baG, baT, 0);
|
||||
}
|
||||
|
||||
S3JniApi(sqlite3_strlike(),jint,1strlike)(
|
||||
JniArgsEnvClass, jbyteArray baG, jbyteArray baT, jint escChar
|
||||
){
|
||||
return s3jni_strlike_glob(1, env, baG, baT, escChar);
|
||||
}
|
||||
|
||||
S3JniApi(sqlite3_sql(),jstring,1sql)(
|
||||
JniArgsEnvClass, jobject jpStmt
|
||||
){
|
||||
@ -4113,7 +4144,8 @@ static void Fts5JniAux_xDestroy(void *p){
|
||||
}
|
||||
|
||||
static Fts5JniAux * Fts5JniAux_alloc(JNIEnv * const env, jobject jObj){
|
||||
Fts5JniAux * s = sqlite3_malloc(sizeof(Fts5JniAux));
|
||||
Fts5JniAux * s = s3jni_malloc(env, sizeof(Fts5JniAux));
|
||||
|
||||
if( s ){
|
||||
jclass klazz;
|
||||
memset(s, 0, sizeof(Fts5JniAux));
|
||||
@ -4146,9 +4178,9 @@ static inline jobject new_fts5_api_wrapper(JNIEnv * const env, fts5_api *sv){
|
||||
return new_NativePointerHolder_object(env, &S3NphRefs.fts5_api, sv);
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a per-JNIEnv global ref to the Fts5ExtensionApi singleton
|
||||
instance, or NULL on OOM.
|
||||
/*
|
||||
** Returns a per-JNIEnv global ref to the Fts5ExtensionApi singleton
|
||||
** instance, or NULL on OOM.
|
||||
*/
|
||||
static jobject s3jni_getFts5ExensionApi(JNIEnv * const env){
|
||||
if( !SJG.fts5.jFtsExt ){
|
||||
@ -4168,8 +4200,8 @@ static jobject s3jni_getFts5ExensionApi(JNIEnv * const env){
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to the fts5_api instance for database connection
|
||||
** db. If an error occurs, return NULL and leave an error in the
|
||||
** Returns a pointer to the fts5_api instance for database connection
|
||||
** db. If an error occurs, returns NULL and leaves an error in the
|
||||
** database handle (accessible using sqlite3_errcode()/errmsg()).
|
||||
*/
|
||||
static fts5_api *s3jni_fts5_api_from_db(sqlite3 *db){
|
||||
@ -4536,7 +4568,8 @@ JniDeclFtsXA(int,xSetAuxdata)(JniArgsEnvObj,jobject jCtx, jobject jAux){
|
||||
Fts5ExtDecl;
|
||||
int rc;
|
||||
S3JniFts5AuxData * pAux;
|
||||
pAux = sqlite3_malloc(sizeof(*pAux));
|
||||
|
||||
pAux = s3jni_malloc(env, sizeof(*pAux));
|
||||
if( !pAux ){
|
||||
if( jAux ){
|
||||
/* Emulate how xSetAuxdata() behaves when it cannot alloc
|
||||
@ -4692,9 +4725,10 @@ static void SQLTester_dup_func(
|
||||
char *z;
|
||||
int n = sqlite3_value_bytes(argv[0]);
|
||||
SQLTesterJni * const p = (SQLTesterJni *)sqlite3_user_data(context);
|
||||
S3JniDeclLocal_env;
|
||||
|
||||
++p->nDup;
|
||||
if( n>0 && (pOut = sqlite3_malloc( (n+16)&~7 ))!=0 ){
|
||||
if( n>0 && (pOut = s3jni_malloc( env, (n+16)&~7 ))!=0 ){
|
||||
pOut[0] = 0x2bbf4b7c;
|
||||
z = (char*)&pOut[1];
|
||||
memcpy(z, sqlite3_value_text(argv[0]), n);
|
||||
|
@ -1531,30 +1531,6 @@ JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1text
|
||||
JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1text64
|
||||
(JNIEnv *, jclass, jobject, jbyteArray, jlong, jint);
|
||||
|
||||
/*
|
||||
* Class: org_sqlite_jni_SQLite3Jni
|
||||
* Method: sqlite3_shutdown
|
||||
* Signature: ()I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1shutdown
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: org_sqlite_jni_SQLite3Jni
|
||||
* Method: sqlite3_status
|
||||
* Signature: (ILorg/sqlite/jni/OutputPointer/Int32;Lorg/sqlite/jni/OutputPointer/Int32;Z)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1status
|
||||
(JNIEnv *, jclass, jint, jobject, jobject, jboolean);
|
||||
|
||||
/*
|
||||
* Class: org_sqlite_jni_SQLite3Jni
|
||||
* Method: sqlite3_status64
|
||||
* Signature: (ILorg/sqlite/jni/OutputPointer/Int64;Lorg/sqlite/jni/OutputPointer/Int64;Z)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1status64
|
||||
(JNIEnv *, jclass, jint, jobject, jobject, jboolean);
|
||||
|
||||
/*
|
||||
* Class: org_sqlite_jni_SQLite3Jni
|
||||
* Method: sqlite3_rollback_hook
|
||||
@ -1579,6 +1555,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1set_1authorizer
|
||||
JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1set_1last_1insert_1rowid
|
||||
(JNIEnv *, jclass, jobject, jlong);
|
||||
|
||||
/*
|
||||
* Class: org_sqlite_jni_SQLite3Jni
|
||||
* Method: sqlite3_shutdown
|
||||
* Signature: ()I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1shutdown
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: org_sqlite_jni_SQLite3Jni
|
||||
* Method: sqlite3_sleep
|
||||
@ -1603,6 +1587,22 @@ JNIEXPORT jstring JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1sourceid
|
||||
JNIEXPORT jstring JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1sql
|
||||
(JNIEnv *, jclass, jobject);
|
||||
|
||||
/*
|
||||
* Class: org_sqlite_jni_SQLite3Jni
|
||||
* Method: sqlite3_status
|
||||
* Signature: (ILorg/sqlite/jni/OutputPointer/Int32;Lorg/sqlite/jni/OutputPointer/Int32;Z)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1status
|
||||
(JNIEnv *, jclass, jint, jobject, jobject, jboolean);
|
||||
|
||||
/*
|
||||
* Class: org_sqlite_jni_SQLite3Jni
|
||||
* Method: sqlite3_status64
|
||||
* Signature: (ILorg/sqlite/jni/OutputPointer/Int64;Lorg/sqlite/jni/OutputPointer/Int64;Z)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1status64
|
||||
(JNIEnv *, jclass, jint, jobject, jobject, jboolean);
|
||||
|
||||
/*
|
||||
* Class: org_sqlite_jni_SQLite3Jni
|
||||
* Method: sqlite3_step
|
||||
|
@ -54,7 +54,7 @@ public abstract class AggregateFunction<T> extends SQLFunction {
|
||||
argument, the context is set to the given initial value. On all other
|
||||
calls, the 2nd argument is ignored.
|
||||
|
||||
@see SQLFunction.PerContextState#getAggregateState()
|
||||
@see SQLFunction.PerContextState#getAggregateState
|
||||
*/
|
||||
protected final ValueHolder<T> getAggregateState(sqlite3_context cx, T initialValue){
|
||||
return map.getAggregateState(cx, initialValue);
|
||||
@ -64,7 +64,7 @@ public abstract class AggregateFunction<T> extends SQLFunction {
|
||||
To be called from the implementation's xFinal() method to fetch
|
||||
the final state of the UDF and remove its mapping.
|
||||
|
||||
see SQLFunction.PerContextState#takeAggregateState()
|
||||
see SQLFunction.PerContextState#takeAggregateState
|
||||
*/
|
||||
protected final T takeAggregateState(sqlite3_context cx){
|
||||
return map.takeAggregateState(cx);
|
||||
|
@ -893,8 +893,7 @@ public final class SQLite3Jni {
|
||||
a complaint about the invalid argument.
|
||||
*/
|
||||
private static native void sqlite3_result_error(
|
||||
@NotNull sqlite3_context cx, @NotNull byte[] msg,
|
||||
int eTextRep
|
||||
@NotNull sqlite3_context cx, @NotNull byte[] msg, int eTextRep
|
||||
);
|
||||
|
||||
public static void sqlite3_result_error(
|
||||
@ -919,22 +918,20 @@ public final class SQLite3Jni {
|
||||
public static void sqlite3_result_error16(
|
||||
@NotNull sqlite3_context cx, @NotNull String msg
|
||||
){
|
||||
final byte[] utf8 = msg.getBytes(StandardCharsets.UTF_16);
|
||||
sqlite3_result_error(cx, utf8, SQLITE_UTF16);
|
||||
final byte[] utf16 = msg.getBytes(StandardCharsets.UTF_16);
|
||||
sqlite3_result_error(cx, utf16, SQLITE_UTF16);
|
||||
}
|
||||
|
||||
/**
|
||||
Equivalent to passing e.getMessage() to
|
||||
sqlite3_result_error(db,String).
|
||||
*/
|
||||
public static void sqlite3_result_error(
|
||||
@NotNull sqlite3_context cx, @NotNull Exception e
|
||||
){
|
||||
sqlite3_result_error(cx, e.getMessage());
|
||||
}
|
||||
|
||||
public static void sqlite3_result_error16(
|
||||
@NotNull sqlite3_context cx, @NotNull Exception e
|
||||
){
|
||||
sqlite3_result_error16(cx, e.getMessage());
|
||||
}
|
||||
|
||||
public static native void sqlite3_result_error_toobig(
|
||||
@NotNull sqlite3_context cx
|
||||
);
|
||||
@ -961,7 +958,7 @@ public final class SQLite3Jni {
|
||||
|
||||
/**
|
||||
Binds the SQL result to the given object, or
|
||||
{@link #sqlite3_result_null(sqlite3_context) sqlite3_result_null()} if {@code o} is null. Use
|
||||
{@link #sqlite3_result_null} if {@code o} is null. Use
|
||||
{@link #sqlite3_value_java_object(sqlite3_value) sqlite3_value_java_object()} or
|
||||
{@link #sqlite3_column_java_object(sqlite3_stmt,int) sqlite3_column_java_object()} to
|
||||
fetch it.
|
||||
@ -1077,13 +1074,13 @@ public final class SQLite3Jni {
|
||||
}
|
||||
|
||||
private static native void sqlite3_result_text(
|
||||
@NotNull sqlite3_context cx, @Nullable byte[] text, int maxLen
|
||||
@NotNull sqlite3_context cx, @Nullable byte[] utf8, int maxLen
|
||||
);
|
||||
|
||||
public static void sqlite3_result_text(
|
||||
@NotNull sqlite3_context cx, @Nullable byte[] text
|
||||
@NotNull sqlite3_context cx, @Nullable byte[] utf8
|
||||
){
|
||||
sqlite3_result_text(cx, text, null==text ? 0 : text.length);
|
||||
sqlite3_result_text(cx, utf8, null==utf8 ? 0 : utf8.length);
|
||||
}
|
||||
|
||||
public static void sqlite3_result_text(
|
||||
@ -1117,34 +1114,14 @@ public final class SQLite3Jni {
|
||||
long maxLength, int encoding
|
||||
);
|
||||
|
||||
/**
|
||||
Cleans up all stale per-thread state managed by the library, as
|
||||
well as any registered auto-extensions, then calls the C-native
|
||||
sqlite3_shutdown(). Calling this while database handles or
|
||||
prepared statements are still active will leak resources. Trying
|
||||
to use those objects after this routine is called invoked
|
||||
undefined behavior.
|
||||
*/
|
||||
public static synchronized native int sqlite3_shutdown();
|
||||
|
||||
public static native int sqlite3_status(
|
||||
int op, @NotNull OutputPointer.Int32 pCurrent,
|
||||
@NotNull OutputPointer.Int32 pHighwater, boolean reset
|
||||
);
|
||||
|
||||
public static native int sqlite3_status64(
|
||||
int op, @NotNull OutputPointer.Int64 pCurrent,
|
||||
@NotNull OutputPointer.Int64 pHighwater, boolean reset
|
||||
);
|
||||
|
||||
/**
|
||||
Sets the current UDF result to the given bytes, which are assumed
|
||||
be encoded in UTF-16 using the platform's byte order.
|
||||
*/
|
||||
public static void sqlite3_result_text16(
|
||||
@NotNull sqlite3_context cx, @Nullable byte[] text
|
||||
@NotNull sqlite3_context cx, @Nullable byte[] utf16
|
||||
){
|
||||
sqlite3_result_text64(cx, text, text.length, SQLITE_UTF16);
|
||||
sqlite3_result_text64(cx, utf16, utf16.length, SQLITE_UTF16);
|
||||
}
|
||||
|
||||
public static void sqlite3_result_text16(
|
||||
@ -1170,12 +1147,34 @@ public final class SQLite3Jni {
|
||||
@NotNull sqlite3 db, long rowid
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
Cleans up all stale per-thread state managed by the library, as
|
||||
well as any registered auto-extensions, then calls the C-native
|
||||
sqlite3_shutdown(). Calling this while database handles or
|
||||
prepared statements are still active will leak resources. Trying
|
||||
to use those objects after this routine is called invoked
|
||||
undefined behavior.
|
||||
*/
|
||||
public static synchronized native int sqlite3_shutdown();
|
||||
|
||||
public static native int sqlite3_sleep(int ms);
|
||||
|
||||
public static native String sqlite3_sourceid();
|
||||
|
||||
public static native String sqlite3_sql(@NotNull sqlite3_stmt stmt);
|
||||
|
||||
|
||||
public static native int sqlite3_status(
|
||||
int op, @NotNull OutputPointer.Int32 pCurrent,
|
||||
@NotNull OutputPointer.Int32 pHighwater, boolean reset
|
||||
);
|
||||
|
||||
public static native int sqlite3_status64(
|
||||
int op, @NotNull OutputPointer.Int64 pCurrent,
|
||||
@NotNull OutputPointer.Int64 pHighwater, boolean reset
|
||||
);
|
||||
|
||||
public static native int sqlite3_step(@NotNull sqlite3_stmt stmt);
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user