Merge all the latest enhancements and fixes from trunk into the jsonb branch.
FossilOrigin-Name: ba91408f4c044feda003ef93784ccefb619f99ab64379ced481ee8e9e890fd41
This commit is contained in:
commit
fb57c8a932
@ -81,6 +81,7 @@ $(bin.version-info): $(dir.tool)/version-info.c $(sqlite3.h) $(dir.top)/Makefile
|
|||||||
# Be explicit about which Java files to compile so that we can work on
|
# Be explicit about which Java files to compile so that we can work on
|
||||||
# in-progress files without requiring them to be in a compilable statae.
|
# in-progress files without requiring them to be in a compilable statae.
|
||||||
JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/annotation/%,\
|
JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/annotation/%,\
|
||||||
|
Experimental.java \
|
||||||
NotNull.java \
|
NotNull.java \
|
||||||
Nullable.java \
|
Nullable.java \
|
||||||
) $(patsubst %,$(dir.src.capi)/%,\
|
) $(patsubst %,$(dir.src.capi)/%,\
|
||||||
@ -93,7 +94,7 @@ JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/annotation/%,\
|
|||||||
CollationNeededCallback.java \
|
CollationNeededCallback.java \
|
||||||
CommitHookCallback.java \
|
CommitHookCallback.java \
|
||||||
ConfigLogCallback.java \
|
ConfigLogCallback.java \
|
||||||
ConfigSqllogCallback.java \
|
ConfigSqlLogCallback.java \
|
||||||
NativePointerHolder.java \
|
NativePointerHolder.java \
|
||||||
OutputPointer.java \
|
OutputPointer.java \
|
||||||
PrepareMultiCallback.java \
|
PrepareMultiCallback.java \
|
||||||
@ -322,7 +323,7 @@ test-one: $(test.deps)
|
|||||||
$(bin.java) $(test.flags.jvm) org.sqlite.jni.wrapper1.Tester2 $(Tester2.flags)
|
$(bin.java) $(test.flags.jvm) org.sqlite.jni.wrapper1.Tester2 $(Tester2.flags)
|
||||||
test-sqllog: $(test.deps)
|
test-sqllog: $(test.deps)
|
||||||
@echo "Testing with -sqllog..."
|
@echo "Testing with -sqllog..."
|
||||||
$(bin.java) $(test.flags.jvm) -sqllog
|
$(bin.java) $(test.flags.jvm) org.sqlite.jni.capi.Tester1 $(Tester1.flags) -sqllog
|
||||||
test-mt: $(test.deps)
|
test-mt: $(test.deps)
|
||||||
@echo "Testing in multi-threaded mode:";
|
@echo "Testing in multi-threaded mode:";
|
||||||
$(bin.java) $(test.flags.jvm) org.sqlite.jni.capi.Tester1 \
|
$(bin.java) $(test.flags.jvm) org.sqlite.jni.capi.Tester1 \
|
||||||
|
@ -16,9 +16,8 @@ Technical support is available in the forum:
|
|||||||
> **FOREWARNING:** this subproject is very much in development and
|
> **FOREWARNING:** this subproject is very much in development and
|
||||||
subject to any number of changes. Please do not rely on any
|
subject to any number of changes. Please do not rely on any
|
||||||
information about its API until this disclaimer is removed. The JNI
|
information about its API until this disclaimer is removed. The JNI
|
||||||
bindings released with version 3.43 are a "tech preview" and 3.44
|
bindings released with version 3.43 are a "tech preview." Once
|
||||||
will be "final," at which point strong backward compatibility
|
finalized, strong backward compatibility guarantees will apply.
|
||||||
guarantees will apply.
|
|
||||||
|
|
||||||
Project goals/requirements:
|
Project goals/requirements:
|
||||||
|
|
||||||
@ -43,11 +42,13 @@ Non-goals:
|
|||||||
- Creation of high-level OO wrapper APIs. Clients are free to create
|
- Creation of high-level OO wrapper APIs. Clients are free to create
|
||||||
them off of the C-style API.
|
them off of the C-style API.
|
||||||
|
|
||||||
|
- Virtual tables are unlikely to be supported due to the amount of
|
||||||
|
glue code needed to fit them into Java.
|
||||||
|
|
||||||
- Support for mixed-mode operation, where client code accesses SQLite
|
- Support for mixed-mode operation, where client code accesses SQLite
|
||||||
both via the Java-side API and the C API via their own native
|
both via the Java-side API and the C API via their own native
|
||||||
code. In such cases, proxy functionalities (primarily callback
|
code. Such cases would be a minefield of potential mis-interactions
|
||||||
handler wrappers of all sorts) may fail because the C-side use of
|
between this project's JNI bindings and mixed-mode client code.
|
||||||
the SQLite APIs will bypass those proxies.
|
|
||||||
|
|
||||||
|
|
||||||
Hello World
|
Hello World
|
||||||
@ -123,15 +124,13 @@ sensible default argument values. In all such cases they are thin
|
|||||||
proxies around the corresponding C APIs and do not introduce new
|
proxies around the corresponding C APIs and do not introduce new
|
||||||
semantics.
|
semantics.
|
||||||
|
|
||||||
In some very few cases, Java-specific capabilities have been added in
|
In a few cases, Java-specific capabilities have been added in
|
||||||
new APIs, all of which have "_java" somewhere in their names.
|
new APIs, all of which have "_java" somewhere in their names.
|
||||||
Examples include:
|
Examples include:
|
||||||
|
|
||||||
- `sqlite3_result_java_object()`
|
- `sqlite3_result_java_object()`
|
||||||
- `sqlite3_column_java_object()`
|
- `sqlite3_column_java_object()`
|
||||||
- `sqlite3_column_java_casted()`
|
|
||||||
- `sqlite3_value_java_object()`
|
- `sqlite3_value_java_object()`
|
||||||
- `sqlite3_value_java_casted()`
|
|
||||||
|
|
||||||
which, as one might surmise, collectively enable the passing of
|
which, as one might surmise, collectively enable the passing of
|
||||||
arbitrary Java objects from user-defined SQL functions through to the
|
arbitrary Java objects from user-defined SQL functions through to the
|
||||||
@ -150,6 +149,9 @@ pending statements have been closed. Be aware that Java garbage
|
|||||||
collection _cannot_ close a database or finalize a prepared statement.
|
collection _cannot_ close a database or finalize a prepared statement.
|
||||||
Those things require explicit API calls.
|
Those things require explicit API calls.
|
||||||
|
|
||||||
|
Classes for which it is sensible support Java's `AutoCloseable`
|
||||||
|
interface so can be used with try-with-resources constructs.
|
||||||
|
|
||||||
|
|
||||||
Golden Rule #2: _Never_ Throw from Callbacks (Unless...)
|
Golden Rule #2: _Never_ Throw from Callbacks (Unless...)
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
@ -159,14 +161,15 @@ retain C-like semantics. For example, they are not permitted to throw
|
|||||||
or propagate exceptions and must return error information (if any) via
|
or propagate exceptions and must return error information (if any) via
|
||||||
result codes or `null`. The only cases where the C-style APIs may
|
result codes or `null`. The only cases where the C-style APIs may
|
||||||
throw is through client-side misuse, e.g. passing in a null where it
|
throw is through client-side misuse, e.g. passing in a null where it
|
||||||
shouldn't be used. The APIs clearly mark function parameters which
|
may cause a `NullPointerException`. The APIs clearly mark function
|
||||||
should not be null, but does not actively defend itself against such
|
parameters which should not be null, but does not generally actively
|
||||||
misuse. Some C-style APIs explicitly accept `null` as a no-op for
|
defend itself against such misuse. Some C-style APIs explicitly accept
|
||||||
usability's sake, and some of the JNI APIs deliberately return an
|
`null` as a no-op for usability's sake, and some of the JNI APIs
|
||||||
error code, instead of segfaulting, when passed a `null`.
|
deliberately return an error code, instead of segfaulting, when passed
|
||||||
|
a `null`.
|
||||||
|
|
||||||
Client-defined callbacks _must never throw exceptions_ unless _very
|
Client-defined callbacks _must never throw exceptions_ unless _very
|
||||||
explicitly documented_ as being throw-safe. Exceptions are generally
|
explitly documented_ as being throw-safe. Exceptions are generally
|
||||||
reserved for higher-level bindings which are constructed to
|
reserved for higher-level bindings which are constructed to
|
||||||
specifically deal with them and ensure that they do not leak C-level
|
specifically deal with them and ensure that they do not leak C-level
|
||||||
resources. In some cases, callback handlers are permitted to throw, in
|
resources. In some cases, callback handlers are permitted to throw, in
|
||||||
@ -292,14 +295,14 @@ int sqlite3_create_function(sqlite3 db, String funcName, int nArgs,
|
|||||||
`SQLFunction` is not used directly, but is instead instantiated via
|
`SQLFunction` is not used directly, but is instead instantiated via
|
||||||
one of its three subclasses:
|
one of its three subclasses:
|
||||||
|
|
||||||
- `SQLFunction.Scalar` implements simple scalar functions using but a
|
- `ScalarFunction` implements simple scalar functions using but a
|
||||||
single callback.
|
single callback.
|
||||||
- `SQLFunction.Aggregate` implements aggregate functions using two
|
- `AggregateFunction` implements aggregate functions using two
|
||||||
callbacks.
|
callbacks.
|
||||||
- `SQLFunction.Window` implements window functions using four
|
- `WindowFunction` implements window functions using four
|
||||||
callbacks.
|
callbacks.
|
||||||
|
|
||||||
Search [`Tester1.java`](/file/ext/jni/src/org/sqlite/jni/Tester1.java) for
|
Search [`Tester1.java`](/file/ext/jni/src/org/sqlite/jni/capi/Tester1.java) for
|
||||||
`SQLFunction` for how it's used.
|
`SQLFunction` for how it's used.
|
||||||
|
|
||||||
Reminder: see the disclaimer at the top of this document regarding the
|
Reminder: see the disclaimer at the top of this document regarding the
|
||||||
|
@ -15,13 +15,14 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** If you found this comment by searching the code for
|
** If you found this comment by searching the code for
|
||||||
** CallStaticObjectMethod then you're the victim of an OpenJDK bug:
|
** CallStaticObjectMethod because it appears in console output then
|
||||||
|
** you're probably the victim of an OpenJDK bug:
|
||||||
**
|
**
|
||||||
** https://bugs.openjdk.org/browse/JDK-8130659
|
** https://bugs.openjdk.org/browse/JDK-8130659
|
||||||
**
|
**
|
||||||
** It's known to happen with OpenJDK v8 but not with v19.
|
** It's known to happen with OpenJDK v8 but not with v19. It was
|
||||||
**
|
** triggered by this code long before it made any use of
|
||||||
** This code does not use JNI's CallStaticObjectMethod().
|
** CallStaticObjectMethod().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -660,10 +661,14 @@ struct S3JniGlobalType {
|
|||||||
|
|
||||||
https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#nio_support
|
https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#nio_support
|
||||||
|
|
||||||
We only store a ref to the following if JNI support for
|
We only store a ref to byteBuffer.klazz if JNI support for
|
||||||
ByteBuffer is available (which we determine during static init).
|
ByteBuffer is available (which we determine during static init).
|
||||||
*/
|
*/
|
||||||
jclass cByteBuffer /* global ref to java.nio.ByteBuffer */;
|
struct {
|
||||||
|
jclass klazz /* global ref to java.nio.ByteBuffer */;
|
||||||
|
jmethodID midAlloc /* ByteBuffer.allocateDirect() */;
|
||||||
|
jmethodID midLimit /* ByteBuffer.limit() */;
|
||||||
|
} byteBuffer;
|
||||||
} g;
|
} g;
|
||||||
/*
|
/*
|
||||||
** The list of Java-side auto-extensions
|
** The list of Java-side auto-extensions
|
||||||
@ -870,6 +875,58 @@ static jbyte * s3jni__jbyteArray_bytes2(JNIEnv * const env, jbyteArray jBA, jsiz
|
|||||||
#define s3jni_jbyteArray_commit(jByteArray,jBytes) \
|
#define s3jni_jbyteArray_commit(jByteArray,jBytes) \
|
||||||
if( jBytes ) (*env)->ReleaseByteArrayElements(env, jByteArray, jBytes, JNI_COMMIT)
|
if( jBytes ) (*env)->ReleaseByteArrayElements(env, jByteArray, jBytes, JNI_COMMIT)
|
||||||
|
|
||||||
|
/*
|
||||||
|
** If jbb is-a java.nio.Buffer object and the JNI environment supports
|
||||||
|
** it, *pBuf is set to the buffer's memory and *pN is set to its
|
||||||
|
** limit() (as opposed to its capacity()). If jbb is NULL, not a
|
||||||
|
** Buffer, or the JNI environment does not support that operation,
|
||||||
|
** *pBuf is set to 0 and *pN is set to 0.
|
||||||
|
**
|
||||||
|
** Note that the length of the buffer can be larger than SQLITE_LIMIT
|
||||||
|
** but this function does not know what byte range of the buffer is
|
||||||
|
** required so cannot check for that violation. The caller is required
|
||||||
|
** to ensure that any to-be-bind()ed range fits within SQLITE_LIMIT.
|
||||||
|
**
|
||||||
|
** Sidebar: it is unfortunate that we cannot get ByteBuffer.limit()
|
||||||
|
** via a JNI method like we can for ByteBuffer.capacity(). We instead
|
||||||
|
** have to call back into Java to get the limit(). Depending on how
|
||||||
|
** the ByteBuffer is used, the limit and capacity might be the same,
|
||||||
|
** but when reusing a buffer, the limit may well change whereas the
|
||||||
|
** capacity is fixed. The problem with, e.g., read()ing blob data to a
|
||||||
|
** ByteBuffer's memory based on its capacity is that Java-level code
|
||||||
|
** is restricted to accessing the range specified in
|
||||||
|
** ByteBuffer.limit(). If we were to honor only the capacity, we
|
||||||
|
** could end up writing to, or reading from, parts of a ByteBuffer
|
||||||
|
** which client code itself cannot access without explicitly modifying
|
||||||
|
** the limit. The penalty we pay for this correctness is that we must
|
||||||
|
** call into Java to get the limit() of every ByteBuffer we work with.
|
||||||
|
**
|
||||||
|
** An alternative to having to call into ByteBuffer.limit() from here
|
||||||
|
** would be to add private native impls of all ByteBuffer-using
|
||||||
|
** methods, each of which adds a jint parameter which _must_ be set to
|
||||||
|
** theBuffer.limit() by public Java APIs which use those private impls
|
||||||
|
** to do the real work.
|
||||||
|
*/
|
||||||
|
static void s3jni__get_nio_buffer(JNIEnv * const env, jobject jbb, void **pBuf, jint * pN ){
|
||||||
|
*pBuf = 0;
|
||||||
|
*pN = 0;
|
||||||
|
if( jbb ){
|
||||||
|
*pBuf = (*env)->GetDirectBufferAddress(env, jbb);
|
||||||
|
if( *pBuf ){
|
||||||
|
/*
|
||||||
|
** Maintenance reminder: do not use
|
||||||
|
** (*env)->GetDirectBufferCapacity(env,jbb), even though it
|
||||||
|
** would be much faster, for reasons explained in this
|
||||||
|
** function's comments.
|
||||||
|
*/
|
||||||
|
*pN = (*env)->CallIntMethod(env, jbb, SJG.g.byteBuffer.midLimit);
|
||||||
|
S3JniExceptionIsFatal("Error calling ByteBuffer.limit() method.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#define s3jni_get_nio_buffer(JOBJ,vpOut,jpOut) \
|
||||||
|
s3jni__get_nio_buffer(env,(JOBJ),(vpOut),(jpOut))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Returns the current JNIEnv object. Fails fatally if it cannot find
|
** Returns the current JNIEnv object. Fails fatally if it cannot find
|
||||||
** the object.
|
** the object.
|
||||||
@ -1068,6 +1125,47 @@ static jstring s3jni_text16_to_jstring(JNIEnv * const env, const void * const p,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Creates a new ByteBuffer instance with a capacity of n. assert()s
|
||||||
|
** that SJG.g.byteBuffer.klazz is not 0 and n>0.
|
||||||
|
*/
|
||||||
|
static jobject s3jni__new_ByteBuffer(JNIEnv * const env, int n){
|
||||||
|
jobject rv = 0;
|
||||||
|
assert( SJG.g.byteBuffer.klazz );
|
||||||
|
assert( SJG.g.byteBuffer.midAlloc );
|
||||||
|
assert( n > 0 );
|
||||||
|
rv = (*env)->CallStaticObjectMethod(env, SJG.g.byteBuffer.klazz,
|
||||||
|
SJG.g.byteBuffer.midAlloc, (jint)n);
|
||||||
|
S3JniIfThrew {
|
||||||
|
S3JniExceptionReport;
|
||||||
|
S3JniExceptionClear;
|
||||||
|
}
|
||||||
|
s3jni_oom_check( rv );
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** If n>0 and sqlite3_jni_supports_nio() is true then this creates a
|
||||||
|
** new ByteBuffer object and copies n bytes from p to it. Returns NULL
|
||||||
|
** if n is 0, sqlite3_jni_supports_nio() is false, or on allocation
|
||||||
|
** error (unless fatal alloc failures are enabled).
|
||||||
|
*/
|
||||||
|
static jobject s3jni__blob_to_ByteBuffer(JNIEnv * const env,
|
||||||
|
const void * p, int n){
|
||||||
|
jobject rv = NULL;
|
||||||
|
assert( n >= 0 );
|
||||||
|
if( 0==n || !SJG.g.byteBuffer.klazz ){
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
rv = s3jni__new_ByteBuffer(env, n);
|
||||||
|
if( rv ){
|
||||||
|
void * tgt = (*env)->GetDirectBufferAddress(env, rv);
|
||||||
|
memcpy(tgt, p, (size_t)n);
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Requires jx to be a Throwable. Calls its toString() method and
|
** Requires jx to be a Throwable. Calls its toString() method and
|
||||||
** returns its value converted to a UTF-8 string. The caller owns the
|
** returns its value converted to a UTF-8 string. The caller owns the
|
||||||
@ -1479,13 +1577,13 @@ static void * NativePointerHolder__get(JNIEnv * env, jobject jNph,
|
|||||||
** argument is a Java sqlite3 object, as this operation only has void
|
** argument is a Java sqlite3 object, as this operation only has void
|
||||||
** pointers to work with.
|
** pointers to work with.
|
||||||
*/
|
*/
|
||||||
#define PtrGet_T(T,OBJ) (T*)NativePointerHolder_get(OBJ, S3JniNph(T))
|
#define PtrGet_T(T,JOBJ) (T*)NativePointerHolder_get((JOBJ), S3JniNph(T))
|
||||||
#define PtrGet_sqlite3(OBJ) PtrGet_T(sqlite3, OBJ)
|
#define PtrGet_sqlite3(JOBJ) PtrGet_T(sqlite3, (JOBJ))
|
||||||
#define PtrGet_sqlite3_backup(OBJ) PtrGet_T(sqlite3_backup, OBJ)
|
#define PtrGet_sqlite3_backup(JOBJ) PtrGet_T(sqlite3_backup, (JOBJ))
|
||||||
#define PtrGet_sqlite3_blob(OBJ) PtrGet_T(sqlite3_blob, OBJ)
|
#define PtrGet_sqlite3_blob(JOBJ) PtrGet_T(sqlite3_blob, (JOBJ))
|
||||||
#define PtrGet_sqlite3_context(OBJ) PtrGet_T(sqlite3_context, OBJ)
|
#define PtrGet_sqlite3_context(JOBJ) PtrGet_T(sqlite3_context, (JOBJ))
|
||||||
#define PtrGet_sqlite3_stmt(OBJ) PtrGet_T(sqlite3_stmt, OBJ)
|
#define PtrGet_sqlite3_stmt(JOBJ) PtrGet_T(sqlite3_stmt, (JOBJ))
|
||||||
#define PtrGet_sqlite3_value(OBJ) PtrGet_T(sqlite3_value, OBJ)
|
#define PtrGet_sqlite3_value(JOBJ) PtrGet_T(sqlite3_value, (JOBJ))
|
||||||
/*
|
/*
|
||||||
** LongPtrGet_T(X,Y) expects X to be an unqualified sqlite3 struct
|
** LongPtrGet_T(X,Y) expects X to be an unqualified sqlite3 struct
|
||||||
** type name and Y to be a native pointer to such an object in the
|
** type name and Y to be a native pointer to such an object in the
|
||||||
@ -1505,12 +1603,12 @@ static void * NativePointerHolder__get(JNIEnv * env, jobject jNph,
|
|||||||
** a difference of microseconds (i.e. below our testing measurement
|
** a difference of microseconds (i.e. below our testing measurement
|
||||||
** threshold) might add up.
|
** threshold) might add up.
|
||||||
*/
|
*/
|
||||||
#define LongPtrGet_T(T,JLongAsPtr) (T*)((intptr_t)(JLongAsPtr))
|
#define LongPtrGet_T(T,JLongAsPtr) (T*)((intptr_t)((JLongAsPtr)))
|
||||||
#define LongPtrGet_sqlite3(JLongAsPtr) LongPtrGet_T(sqlite3,JLongAsPtr)
|
#define LongPtrGet_sqlite3(JLongAsPtr) LongPtrGet_T(sqlite3,(JLongAsPtr))
|
||||||
#define LongPtrGet_sqlite3_backup(JLongAsPtr) LongPtrGet_T(sqlite3_backup,JLongAsPtr)
|
#define LongPtrGet_sqlite3_backup(JLongAsPtr) LongPtrGet_T(sqlite3_backup,(JLongAsPtr))
|
||||||
#define LongPtrGet_sqlite3_blob(JLongAsPtr) LongPtrGet_T(sqlite3_blob,JLongAsPtr)
|
#define LongPtrGet_sqlite3_blob(JLongAsPtr) LongPtrGet_T(sqlite3_blob,(JLongAsPtr))
|
||||||
#define LongPtrGet_sqlite3_stmt(JLongAsPtr) LongPtrGet_T(sqlite3_stmt,JLongAsPtr)
|
#define LongPtrGet_sqlite3_stmt(JLongAsPtr) LongPtrGet_T(sqlite3_stmt,(JLongAsPtr))
|
||||||
#define LongPtrGet_sqlite3_value(JLongAsPtr) LongPtrGet_T(sqlite3_value,JLongAsPtr)
|
#define LongPtrGet_sqlite3_value(JLongAsPtr) LongPtrGet_T(sqlite3_value,(JLongAsPtr))
|
||||||
/*
|
/*
|
||||||
** Extracts the new S3JniDb instance from the free-list, or allocates
|
** Extracts the new S3JniDb instance from the free-list, or allocates
|
||||||
** one if needed, associates it with pDb, and returns. Returns NULL
|
** one if needed, associates it with pDb, and returns. Returns NULL
|
||||||
@ -1897,13 +1995,16 @@ error_oom:
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Requires that jCx and jArgv are sqlite3_context
|
** Requires that jCx and jArgv are sqlite3_context
|
||||||
** resp. array-of-sqlite3_value values initialized by udf_args(). This
|
** resp. array-of-sqlite3_value values initialized by udf_args(). The
|
||||||
|
** latter will be 0-and-NULL for UDF types with no arguments. This
|
||||||
** function zeroes out the nativePointer member of jCx and each entry
|
** function zeroes out the nativePointer member of jCx and each entry
|
||||||
** in jArgv. This is a safety-net precaution to avoid undefined
|
** in jArgv. This is a safety-net precaution to avoid undefined
|
||||||
** behavior if a Java-side UDF holds a reference to one of its
|
** behavior if a Java-side UDF holds a reference to its context or one
|
||||||
** arguments. This MUST be called from any function which successfully
|
** of its arguments. This MUST be called from any function which
|
||||||
** calls udf_args(), after calling the corresponding UDF and checking
|
** successfully calls udf_args(), after calling the corresponding UDF
|
||||||
** its exception status. It MUST NOT be called in any other case.
|
** and checking its exception status, or which Java-wraps a
|
||||||
|
** sqlite3_context for use with a UDF(ish) call. It MUST NOT be called
|
||||||
|
** in any other case.
|
||||||
*/
|
*/
|
||||||
static void udf_unargs(JNIEnv *env, jobject jCx, int argc, jobjectArray jArgv){
|
static void udf_unargs(JNIEnv *env, jobject jCx, int argc, jobjectArray jArgv){
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@ -1911,8 +2012,29 @@ static void udf_unargs(JNIEnv *env, jobject jCx, int argc, jobjectArray jArgv){
|
|||||||
NativePointerHolder_set(S3JniNph(sqlite3_context), jCx, 0);
|
NativePointerHolder_set(S3JniNph(sqlite3_context), jCx, 0);
|
||||||
for( ; i < argc; ++i ){
|
for( ; i < argc; ++i ){
|
||||||
jobject jsv = (*env)->GetObjectArrayElement(env, jArgv, i);
|
jobject jsv = (*env)->GetObjectArrayElement(env, jArgv, i);
|
||||||
assert(jsv);
|
/*
|
||||||
NativePointerHolder_set(S3JniNph(sqlite3_value), jsv, 0);
|
** There is a potential Java-triggerable case of Undefined
|
||||||
|
** Behavior here, but it would require intentional misuse of the
|
||||||
|
** API:
|
||||||
|
**
|
||||||
|
** If a Java UDF grabs an sqlite3_value from its argv and then
|
||||||
|
** assigns that element to null, it becomes unreachable to us so
|
||||||
|
** we cannot clear out its pointer. That Java-side object's
|
||||||
|
** getNativePointer() will then refer to a stale value, so passing
|
||||||
|
** it into (e.g.) sqlite3_value_SOMETHING() would invoke UB.
|
||||||
|
**
|
||||||
|
** High-level wrappers can avoid that possibility if they do not
|
||||||
|
** expose sqlite3_value directly to clients (as is the case in
|
||||||
|
** org.sqlite.jni.wrapper1.SqlFunction).
|
||||||
|
**
|
||||||
|
** One potential (but expensive) workaround for this would be to
|
||||||
|
** privately store a duplicate argv array in each sqlite3_context
|
||||||
|
** wrapper object, and clear the native pointers from that copy.
|
||||||
|
*/
|
||||||
|
assert(jsv && "Someone illegally modified a UDF argument array.");
|
||||||
|
if( jsv ){
|
||||||
|
NativePointerHolder_set(S3JniNph(sqlite3_value), jsv, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2001,6 +2123,7 @@ static int udf_xFV(sqlite3_context* cx, S3JniUdf * s,
|
|||||||
rc = udf_report_exception(env, isFinal, cx, s->zFuncName,
|
rc = udf_report_exception(env, isFinal, cx, s->zFuncName,
|
||||||
zFuncType);
|
zFuncType);
|
||||||
}
|
}
|
||||||
|
udf_unargs(env, jcx, 0, 0);
|
||||||
S3JniUnrefLocal(jcx);
|
S3JniUnrefLocal(jcx);
|
||||||
}else{
|
}else{
|
||||||
if( isFinal ) sqlite3_result_error_nomem(cx);
|
if( isFinal ) sqlite3_result_error_nomem(cx);
|
||||||
@ -2408,6 +2531,112 @@ S3JniApi(sqlite3_bind_blob(),jint,1bind_1blob)(
|
|||||||
return (jint)rc;
|
return (jint)rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Helper for use with s3jni_setup_nio_args().
|
||||||
|
*/
|
||||||
|
struct S3JniNioArgs {
|
||||||
|
jobject jBuf; /* input - ByteBuffer */
|
||||||
|
jint iOffset; /* input - byte offset */
|
||||||
|
jint iHowMany; /* input - byte count to bind/read/write */
|
||||||
|
jint nBuf; /* output - jBuf's buffer size */
|
||||||
|
void * p; /* output - jBuf's buffer memory */
|
||||||
|
void * pStart; /* output - offset of p to bind/read/write */
|
||||||
|
int nOut; /* output - number of bytes from pStart to bind/read/write */
|
||||||
|
};
|
||||||
|
typedef struct S3JniNioArgs S3JniNioArgs;
|
||||||
|
static const S3JniNioArgs S3JniNioArgs_empty = {
|
||||||
|
0,0,0,0,0,0,0
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Internal helper for sqlite3_bind_nio_buffer(),
|
||||||
|
** sqlite3_result_nio_buffer(), and similar methods which take a
|
||||||
|
** ByteBuffer object as either input or output. Populates pArgs and
|
||||||
|
** returns 0 on success, non-0 if the operation should fail. The
|
||||||
|
** caller is required to check for SJG.g.byteBuffer.klazz!=0 before calling
|
||||||
|
** this and reporting it in a way appropriate for that routine. This
|
||||||
|
** function may assert() that SJG.g.byteBuffer.klazz is not 0.
|
||||||
|
**
|
||||||
|
** The (jBuffer, iOffset, iHowMany) arguments are the (ByteBuffer, offset,
|
||||||
|
** length) arguments to the bind/result method.
|
||||||
|
**
|
||||||
|
** If iHowMany is negative then it's treated as "until the end" and
|
||||||
|
** the calculated slice is trimmed to fit if needed. If iHowMany is
|
||||||
|
** positive and extends past the end of jBuffer then SQLITE_ERROR is
|
||||||
|
** returned.
|
||||||
|
**
|
||||||
|
** Returns 0 if everything looks to be in order, else some SQLITE_...
|
||||||
|
** result code
|
||||||
|
*/
|
||||||
|
static int s3jni_setup_nio_args(
|
||||||
|
JNIEnv *env, S3JniNioArgs * pArgs,
|
||||||
|
jobject jBuffer, jint iOffset, jint iHowMany
|
||||||
|
){
|
||||||
|
jlong iEnd = 0;
|
||||||
|
const int bAllowTruncate = iHowMany<0;
|
||||||
|
*pArgs = S3JniNioArgs_empty;
|
||||||
|
pArgs->jBuf = jBuffer;
|
||||||
|
pArgs->iOffset = iOffset;
|
||||||
|
pArgs->iHowMany = iHowMany;
|
||||||
|
assert( SJG.g.byteBuffer.klazz );
|
||||||
|
if( pArgs->iOffset<0 ){
|
||||||
|
return SQLITE_ERROR
|
||||||
|
/* SQLITE_MISUSE or SQLITE_RANGE would fit better but we use
|
||||||
|
SQLITE_ERROR for consistency with the code documented for a
|
||||||
|
negative target blob offset in sqlite3_blob_read/write(). */;
|
||||||
|
}
|
||||||
|
s3jni_get_nio_buffer(pArgs->jBuf, &pArgs->p, &pArgs->nBuf);
|
||||||
|
if( !pArgs->p ){
|
||||||
|
return SQLITE_MISUSE;
|
||||||
|
}else if( pArgs->iOffset>=pArgs->nBuf ){
|
||||||
|
pArgs->pStart = 0;
|
||||||
|
pArgs->nOut = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
assert( pArgs->nBuf > 0 );
|
||||||
|
assert( pArgs->iOffset < pArgs->nBuf );
|
||||||
|
iEnd = pArgs->iHowMany<0
|
||||||
|
? pArgs->nBuf - pArgs->iOffset
|
||||||
|
: pArgs->iOffset + pArgs->iHowMany;
|
||||||
|
if( iEnd>(jlong)pArgs->nBuf ){
|
||||||
|
if( bAllowTruncate ){
|
||||||
|
iEnd = pArgs->nBuf - pArgs->iOffset;
|
||||||
|
}else{
|
||||||
|
return SQLITE_ERROR
|
||||||
|
/* again: for consistency with blob_read/write(), though
|
||||||
|
SQLITE_MISUSE or SQLITE_RANGE would be a better fit. */;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( iEnd - pArgs->iOffset > (jlong)SQLITE_MAX_LENGTH ){
|
||||||
|
return SQLITE_TOOBIG;
|
||||||
|
}
|
||||||
|
assert( pArgs->iOffset >= 0 );
|
||||||
|
assert( iEnd > pArgs->iOffset );
|
||||||
|
pArgs->pStart = pArgs->p + pArgs->iOffset;
|
||||||
|
pArgs->nOut = (int)(iEnd - pArgs->iOffset);
|
||||||
|
assert( pArgs->nOut > 0 );
|
||||||
|
assert( (pArgs->pStart + pArgs->nOut) <= (pArgs->p + pArgs->nBuf) );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
S3JniApi(sqlite3_bind_nio_buffer(),jint,1bind_1nio_1buffer)(
|
||||||
|
JniArgsEnvClass, jobject jpStmt, jint ndx, jobject jBuffer,
|
||||||
|
jint iOffset, jint iN
|
||||||
|
){
|
||||||
|
sqlite3_stmt * pStmt = PtrGet_sqlite3_stmt(jpStmt);
|
||||||
|
S3JniNioArgs args;
|
||||||
|
int rc;
|
||||||
|
if( !pStmt || !SJG.g.byteBuffer.klazz ) return SQLITE_MISUSE;
|
||||||
|
rc = s3jni_setup_nio_args(env, &args, jBuffer, iOffset, iN);
|
||||||
|
if(rc){
|
||||||
|
return rc;
|
||||||
|
}else if( !args.pStart || !args.nOut ){
|
||||||
|
return sqlite3_bind_null(pStmt, ndx);
|
||||||
|
}
|
||||||
|
return sqlite3_bind_blob( pStmt, (int)ndx, args.pStart,
|
||||||
|
args.nOut, SQLITE_TRANSIENT );
|
||||||
|
}
|
||||||
|
|
||||||
S3JniApi(sqlite3_bind_double(),jint,1bind_1double)(
|
S3JniApi(sqlite3_bind_double(),jint,1bind_1double)(
|
||||||
JniArgsEnvClass, jlong jpStmt, jint ndx, jdouble val
|
JniArgsEnvClass, jlong jpStmt, jint ndx, jdouble val
|
||||||
){
|
){
|
||||||
@ -2622,6 +2851,30 @@ S3JniApi(sqlite3_blob_read(),jint,1blob_1read)(
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
S3JniApi(sqlite3_blob_read_nio_buffer(),jint,1blob_1read_1nio_1buffer)(
|
||||||
|
JniArgsEnvClass, jlong jpBlob, jint iSrcOff, jobject jBB, jint iTgtOff, jint iHowMany
|
||||||
|
){
|
||||||
|
sqlite3_blob * const b = LongPtrGet_sqlite3_blob(jpBlob);
|
||||||
|
S3JniNioArgs args;
|
||||||
|
int rc;
|
||||||
|
if( !b || !SJG.g.byteBuffer.klazz || iHowMany<0 ){
|
||||||
|
return SQLITE_MISUSE;
|
||||||
|
}else if( iTgtOff<0 || iSrcOff<0 ){
|
||||||
|
return SQLITE_ERROR
|
||||||
|
/* for consistency with underlying sqlite3_blob_read() */;
|
||||||
|
}else if( 0==iHowMany ){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rc = s3jni_setup_nio_args(env, &args, jBB, iTgtOff, iHowMany);
|
||||||
|
if(rc){
|
||||||
|
return rc;
|
||||||
|
}else if( !args.pStart || !args.nOut ){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
assert( args.iHowMany>0 );
|
||||||
|
return sqlite3_blob_read( b, args.pStart, (int)args.nOut, (int)iSrcOff );
|
||||||
|
}
|
||||||
|
|
||||||
S3JniApi(sqlite3_blob_reopen(),jint,1blob_1reopen)(
|
S3JniApi(sqlite3_blob_reopen(),jint,1blob_1reopen)(
|
||||||
JniArgsEnvClass, jlong jpBlob, jlong iNewRowId
|
JniArgsEnvClass, jlong jpBlob, jlong iNewRowId
|
||||||
){
|
){
|
||||||
@ -2643,6 +2896,29 @@ S3JniApi(sqlite3_blob_write(),jint,1blob_1write)(
|
|||||||
return (jint)rc;
|
return (jint)rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
S3JniApi(sqlite3_blob_write_nio_buffer(),jint,1blob_1write_1nio_1buffer)(
|
||||||
|
JniArgsEnvClass, jlong jpBlob, jint iTgtOff, jobject jBB, jint iSrcOff, jint iHowMany
|
||||||
|
){
|
||||||
|
sqlite3_blob * const b = LongPtrGet_sqlite3_blob(jpBlob);
|
||||||
|
S3JniNioArgs args;
|
||||||
|
int rc;
|
||||||
|
if( !b || !SJG.g.byteBuffer.klazz ){
|
||||||
|
return SQLITE_MISUSE;
|
||||||
|
}else if( iTgtOff<0 || iSrcOff<0 ){
|
||||||
|
return SQLITE_ERROR
|
||||||
|
/* for consistency with underlying sqlite3_blob_write() */;
|
||||||
|
}else if( 0==iHowMany ){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rc = s3jni_setup_nio_args(env, &args, jBB, iSrcOff, iHowMany);
|
||||||
|
if(rc){
|
||||||
|
return rc;
|
||||||
|
}else if( !args.pStart || !args.nOut ){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return sqlite3_blob_write( b, args.pStart, (int)args.nOut, (int)iTgtOff );
|
||||||
|
}
|
||||||
|
|
||||||
/* Central C-to-Java busy handler proxy. */
|
/* Central C-to-Java busy handler proxy. */
|
||||||
static int s3jni_busy_handler(void* pState, int n){
|
static int s3jni_busy_handler(void* pState, int n){
|
||||||
S3JniDb * const ps = (S3JniDb *)pState;
|
S3JniDb * const ps = (S3JniDb *)pState;
|
||||||
@ -2911,6 +3187,21 @@ S3JniApi(sqlite3_column_java_object(),jobject,1column_1java_1object)(
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
S3JniApi(sqlite3_column_nio_buffer(),jobject,1column_1nio_1buffer)(
|
||||||
|
JniArgsEnvClass, jobject jStmt, jint ndx
|
||||||
|
){
|
||||||
|
sqlite3_stmt * const stmt = PtrGet_sqlite3_stmt(jStmt);
|
||||||
|
jobject rv = 0;
|
||||||
|
if( stmt ){
|
||||||
|
const void * const p = sqlite3_column_blob(stmt, (int)ndx);
|
||||||
|
if( p ){
|
||||||
|
const int n = sqlite3_column_bytes(stmt, (int)ndx);
|
||||||
|
rv = s3jni__blob_to_ByteBuffer(env, p, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
S3JniApi(sqlite3_column_text(),jbyteArray,1column_1text)(
|
S3JniApi(sqlite3_column_text(),jbyteArray,1column_1text)(
|
||||||
JniArgsEnvClass, jobject jpStmt, jint ndx
|
JniArgsEnvClass, jobject jpStmt, jint ndx
|
||||||
){
|
){
|
||||||
@ -3088,8 +3379,9 @@ S3JniApi(sqlite3_complete(),jint,1complete)(
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
S3JniApi(sqlite3_config() /*for a small subset of options.*/,
|
S3JniApi(sqlite3_config() /*for a small subset of options.*/
|
||||||
jint,1config__I)(JniArgsEnvClass, jint n){
|
sqlite3_config__enable()/* internal name to avoid name-mangling issues*/,
|
||||||
|
jint,1config_1_1enable)(JniArgsEnvClass, jint n){
|
||||||
switch( n ){
|
switch( n ){
|
||||||
case SQLITE_CONFIG_SINGLETHREAD:
|
case SQLITE_CONFIG_SINGLETHREAD:
|
||||||
case SQLITE_CONFIG_MULTITHREAD:
|
case SQLITE_CONFIG_MULTITHREAD:
|
||||||
@ -3119,8 +3411,9 @@ static void s3jni_config_log(void *ignored, int errCode, const char *z){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
S3JniApi(sqlite3_config() /* for SQLITE_CONFIG_LOG */,
|
S3JniApi(sqlite3_config() /* for SQLITE_CONFIG_LOG */
|
||||||
jint, 1config__Lorg_sqlite_jni_ConfigLogCallback_2
|
sqlite3_config__config_log() /* internal name */,
|
||||||
|
jint, 1config_1_1CONFIG_1LOG
|
||||||
)(JniArgsEnvClass, jobject jLog){
|
)(JniArgsEnvClass, jobject jLog){
|
||||||
S3JniHook * const pHook = &SJG.hook.configlog;
|
S3JniHook * const pHook = &SJG.hook.configlog;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
@ -3194,9 +3487,10 @@ void sqlite3_init_sqllog(void){
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
S3JniApi(sqlite3_config() /* for SQLITE_CONFIG_SQLLOG */,
|
S3JniApi(sqlite3_config() /* for SQLITE_CONFIG_SQLLOG */
|
||||||
jint, 1config__Lorg_sqlite_jni_ConfigSqllogCallback_2)(
|
sqlite3_config__SQLLOG() /*internal name*/,
|
||||||
JniArgsEnvClass, jobject jLog){
|
jint, 1config_1_1SQLLOG
|
||||||
|
)(JniArgsEnvClass, jobject jLog){
|
||||||
#ifndef SQLITE_ENABLE_SQLLOG
|
#ifndef SQLITE_ENABLE_SQLLOG
|
||||||
return SQLITE_MISUSE;
|
return SQLITE_MISUSE;
|
||||||
#else
|
#else
|
||||||
@ -3675,7 +3969,9 @@ S3JniApi(sqlite3_is_interrupted(),jboolean,1is_1interrupted)(
|
|||||||
** any resources owned by that cache entry and making that slot
|
** any resources owned by that cache entry and making that slot
|
||||||
** available for re-use.
|
** available for re-use.
|
||||||
*/
|
*/
|
||||||
JniDecl(jboolean,1java_1uncache_1thread)(JniArgsEnvClass){
|
S3JniApi(sqlite3_java_uncache_thread(), jboolean, 1java_1uncache_1thread)(
|
||||||
|
JniArgsEnvClass
|
||||||
|
){
|
||||||
int rc;
|
int rc;
|
||||||
S3JniEnv_mutex_enter;
|
S3JniEnv_mutex_enter;
|
||||||
rc = S3JniEnv_uncache(env);
|
rc = S3JniEnv_uncache(env);
|
||||||
@ -3683,8 +3979,26 @@ JniDecl(jboolean,1java_1uncache_1thread)(JniArgsEnvClass){
|
|||||||
return rc ? JNI_TRUE : JNI_FALSE;
|
return rc ? JNI_TRUE : JNI_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
JniDecl(jboolean,1jni_1supports_1nio)(JniArgsEnvClass){
|
S3JniApi(sqlite3_jni_db_error(), jint, 1jni_1db_1error)(
|
||||||
return SJG.g.cByteBuffer ? JNI_TRUE : JNI_FALSE;
|
JniArgsEnvClass, jobject jDb, jint jRc, jstring jStr
|
||||||
|
){
|
||||||
|
S3JniDb * const ps = S3JniDb_from_java(jDb);
|
||||||
|
int rc = SQLITE_MISUSE;
|
||||||
|
if( ps ){
|
||||||
|
char *zStr;
|
||||||
|
zStr = jStr
|
||||||
|
? s3jni_jstring_to_utf8( jStr, 0)
|
||||||
|
: NULL;
|
||||||
|
rc = s3jni_db_error( ps->pDb, (int)jRc, zStr );
|
||||||
|
sqlite3_free(zStr);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
S3JniApi(sqlite3_jni_supports_nio(), jboolean,1jni_1supports_1nio)(
|
||||||
|
JniArgsEnvClass
|
||||||
|
){
|
||||||
|
return SJG.g.byteBuffer.klazz ? JNI_TRUE : JNI_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3861,10 +4175,11 @@ S3JniApi(sqlite3_open_v2(),jint,1open_1v2)(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Proxy for the sqlite3_prepare[_v2/3]() family. */
|
/* Proxy for the sqlite3_prepare[_v2/3]() family. */
|
||||||
jint sqlite3_jni_prepare_v123( int prepVersion, JNIEnv * const env, jclass self,
|
static jint sqlite3_jni_prepare_v123( int prepVersion, JNIEnv * const env,
|
||||||
jlong jpDb, jbyteArray baSql,
|
jclass self,
|
||||||
jint nMax, jint prepFlags,
|
jlong jpDb, jbyteArray baSql,
|
||||||
jobject jOutStmt, jobject outTail){
|
jint nMax, jint prepFlags,
|
||||||
|
jobject jOutStmt, jobject outTail){
|
||||||
sqlite3_stmt * pStmt = 0;
|
sqlite3_stmt * pStmt = 0;
|
||||||
jobject jStmt = 0;
|
jobject jStmt = 0;
|
||||||
const char * zTail = 0;
|
const char * zTail = 0;
|
||||||
@ -4417,6 +4732,40 @@ S3JniApi(sqlite3_result_java_object(),void,1result_1java_1object)(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
S3JniApi(sqlite3_result_nio_buffer(),void,1result_1nio_1buffer)(
|
||||||
|
JniArgsEnvClass, jobject jpCtx, jobject jBuffer,
|
||||||
|
jint iOffset, jint iN
|
||||||
|
){
|
||||||
|
sqlite3_context * pCx = PtrGet_sqlite3_context(jpCtx);
|
||||||
|
int rc;
|
||||||
|
S3JniNioArgs args;
|
||||||
|
if( !pCx ){
|
||||||
|
return;
|
||||||
|
}else if( !SJG.g.byteBuffer.klazz ){
|
||||||
|
sqlite3_result_error(
|
||||||
|
pCx, "This JVM does not support JNI access to ByteBuffers.", -1
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rc = s3jni_setup_nio_args(env, &args, jBuffer, iOffset, iN);
|
||||||
|
if(rc){
|
||||||
|
if( iOffset<0 ){
|
||||||
|
sqlite3_result_error(pCx, "Start index may not be negative.", -1);
|
||||||
|
}else if( SQLITE_TOOBIG==rc ){
|
||||||
|
sqlite3_result_error_toobig(pCx);
|
||||||
|
}else{
|
||||||
|
sqlite3_result_error(
|
||||||
|
pCx, "Invalid arguments to sqlite3_result_nio_buffer().", -1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}else if( !args.pStart || !args.nOut ){
|
||||||
|
sqlite3_result_null(pCx);
|
||||||
|
}else{
|
||||||
|
sqlite3_result_blob(pCx, args.pStart, args.nOut, SQLITE_TRANSIENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
S3JniApi(sqlite3_result_null(),void,1result_1null)(
|
S3JniApi(sqlite3_result_null(),void,1result_1null)(
|
||||||
JniArgsEnvClass, jobject jpCx
|
JniArgsEnvClass, jobject jpCx
|
||||||
){
|
){
|
||||||
@ -4945,6 +5294,21 @@ S3JniApi(sqlite3_value_java_object(),jobject,1value_1java_1object)(
|
|||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
S3JniApi(sqlite3_value_nio_buffer(),jobject,1value_1nio_1buffer)(
|
||||||
|
JniArgsEnvClass, jobject jVal
|
||||||
|
){
|
||||||
|
sqlite3_value * const sv = PtrGet_sqlite3_value(jVal);
|
||||||
|
jobject rv = 0;
|
||||||
|
if( sv ){
|
||||||
|
const void * const p = sqlite3_value_blob(sv);
|
||||||
|
if( p ){
|
||||||
|
const int n = sqlite3_value_bytes(sv);
|
||||||
|
rv = s3jni__blob_to_ByteBuffer(env, p, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
S3JniApi(sqlite3_value_text(),jbyteArray,1value_1text)(
|
S3JniApi(sqlite3_value_text(),jbyteArray,1value_1text)(
|
||||||
JniArgsEnvClass, jlong jpSVal
|
JniArgsEnvClass, jlong jpSVal
|
||||||
){
|
){
|
||||||
@ -5951,10 +6315,19 @@ Java_org_sqlite_jni_capi_CApi_init(JniArgsEnvClass){
|
|||||||
unsigned char buf[16] = {0};
|
unsigned char buf[16] = {0};
|
||||||
jobject bb = (*env)->NewDirectByteBuffer(env, buf, 16);
|
jobject bb = (*env)->NewDirectByteBuffer(env, buf, 16);
|
||||||
if( bb ){
|
if( bb ){
|
||||||
SJG.g.cByteBuffer = (*env)->GetObjectClass(env, bb);
|
SJG.g.byteBuffer.klazz = S3JniRefGlobal((*env)->GetObjectClass(env, bb));
|
||||||
|
SJG.g.byteBuffer.midAlloc = (*env)->GetStaticMethodID(
|
||||||
|
env, SJG.g.byteBuffer.klazz, "allocateDirect", "(I)Ljava/nio/ByteBuffer;"
|
||||||
|
);
|
||||||
|
S3JniExceptionIsFatal("Error getting ByteBuffer.allocateDirect() method.");
|
||||||
|
SJG.g.byteBuffer.midLimit = (*env)->GetMethodID(
|
||||||
|
env, SJG.g.byteBuffer.klazz, "limit", "()I"
|
||||||
|
);
|
||||||
|
S3JniExceptionIsFatal("Error getting ByteBuffer.limit() method.");
|
||||||
S3JniUnrefLocal(bb);
|
S3JniUnrefLocal(bb);
|
||||||
}else{
|
}else{
|
||||||
SJG.g.cByteBuffer = 0;
|
SJG.g.byteBuffer.klazz = 0;
|
||||||
|
SJG.g.byteBuffer.midAlloc = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -785,6 +785,14 @@ JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1java_1uncache_
|
|||||||
JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1jni_1supports_1nio
|
JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1jni_1supports_1nio
|
||||||
(JNIEnv *, jclass);
|
(JNIEnv *, jclass);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_sqlite_jni_capi_CApi
|
||||||
|
* Method: sqlite3_jni_db_error
|
||||||
|
* Signature: (Lorg/sqlite/jni/capi/sqlite3;ILjava/lang/String;)I
|
||||||
|
*/
|
||||||
|
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1jni_1db_1error
|
||||||
|
(JNIEnv *, jclass, jobject, jint, jstring);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: org_sqlite_jni_capi_CApi
|
* Class: org_sqlite_jni_capi_CApi
|
||||||
* Method: sqlite3_aggregate_context
|
* Method: sqlite3_aggregate_context
|
||||||
@ -881,6 +889,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1bind_1int64
|
|||||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1bind_1java_1object
|
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1bind_1java_1object
|
||||||
(JNIEnv *, jclass, jlong, jint, jobject);
|
(JNIEnv *, jclass, jlong, jint, jobject);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_sqlite_jni_capi_CApi
|
||||||
|
* Method: sqlite3_bind_nio_buffer
|
||||||
|
* Signature: (Lorg/sqlite/jni/capi/sqlite3_stmt;ILjava/nio/ByteBuffer;II)I
|
||||||
|
*/
|
||||||
|
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1bind_1nio_1buffer
|
||||||
|
(JNIEnv *, jclass, jobject, jint, jobject, jint, jint);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: org_sqlite_jni_capi_CApi
|
* Class: org_sqlite_jni_capi_CApi
|
||||||
* Method: sqlite3_bind_null
|
* Method: sqlite3_bind_null
|
||||||
@ -985,6 +1001,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1open
|
|||||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1read
|
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1read
|
||||||
(JNIEnv *, jclass, jlong, jbyteArray, jint);
|
(JNIEnv *, jclass, jlong, jbyteArray, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_sqlite_jni_capi_CApi
|
||||||
|
* Method: sqlite3_blob_read_nio_buffer
|
||||||
|
* Signature: (JILjava/nio/ByteBuffer;II)I
|
||||||
|
*/
|
||||||
|
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1read_1nio_1buffer
|
||||||
|
(JNIEnv *, jclass, jlong, jint, jobject, jint, jint);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: org_sqlite_jni_capi_CApi
|
* Class: org_sqlite_jni_capi_CApi
|
||||||
* Method: sqlite3_blob_reopen
|
* Method: sqlite3_blob_reopen
|
||||||
@ -1001,6 +1025,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1reopen
|
|||||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1write
|
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1write
|
||||||
(JNIEnv *, jclass, jlong, jbyteArray, jint);
|
(JNIEnv *, jclass, jlong, jbyteArray, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_sqlite_jni_capi_CApi
|
||||||
|
* Method: sqlite3_blob_write_nio_buffer
|
||||||
|
* Signature: (JILjava/nio/ByteBuffer;II)I
|
||||||
|
*/
|
||||||
|
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1write_1nio_1buffer
|
||||||
|
(JNIEnv *, jclass, jlong, jint, jobject, jint, jint);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: org_sqlite_jni_capi_CApi
|
* Class: org_sqlite_jni_capi_CApi
|
||||||
* Method: sqlite3_busy_handler
|
* Method: sqlite3_busy_handler
|
||||||
@ -1097,6 +1129,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1bytes16
|
|||||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1count
|
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1count
|
||||||
(JNIEnv *, jclass, jlong);
|
(JNIEnv *, jclass, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_sqlite_jni_capi_CApi
|
||||||
|
* Method: sqlite3_column_database_name
|
||||||
|
* Signature: (JI)Ljava/lang/String;
|
||||||
|
*/
|
||||||
|
JNIEXPORT jstring JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1database_1name
|
||||||
|
(JNIEnv *, jclass, jlong, jint);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: org_sqlite_jni_capi_CApi
|
* Class: org_sqlite_jni_capi_CApi
|
||||||
* Method: sqlite3_column_decltype
|
* Method: sqlite3_column_decltype
|
||||||
@ -1147,11 +1187,11 @@ JNIEXPORT jstring JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1name
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: org_sqlite_jni_capi_CApi
|
* Class: org_sqlite_jni_capi_CApi
|
||||||
* Method: sqlite3_column_database_name
|
* Method: sqlite3_column_nio_buffer
|
||||||
* Signature: (JI)Ljava/lang/String;
|
* Signature: (Lorg/sqlite/jni/capi/sqlite3_stmt;I)Ljava/nio/ByteBuffer;
|
||||||
*/
|
*/
|
||||||
JNIEXPORT jstring JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1database_1name
|
JNIEXPORT jobject JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1nio_1buffer
|
||||||
(JNIEnv *, jclass, jlong, jint);
|
(JNIEnv *, jclass, jobject, jint);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: org_sqlite_jni_capi_CApi
|
* Class: org_sqlite_jni_capi_CApi
|
||||||
@ -1243,26 +1283,26 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1complete
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: org_sqlite_jni_capi_CApi
|
* Class: org_sqlite_jni_capi_CApi
|
||||||
* Method: sqlite3_config
|
* Method: sqlite3_config__enable
|
||||||
* Signature: (I)I
|
* Signature: (I)I
|
||||||
*/
|
*/
|
||||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config__I
|
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config_1_1enable
|
||||||
(JNIEnv *, jclass, jint);
|
(JNIEnv *, jclass, jint);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: org_sqlite_jni_capi_CApi
|
* Class: org_sqlite_jni_capi_CApi
|
||||||
* Method: sqlite3_config
|
* Method: sqlite3_config__CONFIG_LOG
|
||||||
* Signature: (Lorg/sqlite/jni/capi/ConfigSqllogCallback;)I
|
* Signature: (Lorg/sqlite/jni/capi/ConfigLogCallback;)I
|
||||||
*/
|
*/
|
||||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config__Lorg_sqlite_jni_capi_ConfigSqllogCallback_2
|
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config_1_1CONFIG_1LOG
|
||||||
(JNIEnv *, jclass, jobject);
|
(JNIEnv *, jclass, jobject);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: org_sqlite_jni_capi_CApi
|
* Class: org_sqlite_jni_capi_CApi
|
||||||
* Method: sqlite3_config
|
* Method: sqlite3_config__SQLLOG
|
||||||
* Signature: (Lorg/sqlite/jni/capi/ConfigLogCallback;)I
|
* Signature: (Lorg/sqlite/jni/capi/ConfigSqlLogCallback;)I
|
||||||
*/
|
*/
|
||||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config__Lorg_sqlite_jni_capi_ConfigLogCallback_2
|
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config_1_1SQLLOG
|
||||||
(JNIEnv *, jclass, jobject);
|
(JNIEnv *, jclass, jobject);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1721,6 +1761,14 @@ JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1int64
|
|||||||
JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1java_1object
|
JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1java_1object
|
||||||
(JNIEnv *, jclass, jobject, jobject);
|
(JNIEnv *, jclass, jobject, jobject);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_sqlite_jni_capi_CApi
|
||||||
|
* Method: sqlite3_result_nio_buffer
|
||||||
|
* Signature: (Lorg/sqlite/jni/capi/sqlite3_context;Ljava/nio/ByteBuffer;II)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1nio_1buffer
|
||||||
|
(JNIEnv *, jclass, jobject, jobject, jint, jint);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: org_sqlite_jni_capi_CApi
|
* Class: org_sqlite_jni_capi_CApi
|
||||||
* Method: sqlite3_result_null
|
* Method: sqlite3_result_null
|
||||||
@ -2089,6 +2137,14 @@ JNIEXPORT jlong JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1value_1int64
|
|||||||
JNIEXPORT jobject JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1value_1java_1object
|
JNIEXPORT jobject JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1value_1java_1object
|
||||||
(JNIEnv *, jclass, jlong);
|
(JNIEnv *, jclass, jlong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: org_sqlite_jni_capi_CApi
|
||||||
|
* Method: sqlite3_value_nio_buffer
|
||||||
|
* Signature: (Lorg/sqlite/jni/capi/sqlite3_value;)Ljava/nio/ByteBuffer;
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobject JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1value_1nio_1buffer
|
||||||
|
(JNIEnv *, jclass, jobject);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: org_sqlite_jni_capi_CApi
|
* Class: org_sqlite_jni_capi_CApi
|
||||||
* Method: sqlite3_value_nochange
|
* Method: sqlite3_value_nochange
|
||||||
|
30
ext/jni/src/org/sqlite/jni/annotation/Experimental.java
Normal file
30
ext/jni/src/org/sqlite/jni/annotation/Experimental.java
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
** 2023-09-27
|
||||||
|
**
|
||||||
|
** The author disclaims copyright to this source code. In place of
|
||||||
|
** a legal notice, here is a blessing:
|
||||||
|
**
|
||||||
|
** May you do good and not evil.
|
||||||
|
** May you find forgiveness for yourself and forgive others.
|
||||||
|
** May you share freely, never taking more than you give.
|
||||||
|
**
|
||||||
|
*************************************************************************
|
||||||
|
** This file houses the Experimental annotation for the sqlite3 C API.
|
||||||
|
*/
|
||||||
|
package org.sqlite.jni.annotation;
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
This annotation is for flagging methods, constructors, and types
|
||||||
|
which are expressly experimental and subject to any amount of
|
||||||
|
change or outright removal. Client code should not rely on such
|
||||||
|
features.
|
||||||
|
*/
|
||||||
|
@Documented
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
@Target({
|
||||||
|
ElementType.METHOD,
|
||||||
|
ElementType.CONSTRUCTOR,
|
||||||
|
ElementType.TYPE
|
||||||
|
})
|
||||||
|
public @interface Experimental{}
|
@ -9,9 +9,10 @@
|
|||||||
** May you share freely, never taking more than you give.
|
** May you share freely, never taking more than you give.
|
||||||
**
|
**
|
||||||
*************************************************************************
|
*************************************************************************
|
||||||
** This file houses the NotNull annotaion for the sqlite3 C API.
|
** This file houses the NotNull annotation for the sqlite3 C API.
|
||||||
*/
|
*/
|
||||||
package org.sqlite.jni.annotation;
|
package org.sqlite.jni.annotation;
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This annotation is for flagging parameters which may not legally be
|
This annotation is for flagging parameters which may not legally be
|
||||||
@ -64,7 +65,7 @@ package org.sqlite.jni.annotation;
|
|||||||
part of the public API and client-level code must not rely on
|
part of the public API and client-level code must not rely on
|
||||||
it.</p>
|
it.</p>
|
||||||
*/
|
*/
|
||||||
@java.lang.annotation.Documented
|
@Documented
|
||||||
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@java.lang.annotation.Target(java.lang.annotation.ElementType.PARAMETER)
|
@Target(ElementType.PARAMETER)
|
||||||
public @interface NotNull{}
|
public @interface NotNull{}
|
||||||
|
@ -9,9 +9,10 @@
|
|||||||
** May you share freely, never taking more than you give.
|
** May you share freely, never taking more than you give.
|
||||||
**
|
**
|
||||||
*************************************************************************
|
*************************************************************************
|
||||||
** This file houses the Nullable annotaion for the sqlite3 C API.
|
** This file houses the Nullable annotation for the sqlite3 C API.
|
||||||
*/
|
*/
|
||||||
package org.sqlite.jni.annotation;
|
package org.sqlite.jni.annotation;
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This annotation is for flagging parameters which may legally be
|
This annotation is for flagging parameters which may legally be
|
||||||
@ -26,7 +27,7 @@ package org.sqlite.jni.annotation;
|
|||||||
annotated functions. It is not part of the public API and
|
annotated functions. It is not part of the public API and
|
||||||
client-level code must not rely on it.
|
client-level code must not rely on it.
|
||||||
*/
|
*/
|
||||||
@java.lang.annotation.Documented
|
@Documented
|
||||||
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@java.lang.annotation.Target(java.lang.annotation.ElementType.PARAMETER)
|
@Target(ElementType.PARAMETER)
|
||||||
public @interface Nullable{}
|
public @interface Nullable{}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
** May you share freely, never taking more than you give.
|
** May you share freely, never taking more than you give.
|
||||||
**
|
**
|
||||||
*************************************************************************
|
*************************************************************************
|
||||||
** This file declares JNI bindings for the sqlite3 C API.
|
** This file declares the main JNI bindings for the sqlite3 C API.
|
||||||
*/
|
*/
|
||||||
package org.sqlite.jni.capi;
|
package org.sqlite.jni.capi;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
@ -69,7 +69,7 @@ import java.util.Arrays;
|
|||||||
NUL-terminated, and conversion to a Java byte array must sometimes
|
NUL-terminated, and conversion to a Java byte array must sometimes
|
||||||
be careful to add one. Functions which take a length do not require
|
be careful to add one. Functions which take a length do not require
|
||||||
this so long as the length is provided. Search the CApi class
|
this so long as the length is provided. Search the CApi class
|
||||||
for "\0" for many examples.
|
for "\0" for examples.
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@ -119,16 +119,38 @@ public final class CApi {
|
|||||||
<p>This routine returns false without side effects if the current
|
<p>This routine returns false without side effects if the current
|
||||||
JNIEnv is not cached, else returns true, but this information is
|
JNIEnv is not cached, else returns true, but this information is
|
||||||
primarily for testing of the JNI bindings and is not information
|
primarily for testing of the JNI bindings and is not information
|
||||||
which client-level code can use to make any informed decisions.
|
which client-level code can use to make any informed
|
||||||
|
decisions. Its return type and semantics are not considered
|
||||||
|
stable and may change at any time.
|
||||||
*/
|
*/
|
||||||
public static native boolean sqlite3_java_uncache_thread();
|
public static native boolean sqlite3_java_uncache_thread();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns true if this JVM has JNI-level support for direct memory
|
Returns true if this JVM has JNI-level support for C-level direct
|
||||||
access using java.nio.ByteBuffer, else returns false.
|
memory access using java.nio.ByteBuffer, else returns false.
|
||||||
*/
|
*/
|
||||||
|
@Experimental
|
||||||
public static native boolean sqlite3_jni_supports_nio();
|
public static native boolean sqlite3_jni_supports_nio();
|
||||||
|
|
||||||
|
/**
|
||||||
|
For internal use only. Sets the given db's error code and
|
||||||
|
(optionally) string. If rc is 0, it defaults to SQLITE_ERROR.
|
||||||
|
|
||||||
|
On success it returns rc. On error it may return a more serious
|
||||||
|
code, such as SQLITE_NOMEM. Returns SQLITE_MISUSE if db is null.
|
||||||
|
*/
|
||||||
|
static native int sqlite3_jni_db_error(@NotNull sqlite3 db,
|
||||||
|
int rc, @Nullable String msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Convenience overload which uses e.toString() as the error
|
||||||
|
message.
|
||||||
|
*/
|
||||||
|
static int sqlite3_jni_db_error(@NotNull sqlite3 db,
|
||||||
|
int rc, @NotNull Exception e){
|
||||||
|
return sqlite3_jni_db_error(db, rc, e.toString());
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// Maintenance reminder: please keep the sqlite3_.... functions
|
// Maintenance reminder: please keep the sqlite3_.... functions
|
||||||
// alphabetized. The SQLITE_... values. on the other hand, are
|
// alphabetized. The SQLITE_... values. on the other hand, are
|
||||||
@ -215,7 +237,7 @@ public final class CApi {
|
|||||||
If n is negative, SQLITE_MISUSE is returned. If n>data.length
|
If n is negative, SQLITE_MISUSE is returned. If n>data.length
|
||||||
then n is silently truncated to data.length.
|
then n is silently truncated to data.length.
|
||||||
*/
|
*/
|
||||||
static int sqlite3_bind_blob(
|
public static int sqlite3_bind_blob(
|
||||||
@NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data, int n
|
@NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data, int n
|
||||||
){
|
){
|
||||||
return sqlite3_bind_blob(stmt.getNativePointer(), ndx, data, n);
|
return sqlite3_bind_blob(stmt.getNativePointer(), ndx, data, n);
|
||||||
@ -229,6 +251,30 @@ public final class CApi {
|
|||||||
: sqlite3_bind_blob(stmt.getNativePointer(), ndx, data, data.length);
|
: sqlite3_bind_blob(stmt.getNativePointer(), ndx, data, data.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Convenience overload which is a simple proxy for
|
||||||
|
sqlite3_bind_nio_buffer().
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public static int sqlite3_bind_blob(
|
||||||
|
@NotNull sqlite3_stmt stmt, int ndx, @Nullable java.nio.ByteBuffer data,
|
||||||
|
int begin, int n
|
||||||
|
){
|
||||||
|
return sqlite3_bind_nio_buffer(stmt, ndx, data, begin, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Convenience overload which is equivalant to passing its arguments
|
||||||
|
to sqlite3_bind_nio_buffer() with the values 0 and -1 for the
|
||||||
|
final two arguments.
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public static int sqlite3_bind_blob(
|
||||||
|
@NotNull sqlite3_stmt stmt, int ndx, @Nullable java.nio.ByteBuffer data
|
||||||
|
){
|
||||||
|
return sqlite3_bind_nio_buffer(stmt, ndx, data, 0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
private static native int sqlite3_bind_double(
|
private static native int sqlite3_bind_double(
|
||||||
@NotNull long ptrToStmt, int ndx, double v
|
@NotNull long ptrToStmt, int ndx, double v
|
||||||
);
|
);
|
||||||
@ -261,6 +307,61 @@ public final class CApi {
|
|||||||
@NotNull long ptrToStmt, int ndx, @Nullable Object o
|
@NotNull long ptrToStmt, int ndx, @Nullable Object o
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Binds the contents of the given buffer object as a blob.
|
||||||
|
|
||||||
|
The byte range of the buffer may be restricted by providing a
|
||||||
|
start index and a number of bytes. beginPos may not be negative.
|
||||||
|
Negative howMany is interpretated as the remainder of the buffer
|
||||||
|
past the given start position, up to the buffer's limit() (as
|
||||||
|
opposed its capacity()).
|
||||||
|
|
||||||
|
If beginPos+howMany would extend past the limit() of the buffer
|
||||||
|
then SQLITE_ERROR is returned.
|
||||||
|
|
||||||
|
If any of the following are true, this function behaves like
|
||||||
|
sqlite3_bind_null(): the buffer is null, beginPos is at or past
|
||||||
|
the end of the buffer, howMany is 0, or the calculated slice of
|
||||||
|
the blob has a length of 0.
|
||||||
|
|
||||||
|
If ndx is out of range, it returns SQLITE_RANGE, as documented
|
||||||
|
for sqlite3_bind_blob(). If beginPos is negative or if
|
||||||
|
sqlite3_jni_supports_nio() returns false then SQLITE_MISUSE is
|
||||||
|
returned. Note that this function is bound (as it were) by the
|
||||||
|
SQLITE_LIMIT_LENGTH constraint and SQLITE_TOOBIG is returned if
|
||||||
|
the resulting slice of the buffer exceeds that limit.
|
||||||
|
|
||||||
|
This function does not modify the buffer's streaming-related
|
||||||
|
cursors.
|
||||||
|
|
||||||
|
If the buffer is modified in a separate thread while this
|
||||||
|
operation is running, results are undefined and will likely
|
||||||
|
result in corruption of the bound data or a segmentation fault.
|
||||||
|
|
||||||
|
Design note: this function should arguably take a java.nio.Buffer
|
||||||
|
instead of ByteBuffer, but it can only operate on "direct"
|
||||||
|
buffers and the only such class offered by Java is (apparently)
|
||||||
|
ByteBuffer.
|
||||||
|
|
||||||
|
@see https://docs.oracle.com/javase/8/docs/api/java/nio/Buffer.html
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public static native int sqlite3_bind_nio_buffer(
|
||||||
|
@NotNull sqlite3_stmt stmt, int ndx, @Nullable java.nio.ByteBuffer data,
|
||||||
|
int beginPos, int howMany
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Convenience overload which binds the given buffer's entire
|
||||||
|
contents, up to its limit() (as opposed to its capacity()).
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public static int sqlite3_bind_nio_buffer(
|
||||||
|
@NotNull sqlite3_stmt stmt, int ndx, @Nullable java.nio.ByteBuffer data
|
||||||
|
){
|
||||||
|
return sqlite3_bind_nio_buffer(stmt, ndx, data, 0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Binds the given object at the given index. If o is null then this behaves like
|
Binds the given object at the given index. If o is null then this behaves like
|
||||||
sqlite3_bind_null().
|
sqlite3_bind_null().
|
||||||
@ -465,13 +566,121 @@ public final class CApi {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private static native int sqlite3_blob_read(
|
private static native int sqlite3_blob_read(
|
||||||
@NotNull long ptrToBlob, @NotNull byte[] target, int iOffset
|
@NotNull long ptrToBlob, @NotNull byte[] target, int srcOffset
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
As per C's sqlite3_blob_read(), but writes its output to the
|
||||||
|
given byte array. Note that the final argument is the offset of
|
||||||
|
the source buffer, not the target array.
|
||||||
|
*/
|
||||||
public static int sqlite3_blob_read(
|
public static int sqlite3_blob_read(
|
||||||
@NotNull sqlite3_blob b, @NotNull byte[] target, int iOffset
|
@NotNull sqlite3_blob src, @NotNull byte[] target, int srcOffset
|
||||||
){
|
){
|
||||||
return sqlite3_blob_read(b.getNativePointer(), target, iOffset);
|
return sqlite3_blob_read(src.getNativePointer(), target, srcOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
An internal level of indirection.
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
private static native int sqlite3_blob_read_nio_buffer(
|
||||||
|
@NotNull long ptrToBlob, int srcOffset,
|
||||||
|
@NotNull java.nio.ByteBuffer tgt, int tgtOffset, int howMany
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Reads howMany bytes from offset srcOffset of src into position
|
||||||
|
tgtOffset of tgt.
|
||||||
|
|
||||||
|
Returns SQLITE_MISUSE if src is null, tgt is null, or
|
||||||
|
sqlite3_jni_supports_nio() returns false. Returns SQLITE_ERROR if
|
||||||
|
howMany or either offset are negative. If argument validation
|
||||||
|
succeeds, it returns the result of the underlying call to
|
||||||
|
sqlite3_blob_read() (0 on success).
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public static int sqlite3_blob_read_nio_buffer(
|
||||||
|
@NotNull sqlite3_blob src, int srcOffset,
|
||||||
|
@NotNull java.nio.ByteBuffer tgt, int tgtOffset, int howMany
|
||||||
|
){
|
||||||
|
return (JNI_SUPPORTS_NIO && src!=null && tgt!=null)
|
||||||
|
? sqlite3_blob_read_nio_buffer(
|
||||||
|
src.getNativePointer(), srcOffset, tgt, tgtOffset, howMany
|
||||||
|
)
|
||||||
|
: SQLITE_MISUSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Convenience overload which reads howMany bytes from position
|
||||||
|
srcOffset of src and returns the result as a new ByteBuffer.
|
||||||
|
|
||||||
|
srcOffset may not be negative. If howMany is negative, it is
|
||||||
|
treated as all bytes following srcOffset.
|
||||||
|
|
||||||
|
Returns null if sqlite3_jni_supports_nio(), any arguments are
|
||||||
|
invalid, if the number of bytes to read is 0 or is larger than
|
||||||
|
the src blob, or the underlying call to sqlite3_blob_read() fails
|
||||||
|
for any reason.
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public static java.nio.ByteBuffer sqlite3_blob_read_nio_buffer(
|
||||||
|
@NotNull sqlite3_blob src, int srcOffset, int howMany
|
||||||
|
){
|
||||||
|
if( !JNI_SUPPORTS_NIO || src==null ) return null;
|
||||||
|
else if( srcOffset<0 ) return null;
|
||||||
|
final int nB = sqlite3_blob_bytes(src);
|
||||||
|
if( srcOffset>=nB ) return null;
|
||||||
|
else if( howMany<0 ) howMany = nB - srcOffset;
|
||||||
|
if( srcOffset + howMany > nB ) return null;
|
||||||
|
final java.nio.ByteBuffer tgt =
|
||||||
|
java.nio.ByteBuffer.allocateDirect(howMany);
|
||||||
|
final int rc = sqlite3_blob_read_nio_buffer(
|
||||||
|
src.getNativePointer(), srcOffset, tgt, 0, howMany
|
||||||
|
);
|
||||||
|
return 0==rc ? tgt : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Overload alias for sqlite3_blob_read_nio_buffer().
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public static int sqlite3_blob_read(
|
||||||
|
@NotNull sqlite3_blob src, int srcOffset,
|
||||||
|
@NotNull java.nio.ByteBuffer tgt,
|
||||||
|
int tgtOffset, int howMany
|
||||||
|
){
|
||||||
|
return sqlite3_blob_read_nio_buffer(
|
||||||
|
src, srcOffset, tgt, tgtOffset, howMany
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Convenience overload which uses 0 for both src and tgt offsets
|
||||||
|
and reads a number of bytes equal to the smaller of
|
||||||
|
sqlite3_blob_bytes(src) and tgt.limit().
|
||||||
|
|
||||||
|
On success it sets tgt.limit() to the number of bytes read. On
|
||||||
|
error, tgt.limit() is not modified.
|
||||||
|
|
||||||
|
Returns 0 on success. Returns SQLITE_MISUSE is either argument is
|
||||||
|
null or sqlite3_jni_supports_nio() returns false. Else it returns
|
||||||
|
the result of the underlying call to sqlite3_blob_read().
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public static int sqlite3_blob_read(
|
||||||
|
@NotNull sqlite3_blob src,
|
||||||
|
@NotNull java.nio.ByteBuffer tgt
|
||||||
|
){
|
||||||
|
if(!JNI_SUPPORTS_NIO || src==null || tgt==null) return SQLITE_MISUSE;
|
||||||
|
final int nSrc = sqlite3_blob_bytes(src);
|
||||||
|
final int nTgt = tgt.limit();
|
||||||
|
final int nRead = nTgt<nSrc ? nTgt : nSrc;
|
||||||
|
final int rc = sqlite3_blob_read_nio_buffer(
|
||||||
|
src.getNativePointer(), 0, tgt, 0, nRead
|
||||||
|
);
|
||||||
|
if( 0==rc && nTgt!=nRead ) tgt.limit( nRead );
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native int sqlite3_blob_reopen(
|
private static native int sqlite3_blob_reopen(
|
||||||
@ -492,6 +701,84 @@ public final class CApi {
|
|||||||
return sqlite3_blob_write(b.getNativePointer(), bytes, iOffset);
|
return sqlite3_blob_write(b.getNativePointer(), bytes, iOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
An internal level of indirection.
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
private static native int sqlite3_blob_write_nio_buffer(
|
||||||
|
@NotNull long ptrToBlob, int tgtOffset,
|
||||||
|
@NotNull java.nio.ByteBuffer src,
|
||||||
|
int srcOffset, int howMany
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Writes howMany bytes of memory from offset srcOffset of the src
|
||||||
|
buffer at position tgtOffset of b.
|
||||||
|
|
||||||
|
If howMany is negative then it's equivalent to the number of
|
||||||
|
bytes remaining starting at srcOffset.
|
||||||
|
|
||||||
|
Returns SQLITE_MISUSE if tgt is null or sqlite3_jni_supports_nio()
|
||||||
|
returns false.
|
||||||
|
|
||||||
|
Returns SQLITE_MISUSE if src is null or
|
||||||
|
sqlite3_jni_supports_nio() returns false. Returns SQLITE_ERROR if
|
||||||
|
either offset is negative. If argument validation succeeds, it
|
||||||
|
returns the result of the underlying call to sqlite3_blob_read().
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public static int sqlite3_blob_write_nio_buffer(
|
||||||
|
@NotNull sqlite3_blob tgt, int tgtOffset,
|
||||||
|
@NotNull java.nio.ByteBuffer src,
|
||||||
|
int srcOffset, int howMany
|
||||||
|
){
|
||||||
|
return sqlite3_blob_write_nio_buffer(
|
||||||
|
tgt.getNativePointer(), tgtOffset, src, srcOffset, howMany
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Overload alias for sqlite3_blob_write_nio_buffer().
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public static int sqlite3_blob_write(
|
||||||
|
@NotNull sqlite3_blob tgt, int tgtOffset,
|
||||||
|
@NotNull java.nio.ByteBuffer src,
|
||||||
|
int srcOffset, int howMany
|
||||||
|
){
|
||||||
|
return sqlite3_blob_write_nio_buffer(
|
||||||
|
tgt.getNativePointer(), tgtOffset, src, srcOffset, howMany
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Convenience overload which writes all of src to the given offset
|
||||||
|
of b.
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public static int sqlite3_blob_write(
|
||||||
|
@NotNull sqlite3_blob tgt, int tgtOffset,
|
||||||
|
@NotNull java.nio.ByteBuffer src
|
||||||
|
){
|
||||||
|
return sqlite3_blob_write_nio_buffer(
|
||||||
|
tgt.getNativePointer(), tgtOffset, src, 0, -1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Convenience overload which writes all of src to offset 0
|
||||||
|
of tgt.
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public static int sqlite3_blob_write(
|
||||||
|
@NotNull sqlite3_blob tgt,
|
||||||
|
@NotNull java.nio.ByteBuffer src
|
||||||
|
){
|
||||||
|
return sqlite3_blob_write_nio_buffer(
|
||||||
|
tgt.getNativePointer(), 0, src, 0, -1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private static native int sqlite3_busy_handler(
|
private static native int sqlite3_busy_handler(
|
||||||
@NotNull long ptrToDb, @Nullable BusyHandlerCallback handler
|
@NotNull long ptrToDb, @Nullable BusyHandlerCallback handler
|
||||||
);
|
);
|
||||||
@ -569,6 +856,15 @@ public final class CApi {
|
|||||||
return sqlite3_column_count(stmt.getNativePointer());
|
return sqlite3_column_count(stmt.getNativePointer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static native String sqlite3_column_database_name(@NotNull long ptrToStmt, int ndx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Only available if built with SQLITE_ENABLE_COLUMN_METADATA.
|
||||||
|
*/
|
||||||
|
public static String sqlite3_column_database_name(@NotNull sqlite3_stmt stmt, int ndx){
|
||||||
|
return sqlite3_column_database_name(stmt.getNativePointer(), ndx);
|
||||||
|
}
|
||||||
|
|
||||||
private static native String sqlite3_column_decltype(@NotNull long ptrToStmt, int ndx);
|
private static native String sqlite3_column_decltype(@NotNull long ptrToStmt, int ndx);
|
||||||
|
|
||||||
public static String sqlite3_column_decltype(@NotNull sqlite3_stmt stmt, int ndx){
|
public static String sqlite3_column_decltype(@NotNull sqlite3_stmt stmt, int ndx){
|
||||||
@ -623,14 +919,16 @@ public final class CApi {
|
|||||||
return sqlite3_column_name(stmt.getNativePointer(), ndx);
|
return sqlite3_column_name(stmt.getNativePointer(), ndx);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native String sqlite3_column_database_name(@NotNull long ptrToStmt, int ndx);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Only available if built with SQLITE_ENABLE_COLUMN_METADATA.
|
A variant of sqlite3_column_blob() which returns the blob as a
|
||||||
|
ByteBuffer object. Returns null if its argument is null, if
|
||||||
|
sqlite3_jni_supports_nio() is false, or if sqlite3_column_blob()
|
||||||
|
would return null for the same inputs.
|
||||||
*/
|
*/
|
||||||
public static String sqlite3_column_database_name(@NotNull sqlite3_stmt stmt, int ndx){
|
@Experimental
|
||||||
return sqlite3_column_database_name(stmt.getNativePointer(), ndx);
|
public static native java.nio.ByteBuffer sqlite3_column_nio_buffer(
|
||||||
}
|
@NotNull sqlite3_stmt stmt, int ndx
|
||||||
|
);
|
||||||
|
|
||||||
private static native String sqlite3_column_origin_name(@NotNull long ptrToStmt, int ndx);
|
private static native String sqlite3_column_origin_name(@NotNull long ptrToStmt, int ndx);
|
||||||
|
|
||||||
@ -757,6 +1055,24 @@ public final class CApi {
|
|||||||
return sqlite3_complete( nulTerminateUtf8(sql) );
|
return sqlite3_complete( nulTerminateUtf8(sql) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Internal level of indirection for sqlite3_config(int).
|
||||||
|
*/
|
||||||
|
private static native int sqlite3_config__enable(int op);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Internal level of indirection for sqlite3_config(ConfigLogCallback).
|
||||||
|
*/
|
||||||
|
private static native int sqlite3_config__CONFIG_LOG(
|
||||||
|
@Nullable ConfigLogCallback logger
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Internal level of indirection for sqlite3_config(ConfigSqlLogCallback).
|
||||||
|
*/
|
||||||
|
private static native int sqlite3_config__SQLLOG(
|
||||||
|
@Nullable ConfigSqlLogCallback logger
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
<p>Works like in the C API with the exception that it only supports
|
<p>Works like in the C API with the exception that it only supports
|
||||||
@ -773,12 +1089,14 @@ public final class CApi {
|
|||||||
the rest of the library. This must not be called when any other
|
the rest of the library. This must not be called when any other
|
||||||
library APIs are being called.
|
library APIs are being called.
|
||||||
*/
|
*/
|
||||||
public static native int sqlite3_config(int op);
|
public static int sqlite3_config(int op){
|
||||||
|
return sqlite3_config__enable(op);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
If the native library was built with SQLITE_ENABLE_SQLLOG defined
|
If the native library was built with SQLITE_ENABLE_SQLLOG defined
|
||||||
then this acts as a proxy for C's
|
then this acts as a proxy for C's
|
||||||
sqlite3_config(SQLITE_ENABLE_SQLLOG,...). This sets or clears the
|
sqlite3_config(SQLITE_CONFIG_SQLLOG,...). This sets or clears the
|
||||||
logger. If installation of a logger fails, any previous logger is
|
logger. If installation of a logger fails, any previous logger is
|
||||||
retained.
|
retained.
|
||||||
|
|
||||||
@ -789,13 +1107,17 @@ public final class CApi {
|
|||||||
the rest of the library. This must not be called when any other
|
the rest of the library. This must not be called when any other
|
||||||
library APIs are being called.
|
library APIs are being called.
|
||||||
*/
|
*/
|
||||||
public static native int sqlite3_config( @Nullable ConfigSqllogCallback logger );
|
public static int sqlite3_config( @Nullable ConfigSqlLogCallback logger ){
|
||||||
|
return sqlite3_config__SQLLOG(logger);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The sqlite3_config() overload for handling the SQLITE_CONFIG_LOG
|
The sqlite3_config() overload for handling the SQLITE_CONFIG_LOG
|
||||||
option.
|
option.
|
||||||
*/
|
*/
|
||||||
public static native int sqlite3_config( @Nullable ConfigLogCallback logger );
|
public static int sqlite3_config( @Nullable ConfigLogCallback logger ){
|
||||||
|
return sqlite3_config__CONFIG_LOG(logger);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Unlike the C API, this returns null if its argument is
|
Unlike the C API, this returns null if its argument is
|
||||||
@ -1196,9 +1518,13 @@ public final class CApi {
|
|||||||
array. It loops over the input bytes looking for
|
array. It loops over the input bytes looking for
|
||||||
statements. Each one it finds is passed to p.call(), passing
|
statements. Each one it finds is passed to p.call(), passing
|
||||||
ownership of it to that function. If p.call() returns 0, looping
|
ownership of it to that function. If p.call() returns 0, looping
|
||||||
continues, else the loop stops.
|
continues, else the loop stops and p.call()'s result code is
|
||||||
|
returned. If preparation of any given segment fails, looping
|
||||||
|
stops and that result code is returned.
|
||||||
|
|
||||||
<p>If p.call() throws, the exception is propagated.
|
<p>If p.call() throws, the exception is converted to a db-level
|
||||||
|
error and a non-0 code is returned, in order to retain the
|
||||||
|
C-style error semantics of the API.
|
||||||
|
|
||||||
<p>How each statement is handled, including whether it is finalized
|
<p>How each statement is handled, including whether it is finalized
|
||||||
or not, is up to the callback object. e.g. the callback might
|
or not, is up to the callback object. e.g. the callback might
|
||||||
@ -1230,7 +1556,11 @@ public final class CApi {
|
|||||||
// empty statement (whitespace/comments)
|
// empty statement (whitespace/comments)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
rc = p.call(stmt);
|
try{
|
||||||
|
rc = p.call(stmt);
|
||||||
|
}catch(Exception e){
|
||||||
|
rc = sqlite3_jni_db_error( db, SQLITE_ERROR, e );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -1341,6 +1671,15 @@ public final class CApi {
|
|||||||
If the C API was built with SQLITE_ENABLE_PREUPDATE_HOOK defined,
|
If the C API was built with SQLITE_ENABLE_PREUPDATE_HOOK defined,
|
||||||
this acts as a proxy for C's sqlite3_preupdate_new(), else it
|
this acts as a proxy for C's sqlite3_preupdate_new(), else it
|
||||||
returns SQLITE_MISUSE with no side effects.
|
returns SQLITE_MISUSE with no side effects.
|
||||||
|
|
||||||
|
WARNING: client code _must not_ hold a reference to the returned
|
||||||
|
sqlite3_value object beyond the scope of the preupdate hook in
|
||||||
|
which this function is called. Doing so will leave the client
|
||||||
|
holding a stale pointer, the address of which could point to
|
||||||
|
anything at all after the pre-update hook is complete. This API
|
||||||
|
has no way to record such objects and clear/invalidate them at
|
||||||
|
the end of a pre-update hook. We "could" add infrastructure to do
|
||||||
|
so, but would require significant levels of bookkeeping.
|
||||||
*/
|
*/
|
||||||
public static int sqlite3_preupdate_new(@NotNull sqlite3 db, int col,
|
public static int sqlite3_preupdate_new(@NotNull sqlite3 db, int col,
|
||||||
@NotNull OutputPointer.sqlite3_value out){
|
@NotNull OutputPointer.sqlite3_value out){
|
||||||
@ -1364,6 +1703,9 @@ public final class CApi {
|
|||||||
If the C API was built with SQLITE_ENABLE_PREUPDATE_HOOK defined,
|
If the C API was built with SQLITE_ENABLE_PREUPDATE_HOOK defined,
|
||||||
this acts as a proxy for C's sqlite3_preupdate_old(), else it
|
this acts as a proxy for C's sqlite3_preupdate_old(), else it
|
||||||
returns SQLITE_MISUSE with no side effects.
|
returns SQLITE_MISUSE with no side effects.
|
||||||
|
|
||||||
|
WARNING: see warning in sqlite3_preupdate_new() regarding the
|
||||||
|
potential for stale sqlite3_value handles.
|
||||||
*/
|
*/
|
||||||
public static int sqlite3_preupdate_old(@NotNull sqlite3 db, int col,
|
public static int sqlite3_preupdate_old(@NotNull sqlite3 db, int col,
|
||||||
@NotNull OutputPointer.sqlite3_value out){
|
@NotNull OutputPointer.sqlite3_value out){
|
||||||
@ -1487,6 +1829,41 @@ public final class CApi {
|
|||||||
@NotNull sqlite3_context cx, @NotNull Object o
|
@NotNull sqlite3_context cx, @NotNull Object o
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Similar to sqlite3_bind_nio_buffer(), this works like
|
||||||
|
sqlite3_result_blob() but accepts a java.nio.ByteBuffer as its
|
||||||
|
input source. See sqlite3_bind_nio_buffer() for the semantics of
|
||||||
|
the second and subsequent arguments.
|
||||||
|
|
||||||
|
If cx is null then this function will silently fail. If
|
||||||
|
sqlite3_jni_supports_nio() returns false or iBegin is negative,
|
||||||
|
an error result is set. If (begin+n) extends beyond the end of
|
||||||
|
the buffer, it is silently truncated to fit.
|
||||||
|
|
||||||
|
If any of the following apply, this function behaves like
|
||||||
|
sqlite3_result_null(): the blob is null, the resulting slice of
|
||||||
|
the blob is empty.
|
||||||
|
|
||||||
|
If the resulting slice of the buffer exceeds SQLITE_LIMIT_LENGTH
|
||||||
|
then this function behaves like sqlite3_result_error_toobig().
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public static native void sqlite3_result_nio_buffer(
|
||||||
|
@NotNull sqlite3_context cx, @Nullable java.nio.ByteBuffer blob,
|
||||||
|
int begin, int n
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Convenience overload which uses the whole input object
|
||||||
|
as the result blob content.
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public static void sqlite3_result_nio_buffer(
|
||||||
|
@NotNull sqlite3_context cx, @Nullable java.nio.ByteBuffer blob
|
||||||
|
){
|
||||||
|
sqlite3_result_nio_buffer(cx, blob, 0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
public static native void sqlite3_result_null(
|
public static native void sqlite3_result_null(
|
||||||
@NotNull sqlite3_context cx
|
@NotNull sqlite3_context cx
|
||||||
);
|
);
|
||||||
@ -1581,6 +1958,29 @@ public final class CApi {
|
|||||||
sqlite3_result_blob(cx, blob, (int)(null==blob ? 0 : blob.length));
|
sqlite3_result_blob(cx, blob, (int)(null==blob ? 0 : blob.length));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Convenience overload which behaves like
|
||||||
|
sqlite3_result_nio_buffer().
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public static void sqlite3_result_blob(
|
||||||
|
@NotNull sqlite3_context cx, @Nullable java.nio.ByteBuffer blob,
|
||||||
|
int begin, int n
|
||||||
|
){
|
||||||
|
sqlite3_result_nio_buffer(cx, blob, begin, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Convenience overload which behaves like the two-argument overload of
|
||||||
|
sqlite3_result_nio_buffer().
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public static void sqlite3_result_blob(
|
||||||
|
@NotNull sqlite3_context cx, @Nullable java.nio.ByteBuffer blob
|
||||||
|
){
|
||||||
|
sqlite3_result_nio_buffer(cx, blob);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Binds the given text using C's sqlite3_result_blob64() unless:
|
Binds the given text using C's sqlite3_result_blob64() unless:
|
||||||
|
|
||||||
@ -1638,7 +2038,8 @@ public final class CApi {
|
|||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
|
|
||||||
<li>text is null: translates to a call to sqlite3_result_null()</li>
|
<li>text is null: translates to a call to {@link
|
||||||
|
#sqlite3_result_null}</li>
|
||||||
|
|
||||||
<li>text is too large: translates to a call to
|
<li>text is too large: translates to a call to
|
||||||
{@link #sqlite3_result_error_toobig}</li>
|
{@link #sqlite3_result_error_toobig}</li>
|
||||||
@ -1979,6 +2380,17 @@ public final class CApi {
|
|||||||
return type.isInstance(o) ? (T)o : null;
|
return type.isInstance(o) ? (T)o : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
A variant of sqlite3_column_blob() which returns the blob as a
|
||||||
|
ByteBuffer object. Returns null if its argument is null, if
|
||||||
|
sqlite3_jni_supports_nio() is false, or if sqlite3_value_blob()
|
||||||
|
would return null for the same input.
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public static native java.nio.ByteBuffer sqlite3_value_nio_buffer(
|
||||||
|
@NotNull sqlite3_value v
|
||||||
|
);
|
||||||
|
|
||||||
private static native int sqlite3_value_nochange(@NotNull long ptrToValue);
|
private static native int sqlite3_value_nochange(@NotNull long ptrToValue);
|
||||||
|
|
||||||
public static int sqlite3_value_nochange(@NotNull sqlite3_value v){
|
public static int sqlite3_value_nochange(@NotNull sqlite3_value v){
|
||||||
@ -2478,8 +2890,8 @@ public final class CApi {
|
|||||||
public static final int SQLITE_FAIL = 3;
|
public static final int SQLITE_FAIL = 3;
|
||||||
public static final int SQLITE_REPLACE = 5;
|
public static final int SQLITE_REPLACE = 5;
|
||||||
static {
|
static {
|
||||||
// This MUST come after the SQLITE_MAX_... values or else
|
|
||||||
// attempting to modify them silently fails.
|
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
/* Must come after static init(). */
|
||||||
|
private static final boolean JNI_SUPPORTS_NIO = sqlite3_jni_supports_nio();
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,10 @@ package org.sqlite.jni.capi;
|
|||||||
/**
|
/**
|
||||||
A callback for use with sqlite3_config().
|
A callback for use with sqlite3_config().
|
||||||
*/
|
*/
|
||||||
public interface ConfigSqllogCallback {
|
public interface ConfigSqlLogCallback {
|
||||||
/**
|
/**
|
||||||
Must function as described for a C-level callback for
|
Must function as described for a C-level callback for
|
||||||
{@link CApi#sqlite3_config(ConfigSqllogCallback)}, with the slight signature change.
|
{@link CApi#sqlite3_config(ConfigSqlLogCallback)}, with the slight signature change.
|
||||||
*/
|
*/
|
||||||
void call(sqlite3 db, String msg, int msgType );
|
void call(sqlite3 db, String msg, int msgType );
|
||||||
}
|
}
|
@ -228,4 +228,26 @@ public final class OutputPointer {
|
|||||||
/** Sets the current value. */
|
/** Sets the current value. */
|
||||||
public final void set(byte[] v){value = v;}
|
public final void set(byte[] v){value = v;}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Output pointer for use with native routines which return
|
||||||
|
blobs via java.nio.ByteBuffer.
|
||||||
|
|
||||||
|
See {@link org.sqlite.jni.capi.CApi#sqlite3_jni_supports_nio}
|
||||||
|
*/
|
||||||
|
public static final class ByteBuffer {
|
||||||
|
/**
|
||||||
|
This is public for ease of use. Accessors are provided for
|
||||||
|
consistency with the higher-level types.
|
||||||
|
*/
|
||||||
|
public java.nio.ByteBuffer value;
|
||||||
|
/** Initializes with the value null. */
|
||||||
|
public ByteBuffer(){this(null);}
|
||||||
|
/** Initializes with the value v. */
|
||||||
|
public ByteBuffer(java.nio.ByteBuffer v){value = v;}
|
||||||
|
/** Returns the current value. */
|
||||||
|
public final java.nio.ByteBuffer get(){return value;}
|
||||||
|
/** Sets the current value. */
|
||||||
|
public final void set(java.nio.ByteBuffer v){value = v;}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,10 @@ public interface PrepareMultiCallback extends CallbackProxy {
|
|||||||
sqlite3_prepare_multi() will _not_ finalize st - it is up
|
sqlite3_prepare_multi() will _not_ finalize st - it is up
|
||||||
to the call() implementation how st is handled.
|
to the call() implementation how st is handled.
|
||||||
|
|
||||||
Must return 0 on success or an SQLITE_... code on error.
|
Must return 0 on success or an SQLITE_... code on error. If it
|
||||||
|
throws, sqlite3_prepare_multi() will transform the exception into
|
||||||
|
a db-level error in order to retain the C-style error semantics
|
||||||
|
of the API.
|
||||||
|
|
||||||
See the {@link Finalize} class for a wrapper which finalizes the
|
See the {@link Finalize} class for a wrapper which finalizes the
|
||||||
statement after calling a proxy PrepareMultiCallback.
|
statement after calling a proxy PrepareMultiCallback.
|
||||||
@ -37,7 +40,7 @@ public interface PrepareMultiCallback extends CallbackProxy {
|
|||||||
any sqlite3_stmt passed to its callback.
|
any sqlite3_stmt passed to its callback.
|
||||||
*/
|
*/
|
||||||
public static final class Finalize implements PrepareMultiCallback {
|
public static final class Finalize implements PrepareMultiCallback {
|
||||||
private PrepareMultiCallback p;
|
private final PrepareMultiCallback p;
|
||||||
/**
|
/**
|
||||||
p is the proxy to call() when this.call() is called.
|
p is the proxy to call() when this.call() is called.
|
||||||
*/
|
*/
|
||||||
|
@ -38,6 +38,14 @@ import java.util.concurrent.Future;
|
|||||||
@java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD})
|
@java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD})
|
||||||
@interface SingleThreadOnly{}
|
@interface SingleThreadOnly{}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Annotation for Tester1 tests which must only be run if
|
||||||
|
sqlite3_jni_supports_nio() is true.
|
||||||
|
*/
|
||||||
|
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||||
|
@java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD})
|
||||||
|
@interface RequiresJniNio{}
|
||||||
|
|
||||||
public class Tester1 implements Runnable {
|
public class Tester1 implements Runnable {
|
||||||
//! True when running in multi-threaded mode.
|
//! True when running in multi-threaded mode.
|
||||||
private static boolean mtMode = false;
|
private static boolean mtMode = false;
|
||||||
@ -486,6 +494,7 @@ public class Tester1 implements Runnable {
|
|||||||
stmt = prepare(db, "SELECT a FROM t ORDER BY a DESC;");
|
stmt = prepare(db, "SELECT a FROM t ORDER BY a DESC;");
|
||||||
StringBuilder sbuf = new StringBuilder();
|
StringBuilder sbuf = new StringBuilder();
|
||||||
n = 0;
|
n = 0;
|
||||||
|
final boolean tryNio = sqlite3_jni_supports_nio();
|
||||||
while( SQLITE_ROW == sqlite3_step(stmt) ){
|
while( SQLITE_ROW == sqlite3_step(stmt) ){
|
||||||
final sqlite3_value sv = sqlite3_value_dup(sqlite3_column_value(stmt,0));
|
final sqlite3_value sv = sqlite3_value_dup(sqlite3_column_value(stmt,0));
|
||||||
final String txt = sqlite3_column_text16(stmt, 0);
|
final String txt = sqlite3_column_text16(stmt, 0);
|
||||||
@ -500,6 +509,15 @@ public class Tester1 implements Runnable {
|
|||||||
StandardCharsets.UTF_8)) );
|
StandardCharsets.UTF_8)) );
|
||||||
affirm( txt.length() == sqlite3_value_bytes16(sv)/2 );
|
affirm( txt.length() == sqlite3_value_bytes16(sv)/2 );
|
||||||
affirm( txt.equals(sqlite3_value_text16(sv)) );
|
affirm( txt.equals(sqlite3_value_text16(sv)) );
|
||||||
|
if( tryNio ){
|
||||||
|
java.nio.ByteBuffer bu = sqlite3_value_nio_buffer(sv);
|
||||||
|
byte ba[] = sqlite3_value_blob(sv);
|
||||||
|
affirm( ba.length == bu.capacity() );
|
||||||
|
int i = 0;
|
||||||
|
for( byte b : ba ){
|
||||||
|
affirm( b == bu.get(i++) );
|
||||||
|
}
|
||||||
|
}
|
||||||
sqlite3_value_free(sv);
|
sqlite3_value_free(sv);
|
||||||
++n;
|
++n;
|
||||||
}
|
}
|
||||||
@ -557,6 +575,79 @@ public class Tester1 implements Runnable {
|
|||||||
sqlite3_close_v2(db);
|
sqlite3_close_v2(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresJniNio
|
||||||
|
private void testBindByteBuffer(){
|
||||||
|
/* TODO: these tests need to be much more extensive to check the
|
||||||
|
begin/end range handling. */
|
||||||
|
|
||||||
|
java.nio.ByteBuffer zeroCheck =
|
||||||
|
java.nio.ByteBuffer.allocateDirect(0);
|
||||||
|
affirm( null != zeroCheck );
|
||||||
|
zeroCheck = null;
|
||||||
|
sqlite3 db = createNewDb();
|
||||||
|
execSql(db, "CREATE TABLE t(a)");
|
||||||
|
|
||||||
|
final java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocateDirect(10);
|
||||||
|
buf.put((byte)0x31)/*note that we'll skip this one*/
|
||||||
|
.put((byte)0x32)
|
||||||
|
.put((byte)0x33)
|
||||||
|
.put((byte)0x34)
|
||||||
|
.put((byte)0x35)/*we'll skip this one too*/;
|
||||||
|
|
||||||
|
final int expectTotal = buf.get(1) + buf.get(2) + buf.get(3);
|
||||||
|
sqlite3_stmt stmt = prepare(db, "INSERT INTO t(a) VALUES(?);");
|
||||||
|
affirm( SQLITE_ERROR == sqlite3_bind_blob(stmt, 1, buf, -1, 0),
|
||||||
|
"Buffer offset may not be negative." );
|
||||||
|
affirm( 0 == sqlite3_bind_blob(stmt, 1, buf, 1, 3) );
|
||||||
|
affirm( SQLITE_DONE == sqlite3_step(stmt) );
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
stmt = prepare(db, "SELECT a FROM t;");
|
||||||
|
int total = 0;
|
||||||
|
affirm( SQLITE_ROW == sqlite3_step(stmt) );
|
||||||
|
byte blob[] = sqlite3_column_blob(stmt, 0);
|
||||||
|
java.nio.ByteBuffer nioBlob =
|
||||||
|
sqlite3_column_nio_buffer(stmt, 0);
|
||||||
|
affirm(3 == blob.length);
|
||||||
|
affirm(blob.length == nioBlob.capacity());
|
||||||
|
affirm(blob.length == nioBlob.limit());
|
||||||
|
int i = 0;
|
||||||
|
for(byte b : blob){
|
||||||
|
affirm( i<=3 );
|
||||||
|
affirm(b == buf.get(1 + i));
|
||||||
|
affirm(b == nioBlob.get(i));
|
||||||
|
++i;
|
||||||
|
total += b;
|
||||||
|
}
|
||||||
|
affirm( SQLITE_DONE == sqlite3_step(stmt) );
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
affirm(total == expectTotal);
|
||||||
|
|
||||||
|
SQLFunction func =
|
||||||
|
new ScalarFunction(){
|
||||||
|
public void xFunc(sqlite3_context cx, sqlite3_value[] args){
|
||||||
|
sqlite3_result_blob(cx, buf, 1, 3);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
affirm( 0 == sqlite3_create_function(db, "myfunc", -1, SQLITE_UTF8, func) );
|
||||||
|
stmt = prepare(db, "SELECT myfunc()");
|
||||||
|
affirm( SQLITE_ROW == sqlite3_step(stmt) );
|
||||||
|
blob = sqlite3_column_blob(stmt, 0);
|
||||||
|
affirm(3 == blob.length);
|
||||||
|
i = 0;
|
||||||
|
total = 0;
|
||||||
|
for(byte b : blob){
|
||||||
|
affirm( i<=3 );
|
||||||
|
affirm(b == buf.get(1 + i++));
|
||||||
|
total += b;
|
||||||
|
}
|
||||||
|
affirm( SQLITE_DONE == sqlite3_step(stmt) );
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
affirm(total == expectTotal);
|
||||||
|
|
||||||
|
sqlite3_close_v2(db);
|
||||||
|
}
|
||||||
|
|
||||||
private void testSql(){
|
private void testSql(){
|
||||||
sqlite3 db = createNewDb();
|
sqlite3 db = createNewDb();
|
||||||
sqlite3_stmt stmt = prepare(db, "SELECT 1");
|
sqlite3_stmt stmt = prepare(db, "SELECT 1");
|
||||||
@ -837,15 +928,28 @@ public class Tester1 implements Runnable {
|
|||||||
// To confirm that xFinal() is called with no aggregate state
|
// To confirm that xFinal() is called with no aggregate state
|
||||||
// when the corresponding result set is empty.
|
// when the corresponding result set is empty.
|
||||||
new ValueHolder<>(false);
|
new ValueHolder<>(false);
|
||||||
|
final ValueHolder<sqlite3_value[]> neverEverDoThisInClientCode = new ValueHolder<>(null);
|
||||||
|
final ValueHolder<sqlite3_context> neverEverDoThisInClientCode2 = new ValueHolder<>(null);
|
||||||
SQLFunction func = new AggregateFunction<Integer>(){
|
SQLFunction func = new AggregateFunction<Integer>(){
|
||||||
@Override
|
@Override
|
||||||
public void xStep(sqlite3_context cx, sqlite3_value[] args){
|
public void xStep(sqlite3_context cx, sqlite3_value[] args){
|
||||||
|
if( null==neverEverDoThisInClientCode.value ){
|
||||||
|
/* !!!NEVER!!! hold a reference to an sqlite3_value or
|
||||||
|
sqlite3_context object like this in client code! They
|
||||||
|
are ONLY legal for the duration of their single
|
||||||
|
call. We do it here ONLY to test that the defenses
|
||||||
|
against clients doing this are working. */
|
||||||
|
neverEverDoThisInClientCode.value = args;
|
||||||
|
}
|
||||||
final ValueHolder<Integer> agg = this.getAggregateState(cx, 0);
|
final ValueHolder<Integer> agg = this.getAggregateState(cx, 0);
|
||||||
agg.value += sqlite3_value_int(args[0]);
|
agg.value += sqlite3_value_int(args[0]);
|
||||||
affirm( agg == this.getAggregateState(cx, 0) );
|
affirm( agg == this.getAggregateState(cx, 0) );
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void xFinal(sqlite3_context cx){
|
public void xFinal(sqlite3_context cx){
|
||||||
|
if( null==neverEverDoThisInClientCode2.value ){
|
||||||
|
neverEverDoThisInClientCode2.value = cx;
|
||||||
|
}
|
||||||
final Integer v = this.takeAggregateState(cx);
|
final Integer v = this.takeAggregateState(cx);
|
||||||
if(null == v){
|
if(null == v){
|
||||||
xFinalNull.value = true;
|
xFinalNull.value = true;
|
||||||
@ -870,6 +974,10 @@ public class Tester1 implements Runnable {
|
|||||||
}
|
}
|
||||||
affirm( 1==n );
|
affirm( 1==n );
|
||||||
affirm(!xFinalNull.value);
|
affirm(!xFinalNull.value);
|
||||||
|
affirm( null!=neverEverDoThisInClientCode.value );
|
||||||
|
affirm( null!=neverEverDoThisInClientCode2.value );
|
||||||
|
affirm( 0<neverEverDoThisInClientCode.value.length );
|
||||||
|
affirm( 0==neverEverDoThisInClientCode2.value.getNativePointer() );
|
||||||
sqlite3_reset(stmt);
|
sqlite3_reset(stmt);
|
||||||
affirm( 1==sqlite3_stmt_status(stmt, SQLITE_STMTSTATUS_RUN, false) );
|
affirm( 1==sqlite3_stmt_status(stmt, SQLITE_STMTSTATUS_RUN, false) );
|
||||||
// Ensure that the accumulator is reset on subsequent calls...
|
// Ensure that the accumulator is reset on subsequent calls...
|
||||||
@ -1652,6 +1760,86 @@ public class Tester1 implements Runnable {
|
|||||||
affirm( 100==tgt[0] && 101==tgt[1] && 102==tgt[2], "DEF" );
|
affirm( 100==tgt[0] && 101==tgt[1] && 102==tgt[2], "DEF" );
|
||||||
rc = sqlite3_blob_close(b);
|
rc = sqlite3_blob_close(b);
|
||||||
affirm( 0==rc );
|
affirm( 0==rc );
|
||||||
|
|
||||||
|
if( !sqlite3_jni_supports_nio() ){
|
||||||
|
outln("WARNING: skipping tests for ByteBuffer-using sqlite3_blob APIs ",
|
||||||
|
"because this platform lacks that support.");
|
||||||
|
sqlite3_close_v2(db);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Sanity checks for the java.nio.ByteBuffer-taking overloads of
|
||||||
|
sqlite3_blob_read/write(). */
|
||||||
|
execSql(db, "UPDATE t SET a=zeroblob(10)");
|
||||||
|
b = sqlite3_blob_open(db, "main", "t", "a", 1, 1);
|
||||||
|
affirm( null!=b );
|
||||||
|
java.nio.ByteBuffer bb = java.nio.ByteBuffer.allocateDirect(10);
|
||||||
|
for( byte i = 0; i < 10; ++i ){
|
||||||
|
bb.put((int)i, (byte)(48+i & 0xff));
|
||||||
|
}
|
||||||
|
rc = sqlite3_blob_write(b, 1, bb, 1, 10);
|
||||||
|
affirm( rc==SQLITE_ERROR, "b length < (srcOffset + bb length)" );
|
||||||
|
rc = sqlite3_blob_write(b, -1, bb);
|
||||||
|
affirm( rc==SQLITE_ERROR, "Target offset may not be negative" );
|
||||||
|
rc = sqlite3_blob_write(b, 0, bb, -1, -1);
|
||||||
|
affirm( rc==SQLITE_ERROR, "Source offset may not be negative" );
|
||||||
|
rc = sqlite3_blob_write(b, 1, bb, 1, 8);
|
||||||
|
affirm( rc==0 );
|
||||||
|
// b's contents: 0 49 50 51 52 53 54 55 56 0
|
||||||
|
// ascii: 0 '1' '2' '3' '4' '5' '6' '7' '8' 0
|
||||||
|
byte br[] = new byte[10];
|
||||||
|
java.nio.ByteBuffer bbr =
|
||||||
|
java.nio.ByteBuffer.allocateDirect(bb.limit());
|
||||||
|
rc = sqlite3_blob_read( b, br, 0 );
|
||||||
|
affirm( rc==0 );
|
||||||
|
rc = sqlite3_blob_read( b, bbr );
|
||||||
|
affirm( rc==0 );
|
||||||
|
java.nio.ByteBuffer bbr2 = sqlite3_blob_read_nio_buffer(b, 0, 12);
|
||||||
|
affirm( null==bbr2, "Read size is too big");
|
||||||
|
bbr2 = sqlite3_blob_read_nio_buffer(b, -1, 3);
|
||||||
|
affirm( null==bbr2, "Source offset is negative");
|
||||||
|
bbr2 = sqlite3_blob_read_nio_buffer(b, 5, 6);
|
||||||
|
affirm( null==bbr2, "Read pos+size is too big");
|
||||||
|
bbr2 = sqlite3_blob_read_nio_buffer(b, 4, 7);
|
||||||
|
affirm( null==bbr2, "Read pos+size is too big");
|
||||||
|
bbr2 = sqlite3_blob_read_nio_buffer(b, 4, 6);
|
||||||
|
affirm( null!=bbr2 );
|
||||||
|
java.nio.ByteBuffer bbr3 =
|
||||||
|
java.nio.ByteBuffer.allocateDirect(2 * bb.limit());
|
||||||
|
java.nio.ByteBuffer bbr4 =
|
||||||
|
java.nio.ByteBuffer.allocateDirect(5);
|
||||||
|
rc = sqlite3_blob_read( b, bbr3 );
|
||||||
|
affirm( rc==0 );
|
||||||
|
rc = sqlite3_blob_read( b, bbr4 );
|
||||||
|
affirm( rc==0 );
|
||||||
|
affirm( sqlite3_blob_bytes(b)==bbr3.limit() );
|
||||||
|
affirm( 5==bbr4.limit() );
|
||||||
|
sqlite3_blob_close(b);
|
||||||
|
affirm( 0==br[0] );
|
||||||
|
affirm( 0==br[9] );
|
||||||
|
affirm( 0==bbr.get(0) );
|
||||||
|
affirm( 0==bbr.get(9) );
|
||||||
|
affirm( bbr2.limit() == 6 );
|
||||||
|
affirm( 0==bbr3.get(0) );
|
||||||
|
{
|
||||||
|
Exception ex = null;
|
||||||
|
try{ bbr3.get(11); }
|
||||||
|
catch(Exception e){ex = e;}
|
||||||
|
affirm( ex instanceof IndexOutOfBoundsException,
|
||||||
|
"bbr3.limit() was reset by read()" );
|
||||||
|
ex = null;
|
||||||
|
}
|
||||||
|
affirm( 0==bbr4.get(0) );
|
||||||
|
for( int i = 1; i < 9; ++i ){
|
||||||
|
affirm( br[i] == 48 + i );
|
||||||
|
affirm( br[i] == bbr.get(i) );
|
||||||
|
affirm( br[i] == bbr3.get(i) );
|
||||||
|
if( i>3 ){
|
||||||
|
affirm( br[i] == bbr2.get(i-4) );
|
||||||
|
}
|
||||||
|
if( i < bbr4.limit() ){
|
||||||
|
affirm( br[i] == bbr4.get(i) );
|
||||||
|
}
|
||||||
|
}
|
||||||
sqlite3_close_v2(db);
|
sqlite3_close_v2(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1664,9 +1852,13 @@ public class Tester1 implements Runnable {
|
|||||||
};
|
};
|
||||||
final List<sqlite3_stmt> liStmt = new ArrayList<sqlite3_stmt>();
|
final List<sqlite3_stmt> liStmt = new ArrayList<sqlite3_stmt>();
|
||||||
final PrepareMultiCallback proxy = new PrepareMultiCallback.StepAll();
|
final PrepareMultiCallback proxy = new PrepareMultiCallback.StepAll();
|
||||||
|
final ValueHolder<String> toss = new ValueHolder<>(null);
|
||||||
PrepareMultiCallback m = new PrepareMultiCallback() {
|
PrepareMultiCallback m = new PrepareMultiCallback() {
|
||||||
@Override public int call(sqlite3_stmt st){
|
@Override public int call(sqlite3_stmt st){
|
||||||
liStmt.add(st);
|
liStmt.add(st);
|
||||||
|
if( null!=toss.value ){
|
||||||
|
throw new RuntimeException(toss.value);
|
||||||
|
}
|
||||||
return proxy.call(st);
|
return proxy.call(st);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1676,6 +1868,10 @@ public class Tester1 implements Runnable {
|
|||||||
for( sqlite3_stmt st : liStmt ){
|
for( sqlite3_stmt st : liStmt ){
|
||||||
sqlite3_finalize(st);
|
sqlite3_finalize(st);
|
||||||
}
|
}
|
||||||
|
toss.value = "This is an exception.";
|
||||||
|
rc = sqlite3_prepare_multi(db, "SELECT 1", m);
|
||||||
|
affirm( SQLITE_ERROR==rc );
|
||||||
|
affirm( sqlite3_errmsg(db).indexOf(toss.value)>0 );
|
||||||
sqlite3_close_v2(db);
|
sqlite3_close_v2(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1828,7 +2024,7 @@ public class Tester1 implements Runnable {
|
|||||||
|
|
||||||
if( sqlLog ){
|
if( sqlLog ){
|
||||||
if( sqlite3_compileoption_used("ENABLE_SQLLOG") ){
|
if( sqlite3_compileoption_used("ENABLE_SQLLOG") ){
|
||||||
final ConfigSqllogCallback log = new ConfigSqllogCallback() {
|
final ConfigSqlLogCallback log = new ConfigSqlLogCallback() {
|
||||||
@Override public void call(sqlite3 db, String msg, int op){
|
@Override public void call(sqlite3 db, String msg, int op){
|
||||||
switch(op){
|
switch(op){
|
||||||
case 0: outln("Opening db: ",db); break;
|
case 0: outln("Opening db: ",db); break;
|
||||||
@ -1839,7 +2035,7 @@ public class Tester1 implements Runnable {
|
|||||||
};
|
};
|
||||||
int rc = sqlite3_config( log );
|
int rc = sqlite3_config( log );
|
||||||
affirm( 0==rc );
|
affirm( 0==rc );
|
||||||
rc = sqlite3_config( (ConfigSqllogCallback)null );
|
rc = sqlite3_config( (ConfigSqlLogCallback)null );
|
||||||
affirm( 0==rc );
|
affirm( 0==rc );
|
||||||
rc = sqlite3_config( log );
|
rc = sqlite3_config( log );
|
||||||
affirm( 0==rc );
|
affirm( 0==rc );
|
||||||
@ -1877,18 +2073,20 @@ public class Tester1 implements Runnable {
|
|||||||
if( forceFail ){
|
if( forceFail ){
|
||||||
testMethods.add(m);
|
testMethods.add(m);
|
||||||
}
|
}
|
||||||
|
}else if( m.isAnnotationPresent( RequiresJniNio.class )
|
||||||
|
&& !sqlite3_jni_supports_nio() ){
|
||||||
|
outln("Skipping test for lack of JNI java.nio.ByteBuffer support: ",
|
||||||
|
name,"()\n");
|
||||||
|
++nSkipped;
|
||||||
}else if( !m.isAnnotationPresent( ManualTest.class ) ){
|
}else if( !m.isAnnotationPresent( ManualTest.class ) ){
|
||||||
if( nThread>1 && m.isAnnotationPresent( SingleThreadOnly.class ) ){
|
if( nThread>1 && m.isAnnotationPresent( SingleThreadOnly.class ) ){
|
||||||
if( 0==nSkipped++ ){
|
out("Skipping test in multi-thread mode: ",name,"()\n");
|
||||||
out("Skipping tests in multi-thread mode:");
|
++nSkipped;
|
||||||
}
|
|
||||||
out(" "+name+"()");
|
|
||||||
}else if( name.startsWith("test") ){
|
}else if( name.startsWith("test") ){
|
||||||
testMethods.add(m);
|
testMethods.add(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( nSkipped>0 ) out("\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final long timeStart = System.currentTimeMillis();
|
final long timeStart = System.currentTimeMillis();
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
** May you share freely, never taking more than you give.
|
** May you share freely, never taking more than you give.
|
||||||
**
|
**
|
||||||
*************************************************************************
|
*************************************************************************
|
||||||
** This file holds utility code for the sqlite3 JNI bindings.
|
** This file contains the ValueHolder utility class for the sqlite3
|
||||||
|
** JNI bindings.
|
||||||
*/
|
*/
|
||||||
package org.sqlite.jni.capi;
|
package org.sqlite.jni.capi;
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ import org.sqlite.jni.capi.sqlite3_stmt;
|
|||||||
import org.sqlite.jni.capi.sqlite3_backup;
|
import org.sqlite.jni.capi.sqlite3_backup;
|
||||||
import org.sqlite.jni.capi.sqlite3_blob;
|
import org.sqlite.jni.capi.sqlite3_blob;
|
||||||
import org.sqlite.jni.capi.OutputPointer;
|
import org.sqlite.jni.capi.OutputPointer;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This class represents a database connection, analog to the C-side
|
This class represents a database connection, analog to the C-side
|
||||||
@ -29,7 +30,10 @@ import org.sqlite.jni.capi.OutputPointer;
|
|||||||
*/
|
*/
|
||||||
public final class Sqlite implements AutoCloseable {
|
public final class Sqlite implements AutoCloseable {
|
||||||
private sqlite3 db;
|
private sqlite3 db;
|
||||||
|
private static final boolean JNI_SUPPORTS_NIO =
|
||||||
|
CApi.sqlite3_jni_supports_nio();
|
||||||
|
|
||||||
|
// Result codes
|
||||||
public static final int OK = CApi.SQLITE_OK;
|
public static final int OK = CApi.SQLITE_OK;
|
||||||
public static final int ERROR = CApi.SQLITE_ERROR;
|
public static final int ERROR = CApi.SQLITE_ERROR;
|
||||||
public static final int INTERNAL = CApi.SQLITE_INTERNAL;
|
public static final int INTERNAL = CApi.SQLITE_INTERNAL;
|
||||||
@ -135,14 +139,17 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
public static final int AUTH_USER = CApi.SQLITE_AUTH_USER;
|
public static final int AUTH_USER = CApi.SQLITE_AUTH_USER;
|
||||||
public static final int OK_LOAD_PERMANENTLY = CApi.SQLITE_OK_LOAD_PERMANENTLY;
|
public static final int OK_LOAD_PERMANENTLY = CApi.SQLITE_OK_LOAD_PERMANENTLY;
|
||||||
|
|
||||||
|
// sqlite3_open() flags
|
||||||
public static final int OPEN_READWRITE = CApi.SQLITE_OPEN_READWRITE;
|
public static final int OPEN_READWRITE = CApi.SQLITE_OPEN_READWRITE;
|
||||||
public static final int OPEN_CREATE = CApi.SQLITE_OPEN_CREATE;
|
public static final int OPEN_CREATE = CApi.SQLITE_OPEN_CREATE;
|
||||||
public static final int OPEN_EXRESCODE = CApi.SQLITE_OPEN_EXRESCODE;
|
public static final int OPEN_EXRESCODE = CApi.SQLITE_OPEN_EXRESCODE;
|
||||||
|
|
||||||
|
// transaction state
|
||||||
public static final int TXN_NONE = CApi.SQLITE_TXN_NONE;
|
public static final int TXN_NONE = CApi.SQLITE_TXN_NONE;
|
||||||
public static final int TXN_READ = CApi.SQLITE_TXN_READ;
|
public static final int TXN_READ = CApi.SQLITE_TXN_READ;
|
||||||
public static final int TXN_WRITE = CApi.SQLITE_TXN_WRITE;
|
public static final int TXN_WRITE = CApi.SQLITE_TXN_WRITE;
|
||||||
|
|
||||||
|
// sqlite3_status() ops
|
||||||
public static final int STATUS_MEMORY_USED = CApi.SQLITE_STATUS_MEMORY_USED;
|
public static final int STATUS_MEMORY_USED = CApi.SQLITE_STATUS_MEMORY_USED;
|
||||||
public static final int STATUS_PAGECACHE_USED = CApi.SQLITE_STATUS_PAGECACHE_USED;
|
public static final int STATUS_PAGECACHE_USED = CApi.SQLITE_STATUS_PAGECACHE_USED;
|
||||||
public static final int STATUS_PAGECACHE_OVERFLOW = CApi.SQLITE_STATUS_PAGECACHE_OVERFLOW;
|
public static final int STATUS_PAGECACHE_OVERFLOW = CApi.SQLITE_STATUS_PAGECACHE_OVERFLOW;
|
||||||
@ -151,6 +158,7 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
public static final int STATUS_PAGECACHE_SIZE = CApi.SQLITE_STATUS_PAGECACHE_SIZE;
|
public static final int STATUS_PAGECACHE_SIZE = CApi.SQLITE_STATUS_PAGECACHE_SIZE;
|
||||||
public static final int STATUS_MALLOC_COUNT = CApi.SQLITE_STATUS_MALLOC_COUNT;
|
public static final int STATUS_MALLOC_COUNT = CApi.SQLITE_STATUS_MALLOC_COUNT;
|
||||||
|
|
||||||
|
// sqlite3_db_status() ops
|
||||||
public static final int DBSTATUS_LOOKASIDE_USED = CApi.SQLITE_DBSTATUS_LOOKASIDE_USED;
|
public static final int DBSTATUS_LOOKASIDE_USED = CApi.SQLITE_DBSTATUS_LOOKASIDE_USED;
|
||||||
public static final int DBSTATUS_CACHE_USED = CApi.SQLITE_DBSTATUS_CACHE_USED;
|
public static final int DBSTATUS_CACHE_USED = CApi.SQLITE_DBSTATUS_CACHE_USED;
|
||||||
public static final int DBSTATUS_SCHEMA_USED = CApi.SQLITE_DBSTATUS_SCHEMA_USED;
|
public static final int DBSTATUS_SCHEMA_USED = CApi.SQLITE_DBSTATUS_SCHEMA_USED;
|
||||||
@ -165,6 +173,7 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
public static final int DBSTATUS_CACHE_USED_SHARED = CApi.SQLITE_DBSTATUS_CACHE_USED_SHARED;
|
public static final int DBSTATUS_CACHE_USED_SHARED = CApi.SQLITE_DBSTATUS_CACHE_USED_SHARED;
|
||||||
public static final int DBSTATUS_CACHE_SPILL = CApi.SQLITE_DBSTATUS_CACHE_SPILL;
|
public static final int DBSTATUS_CACHE_SPILL = CApi.SQLITE_DBSTATUS_CACHE_SPILL;
|
||||||
|
|
||||||
|
// Limits
|
||||||
public static final int LIMIT_LENGTH = CApi.SQLITE_LIMIT_LENGTH;
|
public static final int LIMIT_LENGTH = CApi.SQLITE_LIMIT_LENGTH;
|
||||||
public static final int LIMIT_SQL_LENGTH = CApi.SQLITE_LIMIT_SQL_LENGTH;
|
public static final int LIMIT_SQL_LENGTH = CApi.SQLITE_LIMIT_SQL_LENGTH;
|
||||||
public static final int LIMIT_COLUMN = CApi.SQLITE_LIMIT_COLUMN;
|
public static final int LIMIT_COLUMN = CApi.SQLITE_LIMIT_COLUMN;
|
||||||
@ -178,15 +187,18 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
public static final int LIMIT_TRIGGER_DEPTH = CApi.SQLITE_LIMIT_TRIGGER_DEPTH;
|
public static final int LIMIT_TRIGGER_DEPTH = CApi.SQLITE_LIMIT_TRIGGER_DEPTH;
|
||||||
public static final int LIMIT_WORKER_THREADS = CApi.SQLITE_LIMIT_WORKER_THREADS;
|
public static final int LIMIT_WORKER_THREADS = CApi.SQLITE_LIMIT_WORKER_THREADS;
|
||||||
|
|
||||||
|
// sqlite3_prepare_v3() flags
|
||||||
public static final int PREPARE_PERSISTENT = CApi.SQLITE_PREPARE_PERSISTENT;
|
public static final int PREPARE_PERSISTENT = CApi.SQLITE_PREPARE_PERSISTENT;
|
||||||
public static final int PREPARE_NO_VTAB = CApi.SQLITE_PREPARE_NO_VTAB;
|
public static final int PREPARE_NO_VTAB = CApi.SQLITE_PREPARE_NO_VTAB;
|
||||||
|
|
||||||
|
// sqlite3_trace_v2() flags
|
||||||
public static final int TRACE_STMT = CApi.SQLITE_TRACE_STMT;
|
public static final int TRACE_STMT = CApi.SQLITE_TRACE_STMT;
|
||||||
public static final int TRACE_PROFILE = CApi.SQLITE_TRACE_PROFILE;
|
public static final int TRACE_PROFILE = CApi.SQLITE_TRACE_PROFILE;
|
||||||
public static final int TRACE_ROW = CApi.SQLITE_TRACE_ROW;
|
public static final int TRACE_ROW = CApi.SQLITE_TRACE_ROW;
|
||||||
public static final int TRACE_CLOSE = CApi.SQLITE_TRACE_CLOSE;
|
public static final int TRACE_CLOSE = CApi.SQLITE_TRACE_CLOSE;
|
||||||
public static final int TRACE_ALL = TRACE_STMT | TRACE_PROFILE | TRACE_ROW | TRACE_CLOSE;
|
public static final int TRACE_ALL = TRACE_STMT | TRACE_PROFILE | TRACE_ROW | TRACE_CLOSE;
|
||||||
|
|
||||||
|
// sqlite3_db_config() ops
|
||||||
public static final int DBCONFIG_ENABLE_FKEY = CApi.SQLITE_DBCONFIG_ENABLE_FKEY;
|
public static final int DBCONFIG_ENABLE_FKEY = CApi.SQLITE_DBCONFIG_ENABLE_FKEY;
|
||||||
public static final int DBCONFIG_ENABLE_TRIGGER = CApi.SQLITE_DBCONFIG_ENABLE_TRIGGER;
|
public static final int DBCONFIG_ENABLE_TRIGGER = CApi.SQLITE_DBCONFIG_ENABLE_TRIGGER;
|
||||||
public static final int DBCONFIG_ENABLE_FTS3_TOKENIZER = CApi.SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER;
|
public static final int DBCONFIG_ENABLE_FTS3_TOKENIZER = CApi.SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER;
|
||||||
@ -206,6 +218,12 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
public static final int DBCONFIG_STMT_SCANSTATUS = CApi.SQLITE_DBCONFIG_STMT_SCANSTATUS;
|
public static final int DBCONFIG_STMT_SCANSTATUS = CApi.SQLITE_DBCONFIG_STMT_SCANSTATUS;
|
||||||
public static final int DBCONFIG_REVERSE_SCANORDER = CApi.SQLITE_DBCONFIG_REVERSE_SCANORDER;
|
public static final int DBCONFIG_REVERSE_SCANORDER = CApi.SQLITE_DBCONFIG_REVERSE_SCANORDER;
|
||||||
|
|
||||||
|
// sqlite3_config() ops
|
||||||
|
public static final int CONFIG_SINGLETHREAD = CApi.SQLITE_CONFIG_SINGLETHREAD;
|
||||||
|
public static final int CONFIG_MULTITHREAD = CApi.SQLITE_CONFIG_MULTITHREAD;
|
||||||
|
public static final int CONFIG_SERIALIZED = CApi.SQLITE_CONFIG_SERIALIZED;
|
||||||
|
|
||||||
|
// Encodings
|
||||||
public static final int UTF8 = CApi.SQLITE_UTF8;
|
public static final int UTF8 = CApi.SQLITE_UTF8;
|
||||||
public static final int UTF16 = CApi.SQLITE_UTF16;
|
public static final int UTF16 = CApi.SQLITE_UTF16;
|
||||||
public static final int UTF16LE = CApi.SQLITE_UTF16LE;
|
public static final int UTF16LE = CApi.SQLITE_UTF16LE;
|
||||||
@ -213,6 +231,14 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
/* We elide the UTF16_ALIGNED from this interface because it
|
/* We elide the UTF16_ALIGNED from this interface because it
|
||||||
is irrelevant for the Java interface. */
|
is irrelevant for the Java interface. */
|
||||||
|
|
||||||
|
// SQL data type IDs
|
||||||
|
public static final int INTEGER = CApi.SQLITE_INTEGER;
|
||||||
|
public static final int FLOAT = CApi.SQLITE_FLOAT;
|
||||||
|
public static final int TEXT = CApi.SQLITE_TEXT;
|
||||||
|
public static final int BLOB = CApi.SQLITE_BLOB;
|
||||||
|
public static final int NULL = CApi.SQLITE_NULL;
|
||||||
|
|
||||||
|
// Authorizer codes.
|
||||||
public static final int DENY = CApi.SQLITE_DENY;
|
public static final int DENY = CApi.SQLITE_DENY;
|
||||||
public static final int IGNORE = CApi.SQLITE_IGNORE;
|
public static final int IGNORE = CApi.SQLITE_IGNORE;
|
||||||
public static final int CREATE_INDEX = CApi.SQLITE_CREATE_INDEX;
|
public static final int CREATE_INDEX = CApi.SQLITE_CREATE_INDEX;
|
||||||
@ -258,6 +284,32 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
private static final java.util.Map<org.sqlite.jni.capi.sqlite3, Sqlite> nativeToWrapper
|
private static final java.util.Map<org.sqlite.jni.capi.sqlite3, Sqlite> nativeToWrapper
|
||||||
= new java.util.HashMap<>();
|
= new java.util.HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
When any given thread is done using the SQLite library, calling
|
||||||
|
this will free up any native-side resources which may be
|
||||||
|
associated specifically with that thread. This is not strictly
|
||||||
|
necessary, in particular in applications which only use SQLite
|
||||||
|
from a single thread, but may help free some otherwise errant
|
||||||
|
resources.
|
||||||
|
|
||||||
|
Calling into SQLite from a given thread after this has been
|
||||||
|
called in that thread is harmless. The library will simply start
|
||||||
|
to re-cache certain state for that thread.
|
||||||
|
|
||||||
|
Contrariwise, failing to call this will effectively leak a small
|
||||||
|
amount of cached state for the thread, which may add up to
|
||||||
|
significant amounts if the application uses SQLite from many
|
||||||
|
threads.
|
||||||
|
|
||||||
|
This must never be called while actively using SQLite from this
|
||||||
|
thread, e.g. from within a query loop or a callback which is
|
||||||
|
operating on behalf of the library.
|
||||||
|
*/
|
||||||
|
static void uncacheThread(){
|
||||||
|
CApi.sqlite3_java_uncache_thread();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns the Sqlite object associated with the given sqlite3
|
Returns the Sqlite object associated with the given sqlite3
|
||||||
object, or null if there is no such mapping.
|
object, or null if there is no such mapping.
|
||||||
@ -339,6 +391,9 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
private static boolean hasNormalizeSql =
|
private static boolean hasNormalizeSql =
|
||||||
compileOptionUsed("ENABLE_NORMALIZE");
|
compileOptionUsed("ENABLE_NORMALIZE");
|
||||||
|
|
||||||
|
private static boolean hasSqlLog =
|
||||||
|
compileOptionUsed("ENABLE_SQLLOG");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Throws UnsupportedOperationException if check is false.
|
Throws UnsupportedOperationException if check is false.
|
||||||
flag is expected to be the name of an SQLITE_ENABLE_...
|
flag is expected to be the name of an SQLITE_ENABLE_...
|
||||||
@ -407,7 +462,7 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
new org.sqlite.jni.capi.OutputPointer.Int64();
|
new org.sqlite.jni.capi.OutputPointer.Int64();
|
||||||
org.sqlite.jni.capi.OutputPointer.Int64 pHighwater =
|
org.sqlite.jni.capi.OutputPointer.Int64 pHighwater =
|
||||||
new org.sqlite.jni.capi.OutputPointer.Int64();
|
new org.sqlite.jni.capi.OutputPointer.Int64();
|
||||||
checkRc2( CApi.sqlite3_status64(op, pCurrent, pHighwater, resetStats) );
|
checkRcStatic( CApi.sqlite3_status64(op, pCurrent, pHighwater, resetStats) );
|
||||||
final Status s = new Status();
|
final Status s = new Status();
|
||||||
s.current = pCurrent.value;
|
s.current = pCurrent.value;
|
||||||
s.peak = pHighwater.value;
|
s.peak = pHighwater.value;
|
||||||
@ -486,7 +541,7 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
Like checkRc() but behaves as if that function were
|
Like checkRc() but behaves as if that function were
|
||||||
called with a null db object.
|
called with a null db object.
|
||||||
*/
|
*/
|
||||||
private static void checkRc2(int rc){
|
private static void checkRcStatic(int rc){
|
||||||
if( 0!=rc ){
|
if( 0!=rc ){
|
||||||
if( CApi.SQLITE_NOMEM==rc ){
|
if( CApi.SQLITE_NOMEM==rc ){
|
||||||
throw new OutOfMemoryError();
|
throw new OutOfMemoryError();
|
||||||
@ -605,6 +660,14 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
prepareMulti( sql, 0, visitor );
|
prepareMulti( sql, 0, visitor );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Equivallent to prepareMulti(X,prepFlags,visitor), where X is
|
||||||
|
sql.getBytes(StandardCharsets.UTF_8).
|
||||||
|
*/
|
||||||
|
public void prepareMulti(String sql, int prepFlags, PrepareMulti visitor){
|
||||||
|
prepareMulti(sql.getBytes(StandardCharsets.UTF_8), prepFlags, visitor);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A variant of prepare() which can handle multiple SQL statements
|
A variant of prepare() which can handle multiple SQL statements
|
||||||
in a single input string. For each statement in the given string,
|
in a single input string. For each statement in the given string,
|
||||||
@ -619,6 +682,11 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
|
|
||||||
PrepareMultiFinalize offers a proxy which finalizes each
|
PrepareMultiFinalize offers a proxy which finalizes each
|
||||||
statement after it is passed to another client-defined visitor.
|
statement after it is passed to another client-defined visitor.
|
||||||
|
|
||||||
|
Be aware that certain legal SQL constructs may fail in the
|
||||||
|
preparation phase, before the corresponding statement can be
|
||||||
|
stepped. Most notably, authorizer checks which disallow access to
|
||||||
|
something in a statement behave that way.
|
||||||
*/
|
*/
|
||||||
public void prepareMulti(byte sqlUtf8[], int prepFlags, PrepareMulti visitor){
|
public void prepareMulti(byte sqlUtf8[], int prepFlags, PrepareMulti visitor){
|
||||||
int pos = 0, n = 1;
|
int pos = 0, n = 1;
|
||||||
@ -646,14 +714,6 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
Equivallent to prepareMulti(X,prepFlags,visitor), where X is
|
|
||||||
sql.getBytes(StandardCharsets.UTF_8).
|
|
||||||
*/
|
|
||||||
public void prepareMulti(String sql, int prepFlags, PrepareMulti visitor){
|
|
||||||
prepareMulti(sql.getBytes(StandardCharsets.UTF_8), prepFlags, visitor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createFunction(String name, int nArg, int eTextRep, ScalarFunction f){
|
public void createFunction(String name, int nArg, int eTextRep, ScalarFunction f){
|
||||||
int rc = CApi.sqlite3_create_function(thisDb(), name, nArg, eTextRep,
|
int rc = CApi.sqlite3_create_function(thisDb(), name, nArg, eTextRep,
|
||||||
new SqlFunction.ScalarAdapter(f));
|
new SqlFunction.ScalarAdapter(f));
|
||||||
@ -937,21 +997,11 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
public static final class Stmt implements AutoCloseable {
|
public static final class Stmt implements AutoCloseable {
|
||||||
private Sqlite _db = null;
|
private Sqlite _db = null;
|
||||||
private sqlite3_stmt stmt = null;
|
private sqlite3_stmt stmt = null;
|
||||||
/**
|
|
||||||
We save the result column count in order to prevent having to
|
|
||||||
call into C to fetch that value every time we need to check
|
|
||||||
that value for the columnXyz() methods.
|
|
||||||
|
|
||||||
Design note: if this is final then we cannot zero it in
|
|
||||||
finalizeStmt().
|
|
||||||
*/
|
|
||||||
private int resultColCount;
|
|
||||||
|
|
||||||
/** Only called by the prepare() factory functions. */
|
/** Only called by the prepare() factory functions. */
|
||||||
Stmt(Sqlite db, sqlite3_stmt stmt){
|
Stmt(Sqlite db, sqlite3_stmt stmt){
|
||||||
this._db = db;
|
this._db = db;
|
||||||
this.stmt = stmt;
|
this.stmt = stmt;
|
||||||
this.resultColCount = CApi.sqlite3_column_count(stmt);
|
|
||||||
synchronized(nativeToWrapper){
|
synchronized(nativeToWrapper){
|
||||||
nativeToWrapper.put(this.stmt, this);
|
nativeToWrapper.put(this.stmt, this);
|
||||||
}
|
}
|
||||||
@ -977,7 +1027,7 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
If this statement is still opened, its low-level handle is
|
If this statement is still opened, its low-level handle is
|
||||||
returned, eelse an IllegalArgumentException is thrown.
|
returned, else an IllegalArgumentException is thrown.
|
||||||
*/
|
*/
|
||||||
private sqlite3_stmt thisStmt(){
|
private sqlite3_stmt thisStmt(){
|
||||||
if( null==stmt || 0==stmt.getNativePointer() ){
|
if( null==stmt || 0==stmt.getNativePointer() ){
|
||||||
@ -986,10 +1036,10 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Throws if n is out of range of this.resultColCount. Intended
|
/** Throws if n is out of range of this statement's result column
|
||||||
to be used by the columnXyz() methods. */
|
count. Intended to be used by the columnXyz() methods. */
|
||||||
private sqlite3_stmt checkColIndex(int n){
|
private sqlite3_stmt checkColIndex(int n){
|
||||||
if(n<0 || n>=this.resultColCount){
|
if(n<0 || n>=columnCount()){
|
||||||
throw new IllegalArgumentException("Column index "+n+" is out of range.");
|
throw new IllegalArgumentException("Column index "+n+" is out of range.");
|
||||||
}
|
}
|
||||||
return thisStmt();
|
return thisStmt();
|
||||||
@ -1013,7 +1063,6 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
CApi.sqlite3_finalize(stmt);
|
CApi.sqlite3_finalize(stmt);
|
||||||
stmt = null;
|
stmt = null;
|
||||||
_db = null;
|
_db = null;
|
||||||
resultColCount = 0;
|
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -1055,6 +1104,22 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Works like sqlite3_step(), returning the same result codes as
|
||||||
|
that function unless throwOnError is true, in which case it
|
||||||
|
will throw an SqliteException for any result codes other than
|
||||||
|
Sqlite.ROW or Sqlite.DONE.
|
||||||
|
|
||||||
|
The utility of this overload over the no-argument one is the
|
||||||
|
ability to handle BUSY and LOCKED errors more easily.
|
||||||
|
*/
|
||||||
|
public int step(boolean throwOnError){
|
||||||
|
final int rc = (null==stmt)
|
||||||
|
? Sqlite.MISUSE
|
||||||
|
: CApi.sqlite3_step(stmt);
|
||||||
|
return throwOnError ? checkRc(rc) : rc;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns the Sqlite which prepared this statement, or null if
|
Returns the Sqlite which prepared this statement, or null if
|
||||||
this statement has been finalized.
|
this statement has been finalized.
|
||||||
@ -1184,8 +1249,18 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
public String columnDeclType(int ndx){
|
public String columnDeclType(int ndx){
|
||||||
return CApi.sqlite3_column_decltype( checkColIndex(ndx), ndx );
|
return CApi.sqlite3_column_decltype( checkColIndex(ndx), ndx );
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
Analog to sqlite3_column_count() but throws if this statement
|
||||||
|
has been finalized.
|
||||||
|
*/
|
||||||
public int columnCount(){
|
public int columnCount(){
|
||||||
return resultColCount;
|
/* We cannot reliably cache the column count in a class
|
||||||
|
member because an ALTER TABLE from a separate statement
|
||||||
|
can invalidate that count and we have no way, short of
|
||||||
|
installing a COMMIT handler or the like, of knowing when
|
||||||
|
to re-read it. We cannot install such a handler without
|
||||||
|
interfering with a client's ability to do so. */
|
||||||
|
return CApi.sqlite3_column_count(thisStmt());
|
||||||
}
|
}
|
||||||
public int columnDataCount(){
|
public int columnDataCount(){
|
||||||
return CApi.sqlite3_data_count( thisStmt() );
|
return CApi.sqlite3_data_count( thisStmt() );
|
||||||
@ -1753,6 +1828,17 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
this.b = b;
|
this.b = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
If this blob is still opened, its low-level handle is
|
||||||
|
returned, else an IllegalArgumentException is thrown.
|
||||||
|
*/
|
||||||
|
private sqlite3_blob thisBlob(){
|
||||||
|
if( null==b || 0==b.getNativePointer() ){
|
||||||
|
throw new IllegalArgumentException("This Blob has been finalized.");
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Analog to sqlite3_blob_close().
|
Analog to sqlite3_blob_close().
|
||||||
*/
|
*/
|
||||||
@ -1764,32 +1850,43 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Throws if the JVM does not have JNI-level support for
|
||||||
|
ByteBuffer.
|
||||||
|
*/
|
||||||
|
private void checkNio(){
|
||||||
|
if( !Sqlite.JNI_SUPPORTS_NIO ){
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"This JVM does not support JNI access to ByteBuffer."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
Analog to sqlite3_blob_reopen() but throws on error.
|
Analog to sqlite3_blob_reopen() but throws on error.
|
||||||
*/
|
*/
|
||||||
public void reopen(long newRowId){
|
public void reopen(long newRowId){
|
||||||
db.checkRc( CApi.sqlite3_blob_reopen(b, newRowId) );
|
db.checkRc( CApi.sqlite3_blob_reopen(thisBlob(), newRowId) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Analog to sqlite3_blob_write() but throws on error.
|
Analog to sqlite3_blob_write() but throws on error.
|
||||||
*/
|
*/
|
||||||
public void write( byte[] bytes, int atOffset ){
|
public void write( byte[] bytes, int atOffset ){
|
||||||
db.checkRc( CApi.sqlite3_blob_write(b, bytes, atOffset) );
|
db.checkRc( CApi.sqlite3_blob_write(thisBlob(), bytes, atOffset) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Analog to sqlite3_blob_read() but throws on error.
|
Analog to sqlite3_blob_read() but throws on error.
|
||||||
*/
|
*/
|
||||||
public void read( byte[] dest, int atOffset ){
|
public void read( byte[] dest, int atOffset ){
|
||||||
db.checkRc( CApi.sqlite3_blob_read(b, dest, atOffset) );
|
db.checkRc( CApi.sqlite3_blob_read(thisBlob(), dest, atOffset) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Analog to sqlite3_blob_bytes().
|
Analog to sqlite3_blob_bytes().
|
||||||
*/
|
*/
|
||||||
public int bytes(){
|
public int bytes(){
|
||||||
return CApi.sqlite3_blob_bytes(b);
|
return CApi.sqlite3_blob_bytes(thisBlob());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1814,4 +1911,81 @@ public final class Sqlite implements AutoCloseable {
|
|||||||
return new Blob(this, out.take());
|
return new Blob(this, out.take());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Callback for use with libConfigLog().
|
||||||
|
*/
|
||||||
|
public interface ConfigLog {
|
||||||
|
/**
|
||||||
|
Must function as described for a C-level callback for
|
||||||
|
sqlite3_config()'s SQLITE_CONFIG_LOG callback, with the slight
|
||||||
|
signature change. Any exceptions thrown from this callback are
|
||||||
|
necessarily suppressed.
|
||||||
|
*/
|
||||||
|
void call(int errCode, String msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Analog to sqlite3_config() with the SQLITE_CONFIG_LOG option,
|
||||||
|
this sets or (if log is null) clears the current logger.
|
||||||
|
*/
|
||||||
|
public static void libConfigLog(ConfigLog log){
|
||||||
|
final org.sqlite.jni.capi.ConfigLogCallback l =
|
||||||
|
null==log
|
||||||
|
? null
|
||||||
|
: new org.sqlite.jni.capi.ConfigLogCallback() {
|
||||||
|
@Override public void call(int errCode, String msg){
|
||||||
|
log.call(errCode, msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
checkRcStatic(CApi.sqlite3_config(l));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Callback for use with libConfigSqlLog().
|
||||||
|
*/
|
||||||
|
public interface ConfigSqlLog {
|
||||||
|
/**
|
||||||
|
Must function as described for a C-level callback for
|
||||||
|
sqlite3_config()'s SQLITE_CONFIG_SQLLOG callback, with the
|
||||||
|
slight signature change. Any exceptions thrown from this
|
||||||
|
callback are necessarily suppressed.
|
||||||
|
*/
|
||||||
|
void call(Sqlite db, String msg, int msgType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Analog to sqlite3_config() with the SQLITE_CONFIG_SQLLOG option,
|
||||||
|
this sets or (if log is null) clears the current logger.
|
||||||
|
|
||||||
|
If SQLite is built without SQLITE_ENABLE_SQLLOG defined then this
|
||||||
|
will throw an UnsupportedOperationException.
|
||||||
|
*/
|
||||||
|
public static void libConfigSqlLog(ConfigSqlLog log){
|
||||||
|
Sqlite.checkSupported(hasNormalizeSql, "SQLITE_ENABLE_SQLLOG");
|
||||||
|
final org.sqlite.jni.capi.ConfigSqlLogCallback l =
|
||||||
|
null==log
|
||||||
|
? null
|
||||||
|
: new org.sqlite.jni.capi.ConfigSqlLogCallback() {
|
||||||
|
@Override public void call(sqlite3 db, String msg, int msgType){
|
||||||
|
try{
|
||||||
|
log.call(fromNative(db), msg, msgType);
|
||||||
|
}catch(Exception e){
|
||||||
|
/* Suppressed */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
checkRcStatic(CApi.sqlite3_config(l));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Analog to the C-level sqlite3_config() with one of the
|
||||||
|
SQLITE_CONFIG_... constants defined as CONFIG_... in this
|
||||||
|
class. Throws on error, including passing of an unknown option or
|
||||||
|
if a specified option is not supported by the underlying build of
|
||||||
|
the SQLite library.
|
||||||
|
*/
|
||||||
|
public static void libConfigOp( int op ){
|
||||||
|
checkRcStatic(CApi.sqlite3_config(op));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,14 +12,13 @@
|
|||||||
** This file contains a set of tests for the sqlite3 JNI bindings.
|
** This file contains a set of tests for the sqlite3 JNI bindings.
|
||||||
*/
|
*/
|
||||||
package org.sqlite.jni.wrapper1;
|
package org.sqlite.jni.wrapper1;
|
||||||
//import static org.sqlite.jni.capi.CApi.*;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import org.sqlite.jni.capi.*;
|
import org.sqlite.jni.capi.CApi;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
An annotation for Tester2 tests which we do not want to run in
|
An annotation for Tester2 tests which we do not want to run in
|
||||||
@ -133,49 +132,29 @@ public class Tester2 implements Runnable {
|
|||||||
Executes all SQL statements in the given string. If throwOnError
|
Executes all SQL statements in the given string. If throwOnError
|
||||||
is true then it will throw for any prepare/step errors, else it
|
is true then it will throw for any prepare/step errors, else it
|
||||||
will return the corresponding non-0 result code.
|
will return the corresponding non-0 result code.
|
||||||
|
|
||||||
TODO: reimplement this in the high-level API once it has the
|
|
||||||
multi-prepare capability.
|
|
||||||
*/
|
*/
|
||||||
public static int execSql(Sqlite dbw, boolean throwOnError, String sql){
|
public static int execSql(Sqlite dbw, boolean throwOnError, String sql){
|
||||||
final sqlite3 db = dbw.nativeHandle();
|
final ValueHolder<Integer> rv = new ValueHolder<>(0);
|
||||||
OutputPointer.Int32 oTail = new OutputPointer.Int32();
|
final Sqlite.PrepareMulti pm = new Sqlite.PrepareMulti(){
|
||||||
final byte[] sqlUtf8 = sql.getBytes(StandardCharsets.UTF_8);
|
@Override public void call(Sqlite.Stmt stmt){
|
||||||
int pos = 0, n = 1;
|
try{
|
||||||
byte[] sqlChunk = sqlUtf8;
|
while( Sqlite.ROW == (rv.value = stmt.step(throwOnError)) ){}
|
||||||
int rc = 0;
|
}
|
||||||
sqlite3_stmt stmt = null;
|
finally{ stmt.finalizeStmt(); }
|
||||||
final OutputPointer.sqlite3_stmt outStmt = new OutputPointer.sqlite3_stmt();
|
}
|
||||||
while(pos < sqlChunk.length){
|
};
|
||||||
if(pos > 0){
|
try {
|
||||||
sqlChunk = Arrays.copyOfRange(sqlChunk, pos,
|
dbw.prepareMulti(sql, pm);
|
||||||
sqlChunk.length);
|
}catch(SqliteException se){
|
||||||
}
|
if( throwOnError ){
|
||||||
if( 0==sqlChunk.length ) break;
|
throw se;
|
||||||
rc = CApi.sqlite3_prepare_v2(db, sqlChunk, outStmt, oTail);
|
}else{
|
||||||
if( throwOnError ) affirm(0 == rc);
|
/* This error (likely) happened in the prepare() phase and we
|
||||||
else if( 0!=rc ) break;
|
need to preempt it. */
|
||||||
pos = oTail.value;
|
rv.value = se.errcode();
|
||||||
stmt = outStmt.take();
|
|
||||||
if( null == stmt ){
|
|
||||||
// empty statement was parsed.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
affirm(0 != stmt.getNativePointer());
|
|
||||||
while( CApi.SQLITE_ROW == (rc = CApi.sqlite3_step(stmt)) ){
|
|
||||||
}
|
|
||||||
CApi.sqlite3_finalize(stmt);
|
|
||||||
affirm(0 == stmt.getNativePointer());
|
|
||||||
if(Sqlite.DONE!=rc){
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CApi.sqlite3_finalize(stmt);
|
return (rv.value==Sqlite.DONE) ? 0 : rv.value;
|
||||||
if(CApi.SQLITE_ROW==rc || CApi.SQLITE_DONE==rc) rc = 0;
|
|
||||||
if( 0!=rc && throwOnError){
|
|
||||||
throw new SqliteException(db);
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void execSql(Sqlite db, String sql){
|
static void execSql(Sqlite db, String sql){
|
||||||
@ -187,14 +166,6 @@ public class Tester2 implements Runnable {
|
|||||||
affirm(Sqlite.libVersionNumber() == CApi.SQLITE_VERSION_NUMBER);
|
affirm(Sqlite.libVersionNumber() == CApi.SQLITE_VERSION_NUMBER);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy/paste/rename this to add new tests. */
|
|
||||||
private void _testTemplate(){
|
|
||||||
//final sqlite3 db = createNewDb();
|
|
||||||
//sqlite3_stmt stmt = prepare(db,"SELECT 1");
|
|
||||||
//sqlite3_finalize(stmt);
|
|
||||||
//sqlite3_close_v2(db);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void nap() throws InterruptedException {
|
private void nap() throws InterruptedException {
|
||||||
if( takeNaps ){
|
if( takeNaps ){
|
||||||
Thread.sleep(java.util.concurrent.ThreadLocalRandom.current().nextInt(3, 17), 0);
|
Thread.sleep(java.util.concurrent.ThreadLocalRandom.current().nextInt(3, 17), 0);
|
||||||
@ -274,14 +245,14 @@ public class Tester2 implements Runnable {
|
|||||||
affirm( "17".equals(stmt.columnText16(0)) );
|
affirm( "17".equals(stmt.columnText16(0)) );
|
||||||
affirm( !stmt.step() );
|
affirm( !stmt.step() );
|
||||||
stmt.reset();
|
stmt.reset();
|
||||||
affirm( stmt.step() );
|
affirm( Sqlite.ROW==stmt.step(false) );
|
||||||
affirm( !stmt.step() );
|
affirm( !stmt.step() );
|
||||||
affirm( 0 == stmt.finalizeStmt() );
|
affirm( 0 == stmt.finalizeStmt() );
|
||||||
affirm( null==stmt.nativeHandle() );
|
affirm( null==stmt.nativeHandle() );
|
||||||
|
|
||||||
stmt = db.prepare("SELECT ?");
|
stmt = db.prepare("SELECT ?");
|
||||||
stmt.bindObject(1, db);
|
stmt.bindObject(1, db);
|
||||||
affirm( stmt.step() );
|
affirm( Sqlite.ROW == stmt.step(false) );
|
||||||
affirm( db==stmt.columnObject(0) );
|
affirm( db==stmt.columnObject(0) );
|
||||||
affirm( db==stmt.columnObject(0, Sqlite.class ) );
|
affirm( db==stmt.columnObject(0, Sqlite.class ) );
|
||||||
affirm( null==stmt.columnObject(0, Sqlite.Stmt.class ) );
|
affirm( null==stmt.columnObject(0, Sqlite.Stmt.class ) );
|
||||||
@ -782,9 +753,9 @@ public class Tester2 implements Runnable {
|
|||||||
affirm( newHook == oldHook );
|
affirm( newHook == oldHook );
|
||||||
execSql(db, "BEGIN; update t set a='i' where a='h'; COMMIT;");
|
execSql(db, "BEGIN; update t set a='i' where a='h'; COMMIT;");
|
||||||
affirm( 5 == counter.value );
|
affirm( 5 == counter.value );
|
||||||
hookResult.value = CApi.SQLITE_ERROR;
|
hookResult.value = Sqlite.ERROR;
|
||||||
int rc = execSql(db, false, "BEGIN; update t set a='j' where a='i'; COMMIT;");
|
int rc = execSql(db, false, "BEGIN; update t set a='j' where a='i'; COMMIT;");
|
||||||
affirm( CApi.SQLITE_CONSTRAINT_COMMITHOOK == rc );
|
affirm( Sqlite.CONSTRAINT_COMMITHOOK == rc );
|
||||||
affirm( 6 == counter.value );
|
affirm( 6 == counter.value );
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
@ -930,10 +901,21 @@ public class Tester2 implements Runnable {
|
|||||||
stmt.finalizeStmt();
|
stmt.finalizeStmt();
|
||||||
|
|
||||||
b = db.blobOpen("main", "t", "a", db.lastInsertRowId(), false);
|
b = db.blobOpen("main", "t", "a", db.lastInsertRowId(), false);
|
||||||
b.reopen(2);
|
|
||||||
final byte[] tgt = new byte[3];
|
final byte[] tgt = new byte[3];
|
||||||
b.read( tgt, 0 );
|
b.read( tgt, 0 );
|
||||||
affirm( 100==tgt[0] && 101==tgt[1] && 102==tgt[2], "DEF" );
|
affirm( 100==tgt[0] && 101==tgt[1] && 102==tgt[2], "DEF" );
|
||||||
|
execSql(db,"UPDATE t SET a=zeroblob(10) WHERE rowid=2");
|
||||||
|
b.close();
|
||||||
|
b = db.blobOpen("main", "t", "a", db.lastInsertRowId(), true);
|
||||||
|
byte[] bw = new byte[]{
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
||||||
|
};
|
||||||
|
b.write(bw, 0);
|
||||||
|
byte[] br = new byte[10];
|
||||||
|
b.read(br, 0);
|
||||||
|
for( int i = 0; i < br.length; ++i ){
|
||||||
|
affirm(bw[i] == br[i]);
|
||||||
|
}
|
||||||
b.close();
|
b.close();
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
@ -968,6 +950,15 @@ public class Tester2 implements Runnable {
|
|||||||
affirm( 9 == fCount.value );
|
affirm( 9 == fCount.value );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Copy/paste/rename this to add new tests. */
|
||||||
|
private void _testTemplate(){
|
||||||
|
try (Sqlite db = openDb()) {
|
||||||
|
Sqlite.Stmt stmt = db.prepare("SELECT 1");
|
||||||
|
stmt.finalizeStmt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void runTests(boolean fromThread) throws Exception {
|
private void runTests(boolean fromThread) throws Exception {
|
||||||
List<java.lang.reflect.Method> mlist = testMethods;
|
List<java.lang.reflect.Method> mlist = testMethods;
|
||||||
affirm( null!=mlist );
|
affirm( null!=mlist );
|
||||||
@ -1014,8 +1005,7 @@ public class Tester2 implements Runnable {
|
|||||||
listErrors.add(e);
|
listErrors.add(e);
|
||||||
}
|
}
|
||||||
}finally{
|
}finally{
|
||||||
affirm( CApi.sqlite3_java_uncache_thread() );
|
Sqlite.uncacheThread();
|
||||||
affirm( !CApi.sqlite3_java_uncache_thread() );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1088,38 +1078,28 @@ public class Tester2 implements Runnable {
|
|||||||
|
|
||||||
if( sqlLog ){
|
if( sqlLog ){
|
||||||
if( Sqlite.compileOptionUsed("ENABLE_SQLLOG") ){
|
if( Sqlite.compileOptionUsed("ENABLE_SQLLOG") ){
|
||||||
final ConfigSqllogCallback log = new ConfigSqllogCallback() {
|
Sqlite.libConfigSqlLog( new Sqlite.ConfigSqlLog() {
|
||||||
@Override public void call(sqlite3 db, String msg, int op){
|
@Override public void call(Sqlite db, String msg, int op){
|
||||||
switch(op){
|
switch(op){
|
||||||
case 0: outln("Opening db: ",db); break;
|
case 0: outln("Opening db: ",db); break;
|
||||||
case 1: outln("SQL ",db,": ",msg); break;
|
case 1: outln("SQL ",db,": ",msg); break;
|
||||||
case 2: outln("Closing db: ",db); break;
|
case 2: outln("Closing db: ",db); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
int rc = CApi.sqlite3_config( log );
|
);
|
||||||
affirm( 0==rc );
|
|
||||||
rc = CApi.sqlite3_config( (ConfigSqllogCallback)null );
|
|
||||||
affirm( 0==rc );
|
|
||||||
rc = CApi.sqlite3_config( log );
|
|
||||||
affirm( 0==rc );
|
|
||||||
}else{
|
}else{
|
||||||
outln("WARNING: -sqllog is not active because library was built ",
|
outln("WARNING: -sqllog is not active because library was built ",
|
||||||
"without SQLITE_ENABLE_SQLLOG.");
|
"without SQLITE_ENABLE_SQLLOG.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( configLog ){
|
if( configLog ){
|
||||||
final ConfigLogCallback log = new ConfigLogCallback() {
|
Sqlite.libConfigLog( new Sqlite.ConfigLog() {
|
||||||
@Override public void call(int code, String msg){
|
@Override public void call(int code, String msg){
|
||||||
outln("ConfigLogCallback: ",ResultCode.getEntryForInt(code),": ", msg);
|
outln("ConfigLog: ",Sqlite.errstr(code),": ", msg);
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
int rc = CApi.sqlite3_config( log );
|
);
|
||||||
affirm( 0==rc );
|
|
||||||
rc = CApi.sqlite3_config( (ConfigLogCallback)null );
|
|
||||||
affirm( 0==rc );
|
|
||||||
rc = CApi.sqlite3_config( log );
|
|
||||||
affirm( 0==rc );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
quietMode = squelchTestOutput;
|
quietMode = squelchTestOutput;
|
||||||
@ -1152,39 +1132,16 @@ public class Tester2 implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final long timeStart = System.currentTimeMillis();
|
final long timeStart = System.currentTimeMillis();
|
||||||
int nLoop = 0;
|
|
||||||
switch( CApi.sqlite3_threadsafe() ){ /* Sanity checking */
|
|
||||||
case 0:
|
|
||||||
affirm( CApi.SQLITE_ERROR==CApi.sqlite3_config( CApi.SQLITE_CONFIG_SINGLETHREAD ),
|
|
||||||
"Could not switch to single-thread mode." );
|
|
||||||
affirm( CApi.SQLITE_ERROR==CApi.sqlite3_config( CApi.SQLITE_CONFIG_MULTITHREAD ),
|
|
||||||
"Could switch to multithread mode." );
|
|
||||||
affirm( CApi.SQLITE_ERROR==CApi.sqlite3_config( CApi.SQLITE_CONFIG_SERIALIZED ),
|
|
||||||
"Could not switch to serialized threading mode." );
|
|
||||||
outln("This is a single-threaded build. Not using threads.");
|
|
||||||
nThread = 1;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
affirm( 0==CApi.sqlite3_config( CApi.SQLITE_CONFIG_SINGLETHREAD ),
|
|
||||||
"Could not switch to single-thread mode." );
|
|
||||||
affirm( 0==CApi.sqlite3_config( CApi.SQLITE_CONFIG_MULTITHREAD ),
|
|
||||||
"Could not switch to multithread mode." );
|
|
||||||
affirm( 0==CApi.sqlite3_config( CApi.SQLITE_CONFIG_SERIALIZED ),
|
|
||||||
"Could not switch to serialized threading mode." );
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
affirm( false, "Unhandled SQLITE_THREADSAFE value." );
|
|
||||||
}
|
|
||||||
outln("libversion_number: ",
|
outln("libversion_number: ",
|
||||||
CApi.sqlite3_libversion_number(),"\n",
|
Sqlite.libVersionNumber(),"\n",
|
||||||
CApi.sqlite3_libversion(),"\n",CApi.SQLITE_SOURCE_ID,"\n",
|
Sqlite.libVersion(),"\n",Sqlite.libSourceId(),"\n",
|
||||||
"SQLITE_THREADSAFE=",CApi.sqlite3_threadsafe());
|
"SQLITE_THREADSAFE=",CApi.sqlite3_threadsafe());
|
||||||
final boolean showLoopCount = (nRepeat>1 && nThread>1);
|
final boolean showLoopCount = (nRepeat>1 && nThread>1);
|
||||||
if( showLoopCount ){
|
if( showLoopCount ){
|
||||||
outln("Running ",nRepeat," loop(s) with ",nThread," thread(s) each.");
|
outln("Running ",nRepeat," loop(s) with ",nThread," thread(s) each.");
|
||||||
}
|
}
|
||||||
if( takeNaps ) outln("Napping between tests is enabled.");
|
if( takeNaps ) outln("Napping between tests is enabled.");
|
||||||
|
int nLoop = 0;
|
||||||
for( int n = 0; n < nRepeat; ++n ){
|
for( int n = 0; n < nRepeat; ++n ){
|
||||||
++nLoop;
|
++nLoop;
|
||||||
if( showLoopCount ) out((1==nLoop ? "" : " ")+nLoop);
|
if( showLoopCount ) out((1==nLoop ? "" : " ")+nLoop);
|
||||||
@ -1226,7 +1183,7 @@ public class Tester2 implements Runnable {
|
|||||||
if( doSomethingForDev ){
|
if( doSomethingForDev ){
|
||||||
CApi.sqlite3_jni_internal_details();
|
CApi.sqlite3_jni_internal_details();
|
||||||
}
|
}
|
||||||
affirm( 0==CApi.sqlite3_release_memory(1) );
|
affirm( 0==Sqlite.libReleaseMemory(1) );
|
||||||
CApi.sqlite3_shutdown();
|
CApi.sqlite3_shutdown();
|
||||||
int nMethods = 0;
|
int nMethods = 0;
|
||||||
int nNatives = 0;
|
int nNatives = 0;
|
||||||
|
@ -9,13 +9,13 @@
|
|||||||
** May you share freely, never taking more than you give.
|
** May you share freely, never taking more than you give.
|
||||||
**
|
**
|
||||||
*************************************************************************
|
*************************************************************************
|
||||||
** This file contains a set of tests for the sqlite3 JNI bindings.
|
** This file contains the ValueHolder utility class.
|
||||||
*/
|
*/
|
||||||
package org.sqlite.jni.wrapper1;
|
package org.sqlite.jni.wrapper1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A helper class which simply holds a single value. Its primary use
|
A helper class which simply holds a single value. Its primary use
|
||||||
is for communicating values out of anonymous classes, as doing so
|
is for communicating values out of anonymous callbacks, as doing so
|
||||||
requires a "final" reference.
|
requires a "final" reference.
|
||||||
*/
|
*/
|
||||||
public class ValueHolder<T> {
|
public class ValueHolder<T> {
|
||||||
|
@ -22,7 +22,7 @@ const tryOpfsVfs = async function(sqlite3){
|
|||||||
const opfs = sqlite3.opfs;
|
const opfs = sqlite3.opfs;
|
||||||
log("tryOpfsVfs()");
|
log("tryOpfsVfs()");
|
||||||
if(!sqlite3.opfs){
|
if(!sqlite3.opfs){
|
||||||
const e = toss("OPFS is not available.");
|
const e = new Error("OPFS is not available.");
|
||||||
error(e);
|
error(e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
55
manifest
55
manifest
@ -1,5 +1,5 @@
|
|||||||
C Merge\srecent\strunk\senhancements\sand\sfixes\sinto\sthe\sjsonb\sbranch.
|
C Merge\sall\sthe\slatest\senhancements\sand\sfixes\sfrom\strunk\sinto\sthe\sjsonb\sbranch.
|
||||||
D 2023-11-10T18:59:23.439
|
D 2023-11-15T13:23:40.944
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||||
@ -238,29 +238,30 @@ F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
|
|||||||
F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9
|
F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9
|
||||||
F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282
|
F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282
|
||||||
F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
|
F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
|
||||||
F ext/jni/GNUmakefile f2f3a31923293659b95225e932a286af1f2287d75bf88ad6c0fd1b9d9cd020d4
|
F ext/jni/GNUmakefile 59eb05f2a363bdfac8d15d66bed624bfe1ff289229184f3861b95f98a19cf4b2
|
||||||
F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4
|
F ext/jni/README.md d899789a9082a07b99bf30b1bbb6204ae57c060efcaa634536fa669323918f42
|
||||||
F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
|
F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
|
||||||
F ext/jni/src/c/sqlite3-jni.c 3774703e5865e7ff776b762de5386af8aa703e569bbb3a85c423c3f8473a3c26
|
F ext/jni/src/c/sqlite3-jni.c 6040c0de97644a1fb14bb589ee9f2f4208f6e6b165d14a0e33ed24945b118838
|
||||||
F ext/jni/src/c/sqlite3-jni.h 891444578550a7aa69fe5e0dedb3e6dedad752501ba99801f17797be51796934
|
F ext/jni/src/c/sqlite3-jni.h 913ab8e8fee432ae40f0e387c8231118d17053714703f5ded18202912a8a3fbf
|
||||||
F ext/jni/src/org/sqlite/jni/annotation/NotNull.java 02091a8112e33389f1c160f506cd413168c8dfacbeda608a4946c6e3557b7d5a
|
F ext/jni/src/org/sqlite/jni/annotation/Experimental.java 8603498634e41d0f7c70f661f64e05df64376562ea8f126829fd1e0cdd47e82b
|
||||||
F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 0b1879852707f752512d4db9d7edd0d8db2f0c2612316ce1c832715e012ff6ba
|
F ext/jni/src/org/sqlite/jni/annotation/NotNull.java 38e7e58a69b26dc100e458b31dfa3b2a7d67bc36d051325526ef1987d5bc8a24
|
||||||
|
F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 56e3dee1f3f703a545dfdeddc1c3d64d1581172b1ad01ffcae95c18547fafd90
|
||||||
F ext/jni/src/org/sqlite/jni/annotation/package-info.java 977b374aed9d5853cbf3438ba3b0940abfa2ea4574f702a2448ee143b98ac3ca
|
F ext/jni/src/org/sqlite/jni/annotation/package-info.java 977b374aed9d5853cbf3438ba3b0940abfa2ea4574f702a2448ee143b98ac3ca
|
||||||
F ext/jni/src/org/sqlite/jni/capi/AbstractCollationCallback.java 1afa90d3f236f79cc7fcd2497e111992644f7596fbc8e8bcf7f1908ae00acd6c
|
F ext/jni/src/org/sqlite/jni/capi/AbstractCollationCallback.java 1afa90d3f236f79cc7fcd2497e111992644f7596fbc8e8bcf7f1908ae00acd6c
|
||||||
F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java 0b72cdff61533b564d65b63418129656daa9a9f30e7e7be982bd5ab394b1dbd0
|
F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java 0b72cdff61533b564d65b63418129656daa9a9f30e7e7be982bd5ab394b1dbd0
|
||||||
F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java c045a5b47e02bb5f1af91973814a905f12048c428a3504fbc5266d1c1be3de5a
|
F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java c045a5b47e02bb5f1af91973814a905f12048c428a3504fbc5266d1c1be3de5a
|
||||||
F ext/jni/src/org/sqlite/jni/capi/AutoExtensionCallback.java 74cc4998a73d6563542ecb90804a3c4f4e828cb4bd69e61226d1a51f4646e759
|
F ext/jni/src/org/sqlite/jni/capi/AutoExtensionCallback.java 74cc4998a73d6563542ecb90804a3c4f4e828cb4bd69e61226d1a51f4646e759
|
||||||
F ext/jni/src/org/sqlite/jni/capi/BusyHandlerCallback.java 7b8e19810c42b0ad21a04b5d8c804b32ee5905d137148703f16a75b612c380ca
|
F ext/jni/src/org/sqlite/jni/capi/BusyHandlerCallback.java 7b8e19810c42b0ad21a04b5d8c804b32ee5905d137148703f16a75b612c380ca
|
||||||
F ext/jni/src/org/sqlite/jni/capi/CApi.java 92d443b08175c798e132a312f71b1a42140c60d473d35c149e3d95a45b6550f3
|
F ext/jni/src/org/sqlite/jni/capi/CApi.java d428a1fd3b827f01c55d10d21ff35e33e7dac9e8a1d92a8b5c7d7255e67407d8
|
||||||
F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b
|
F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b
|
||||||
F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a
|
F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a
|
||||||
F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab
|
F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab
|
||||||
F ext/jni/src/org/sqlite/jni/capi/CommitHookCallback.java 482f53dfec9e3ac2a9070d3fceebd56250932aaaf7c4f5bc8de29fc011416e0c
|
F ext/jni/src/org/sqlite/jni/capi/CommitHookCallback.java 482f53dfec9e3ac2a9070d3fceebd56250932aaaf7c4f5bc8de29fc011416e0c
|
||||||
F ext/jni/src/org/sqlite/jni/capi/ConfigLogCallback.java b995ca412f59b631803b93aa5b3684fce62e335d1e123207084c054abfd488d4
|
F ext/jni/src/org/sqlite/jni/capi/ConfigLogCallback.java b995ca412f59b631803b93aa5b3684fce62e335d1e123207084c054abfd488d4
|
||||||
F ext/jni/src/org/sqlite/jni/capi/ConfigSqllogCallback.java 701f2e4d8bdeb27cfbeeb56315d15b13d8752b0fdbca705f31bd4366c58d8a33
|
F ext/jni/src/org/sqlite/jni/capi/ConfigSqlLogCallback.java e5723900b6458bc6288f52187090a78ebe0a20f403ac7c887ec9061dfe51aba7 w ext/jni/src/org/sqlite/jni/capi/ConfigSqllogCallback.java
|
||||||
F ext/jni/src/org/sqlite/jni/capi/NativePointerHolder.java b7036dcb1ef1b39f1f36ac605dde0ff1a24a9a01ade6aa1a605039443e089a61
|
F ext/jni/src/org/sqlite/jni/capi/NativePointerHolder.java b7036dcb1ef1b39f1f36ac605dde0ff1a24a9a01ade6aa1a605039443e089a61
|
||||||
F ext/jni/src/org/sqlite/jni/capi/OutputPointer.java 68f60aec7aeb5cd4e5fb83449037f668c63cb99f682ee1036cc226d0cbd909b9
|
F ext/jni/src/org/sqlite/jni/capi/OutputPointer.java 246b0e66c4603f41c567105a21189d138aaf8c58203ecd4928802333da553e7c
|
||||||
F ext/jni/src/org/sqlite/jni/capi/PrepareMultiCallback.java aca8f9fa72e3b6602bc9a7dd3ae9f5b2808103fbbee9b2749dc96c19cdc261a1
|
F ext/jni/src/org/sqlite/jni/capi/PrepareMultiCallback.java 97352091abd7556167f4799076396279a51749fdae2b72a6ba61cd39b3df0359
|
||||||
F ext/jni/src/org/sqlite/jni/capi/PreupdateHookCallback.java efcf57545c5e282d1dd332fa63329b3b218d98f356ef107a9dbe3979be82213a
|
F ext/jni/src/org/sqlite/jni/capi/PreupdateHookCallback.java efcf57545c5e282d1dd332fa63329b3b218d98f356ef107a9dbe3979be82213a
|
||||||
F ext/jni/src/org/sqlite/jni/capi/ProgressHandlerCallback.java 01bc0c238eed2d5f93c73522cb7849a445cc9098c2ed1e78248fa20ed1cfde5b
|
F ext/jni/src/org/sqlite/jni/capi/ProgressHandlerCallback.java 01bc0c238eed2d5f93c73522cb7849a445cc9098c2ed1e78248fa20ed1cfde5b
|
||||||
F ext/jni/src/org/sqlite/jni/capi/ResultCode.java 8141171f1bcf9f46eef303b9d3c5dc2537a25ad1628f3638398d8a60cacefa7f
|
F ext/jni/src/org/sqlite/jni/capi/ResultCode.java 8141171f1bcf9f46eef303b9d3c5dc2537a25ad1628f3638398d8a60cacefa7f
|
||||||
@ -269,10 +270,10 @@ F ext/jni/src/org/sqlite/jni/capi/SQLFunction.java 0d1e9afc9ff8a2adb94a155b72385
|
|||||||
F ext/jni/src/org/sqlite/jni/capi/SQLTester.java 09bee15aa0eedac68d767ae21d9a6a62a31ade59182a3ccbf036d6463d9e30b1
|
F ext/jni/src/org/sqlite/jni/capi/SQLTester.java 09bee15aa0eedac68d767ae21d9a6a62a31ade59182a3ccbf036d6463d9e30b1
|
||||||
F ext/jni/src/org/sqlite/jni/capi/ScalarFunction.java 93b9700fca4c68075ccab12fe0fbbc76c91cafc9f368e835b9bd7cd7732c8615
|
F ext/jni/src/org/sqlite/jni/capi/ScalarFunction.java 93b9700fca4c68075ccab12fe0fbbc76c91cafc9f368e835b9bd7cd7732c8615
|
||||||
F ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java addf120e0e76e5be1ff2260daa7ce305ff9b5fafd64153a7a28e9d8f000a815f
|
F ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java addf120e0e76e5be1ff2260daa7ce305ff9b5fafd64153a7a28e9d8f000a815f
|
||||||
F ext/jni/src/org/sqlite/jni/capi/Tester1.java b1a0c015d92a8d0c07a8f6751e9b057557cec9d803e002d48ee5f3b9963abd55
|
F ext/jni/src/org/sqlite/jni/capi/Tester1.java e5fa17301b7266c1cbe4bcce67788e08e45871c7c72c153d515abb37e501de0a
|
||||||
F ext/jni/src/org/sqlite/jni/capi/TraceV2Callback.java 0a25e117a0daae3394a77f24713e36d7b44c67d6e6d30e9e1d56a63442eef723
|
F ext/jni/src/org/sqlite/jni/capi/TraceV2Callback.java 0a25e117a0daae3394a77f24713e36d7b44c67d6e6d30e9e1d56a63442eef723
|
||||||
F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java c8bdf7848e6599115d601bcc9427ff902cb33129b9be32870ac6808e04b6ae56
|
F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java c8bdf7848e6599115d601bcc9427ff902cb33129b9be32870ac6808e04b6ae56
|
||||||
F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 22d365746a78c5cd7ae10c39444eb7bbf1a819aad4bb7eb77b1edc47773a3950
|
F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 2ce069f3e007fdbbe1f4e507a5a407fc9679da31a0aa40985e6317ed4d5ec7b5
|
||||||
F ext/jni/src/org/sqlite/jni/capi/WindowFunction.java caf4396f91b2567904cf94bc538a069fd62260d975bd037d15a02a890ed1ef9e
|
F ext/jni/src/org/sqlite/jni/capi/WindowFunction.java caf4396f91b2567904cf94bc538a069fd62260d975bd037d15a02a890ed1ef9e
|
||||||
F ext/jni/src/org/sqlite/jni/capi/XDestroyCallback.java f3abb8dd7381f53ebba909437090caf68200f06717b8a7d6aa96fa3e8133117d
|
F ext/jni/src/org/sqlite/jni/capi/XDestroyCallback.java f3abb8dd7381f53ebba909437090caf68200f06717b8a7d6aa96fa3e8133117d
|
||||||
F ext/jni/src/org/sqlite/jni/capi/package-info.java 08ff986a65d2be9162442c82d28a65ce431d826f188520717c2ecb1484d0a50e
|
F ext/jni/src/org/sqlite/jni/capi/package-info.java 08ff986a65d2be9162442c82d28a65ce431d826f188520717c2ecb1484d0a50e
|
||||||
@ -296,10 +297,10 @@ F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe
|
|||||||
F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483
|
F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483
|
||||||
F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03
|
F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03
|
||||||
F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 27b141f5914c7cb0e40e90a301d5e05b77f3bd42236834a68031b7086381fafd
|
F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 27b141f5914c7cb0e40e90a301d5e05b77f3bd42236834a68031b7086381fafd
|
||||||
F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 0ef62b43b1d6a9f044e106b56c9ea42bc7150b82ebeb79cff58f5be08cb9a435
|
F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java ada39f18e4e3e9d4868dadbc3f7bfe1c6c7fde74fb1fb2954c3f0f70120b805c
|
||||||
F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 982538ddb4c0719ef87dfa664cd137b09890b546029a7477810bd64d4c47ee35
|
F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 982538ddb4c0719ef87dfa664cd137b09890b546029a7477810bd64d4c47ee35
|
||||||
F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 40806dbbf8e120f115e33255d1813db13b40f0a598869e299a947a580429939b
|
F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java ce45f2ec85facbb73690096547ed166e7be82299e3d92eaa206f82b60a6ec969
|
||||||
F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af
|
F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java a84e90c43724a69c2ecebd601bc8e5139f869b7d08cb705c77ef757dacdd0593
|
||||||
F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java c7d1452f9ff26175b3c19bbf273116cc2846610af68e01756d755f037fe7319f
|
F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java c7d1452f9ff26175b3c19bbf273116cc2846610af68e01756d755f037fe7319f
|
||||||
F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745
|
F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745
|
||||||
F ext/jni/src/tests/000-001-ignored.test e17e874c6ab3c437f1293d88093cf06286083b65bf162317f91bbfd92f961b70
|
F ext/jni/src/tests/000-001-ignored.test e17e874c6ab3c437f1293d88093cf06286083b65bf162317f91bbfd92f961b70
|
||||||
@ -633,7 +634,7 @@ F ext/wasm/split-speedtest1-script.sh a3e271938d4d14ee49105eb05567c6a69ba4c1f129
|
|||||||
F ext/wasm/sql/000-mandelbrot.sql 775337a4b80938ac8146aedf88808282f04d02d983d82675bd63d9c2d97a15f0
|
F ext/wasm/sql/000-mandelbrot.sql 775337a4b80938ac8146aedf88808282f04d02d983d82675bd63d9c2d97a15f0
|
||||||
F ext/wasm/sql/001-sudoku.sql 35b7cb7239ba5d5f193bc05ec379bcf66891bce6f2a5b3879f2f78d0917299b5
|
F ext/wasm/sql/001-sudoku.sql 35b7cb7239ba5d5f193bc05ec379bcf66891bce6f2a5b3879f2f78d0917299b5
|
||||||
F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555e685bce3da8c3f
|
F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555e685bce3da8c3f
|
||||||
F ext/wasm/test-opfs-vfs.js f09266873e1a34d9bdb6d3981ec8c9e382f31f215c9fd2f9016d2394b8ae9b7b
|
F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c
|
||||||
F ext/wasm/tester1-worker.html ebc4b820a128963afce328ecf63ab200bd923309eb939f4110510ab449e9814c
|
F ext/wasm/tester1-worker.html ebc4b820a128963afce328ecf63ab200bd923309eb939f4110510ab449e9814c
|
||||||
F ext/wasm/tester1.c-pp.html 1c1bc78b858af2019e663b1a31e76657b73dc24bede28ca92fbe917c3a972af2
|
F ext/wasm/tester1.c-pp.html 1c1bc78b858af2019e663b1a31e76657b73dc24bede28ca92fbe917c3a972af2
|
||||||
F ext/wasm/tester1.c-pp.js a92dc256738dbd1b50f142d1fd0c835294ba09b7bb6526650360e942f88cb63f
|
F ext/wasm/tester1.c-pp.js a92dc256738dbd1b50f142d1fd0c835294ba09b7bb6526650360e942f88cb63f
|
||||||
@ -674,7 +675,7 @@ F src/date.c 3b8d02977d160e128469de38493b4085f7c5cf4073193459909a6af3cf6d7c91
|
|||||||
F src/dbpage.c 80e46e1df623ec40486da7a5086cb723b0275a6e2a7b01d9f9b5da0f04ba2782
|
F src/dbpage.c 80e46e1df623ec40486da7a5086cb723b0275a6e2a7b01d9f9b5da0f04ba2782
|
||||||
F src/dbstat.c 3b677254d512fcafd4d0b341bf267b38b235ccfddbef24f9154e19360fa22e43
|
F src/dbstat.c 3b677254d512fcafd4d0b341bf267b38b235ccfddbef24f9154e19360fa22e43
|
||||||
F src/delete.c cb766727c78e715f9fb7ec8a7d03658ed2a3016343ca687acfcec9083cdca500
|
F src/delete.c cb766727c78e715f9fb7ec8a7d03658ed2a3016343ca687acfcec9083cdca500
|
||||||
F src/expr.c 433f12e1237524482b0b2681c07da3cd54ddada2a625237cecde419f3e3a2553
|
F src/expr.c 88629faed0b576b7ffa3d82ce44cbcee4ed476a2bf1ea4e1d6bf1260e03b19cb
|
||||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||||
F src/fkey.c a47610f0a5c6cb0ad79f8fcef039c01833dec0c751bb695f28dc0ec6a4c3ba00
|
F src/fkey.c a47610f0a5c6cb0ad79f8fcef039c01833dec0c751bb695f28dc0ec6a4c3ba00
|
||||||
F src/func.c 472f6dcfa39cf54f89a6aec76c79c225fb880a6c14469c15d361331662b9bf43
|
F src/func.c 472f6dcfa39cf54f89a6aec76c79c225fb880a6c14469c15d361331662b9bf43
|
||||||
@ -724,7 +725,7 @@ F src/printf.c 9da63b9ae1c14789bcae12840f5d800fd9302500cd2d62733fac77f0041b4750
|
|||||||
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
|
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
|
||||||
F src/resolve.c d017bad7ba8e778617701a0e986fdeb393d67d6afa84fb28ef4e8b8ad2acf916
|
F src/resolve.c d017bad7ba8e778617701a0e986fdeb393d67d6afa84fb28ef4e8b8ad2acf916
|
||||||
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
|
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
|
||||||
F src/select.c 47797c57c5ee2ad183b34a2e5d643ec7519366686bbe44a9a81df9fe304f28a7
|
F src/select.c 503331aca8785254a7bf3d74ab338a99118fa297e1184a4dde33b3cdf7a9d341
|
||||||
F src/shell.c.in 297625a1ba6ea1c08bc2ea1b838b646cad309b62bf08df0e379355629404f140
|
F src/shell.c.in 297625a1ba6ea1c08bc2ea1b838b646cad309b62bf08df0e379355629404f140
|
||||||
F src/sqlite.h.in 4f841d3d117b830ee5ee45e8d89ceff1195f3ebb72d041ace8d116ba4c103b35
|
F src/sqlite.h.in 4f841d3d117b830ee5ee45e8d89ceff1195f3ebb72d041ace8d116ba4c103b35
|
||||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||||
@ -787,7 +788,7 @@ F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394
|
|||||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||||
F src/tokenize.c 23d9f4539880b40226254ad9072f4ecf12eb1902e62aea47aac29928afafcfd5
|
F src/tokenize.c 23d9f4539880b40226254ad9072f4ecf12eb1902e62aea47aac29928afafcfd5
|
||||||
F src/treeview.c 62fafcd31eea60b718f8daf448116b7b19f90134ebc6c20777ddbb07f56a3d28
|
F src/treeview.c c6fc972683fd00f975d8b32a81c1f25d2fb7d4035366bf45c9f5622d3ccd70ee
|
||||||
F src/trigger.c 0905b96b04bb6658509f711a8207287f1315cdbc3df1a1b13ba6483c8e341c81
|
F src/trigger.c 0905b96b04bb6658509f711a8207287f1315cdbc3df1a1b13ba6483c8e341c81
|
||||||
F src/update.c 6904814dd62a7a93bbb86d9f1419c7f134a9119582645854ab02b36b676d9f92
|
F src/update.c 6904814dd62a7a93bbb86d9f1419c7f134a9119582645854ab02b36b676d9f92
|
||||||
F src/upsert.c fa125a8d3410ce9a97b02cb50f7ae68a2476c405c76aa692d3acf6b8586e9242
|
F src/upsert.c fa125a8d3410ce9a97b02cb50f7ae68a2476c405c76aa692d3acf6b8586e9242
|
||||||
@ -809,7 +810,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
|||||||
F src/wal.c bba7db5dae3ffe2c6b9c173fc10be4b570b125e985cb5b95a6c22716213adde4
|
F src/wal.c bba7db5dae3ffe2c6b9c173fc10be4b570b125e985cb5b95a6c22716213adde4
|
||||||
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
|
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
|
||||||
F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2
|
F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2
|
||||||
F src/where.c 5b14ccd10ed4cfa3d62fa83bfa623aeda4d26dbc9f451c895a21797f0a024436
|
F src/where.c 1fdc69ce1333e9bd6d7d3df9fa5af1373a3f5bfdd52108d1dbc0ca85a55f777e
|
||||||
F src/whereInt.h 4b38c5889514e3aead3f27d0ee9a26e47c3f150efc59e2a8b4e3bc8835e4d7a1
|
F src/whereInt.h 4b38c5889514e3aead3f27d0ee9a26e47c3f150efc59e2a8b4e3bc8835e4d7a1
|
||||||
F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1
|
F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1
|
||||||
F src/whereexpr.c dc5096eca5ed503999be3bdee8a90c51361289a678d396a220912e9cb73b3c00
|
F src/whereexpr.c dc5096eca5ed503999be3bdee8a90c51361289a678d396a220912e9cb73b3c00
|
||||||
@ -819,7 +820,7 @@ F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867d
|
|||||||
F test/affinity3.test f094773025eddf31135c7ad4cde722b7696f8eb07b97511f98585addf2a510a9
|
F test/affinity3.test f094773025eddf31135c7ad4cde722b7696f8eb07b97511f98585addf2a510a9
|
||||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||||
F test/aggfault.test 777f269d0da5b0c2524c7ff6d99ae9a93db4f1b1839a914dd2a12e3035c29829
|
F test/aggfault.test 777f269d0da5b0c2524c7ff6d99ae9a93db4f1b1839a914dd2a12e3035c29829
|
||||||
F test/aggnested.test 7929208e173f5dbdbe8f67afbc59c07db99199d39ba5ce2d8a16be2c63600f53
|
F test/aggnested.test ce85a6af7d59c3109e35c5f03b2cd11da1a9b1417371e2f942102d0f0d77fd62
|
||||||
F test/aggorderby.test e6b98dbbf3ababa96892435d387de2dcf602ef02c2b848d2d817473066f154ba
|
F test/aggorderby.test e6b98dbbf3ababa96892435d387de2dcf602ef02c2b848d2d817473066f154ba
|
||||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||||
F test/all.test 2ecb8bbd52416642e41c9081182a8df05d42c75637afd4488aace78cc4b69e13
|
F test/all.test 2ecb8bbd52416642e41c9081182a8df05d42c75637afd4488aace78cc4b69e13
|
||||||
@ -1309,7 +1310,7 @@ F test/joinC.test 1f1a602c2127f55f136e2cbd3bf2d26546614bf8cffe5902ec1ac9c07f87f2
|
|||||||
F test/joinD.test 2ce62e7353a0702ca5e70008faf319c1d4686aa19fba34275c6d1da0e960be28
|
F test/joinD.test 2ce62e7353a0702ca5e70008faf319c1d4686aa19fba34275c6d1da0e960be28
|
||||||
F test/joinE.test d5d182f3812771e2c0d97c9dcf5dbe4c41c8e21c82560e59358731c4a3981d6b
|
F test/joinE.test d5d182f3812771e2c0d97c9dcf5dbe4c41c8e21c82560e59358731c4a3981d6b
|
||||||
F test/joinF.test 53dd66158806823ea680dd7543b5406af151b5aafa5cd06a7f3231cd94938127
|
F test/joinF.test 53dd66158806823ea680dd7543b5406af151b5aafa5cd06a7f3231cd94938127
|
||||||
F test/joinH.test c4301c738b05b845f273b0d94de74e953626d809dc945352909aedb199b42e5f
|
F test/joinH.test f69e5b53b7d887914e854b6a131efbed4ea9f5ca52bdab81788bfc3e79299f43
|
||||||
F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497
|
F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497
|
||||||
F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4
|
F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4
|
||||||
F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e
|
F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e
|
||||||
@ -2140,8 +2141,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 72393b003f9f8675e4a124dddd09607b5b34ddefe56716b283c68c0982fb3d96 ac39800bb2685fa287c7d834faed75f0bc61320ef986de314392d6eadb574d30
|
P 091a5f058dfe2115fb9213655b34f00bcec80aebb299b571975cfe4ecd5ec206 9264955e6e47aa8fc3a6f8bed192a6c12f43de49f7fba2e0cc080e47abedde14
|
||||||
R 6d3d51033686bbc98309c106a216587b
|
R cb95d20763613c633369d4c9e1ac8345
|
||||||
U drh
|
U drh
|
||||||
Z 403b43107da0aaabcdd1c627364824ec
|
Z c8298398287bfd474381f2a9e0abdbd8
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
@ -1 +1 @@
|
|||||||
091a5f058dfe2115fb9213655b34f00bcec80aebb299b571975cfe4ecd5ec206
|
ba91408f4c044feda003ef93784ccefb619f99ab64379ced481ee8e9e890fd41
|
@ -6769,13 +6769,14 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
|||||||
case TK_AGG_FUNCTION: {
|
case TK_AGG_FUNCTION: {
|
||||||
if( (pNC->ncFlags & NC_InAggFunc)==0
|
if( (pNC->ncFlags & NC_InAggFunc)==0
|
||||||
&& pWalker->walkerDepth==pExpr->op2
|
&& pWalker->walkerDepth==pExpr->op2
|
||||||
|
&& pExpr->pAggInfo==0
|
||||||
){
|
){
|
||||||
/* Check to see if pExpr is a duplicate of another aggregate
|
/* Check to see if pExpr is a duplicate of another aggregate
|
||||||
** function that is already in the pAggInfo structure
|
** function that is already in the pAggInfo structure
|
||||||
*/
|
*/
|
||||||
struct AggInfo_func *pItem = pAggInfo->aFunc;
|
struct AggInfo_func *pItem = pAggInfo->aFunc;
|
||||||
for(i=0; i<pAggInfo->nFunc; i++, pItem++){
|
for(i=0; i<pAggInfo->nFunc; i++, pItem++){
|
||||||
if( pItem->pFExpr==pExpr ) break;
|
if( NEVER(pItem->pFExpr==pExpr) ) break;
|
||||||
if( sqlite3ExprCompare(0, pItem->pFExpr, pExpr, -1)==0 ){
|
if( sqlite3ExprCompare(0, pItem->pFExpr, pExpr, -1)==0 ){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -7416,7 +7416,7 @@ int sqlite3Select(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(j=pTabList->nSrc-1; j>=i; j--){
|
for(j=pTabList->nSrc-1; j>=0; j--){
|
||||||
pTabList->a[j].fg.jointype &= ~JT_LTORJ;
|
pTabList->a[j].fg.jointype &= ~JT_LTORJ;
|
||||||
if( pTabList->a[j].fg.jointype & JT_RIGHT ) break;
|
if( pTabList->a[j].fg.jointype & JT_RIGHT ) break;
|
||||||
}
|
}
|
||||||
|
@ -781,7 +781,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
|||||||
assert( pExpr->x.pList->nExpr==2 );
|
assert( pExpr->x.pList->nExpr==2 );
|
||||||
pY = pExpr->x.pList->a[0].pExpr;
|
pY = pExpr->x.pList->a[0].pExpr;
|
||||||
pZ = pExpr->x.pList->a[1].pExpr;
|
pZ = pExpr->x.pList->a[1].pExpr;
|
||||||
sqlite3TreeViewLine(pView, "BETWEEN");
|
sqlite3TreeViewLine(pView, "BETWEEN%s", zFlgs);
|
||||||
sqlite3TreeViewExpr(pView, pX, 1);
|
sqlite3TreeViewExpr(pView, pX, 1);
|
||||||
sqlite3TreeViewExpr(pView, pY, 1);
|
sqlite3TreeViewExpr(pView, pY, 1);
|
||||||
sqlite3TreeViewExpr(pView, pZ, 0);
|
sqlite3TreeViewExpr(pView, pZ, 0);
|
||||||
|
12
src/where.c
12
src/where.c
@ -678,12 +678,22 @@ static void translateColumnToCopy(
|
|||||||
for(; iStart<iEnd; iStart++, pOp++){
|
for(; iStart<iEnd; iStart++, pOp++){
|
||||||
if( pOp->p1!=iTabCur ) continue;
|
if( pOp->p1!=iTabCur ) continue;
|
||||||
if( pOp->opcode==OP_Column ){
|
if( pOp->opcode==OP_Column ){
|
||||||
|
#ifdef SQLITE_DEBUG
|
||||||
|
if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
|
||||||
|
printf("TRANSLATE OP_Column to OP_Copy at %d\n", iStart);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
pOp->opcode = OP_Copy;
|
pOp->opcode = OP_Copy;
|
||||||
pOp->p1 = pOp->p2 + iRegister;
|
pOp->p1 = pOp->p2 + iRegister;
|
||||||
pOp->p2 = pOp->p3;
|
pOp->p2 = pOp->p3;
|
||||||
pOp->p3 = 0;
|
pOp->p3 = 0;
|
||||||
pOp->p5 = 2; /* Cause the MEM_Subtype flag to be cleared */
|
pOp->p5 = 2; /* Cause the MEM_Subtype flag to be cleared */
|
||||||
}else if( pOp->opcode==OP_Rowid ){
|
}else if( pOp->opcode==OP_Rowid ){
|
||||||
|
#ifdef SQLITE_DEBUG
|
||||||
|
if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
|
||||||
|
printf("TRANSLATE OP_Rowid to OP_Sequence at %d\n", iStart);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
pOp->opcode = OP_Sequence;
|
pOp->opcode = OP_Sequence;
|
||||||
pOp->p1 = iAutoidxCur;
|
pOp->p1 = iAutoidxCur;
|
||||||
#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
|
#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
|
||||||
@ -5818,7 +5828,7 @@ static SQLITE_NOINLINE void whereAddIndexedExpr(
|
|||||||
FuncDef *pDef;
|
FuncDef *pDef;
|
||||||
sqlite3 *db = pParse->db;
|
sqlite3 *db = pParse->db;
|
||||||
assert( ExprUseXList(pExpr) );
|
assert( ExprUseXList(pExpr) );
|
||||||
n = ALWAYS(pExpr->x.pList) ? pExpr->x.pList->nExpr : 0;
|
n = pExpr->x.pList ? pExpr->x.pList->nExpr : 0;
|
||||||
pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
|
pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
|
||||||
if( pDef==0 || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){
|
if( pDef==0 || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){
|
||||||
continue;
|
continue;
|
||||||
|
@ -412,7 +412,65 @@ do_execsql_test 8.2 {
|
|||||||
) FROM t1;
|
) FROM t1;
|
||||||
} {123}
|
} {123}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# dbsqlfuzz 04408efc51ae46897c4c122b407412045ed221b4
|
||||||
|
#
|
||||||
|
reset_db
|
||||||
|
|
||||||
|
do_execsql_test 9.1 {
|
||||||
|
WITH out(i, j, k) AS (
|
||||||
|
VALUES(1234, 5678, 9012)
|
||||||
|
)
|
||||||
|
SELECT (
|
||||||
|
SELECT (
|
||||||
|
SELECT min(abc) = ( SELECT ( SELECT 1234 fROM (SELECT abc) ) )
|
||||||
|
FROM (
|
||||||
|
SELECT sum( out.i ) + ( SELECT sum( out.i ) ) AS abc FROM (SELECT out.j)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) FROM out;
|
||||||
|
} {0}
|
||||||
|
|
||||||
|
do_execsql_test 9.2 {
|
||||||
|
CREATE TABLE t1(a);
|
||||||
|
CREATE TABLE t2(b);
|
||||||
|
INSERT INTO t1 VALUES(1), (2), (3);
|
||||||
|
INSERT INTO t2 VALUES(4), (5), (6);
|
||||||
|
|
||||||
|
SELECT (
|
||||||
|
SELECT min(y) + (SELECT x) FROM (
|
||||||
|
SELECT sum(a) AS x, b AS y FROM t2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
FROM t1;
|
||||||
|
} {10}
|
||||||
|
|
||||||
|
do_execsql_test 9.3 {
|
||||||
|
SELECT (
|
||||||
|
SELECT min(y) + (SELECT (SELECT x)) FROM (
|
||||||
|
SELECT sum(a) AS x, b AS y FROM t2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
FROM t1;
|
||||||
|
} {10}
|
||||||
|
|
||||||
|
do_execsql_test 9.4 {
|
||||||
|
SELECT (
|
||||||
|
SELECT (SELECT x) FROM (
|
||||||
|
SELECT sum(a) AS x, b AS y FROM t2
|
||||||
|
) GROUP BY y
|
||||||
|
)
|
||||||
|
FROM t1;
|
||||||
|
} {6}
|
||||||
|
|
||||||
|
do_execsql_test 9.5 {
|
||||||
|
SELECT (
|
||||||
|
SELECT (SELECT (SELECT x)) FROM (
|
||||||
|
SELECT sum(a) AS x, b AS y FROM t2
|
||||||
|
) GROUP BY y
|
||||||
|
)
|
||||||
|
FROM t1;
|
||||||
|
} {6}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -290,5 +290,23 @@ do_execsql_test 11.3 {
|
|||||||
SELECT * FROM t1 LEFT JOIN t2 RIGHT JOIN t3 ON (t2.c=10) WHERE t1.a=1
|
SELECT * FROM t1 LEFT JOIN t2 RIGHT JOIN t3 ON (t2.c=10) WHERE t1.a=1
|
||||||
} {}
|
} {}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
reset_db
|
||||||
|
|
||||||
|
do_execsql_test 12.1 {
|
||||||
|
CREATE TABLE t1(a1 INT, b1 TEXT);
|
||||||
|
INSERT INTO t1 VALUES(88,'');
|
||||||
|
CREATE TABLE t2(c2 INT, d2 TEXT);
|
||||||
|
INSERT INTO t2 VALUES(88,'');
|
||||||
|
CREATE TABLE t3(e3 TEXT PRIMARY KEY);
|
||||||
|
INSERT INTO t3 VALUES('');
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 12.2 {
|
||||||
|
SELECT * FROM t1 LEFT JOIN t2 ON true RIGHT JOIN t3 ON d2=e3 WHERE c2 BETWEEN NULL AND a1;
|
||||||
|
}
|
||||||
|
do_execsql_test 12.3 {
|
||||||
|
SELECT * FROM t1 LEFT JOIN t2 ON true RIGHT JOIN t3 ON d2=e3 WHERE c2 BETWEEN NULL AND a1;
|
||||||
|
}
|
||||||
|
|
||||||
finish_test
|
finish_test
|
||||||
|
Loading…
Reference in New Issue
Block a user