mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-01 06:27:03 +03:00
Add more JNI docs, tests, and a handful of Java-side overloads.
FossilOrigin-Name: d19a431facbde6a6b960664674753ee85d2c051a76109ce7db0b079c65fbdea0
This commit is contained in:
@ -223,19 +223,18 @@ $(sqlite3-jni.h): $(sqlite3-jni.h.in) $(MAKEFILE)
|
||||
$(sqlite3-jni.dll): $(sqlite3-jni.h) $(sqlite3.c) $(sqlite3.h)
|
||||
$(sqlite3-jni.dll): $(dir.bld.c) $(sqlite3-jni.c) $(SQLite3Jni.java) $(MAKEFILE)
|
||||
$(CC) $(sqlite3-jni.dll.cflags) $(SQLITE_OPT) \
|
||||
$(sqlite3-jni.c) -shared -o $@ -lpthread
|
||||
$(sqlite3-jni.c) -shared -o $@
|
||||
all: $(sqlite3-jni.dll)
|
||||
|
||||
.PHONY: test
|
||||
test.flags ?= -v
|
||||
test.flags ?=
|
||||
test.main.flags = -ea -Djava.library.path=$(dir.bld.c) \
|
||||
$(java.flags) -cp $(classpath) \
|
||||
org.sqlite.jni.Tester1
|
||||
test: $(SQLite3Jni.class) $(sqlite3-jni.dll)
|
||||
$(bin.java) -ea -Djava.library.path=$(dir.bld.c) \
|
||||
$(java.flags) -cp $(classpath) \
|
||||
org.sqlite.jni.Tester1 $(test.flags)
|
||||
test-mt: $(SQLite3Jni.class) $(sqlite3-jni.dll)
|
||||
$(bin.java) -ea -Djava.library.path=$(dir.bld.c) \
|
||||
$(java.flags) -cp $(classpath) \
|
||||
org.sqlite.jni.Tester1 -t 7 -r 50 -shuffle $(test.flags)
|
||||
$(bin.java) $(test.main.flags) $(test.flags)
|
||||
@echo "Again in multi-threaded mode:"
|
||||
$(bin.java) $(test.main.flags) -t 5 -r 20 -shuffle $(test.flags)
|
||||
|
||||
tester.scripts := $(sort $(wildcard $(dir.src)/tests/*.test))
|
||||
tester.flags ?= # --verbose
|
||||
@ -271,7 +270,7 @@ endif
|
||||
|
||||
tester-ext: tester-local
|
||||
tester: tester-ext
|
||||
tests: test test-mt tester
|
||||
tests: test tester
|
||||
package.jar.in := $(abspath $(dir.src)/jar.in)
|
||||
CLEAN_FILES += $(package.jar.in)
|
||||
$(package.jar.in): $(MAKEFILE) $(CLASS_FILES.main)
|
||||
|
@ -16,7 +16,7 @@ Technical support is available in the forum:
|
||||
> **FOREWARNING:** this subproject is very much in development and
|
||||
subject to any number of changes. Please do not rely on any
|
||||
information about its API until this disclaimer is removed. The JNI
|
||||
bindgins released with version 3.43 are a "tech preview" and 3.44
|
||||
bindings released with version 3.43 are a "tech preview" and 3.44
|
||||
will be "final," at which point strong backward compatibility
|
||||
guarantees will apply.
|
||||
|
||||
@ -43,29 +43,34 @@ Non-goals:
|
||||
- Creation of high-level OO wrapper APIs. Clients are free to create
|
||||
them off of the C-style API.
|
||||
|
||||
|
||||
Hello World
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
```java
|
||||
import org.sqlite.jni.*;
|
||||
import static org.sqlite.jni.SQLite3Jni;
|
||||
import static SQLite3Jni.*;
|
||||
|
||||
...
|
||||
OutputPointer.sqlite3 out = new OutputPointer.sqlite3();
|
||||
int rc = sqlite3_open(":memory:", out);
|
||||
final sqlite3 db = out.take();
|
||||
|
||||
final sqlite3 db = sqlite3_open(":memory:");
|
||||
try {
|
||||
final int rc = sqlite3_errcode(db);
|
||||
if( 0 != rc ){
|
||||
if( null != db ){
|
||||
System.out.print("Error opening db: "+sqlite3_errmsg(db));
|
||||
sqlite3_close(db);
|
||||
}else{
|
||||
System.out.print("Error opening db: rc="+rc);
|
||||
}
|
||||
... handle error ...
|
||||
}
|
||||
|
||||
... use db ...
|
||||
|
||||
// ... else use the db ...
|
||||
}finally{
|
||||
// ALWAYS close databases using sqlite3_close() or sqlite3_close_v2()
|
||||
// when done with them. All of their active statement handles must
|
||||
// first have been passed to sqlite3_finalize().
|
||||
sqlite3_close_v2(db);
|
||||
}
|
||||
```
|
||||
|
||||
Building
|
||||
@ -86,28 +91,90 @@ $ make test
|
||||
$ make clean
|
||||
```
|
||||
|
||||
The jar distribution can be created with `make jar`.
|
||||
The jar distribution can be created with `make jar`, but note that it
|
||||
does not contain the binary DLL file. A different DLL is needed for
|
||||
each target platform.
|
||||
|
||||
|
||||
<a id='1to1ish'></a>
|
||||
One-to-One(-ish) Mapping to C
|
||||
========================================================================
|
||||
|
||||
This JNI binding aims to provide as close to a 1-to-1 experience with
|
||||
the C API as cross-language semantics allow. Changes are necessarily
|
||||
made where cross-language semantics do not allow a 1-to-1, and
|
||||
judiciously made where a 1-to-1 mapping would be unduly cumbersome to
|
||||
use in Java.
|
||||
the C API as cross-language semantics allow. Interface changes are
|
||||
necessarily made where cross-language semantics do not allow a 1-to-1,
|
||||
and judiciously made where a 1-to-1 mapping would be unduly cumbersome
|
||||
to use in Java. In all cases, this binding makes every effort to
|
||||
provide semantics compatible with the C API documentation even if the
|
||||
interface to those semantics is slightly different. Any cases which
|
||||
deviate from those semantics (either removing or adding semantics) are
|
||||
clearly documented.
|
||||
|
||||
Golden Rule: _Never_ Throw from Callbacks (Unless...)
|
||||
Where it makes sense to do so for usability, Java-side overloads are
|
||||
provided which accept or return data in alternative forms or provide
|
||||
sensible default argument values. In all such cases they are thin
|
||||
proxies around the corresponding C APIs and do not introduce new
|
||||
semantics.
|
||||
|
||||
In some very few cases, Java-specific capabilities have been added in
|
||||
new APIs, all of which have "_java" somewhere in their names.
|
||||
Examples include:
|
||||
|
||||
- `sqlite3_result_java_object()`
|
||||
- `sqlite3_column_java_object()`
|
||||
- `sqlite3_column_java_casted()`
|
||||
- `sqlite3_value_java_object()`
|
||||
- `sqlite3_value_java_casted()`
|
||||
|
||||
which, as one might surmise, collectively enable the passing of
|
||||
arbitrary Java objects from user-defined SQL functions through to the
|
||||
caller.
|
||||
|
||||
|
||||
Golden Rule: Garbage Collection Cannot Free SQLite Resources
|
||||
------------------------------------------------------------------------
|
||||
|
||||
It is important that all databases and prepared statement handles get
|
||||
cleaned up by client code. A database cannot be closed if it has open
|
||||
statement handles. `sqlite3_close()` fails if the db cannot be closed
|
||||
whereas `sqlite3_close_v2()` recognizes that case and marks the db as
|
||||
a "zombie," pending finalization when the library detects that all
|
||||
pending statements have been closed. Be aware that Java garbage
|
||||
collection _cannot_ close a database or finalize a prepared statement.
|
||||
Those things require explicit API calls.
|
||||
|
||||
|
||||
Golden Rule #2: _Never_ Throw from Callbacks (Unless...)
|
||||
------------------------------------------------------------------------
|
||||
|
||||
All routines in this API, barring explicitly documented exceptions,
|
||||
retain C-like semantics. For example, they are not permitted to throw
|
||||
or propagate exceptions and must return error information (if any) via
|
||||
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
|
||||
shouldn't be used. The APIs clearly mark function parameters which
|
||||
should not be null, but does not actively defend itself against such
|
||||
misuse. Some C-style APIs explicitly accept `null` as a no-op for
|
||||
usability's sake, and some of the JNI APIs deliberately return an
|
||||
error code, instead of segfaulting, when passed a `null`.
|
||||
|
||||
Client-defined callbacks _must never throw exceptions_ unless _very
|
||||
explicitly documented_ as being throw-safe. Exceptions are generally
|
||||
reserved for higher-level bindings which are constructed to
|
||||
specifically deal with them and ensure that they do not leak C-level
|
||||
resources. In some cases, callback handlers (see below) are permitted
|
||||
to throw, in which cases they get translated to C-level result codes
|
||||
and/or messages.
|
||||
resources. In some cases, callback handlers are permitted to throw, in
|
||||
which cases they get translated to C-level result codes and/or
|
||||
messages. If a callback which is not permitted to throw throws, its
|
||||
exception may trigger debug output but will otherwise be suppressed.
|
||||
|
||||
The reason some callbacks are permitted to throw and others not is
|
||||
because all such callbacks act as proxies for C function callback
|
||||
interfaces and some of those interfaces have no error-reporting
|
||||
mechanism. Those which are capable of propagating errors back through
|
||||
the library convert exceptions from callbacks into corresponding
|
||||
C-level error information. Those which cannot propagate errors
|
||||
necessarily suppress any exceptions in order to maintain the C-style
|
||||
semantics of the APIs.
|
||||
|
||||
|
||||
Awkward Callback Names
|
||||
@ -246,4 +313,5 @@ in-flux nature of this API.
|
||||
|
||||
Various APIs which accept callbacks, e.g. `sqlite3_trace_v2()` and
|
||||
`sqlite3_update_hook()`, use interfaces similar to those shown above.
|
||||
|
||||
Despite the changes in signature, the JNI layer makes every effort to
|
||||
provide the same semantics as the C API documentation suggests.
|
||||
|
@ -46,11 +46,13 @@ $(sqlite3-jni.dll):
|
||||
echo "*** to configure it for your system. ***"; \
|
||||
echo "************************************************************************"
|
||||
$(CC) $(CFLAGS) $(SQLITE_OPT) \
|
||||
src/sqlite3-jni.c -lpthread -shared -o $@
|
||||
src/sqlite3-jni.c -shared -o $@
|
||||
@echo "Now try running it with: make test"
|
||||
|
||||
test.flags = -Djava.library.path=. sqlite3-jni-*.jar
|
||||
test: $(sqlite3-jni.dll)
|
||||
java -jar -Djava.library.path=. sqlite3-jni-*.jar
|
||||
java -jar $(test.flags)
|
||||
java -jar $(test.flags) -t 7 -r 10 -shuffle
|
||||
|
||||
clean:
|
||||
-rm -f $(sqlite3-jni.dll)
|
||||
|
@ -1429,7 +1429,7 @@ typedef struct {
|
||||
} ResultJavaVal;
|
||||
|
||||
/* For use with sqlite3_result/value_pointer() */
|
||||
#define ResultJavaValuePtrStr "ResultJavaVal"
|
||||
#define ResultJavaValuePtrStr "org.sqlite.jni.ResultJavaVal"
|
||||
|
||||
/*
|
||||
** Allocate a new ResultJavaVal and assign it a new global ref of
|
||||
@ -1915,15 +1915,10 @@ JDECL(jint,1auto_1extension)(JENV_CSELF, jobject jAutoExt){
|
||||
|
||||
JDECL(jint,1bind_1blob)(JENV_CSELF, jobject jpStmt,
|
||||
jint ndx, jbyteArray baData, jint nMax){
|
||||
int rc;
|
||||
if(!baData){
|
||||
rc = sqlite3_bind_null(PtrGet_sqlite3_stmt(jpStmt), ndx);
|
||||
}else{
|
||||
jbyte * const pBuf = JBA_TOC(baData);
|
||||
rc = sqlite3_bind_blob(PtrGet_sqlite3_stmt(jpStmt), (int)ndx, pBuf, (int)nMax,
|
||||
SQLITE_TRANSIENT);
|
||||
jbyte * const pBuf = baData ? JBA_TOC(baData) : 0;
|
||||
int const rc = sqlite3_bind_blob(PtrGet_sqlite3_stmt(jpStmt), (int)ndx,
|
||||
pBuf, (int)nMax, SQLITE_TRANSIENT);
|
||||
JBA_RELEASE(baData,pBuf);
|
||||
}
|
||||
return (jint)rc;
|
||||
}
|
||||
|
||||
@ -1960,15 +1955,21 @@ JDECL(jint,1bind_1parameter_1index)(JENV_CSELF, jobject jpStmt, jbyteArray jName
|
||||
|
||||
JDECL(jint,1bind_1text)(JENV_CSELF, jobject jpStmt,
|
||||
jint ndx, jbyteArray baData, jint nMax){
|
||||
if(baData){
|
||||
jbyte * const pBuf = JBA_TOC(baData);
|
||||
int rc = sqlite3_bind_text(PtrGet_sqlite3_stmt(jpStmt), (int)ndx, (const char *)pBuf,
|
||||
jbyte * const pBuf = baData ? JBA_TOC(baData) : 0;
|
||||
int const rc = sqlite3_bind_text(PtrGet_sqlite3_stmt(jpStmt), (int)ndx,
|
||||
(const char *)pBuf,
|
||||
(int)nMax, SQLITE_TRANSIENT);
|
||||
JBA_RELEASE(baData, pBuf);
|
||||
return (jint)rc;
|
||||
}else{
|
||||
return sqlite3_bind_null(PtrGet_sqlite3_stmt(jpStmt), (int)ndx);
|
||||
}
|
||||
|
||||
JDECL(jint,1bind_1text16)(JENV_CSELF, jobject jpStmt,
|
||||
jint ndx, jbyteArray baData, jint nMax){
|
||||
jbyte * const pBuf = baData ? JBA_TOC(baData) : 0;
|
||||
int const rc = sqlite3_bind_text16(PtrGet_sqlite3_stmt(jpStmt), (int)ndx,
|
||||
pBuf, (int)nMax, SQLITE_TRANSIENT);
|
||||
JBA_RELEASE(baData, pBuf);
|
||||
return (jint)rc;
|
||||
}
|
||||
|
||||
JDECL(jint,1bind_1zeroblob)(JENV_CSELF, jobject jpStmt,
|
||||
@ -3595,18 +3596,19 @@ JDECL(jbyteArray,1value_1text_1utf8)(JENV_CSELF, jobject jpSVal){
|
||||
}
|
||||
|
||||
static jbyteArray value_text16(int mode, JNIEnv * const env, jobject jpSVal){
|
||||
int const nLen = sqlite3_value_bytes16(PtrGet_sqlite3_value(jpSVal));
|
||||
sqlite3_value * const sv = PtrGet_sqlite3_value(jpSVal);
|
||||
int const nLen = sqlite3_value_bytes16(sv);
|
||||
jbyteArray jba;
|
||||
const jbyte * pBytes;
|
||||
switch(mode){
|
||||
case SQLITE_UTF16:
|
||||
pBytes = sqlite3_value_text16(PtrGet_sqlite3_value(jpSVal));
|
||||
pBytes = sqlite3_value_text16(sv);
|
||||
break;
|
||||
case SQLITE_UTF16LE:
|
||||
pBytes = sqlite3_value_text16le(PtrGet_sqlite3_value(jpSVal));
|
||||
pBytes = sqlite3_value_text16le(sv);
|
||||
break;
|
||||
case SQLITE_UTF16BE:
|
||||
pBytes = sqlite3_value_text16be(PtrGet_sqlite3_value(jpSVal));
|
||||
pBytes = sqlite3_value_text16be(sv);
|
||||
break;
|
||||
default:
|
||||
assert(!"not possible");
|
||||
|
@ -843,6 +843,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1bind_1parameter_1
|
||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1bind_1text
|
||||
(JNIEnv *, jclass, jobject, jint, jbyteArray, jint);
|
||||
|
||||
/*
|
||||
* Class: org_sqlite_jni_SQLite3Jni
|
||||
* Method: sqlite3_bind_text16
|
||||
* Signature: (Lorg/sqlite/jni/sqlite3_stmt;I[BI)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1bind_1text16
|
||||
(JNIEnv *, jclass, jobject, jint, jbyteArray, jint);
|
||||
|
||||
/*
|
||||
* Class: org_sqlite_jni_SQLite3Jni
|
||||
* Method: sqlite3_bind_zeroblob
|
||||
|
@ -14,24 +14,24 @@
|
||||
package org.sqlite.jni;
|
||||
|
||||
/**
|
||||
A callback for use with sqlite3_auto_extension().
|
||||
A callback for use with the sqlite3_auto_extension() family of
|
||||
APIs.
|
||||
*/
|
||||
public interface AutoExtension {
|
||||
/**
|
||||
Must function as described for a sqlite3_auto_extension()
|
||||
callback, with the caveat that the signature is more limited.
|
||||
callback, with the caveat that the signature is shorter.
|
||||
|
||||
As an exception (as it were) to the callbacks-must-not-throw
|
||||
rule, AutoExtensions may throw and the exception's error message
|
||||
AutoExtensions may throw and the exception's error message
|
||||
will be set as the db's error string.
|
||||
|
||||
Hints for implementations:
|
||||
Tips for implementations:
|
||||
|
||||
- Opening a database from an auto-extension handler will lead to
|
||||
an endless recursion of the auto-handler triggering itself
|
||||
indirectly for each newly-opened database.
|
||||
|
||||
- If this routine is stateful, it is a good idea to make the
|
||||
- If this routine is stateful, it may be useful to make the
|
||||
overridden method synchronized.
|
||||
|
||||
- Results are undefined if db is closed by an auto-extension.
|
||||
|
@ -154,20 +154,27 @@ public final class SQLite3Jni {
|
||||
Functions almost as documented for the C API, with these
|
||||
exceptions:
|
||||
|
||||
- The callback interface is more limited because of
|
||||
cross-language differences. Specifically, auto-extensions do
|
||||
not have access to the sqlite3_api object which native
|
||||
auto-extensions do.
|
||||
- The callback interface is is shorter because of cross-language
|
||||
differences. Specifically, 3rd argument to the C auto-extension
|
||||
callback interface is unnecessary here.
|
||||
|
||||
- If the list of auto-extensions is manipulated from an
|
||||
auto-extension, it is undefined which, if any, auto-extensions
|
||||
will subsequently execute for the current database (it depends
|
||||
on multiple factors).
|
||||
|
||||
The C API docs do not specifically say so, if the list of
|
||||
auto-extensions is manipulated from an auto-extension, it is
|
||||
undefined which, if any, auto-extensions will subsequently
|
||||
execute for the current database.
|
||||
|
||||
See the AutoExtension class docs for more information.
|
||||
*/
|
||||
public static native int sqlite3_auto_extension(@NotNull AutoExtension callback);
|
||||
|
||||
/**
|
||||
Results are undefined if data is not null and n<0 || n>=data.length.
|
||||
*/
|
||||
public static native int sqlite3_bind_blob(
|
||||
@NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data, int n
|
||||
);
|
||||
|
||||
public static int sqlite3_bind_blob(
|
||||
@NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data
|
||||
){
|
||||
@ -176,10 +183,6 @@ public final class SQLite3Jni {
|
||||
: sqlite3_bind_blob(stmt, ndx, data, data.length);
|
||||
}
|
||||
|
||||
private static native int sqlite3_bind_blob(
|
||||
@NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data, int n
|
||||
);
|
||||
|
||||
public static native int sqlite3_bind_double(
|
||||
@NotNull sqlite3_stmt stmt, int ndx, double v
|
||||
);
|
||||
@ -200,13 +203,10 @@ public final class SQLite3Jni {
|
||||
@NotNull sqlite3_stmt stmt
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
A level of indirection required to ensure that the input to the
|
||||
C-level function of the same name is a NUL-terminated UTF-8
|
||||
string.
|
||||
Requires that paramName be a NUL-terminated UTF-8 string.
|
||||
*/
|
||||
private static native int sqlite3_bind_parameter_index(
|
||||
public static native int sqlite3_bind_parameter_index(
|
||||
@NotNull sqlite3_stmt stmt, byte[] paramName
|
||||
);
|
||||
|
||||
@ -218,14 +218,22 @@ public final class SQLite3Jni {
|
||||
}
|
||||
|
||||
/**
|
||||
Works like the C-level sqlite3_bind_text() but (A) assumes
|
||||
SQLITE_TRANSIENT for the final parameter and (B) behaves like
|
||||
sqlite3_bind_null() if the data argument is null.
|
||||
Works like the C-level sqlite3_bind_text() but assumes
|
||||
SQLITE_TRANSIENT for the final C API parameter.
|
||||
|
||||
Results are undefined if data is not null and
|
||||
maxBytes>=data.length. If maxBytes is negative then results are
|
||||
undefined if data is not null and does not contain a NUL byte.
|
||||
*/
|
||||
private static native int sqlite3_bind_text(
|
||||
@NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data, int maxBytes
|
||||
);
|
||||
|
||||
/**
|
||||
Converts data, if not null, to a UTF-8-encoded byte array and
|
||||
binds it as such, returning the result of the C-level
|
||||
sqlite3_bind_null() or sqlite3_bind_text().
|
||||
*/
|
||||
public static int sqlite3_bind_text(
|
||||
@NotNull sqlite3_stmt stmt, int ndx, @Nullable String data
|
||||
){
|
||||
@ -234,6 +242,9 @@ public final class SQLite3Jni {
|
||||
return sqlite3_bind_text(stmt, ndx, utf8, utf8.length);
|
||||
}
|
||||
|
||||
/**
|
||||
Requires that data be null or in UTF-8 encoding.
|
||||
*/
|
||||
public static int sqlite3_bind_text(
|
||||
@NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data
|
||||
){
|
||||
@ -242,6 +253,41 @@ public final class SQLite3Jni {
|
||||
: sqlite3_bind_text(stmt, ndx, data, data.length);
|
||||
}
|
||||
|
||||
/**
|
||||
Identical to the sqlite3_bind_text() overload with the same
|
||||
signature but requires that its input be encoded in UTF-16 in
|
||||
platform byte order.
|
||||
*/
|
||||
private static native int sqlite3_bind_text16(
|
||||
@NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data, int maxBytes
|
||||
);
|
||||
|
||||
/**
|
||||
Converts its string argument to UTF-16 and binds it as such, returning
|
||||
the result of the C-side function of the same name. The 3rd argument
|
||||
may be null.
|
||||
*/
|
||||
public static int sqlite3_bind_text16(
|
||||
@NotNull sqlite3_stmt stmt, int ndx, @Nullable String data
|
||||
){
|
||||
if(null == data) return sqlite3_bind_null(stmt, ndx);
|
||||
final byte[] bytes = data.getBytes(StandardCharsets.UTF_16);
|
||||
return sqlite3_bind_text16(stmt, ndx, bytes, bytes.length);
|
||||
}
|
||||
|
||||
/**
|
||||
Requires that data be null or in UTF-16 encoding in platform byte
|
||||
order. Returns the result of the C-level sqlite3_bind_null() or
|
||||
sqlite3_bind_text().
|
||||
*/
|
||||
public static int sqlite3_bind_text16(
|
||||
@NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data
|
||||
){
|
||||
return (null == data)
|
||||
? sqlite3_bind_null(stmt, ndx)
|
||||
: sqlite3_bind_text16(stmt, ndx, data, data.length);
|
||||
}
|
||||
|
||||
public static native int sqlite3_bind_zeroblob(
|
||||
@NotNull sqlite3_stmt stmt, int ndx, int n
|
||||
);
|
||||
@ -253,8 +299,7 @@ public final class SQLite3Jni {
|
||||
/**
|
||||
As for the C-level function of the same name, with a BusyHandler
|
||||
instance in place of a callback function. Pass it a null handler
|
||||
to clear the busy handler. Calling this multiple times with the
|
||||
same object is a no-op on the second and subsequent calls.
|
||||
to clear the busy handler.
|
||||
*/
|
||||
public static native int sqlite3_busy_handler(
|
||||
@NotNull sqlite3 db, @Nullable BusyHandler handler
|
||||
@ -595,15 +640,41 @@ public final class SQLite3Jni {
|
||||
@Nullable String filename, @NotNull OutputPointer.sqlite3 ppDb
|
||||
);
|
||||
|
||||
/**
|
||||
Convenience overload which returns its db handle directly. The returned
|
||||
object might not have been successfully opened: use sqlite3_errcode() to
|
||||
check whether it is in an error state.
|
||||
|
||||
Ownership of the returned value is passed to the caller, who must eventually
|
||||
pass it to sqlite3_close() or sqlite3_close_v2().
|
||||
*/
|
||||
public static sqlite3 sqlite3_open(@Nullable String filename){
|
||||
final OutputPointer.sqlite3 out = new OutputPointer.sqlite3();
|
||||
sqlite3_open(filename, out);
|
||||
return out.take();
|
||||
};
|
||||
|
||||
public static native int sqlite3_open_v2(
|
||||
@Nullable String filename, @NotNull OutputPointer.sqlite3 ppDb,
|
||||
int flags, @Nullable String zVfs
|
||||
);
|
||||
|
||||
/**
|
||||
Has the same semantics as the sqlite3-returning sqlite3_open()
|
||||
but uses sqlite3_open_v2() instead of sqlite3_open().
|
||||
*/
|
||||
public static sqlite3 sqlite3_open_v2(@Nullable String filename, int flags,
|
||||
@Nullable String zVfs){
|
||||
final OutputPointer.sqlite3 out = new OutputPointer.sqlite3();
|
||||
sqlite3_open_v2(filename, out, flags, zVfs);
|
||||
return out.take();
|
||||
};
|
||||
|
||||
/**
|
||||
The sqlite3_prepare() family of functions require slightly
|
||||
different signatures than their native counterparts, but
|
||||
overloading allows us to install several convenience forms.
|
||||
different signatures than their native counterparts, but (A) they
|
||||
retain functionally equivalent semantics and (B) overloading
|
||||
allows us to install several convenience forms.
|
||||
|
||||
All of them which take their SQL in the form of a byte[] require
|
||||
that it be in UTF-8 encoding unless explicitly noted otherwise.
|
||||
@ -648,6 +719,26 @@ public final class SQLite3Jni {
|
||||
return sqlite3_prepare(db, utf8, utf8.length, outStmt, null);
|
||||
}
|
||||
|
||||
/**
|
||||
Convenience overload which returns its statement handle directly,
|
||||
or null on error or when reading only whitespace or
|
||||
comments. sqlite3_errcode() can be used to determine whether
|
||||
there was an error or the input was empty. Ownership of the
|
||||
returned object is passed to the caller, who must eventually pass
|
||||
it to sqlite3_finalize().
|
||||
*/
|
||||
public static sqlite3_stmt sqlite3_prepare(
|
||||
@NotNull sqlite3 db, @NotNull String sql
|
||||
){
|
||||
final OutputPointer.sqlite3_stmt out = new OutputPointer.sqlite3_stmt();
|
||||
sqlite3_prepare(db, sql, out);
|
||||
return out.take();
|
||||
}
|
||||
|
||||
/**
|
||||
See sqlite3_prepare() for details about the slight API differences
|
||||
from the C API.
|
||||
*/
|
||||
private static native int sqlite3_prepare_v2(
|
||||
@NotNull sqlite3 db, @NotNull byte[] sqlUtf8, int maxBytes,
|
||||
@NotNull OutputPointer.sqlite3_stmt outStmt,
|
||||
@ -677,6 +768,18 @@ public final class SQLite3Jni {
|
||||
return sqlite3_prepare_v2(db, utf8, utf8.length, outStmt, null);
|
||||
}
|
||||
|
||||
/**
|
||||
Works identically to the sqlite3_stmt-returning sqlite3_prepare()
|
||||
but uses sqlite3_prepare_v2().
|
||||
*/
|
||||
public static sqlite3_stmt sqlite3_prepare_v2(
|
||||
@NotNull sqlite3 db, @NotNull String sql
|
||||
){
|
||||
final OutputPointer.sqlite3_stmt out = new OutputPointer.sqlite3_stmt();
|
||||
sqlite3_prepare_v2(db, sql, out);
|
||||
return out.take();
|
||||
}
|
||||
|
||||
private static native int sqlite3_prepare_v3(
|
||||
@NotNull sqlite3 db, @NotNull byte[] sqlUtf8, int maxBytes,
|
||||
int prepFlags, @NotNull OutputPointer.sqlite3_stmt outStmt,
|
||||
@ -706,6 +809,18 @@ public final class SQLite3Jni {
|
||||
return sqlite3_prepare_v3(db, utf8, utf8.length, prepFlags, outStmt, null);
|
||||
}
|
||||
|
||||
/**
|
||||
Works identically to the sqlite3_stmt-returning sqlite3_prepare()
|
||||
but uses sqlite3_prepare_v3().
|
||||
*/
|
||||
public static sqlite3_stmt sqlite3_prepare_v3(
|
||||
@NotNull sqlite3 db, @NotNull String sql, int prepFlags
|
||||
){
|
||||
final OutputPointer.sqlite3_stmt out = new OutputPointer.sqlite3_stmt();
|
||||
sqlite3_prepare_v3(db, sql, prepFlags, out);
|
||||
return out.take();
|
||||
}
|
||||
|
||||
/**
|
||||
If the C API was built with SQLITE_ENABLE_PREUPDATE_HOOK defined, this
|
||||
acts as a proxy for C's sqlite3_preupdate_blobwrite(), else it returns
|
||||
|
@ -21,6 +21,16 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
An annotation for Tester1 tests which we do not want to run in
|
||||
reflection-driven test mode because either they are not suitable
|
||||
for multi-threaded threaded mode or we have to control their execution
|
||||
order.
|
||||
*/
|
||||
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||
@java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD})
|
||||
@interface ManualTest{}
|
||||
|
||||
public class Tester1 implements Runnable {
|
||||
//! True when running in multi-threaded mode.
|
||||
private static boolean mtMode = false;
|
||||
@ -30,6 +40,10 @@ public class Tester1 implements Runnable {
|
||||
private static boolean shuffle = false;
|
||||
//! True to dump the list of to-run tests to stdout.
|
||||
private static boolean listRunTests = false;
|
||||
//! True to squelch all out() and outln() output.
|
||||
private static boolean quietMode = false;
|
||||
//! Total number of runTests() calls.
|
||||
private static int nTestRuns = 0;
|
||||
//! List of test*() methods to run.
|
||||
private static List<java.lang.reflect.Method> testMethods = null;
|
||||
//! List of exceptions collected by run()
|
||||
@ -48,28 +62,38 @@ public class Tester1 implements Runnable {
|
||||
static final Metrics metrics = new Metrics();
|
||||
|
||||
public synchronized static void outln(){
|
||||
if( !quietMode ){
|
||||
System.out.println("");
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized static void outln(Object val){
|
||||
if( !quietMode ){
|
||||
System.out.print(Thread.currentThread().getName()+": ");
|
||||
System.out.println(val);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized static void out(Object val){
|
||||
if( !quietMode ){
|
||||
System.out.print(val);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public synchronized static void out(Object... vals){
|
||||
if( !quietMode ){
|
||||
System.out.print(Thread.currentThread().getName()+": ");
|
||||
for(Object v : vals) out(v);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public synchronized static void outln(Object... vals){
|
||||
if( !quietMode ){
|
||||
out(vals); out("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static volatile int affirmCount = 0;
|
||||
public synchronized static void affirm(Boolean v, String comment){
|
||||
@ -85,6 +109,7 @@ public class Tester1 implements Runnable {
|
||||
affirm(v, "Affirmation failed.");
|
||||
}
|
||||
|
||||
@ManualTest /* because testing this for threading is pointless */
|
||||
private void test1(){
|
||||
affirm(sqlite3_libversion_number() == SQLITE_VERSION_NUMBER);
|
||||
affirm(SQLITE_MAX_LENGTH > 0);
|
||||
@ -280,6 +305,16 @@ public class Tester1 implements Runnable {
|
||||
affirm(0 != stmt.getNativePointer());
|
||||
sqlite3_finalize(stmt);
|
||||
affirm(0 == stmt.getNativePointer() );
|
||||
|
||||
affirm( 0==sqlite3_errcode(db) );
|
||||
stmt = sqlite3_prepare(db, "intentional error");
|
||||
affirm( null==stmt );
|
||||
affirm( 0!=sqlite3_errcode(db) );
|
||||
affirm( 0==sqlite3_errmsg(db).indexOf("near \"intentional\"") );
|
||||
sqlite3_finalize(stmt);
|
||||
stmt = sqlite3_prepare(db, "/* empty input*/\n-- comments only");
|
||||
affirm( null==stmt );
|
||||
affirm( 0==sqlite3_errcode(db) );
|
||||
sqlite3_close_v2(db);
|
||||
}
|
||||
|
||||
@ -383,8 +418,11 @@ public class Tester1 implements Runnable {
|
||||
sqlite3_stmt stmt = prepare(db, "INSERT INTO t(a) VALUES(?);");
|
||||
String[] list1 = { "hell🤩", "w😃rld", "!" };
|
||||
int rc;
|
||||
int n = 0;
|
||||
for( String e : list1 ){
|
||||
rc = sqlite3_bind_text(stmt, 1, e);
|
||||
rc = (0==n)
|
||||
? sqlite3_bind_text(stmt, 1, e)
|
||||
: sqlite3_bind_text16(stmt, 1, e);
|
||||
affirm(0 == rc);
|
||||
rc = sqlite3_step(stmt);
|
||||
affirm(SQLITE_DONE==rc);
|
||||
@ -393,7 +431,7 @@ public class Tester1 implements Runnable {
|
||||
sqlite3_finalize(stmt);
|
||||
stmt = prepare(db, "SELECT a FROM t ORDER BY a DESC;");
|
||||
StringBuilder sbuf = new StringBuilder();
|
||||
int n = 0;
|
||||
n = 0;
|
||||
while( SQLITE_ROW == sqlite3_step(stmt) ){
|
||||
String txt = sqlite3_column_text16(stmt, 0);
|
||||
//outln("txt = "+txt);
|
||||
@ -521,6 +559,7 @@ public class Tester1 implements Runnable {
|
||||
affirm(xDestroyCalled.value);
|
||||
}
|
||||
|
||||
@ManualTest /* because threading is meaningless here */
|
||||
private void testToUtf8(){
|
||||
/**
|
||||
https://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html
|
||||
@ -873,6 +912,7 @@ public class Tester1 implements Runnable {
|
||||
affirm( 7 == counter.value );
|
||||
}
|
||||
|
||||
@ManualTest /* because threads inherently break this test */
|
||||
private void testBusy(){
|
||||
final String dbName = "_busy-handler.db";
|
||||
final OutputPointer.sqlite3 outDb = new OutputPointer.sqlite3();
|
||||
@ -1156,6 +1196,8 @@ public class Tester1 implements Runnable {
|
||||
it throws.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@ManualTest /* because the Fts5 parts are not yet known to be
|
||||
thread-safe */
|
||||
private void testFts5() throws Exception {
|
||||
if( !sqlite3_compileoption_used("ENABLE_FTS5") ){
|
||||
//outln("SQLITE_ENABLE_FTS5 is not set. Skipping FTS5 tests.");
|
||||
@ -1206,6 +1248,8 @@ public class Tester1 implements Runnable {
|
||||
sqlite3_close(db);
|
||||
}
|
||||
|
||||
@ManualTest/* because multiple threads legitimately make these
|
||||
results unpredictable */
|
||||
private synchronized void testAutoExtension(){
|
||||
final ValueHolder<Integer> val = new ValueHolder<>(0);
|
||||
final ValueHolder<String> toss = new ValueHolder<>(null);
|
||||
@ -1296,6 +1340,7 @@ public class Tester1 implements Runnable {
|
||||
affirm( 8 == val.value );
|
||||
}
|
||||
|
||||
@ManualTest /* because we only want to run this test manually */
|
||||
private void testSleep(){
|
||||
out("Sleeping briefly... ");
|
||||
sqlite3_sleep(600);
|
||||
@ -1308,6 +1353,7 @@ public class Tester1 implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
@ManualTest /* because we only want to run this test on demand */
|
||||
private void testFail(){
|
||||
affirm( false, "Intentional failure." );
|
||||
}
|
||||
@ -1355,6 +1401,9 @@ public class Tester1 implements Runnable {
|
||||
testFts5();
|
||||
}
|
||||
}
|
||||
synchronized( this.getClass() ){
|
||||
++nTestRuns;
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
@ -1375,6 +1424,8 @@ public class Tester1 implements Runnable {
|
||||
|
||||
CLI flags:
|
||||
|
||||
-q|-quiet: disables most test output.
|
||||
|
||||
-t|-thread N: runs the tests in N threads
|
||||
concurrently. Default=1.
|
||||
|
||||
@ -1400,6 +1451,7 @@ public class Tester1 implements Runnable {
|
||||
Integer nRepeat = 1;
|
||||
boolean forceFail = false;
|
||||
boolean sqlLog = false;
|
||||
boolean squelchTestOutput = false;
|
||||
for( int i = 0; i < args.length; ){
|
||||
String arg = args[i++];
|
||||
if(arg.startsWith("-")){
|
||||
@ -1421,6 +1473,8 @@ public class Tester1 implements Runnable {
|
||||
sqlLog = true;
|
||||
}else if(arg.equals("naps")){
|
||||
takeNaps = true;
|
||||
}else if(arg.equals("q") || arg.equals("quiet")){
|
||||
squelchTestOutput = true;
|
||||
}else{
|
||||
throw new IllegalArgumentException("Unhandled flag:"+arg);
|
||||
}
|
||||
@ -1430,20 +1484,17 @@ public class Tester1 implements Runnable {
|
||||
{
|
||||
// Build list of tests to run from the methods named test*().
|
||||
testMethods = new ArrayList<>();
|
||||
final List<String> excludes = new ArrayList<>();
|
||||
// Tests we want to control the order of:
|
||||
if( !forceFail ) excludes.add("testFail");
|
||||
excludes.add("test1");
|
||||
excludes.add("testAutoExtension");
|
||||
excludes.add("testBusy");
|
||||
excludes.add("testFts5");
|
||||
excludes.add("testSleep");
|
||||
excludes.add("testToUtf8");
|
||||
for(java.lang.reflect.Method m : Tester1.class.getDeclaredMethods()){
|
||||
for(final java.lang.reflect.Method m : Tester1.class.getDeclaredMethods()){
|
||||
final String name = m.getName();
|
||||
if( name.startsWith("test") && excludes.indexOf(name)<0 ){
|
||||
if( name.equals("testFail") ){
|
||||
if( forceFail ){
|
||||
testMethods.add(m);
|
||||
}
|
||||
}else if( !m.isAnnotationPresent( ManualTest.class ) ){
|
||||
if( name.startsWith("test") ){
|
||||
testMethods.add(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1465,6 +1516,11 @@ public class Tester1 implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
quietMode = squelchTestOutput;
|
||||
outln("If you just saw warning messages regarding CallStaticObjectMethod, ",
|
||||
"you are very likely seeing the side effects of a known openjdk8 ",
|
||||
"bug. It is unsightly but does not affect the library.");
|
||||
|
||||
final long timeStart = System.currentTimeMillis();
|
||||
int nLoop = 0;
|
||||
affirm( 0==sqlite3_config( SQLITE_CONFIG_SINGLETHREAD ),
|
||||
@ -1476,7 +1532,7 @@ public class Tester1 implements Runnable {
|
||||
outln("libversion_number: ",
|
||||
sqlite3_libversion_number(),"\n",
|
||||
sqlite3_libversion(),"\n",SQLITE_SOURCE_ID);
|
||||
outln("Running ",nRepeat," loop(s) over ",nThread," thread(s).");
|
||||
outln("Running ",nRepeat," loop(s) with ",nThread," thread(s) each.");
|
||||
if( takeNaps ) outln("Napping between tests is enabled.");
|
||||
for( int n = 0; n < nRepeat; ++n ){
|
||||
if( nThread==null || nThread<=1 ){
|
||||
@ -1500,6 +1556,7 @@ public class Tester1 implements Runnable {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
if( !listErrors.isEmpty() ){
|
||||
quietMode = false;
|
||||
outln("TEST ERRORS:");
|
||||
Exception err = null;
|
||||
for( Exception e : listErrors ){
|
||||
@ -1510,9 +1567,10 @@ public class Tester1 implements Runnable {
|
||||
}
|
||||
}
|
||||
outln();
|
||||
quietMode = false;
|
||||
|
||||
final long timeEnd = System.currentTimeMillis();
|
||||
outln("Tests done. Metrics:");
|
||||
outln("Tests done. Metrics across ",nTestRuns," total iteration(s):");
|
||||
outln("\tAssertions checked: ",affirmCount);
|
||||
outln("\tDatabases opened: ",metrics.dbOpen);
|
||||
if( doSomethingForDev ){
|
||||
|
@ -72,7 +72,8 @@ public class TesterFts5 {
|
||||
affirm( xDestroyCalled.value );
|
||||
}
|
||||
|
||||
public TesterFts5(){
|
||||
public TesterFts5(boolean verbose){
|
||||
if(verbose){
|
||||
final long timeStart = System.currentTimeMillis();
|
||||
final int oldAffirmCount = Tester1.affirmCount;
|
||||
test1();
|
||||
@ -80,5 +81,9 @@ public class TesterFts5 {
|
||||
final long timeEnd = System.currentTimeMillis();
|
||||
outln("FTS5 Tests done. Assertions checked = ",affirmCount,
|
||||
", Total time = ",(timeEnd - timeStart),"ms");
|
||||
}else{
|
||||
test1();
|
||||
}
|
||||
}
|
||||
public TesterFts5(){ this(false); }
|
||||
}
|
||||
|
28
manifest
28
manifest
@ -1,5 +1,5 @@
|
||||
C JNI\scleanups\sregarding\sbuilding\swith\scertain\sfeatures\sdisabled.
|
||||
D 2023-08-23T17:52:51.175
|
||||
C Add\smore\sJNI\sdocs,\stests,\sand\sa\shandful\sof\sJava-side\soverloads.
|
||||
D 2023-08-24T11:57:51.863
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@ -232,13 +232,13 @@ F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
|
||||
F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9
|
||||
F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282
|
||||
F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
|
||||
F ext/jni/GNUmakefile 14b7c3abd1ae8693203b08b0e06bb359f8924ad2243f15953e9c6e456ae317b5
|
||||
F ext/jni/README.md 1693e865d366f5ebaa756732ea0d4b786515caf3cfbcd4dcb8758274373913b0
|
||||
F ext/jni/jar-dist.make 9a03d10dbb5a74c724bfec4b76fd9e4c9865cbbc858d731cb48f38ac897d73a3
|
||||
F ext/jni/src/c/sqlite3-jni.c 0ca96134d7fb3f313a7a49487f68a8d7a6d7545470c84532aa1ce63d2cdc432e
|
||||
F ext/jni/src/c/sqlite3-jni.h c5cb0348efe4e5f3d125a240e2437e8475de14a586c2f859e2acdcde4116244d
|
||||
F ext/jni/GNUmakefile 0a823c56f081294e7797dae303380ac989ebaa801bba970968342b7358f07aed
|
||||
F ext/jni/README.md 64bf1da0d562d051207ca1c5cfa52e8b7a69120533cc034a3da7670ef920cbef
|
||||
F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
|
||||
F ext/jni/src/c/sqlite3-jni.c e1e3cde4d08925282b5bc949f9ed8f613a6a2c6f60d0c697e79d59fb49f9fe4b
|
||||
F ext/jni/src/c/sqlite3-jni.h cc24d6742b29a52338ffd3b47caf923facb8ae77f9c2fc9c2de82673bf339ea2
|
||||
F ext/jni/src/org/sqlite/jni/Authorizer.java 1308988f7f40579ea0e4deeaec3c6be971630566bd021c31367fe3f5140db892
|
||||
F ext/jni/src/org/sqlite/jni/AutoExtension.java 3b62c915e45ce73f63343ca9195ec63592244d616a1908b7587bdd45de1b97dd
|
||||
F ext/jni/src/org/sqlite/jni/AutoExtension.java bcc1849b2fccbe5e2d7ac9e9ac7f8d05a6d7088a8fedbaad90e39569745a61e6
|
||||
F ext/jni/src/org/sqlite/jni/BusyHandler.java 1b1d3e5c86cd796a0580c81b6af6550ad943baa25e47ada0dcca3aff3ebe978c
|
||||
F ext/jni/src/org/sqlite/jni/Collation.java 8dffbb00938007ad0967b2ab424d3c908413af1bbd3d212b9c9899910f1218d1
|
||||
F ext/jni/src/org/sqlite/jni/CollationNeeded.java ad67843b6dd1c06b6b0a1dc72887b7c48e2a98042fcf6cacf14d42444037eab8
|
||||
@ -257,9 +257,9 @@ F ext/jni/src/org/sqlite/jni/ResultCode.java ba701f20213a5f259e94cfbfdd36eb7ac7c
|
||||
F ext/jni/src/org/sqlite/jni/RollbackHook.java b04c8abcc6ade44a8a57129e33765793f69df0ba909e49ba18d73f4268d92564
|
||||
F ext/jni/src/org/sqlite/jni/SQLFunction.java f697cf2a81c4119f2baf0682af689686f0466f1dd83dba00885f5603e693fe16
|
||||
F ext/jni/src/org/sqlite/jni/SQLLog.java c60610b35208416940822e834d61f08fbbe5d6e06b374b541b49e41fd56c9798
|
||||
F ext/jni/src/org/sqlite/jni/SQLite3Jni.java f64554457fa30a048ef99374bfac3c4b986e3528353dce3086a98a858e3fe000
|
||||
F ext/jni/src/org/sqlite/jni/Tester1.java 69ea63a5b235f94f914dff6fe3ecd103ee0a8023b8737db071b46c0c75375e26
|
||||
F ext/jni/src/org/sqlite/jni/TesterFts5.java de095e3b701fba0c56d7b8b2993dc22bcbaa9de8f992904a93729ad729a91576
|
||||
F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 956063c854c4f662183c41c65d0ab48b5e2127824b8053eeb05b9fc40f0d09e3
|
||||
F ext/jni/src/org/sqlite/jni/Tester1.java b5a4bb2a969df053d5c138887f04039a79b36170372a2efdf5dfbd6ac90db4c9
|
||||
F ext/jni/src/org/sqlite/jni/TesterFts5.java 6f135c60e24c89e8eecb9fe61dde0f3bb2906de668ca6c9186bcf34bdaf94629
|
||||
F ext/jni/src/org/sqlite/jni/Tracer.java a5cece9f947b0af27669b8baec300b6dd7ff859c3e6a6e4a1bd8b50f9714775d
|
||||
F ext/jni/src/org/sqlite/jni/UpdateHook.java e58645a1727f8a9bbe72dc072ec5b40d9f9362cb0aa24acfe93f49ff56a9016d
|
||||
F ext/jni/src/org/sqlite/jni/ValueHolder.java f022873abaabf64f3dd71ab0d6037c6e71cece3b8819fa10bf26a5461dc973ee
|
||||
@ -2094,8 +2094,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P d67255f7251cc5d1d27d77d4c84ff216e2da71202db989718189a6b4beff1cd0
|
||||
R b911867dcaf18c3e131e156c82d306fe
|
||||
P a9e6d5158b8a4a6b8554a5f8f0a35785ee450d42ea877275dc27085e89716c18
|
||||
R cb79df5ad40cc86377d98f5a1329b589
|
||||
U stephan
|
||||
Z bdef86836c9254e732e1b6d744febf17
|
||||
Z 39e8fbdcbc2ebaa58ed84b96f0374c06
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
@ -1 +1 @@
|
||||
a9e6d5158b8a4a6b8554a5f8f0a35785ee450d42ea877275dc27085e89716c18
|
||||
d19a431facbde6a6b960664674753ee85d2c051a76109ce7db0b079c65fbdea0
|
Reference in New Issue
Block a user