1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-05 15:55:57 +03:00

Merge the latest trunk fixes and enhancements into the jsonb branch, and

especially the JSON cache spill UAF fix.

FossilOrigin-Name: 9422c24f4a8b290dcae61e50ec81be5b314b22c61a2bca1e194e47da1316b6e6
This commit is contained in:
drh
2023-10-09 12:57:03 +00:00
45 changed files with 2980 additions and 1830 deletions

View File

@@ -45,9 +45,9 @@ DISTCLEAN_FILES := $(dir.jni)/*~ $(dir.src.c)/*~ $(dir.src.jni)/*~
sqlite3-jni.h := $(dir.src.c)/sqlite3-jni.h
.NOTPARALLEL: $(sqlite3-jni.h)
SQLite3Jni.java := src/org/sqlite/jni/SQLite3Jni.java
CApi.java := src/org/sqlite/jni/CApi.java
SQLTester.java := src/org/sqlite/jni/SQLTester.java
SQLite3Jni.class := $(SQLite3Jni.java:.java=.class)
CApi.class := $(CApi.java:.java=.class)
SQLTester.class := $(SQLTester.java:.java=.class)
########################################################################
@@ -78,7 +78,6 @@ $(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
# in-progress files without requiring them to be in a compilable statae.
JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/%,\
annotation/Canonical.java \
annotation/NotNull.java \
annotation/Nullable.java \
AbstractCollationCallback.java \
@@ -99,9 +98,11 @@ JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/%,\
ResultCode.java \
RollbackHookCallback.java \
ScalarFunction.java \
Sqlite.java \
SqliteException.java \
SQLFunction.java \
CallbackProxy.java \
SQLite3Jni.java \
CApi.java \
TableColumnMetadata.java \
TraceV2Callback.java \
UpdateHookCallback.java \
@@ -114,6 +115,7 @@ JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/%,\
)
JAVA_FILES.unittest := $(patsubst %,$(dir.src.jni)/%,\
Tester1.java \
Tester2.java \
)
ifeq (1,$(enable.fts5))
JAVA_FILES.unittest += $(patsubst %,$(dir.src.jni)/%,\
@@ -243,7 +245,7 @@ $$(dir.bld.c)/org_sqlite_jni$(3)_$(2).h: $(1)/$(2).java
endef
# Invoke ADD_JNI_H once for each Java file which includes JNI
# declarations:
$(eval $(call ADD_JNI_H,$(dir.src.jni),SQLite3Jni,))
$(eval $(call ADD_JNI_H,$(dir.src.jni),CApi,))
$(eval $(call ADD_JNI_H,$(dir.src.jni),SQLTester,))
ifeq (1,$(enable.fts5))
$(eval $(call ADD_JNI_H,$(dir.src.fts5),Fts5ExtensionApi,_fts5))
@@ -295,19 +297,23 @@ $(package.dll): $(sqlite3-jni.c) $(MAKEFILE)
all: $(package.dll)
.PHONY: test test-one
test.flags ?=
test.main.flags = -ea -Djava.library.path=$(dir.bld.c) \
$(java.flags) -cp $(classpath) \
org.sqlite.jni.Tester1
Tester1.flags ?=
Tester2.flags ?=
test.flags.jvm = -ea -Djava.library.path=$(dir.bld.c) \
$(java.flags) -cp $(classpath)
test.deps := $(CLASS_FILES) $(package.dll)
test-one: $(test.deps)
$(bin.java) $(test.main.flags) $(test.flags)
$(bin.java) $(test.flags.jvm) org.sqlite.jni.Tester1 $(Tester1.flags)
# $(bin.java) $(test.flags.jvm) org.sqlite.jni.Tester2 $(Tester2.flags)
test-sqllog: $(test.deps)
@echo "Testing with -sqllog..."
$(bin.java) $(test.main.flags) -sqllog
$(bin.java) $(test.flags.jvm) -sqllog
test-mt: $(test.deps)
@echo "Testing in multi-threaded mode:";
$(bin.java) $(test.main.flags) -t 7 -r 50 -shuffle $(test.flags)
$(bin.java) $(test.flags.jvm) org.sqlite.jni.Tester1 \
-t 7 -r 50 -shuffle $(Tester1.flags)
$(bin.java) $(test.flags.jvm) org.sqlite.jni.Tester2 \
-t 7 -r 50 -shuffle $(Tester2.flags)
test: test-one test-mt
tests: test test-sqllog

View File

@@ -55,7 +55,7 @@ Hello World
```java
import org.sqlite.jni.*;
import static org.sqlite.jni.SQLite3Jni.*;
import static org.sqlite.jni.CApi.*;
...

View File

@@ -10,7 +10,7 @@
**
*************************************************************************
** This file implements the JNI bindings declared in
** org.sqlite.jni.SQLiteJni (from which sqlite3-jni.h is generated).
** org.sqlite.jni.CApi (from which sqlite3-jni.h is generated).
*/
/*
@@ -161,7 +161,7 @@
** prefix seen in this macro.
*/
#define JniFuncName(Suffix) \
Java_org_sqlite_jni_SQLite3Jni_sqlite3_ ## Suffix
Java_org_sqlite_jni_CApi_sqlite3_ ## Suffix
/* Prologue for JNI function declarations and definitions. */
#define JniDecl(ReturnType,Suffix) \
@@ -5661,11 +5661,11 @@ Java_org_sqlite_jni_SQLTester_installCustomExtensions(JniArgsEnvClass){
////////////////////////////////////////////////////////////////////////
/*
** Called during static init of the SQLite3Jni class to set up global
** Called during static init of the CApi class to set up global
** state.
*/
JNIEXPORT void JNICALL
Java_org_sqlite_jni_SQLite3Jni_init(JniArgsEnvClass){
Java_org_sqlite_jni_CApi_init(JniArgsEnvClass){
jclass klazz;
memset(&S3JniGlobal, 0, sizeof(S3JniGlobal));

File diff suppressed because it is too large Load Diff

View File

@@ -15,7 +15,7 @@ package org.sqlite.jni;
import org.sqlite.jni.annotation.*;
/**
Callback for use with {@link SQLite3Jni#sqlite3_set_authorizer}.
Callback for use with {@link CApi#sqlite3_set_authorizer}.
*/
public interface AuthorizerCallback extends CallbackProxy {
/**

View File

@@ -14,7 +14,7 @@
package org.sqlite.jni;
/**
Callback for use with the {@link SQLite3Jni#sqlite3_auto_extension}
Callback for use with the {@link CApi#sqlite3_auto_extension}
family of APIs.
*/
public interface AutoExtensionCallback extends CallbackProxy {

View File

@@ -14,7 +14,7 @@
package org.sqlite.jni;
/**
Callback for use with {@link SQLite3Jni#sqlite3_busy_handler}.
Callback for use with {@link CApi#sqlite3_busy_handler}.
*/
public interface BusyHandlerCallback extends CallbackProxy {
/**

View File

@@ -15,7 +15,7 @@ package org.sqlite.jni;
import org.sqlite.jni.annotation.NotNull;
/**
Callback for use with {@link SQLite3Jni#sqlite3_create_collation}.
Callback for use with {@link CApi#sqlite3_create_collation}.
@see AbstractCollationCallback
*/

View File

@@ -14,7 +14,7 @@
package org.sqlite.jni;
/**
Callback for use with {@link SQLite3Jni#sqlite3_collation_needed}.
Callback for use with {@link CApi#sqlite3_collation_needed}.
*/
public interface CollationNeededCallback extends CallbackProxy {
/**

View File

@@ -14,7 +14,7 @@
package org.sqlite.jni;
/**
Callback for use with {@link SQLite3Jni#sqlite3_commit_hook}.
Callback for use with {@link CApi#sqlite3_commit_hook}.
*/
public interface CommitHookCallback extends CallbackProxy {
/**

View File

@@ -19,7 +19,7 @@ package org.sqlite.jni;
public interface ConfigLogCallback {
/**
Must function as described for a C-level callback for
{@link SQLite3Jni#sqlite3_config(ConfigLogCallback)}, with the slight signature change.
{@link CApi#sqlite3_config(ConfigLogCallback)}, with the slight signature change.
*/
void call(int errCode, String msg);
}

View File

@@ -19,7 +19,7 @@ package org.sqlite.jni;
public interface ConfigSqllogCallback {
/**
Must function as described for a C-level callback for
{@link SQLite3Jni#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 );
}

View File

@@ -14,7 +14,7 @@
package org.sqlite.jni;
/**
Callback for use with {@link SQLite3Jni#sqlite3_prepare_multi}.
Callback for use with {@link CApi#sqlite3_prepare_multi}.
*/
public interface PrepareMultiCallback extends CallbackProxy {
@@ -53,7 +53,7 @@ public interface PrepareMultiCallback extends CallbackProxy {
try {
return this.p.call(st);
}finally{
SQLite3Jni.sqlite3_finalize(st);
CApi.sqlite3_finalize(st);
}
}
}
@@ -70,9 +70,9 @@ public interface PrepareMultiCallback extends CallbackProxy {
else the result of the final step is returned.
*/
@Override public int call(sqlite3_stmt st){
int rc = SQLite3Jni.SQLITE_DONE;
while( SQLite3Jni.SQLITE_ROW == (rc = SQLite3Jni.sqlite3_step(st)) ){}
return SQLite3Jni.SQLITE_DONE==rc ? 0 : rc;
int rc = CApi.SQLITE_DONE;
while( CApi.SQLITE_ROW == (rc = CApi.sqlite3_step(st)) ){}
return CApi.SQLITE_DONE==rc ? 0 : rc;
}
}
}

View File

@@ -14,7 +14,7 @@
package org.sqlite.jni;
/**
Callback for use with {@link SQLite3Jni#sqlite3_preupdate_hook}.
Callback for use with {@link CApi#sqlite3_preupdate_hook}.
*/
public interface PreupdateHookCallback extends CallbackProxy {
/**

View File

@@ -14,7 +14,7 @@
package org.sqlite.jni;
/**
Callback for use with {@link SQLite3Jni#sqlite3_progress_handler}.
Callback for use with {@link CApi#sqlite3_progress_handler}.
*/
public interface ProgressHandlerCallback extends CallbackProxy {
/**

View File

@@ -20,110 +20,110 @@ package org.sqlite.jni;
find it useful to map SQLite result codes to human-readable names.
*/
public enum ResultCode {
SQLITE_OK(SQLite3Jni.SQLITE_OK),
SQLITE_ERROR(SQLite3Jni.SQLITE_ERROR),
SQLITE_INTERNAL(SQLite3Jni.SQLITE_INTERNAL),
SQLITE_PERM(SQLite3Jni.SQLITE_PERM),
SQLITE_ABORT(SQLite3Jni.SQLITE_ABORT),
SQLITE_BUSY(SQLite3Jni.SQLITE_BUSY),
SQLITE_LOCKED(SQLite3Jni.SQLITE_LOCKED),
SQLITE_NOMEM(SQLite3Jni.SQLITE_NOMEM),
SQLITE_READONLY(SQLite3Jni.SQLITE_READONLY),
SQLITE_INTERRUPT(SQLite3Jni.SQLITE_INTERRUPT),
SQLITE_IOERR(SQLite3Jni.SQLITE_IOERR),
SQLITE_CORRUPT(SQLite3Jni.SQLITE_CORRUPT),
SQLITE_NOTFOUND(SQLite3Jni.SQLITE_NOTFOUND),
SQLITE_FULL(SQLite3Jni.SQLITE_FULL),
SQLITE_CANTOPEN(SQLite3Jni.SQLITE_CANTOPEN),
SQLITE_PROTOCOL(SQLite3Jni.SQLITE_PROTOCOL),
SQLITE_EMPTY(SQLite3Jni.SQLITE_EMPTY),
SQLITE_SCHEMA(SQLite3Jni.SQLITE_SCHEMA),
SQLITE_TOOBIG(SQLite3Jni.SQLITE_TOOBIG),
SQLITE_CONSTRAINT(SQLite3Jni.SQLITE_CONSTRAINT),
SQLITE_MISMATCH(SQLite3Jni.SQLITE_MISMATCH),
SQLITE_MISUSE(SQLite3Jni.SQLITE_MISUSE),
SQLITE_NOLFS(SQLite3Jni.SQLITE_NOLFS),
SQLITE_AUTH(SQLite3Jni.SQLITE_AUTH),
SQLITE_FORMAT(SQLite3Jni.SQLITE_FORMAT),
SQLITE_RANGE(SQLite3Jni.SQLITE_RANGE),
SQLITE_NOTADB(SQLite3Jni.SQLITE_NOTADB),
SQLITE_NOTICE(SQLite3Jni.SQLITE_NOTICE),
SQLITE_WARNING(SQLite3Jni.SQLITE_WARNING),
SQLITE_ROW(SQLite3Jni.SQLITE_ROW),
SQLITE_DONE(SQLite3Jni.SQLITE_DONE),
SQLITE_ERROR_MISSING_COLLSEQ(SQLite3Jni.SQLITE_ERROR_MISSING_COLLSEQ),
SQLITE_ERROR_RETRY(SQLite3Jni.SQLITE_ERROR_RETRY),
SQLITE_ERROR_SNAPSHOT(SQLite3Jni.SQLITE_ERROR_SNAPSHOT),
SQLITE_IOERR_READ(SQLite3Jni.SQLITE_IOERR_READ),
SQLITE_IOERR_SHORT_READ(SQLite3Jni.SQLITE_IOERR_SHORT_READ),
SQLITE_IOERR_WRITE(SQLite3Jni.SQLITE_IOERR_WRITE),
SQLITE_IOERR_FSYNC(SQLite3Jni.SQLITE_IOERR_FSYNC),
SQLITE_IOERR_DIR_FSYNC(SQLite3Jni.SQLITE_IOERR_DIR_FSYNC),
SQLITE_IOERR_TRUNCATE(SQLite3Jni.SQLITE_IOERR_TRUNCATE),
SQLITE_IOERR_FSTAT(SQLite3Jni.SQLITE_IOERR_FSTAT),
SQLITE_IOERR_UNLOCK(SQLite3Jni.SQLITE_IOERR_UNLOCK),
SQLITE_IOERR_RDLOCK(SQLite3Jni.SQLITE_IOERR_RDLOCK),
SQLITE_IOERR_DELETE(SQLite3Jni.SQLITE_IOERR_DELETE),
SQLITE_IOERR_BLOCKED(SQLite3Jni.SQLITE_IOERR_BLOCKED),
SQLITE_IOERR_NOMEM(SQLite3Jni.SQLITE_IOERR_NOMEM),
SQLITE_IOERR_ACCESS(SQLite3Jni.SQLITE_IOERR_ACCESS),
SQLITE_IOERR_CHECKRESERVEDLOCK(SQLite3Jni.SQLITE_IOERR_CHECKRESERVEDLOCK),
SQLITE_IOERR_LOCK(SQLite3Jni.SQLITE_IOERR_LOCK),
SQLITE_IOERR_CLOSE(SQLite3Jni.SQLITE_IOERR_CLOSE),
SQLITE_IOERR_DIR_CLOSE(SQLite3Jni.SQLITE_IOERR_DIR_CLOSE),
SQLITE_IOERR_SHMOPEN(SQLite3Jni.SQLITE_IOERR_SHMOPEN),
SQLITE_IOERR_SHMSIZE(SQLite3Jni.SQLITE_IOERR_SHMSIZE),
SQLITE_IOERR_SHMLOCK(SQLite3Jni.SQLITE_IOERR_SHMLOCK),
SQLITE_IOERR_SHMMAP(SQLite3Jni.SQLITE_IOERR_SHMMAP),
SQLITE_IOERR_SEEK(SQLite3Jni.SQLITE_IOERR_SEEK),
SQLITE_IOERR_DELETE_NOENT(SQLite3Jni.SQLITE_IOERR_DELETE_NOENT),
SQLITE_IOERR_MMAP(SQLite3Jni.SQLITE_IOERR_MMAP),
SQLITE_IOERR_GETTEMPPATH(SQLite3Jni.SQLITE_IOERR_GETTEMPPATH),
SQLITE_IOERR_CONVPATH(SQLite3Jni.SQLITE_IOERR_CONVPATH),
SQLITE_IOERR_VNODE(SQLite3Jni.SQLITE_IOERR_VNODE),
SQLITE_IOERR_AUTH(SQLite3Jni.SQLITE_IOERR_AUTH),
SQLITE_IOERR_BEGIN_ATOMIC(SQLite3Jni.SQLITE_IOERR_BEGIN_ATOMIC),
SQLITE_IOERR_COMMIT_ATOMIC(SQLite3Jni.SQLITE_IOERR_COMMIT_ATOMIC),
SQLITE_IOERR_ROLLBACK_ATOMIC(SQLite3Jni.SQLITE_IOERR_ROLLBACK_ATOMIC),
SQLITE_IOERR_DATA(SQLite3Jni.SQLITE_IOERR_DATA),
SQLITE_IOERR_CORRUPTFS(SQLite3Jni.SQLITE_IOERR_CORRUPTFS),
SQLITE_LOCKED_SHAREDCACHE(SQLite3Jni.SQLITE_LOCKED_SHAREDCACHE),
SQLITE_LOCKED_VTAB(SQLite3Jni.SQLITE_LOCKED_VTAB),
SQLITE_BUSY_RECOVERY(SQLite3Jni.SQLITE_BUSY_RECOVERY),
SQLITE_BUSY_SNAPSHOT(SQLite3Jni.SQLITE_BUSY_SNAPSHOT),
SQLITE_BUSY_TIMEOUT(SQLite3Jni.SQLITE_BUSY_TIMEOUT),
SQLITE_CANTOPEN_NOTEMPDIR(SQLite3Jni.SQLITE_CANTOPEN_NOTEMPDIR),
SQLITE_CANTOPEN_ISDIR(SQLite3Jni.SQLITE_CANTOPEN_ISDIR),
SQLITE_CANTOPEN_FULLPATH(SQLite3Jni.SQLITE_CANTOPEN_FULLPATH),
SQLITE_CANTOPEN_CONVPATH(SQLite3Jni.SQLITE_CANTOPEN_CONVPATH),
SQLITE_CANTOPEN_SYMLINK(SQLite3Jni.SQLITE_CANTOPEN_SYMLINK),
SQLITE_CORRUPT_VTAB(SQLite3Jni.SQLITE_CORRUPT_VTAB),
SQLITE_CORRUPT_SEQUENCE(SQLite3Jni.SQLITE_CORRUPT_SEQUENCE),
SQLITE_CORRUPT_INDEX(SQLite3Jni.SQLITE_CORRUPT_INDEX),
SQLITE_READONLY_RECOVERY(SQLite3Jni.SQLITE_READONLY_RECOVERY),
SQLITE_READONLY_CANTLOCK(SQLite3Jni.SQLITE_READONLY_CANTLOCK),
SQLITE_READONLY_ROLLBACK(SQLite3Jni.SQLITE_READONLY_ROLLBACK),
SQLITE_READONLY_DBMOVED(SQLite3Jni.SQLITE_READONLY_DBMOVED),
SQLITE_READONLY_CANTINIT(SQLite3Jni.SQLITE_READONLY_CANTINIT),
SQLITE_READONLY_DIRECTORY(SQLite3Jni.SQLITE_READONLY_DIRECTORY),
SQLITE_ABORT_ROLLBACK(SQLite3Jni.SQLITE_ABORT_ROLLBACK),
SQLITE_CONSTRAINT_CHECK(SQLite3Jni.SQLITE_CONSTRAINT_CHECK),
SQLITE_CONSTRAINT_COMMITHOOK(SQLite3Jni.SQLITE_CONSTRAINT_COMMITHOOK),
SQLITE_CONSTRAINT_FOREIGNKEY(SQLite3Jni.SQLITE_CONSTRAINT_FOREIGNKEY),
SQLITE_CONSTRAINT_FUNCTION(SQLite3Jni.SQLITE_CONSTRAINT_FUNCTION),
SQLITE_CONSTRAINT_NOTNULL(SQLite3Jni.SQLITE_CONSTRAINT_NOTNULL),
SQLITE_CONSTRAINT_PRIMARYKEY(SQLite3Jni.SQLITE_CONSTRAINT_PRIMARYKEY),
SQLITE_CONSTRAINT_TRIGGER(SQLite3Jni.SQLITE_CONSTRAINT_TRIGGER),
SQLITE_CONSTRAINT_UNIQUE(SQLite3Jni.SQLITE_CONSTRAINT_UNIQUE),
SQLITE_CONSTRAINT_VTAB(SQLite3Jni.SQLITE_CONSTRAINT_VTAB),
SQLITE_CONSTRAINT_ROWID(SQLite3Jni.SQLITE_CONSTRAINT_ROWID),
SQLITE_CONSTRAINT_PINNED(SQLite3Jni.SQLITE_CONSTRAINT_PINNED),
SQLITE_CONSTRAINT_DATATYPE(SQLite3Jni.SQLITE_CONSTRAINT_DATATYPE),
SQLITE_NOTICE_RECOVER_WAL(SQLite3Jni.SQLITE_NOTICE_RECOVER_WAL),
SQLITE_NOTICE_RECOVER_ROLLBACK(SQLite3Jni.SQLITE_NOTICE_RECOVER_ROLLBACK),
SQLITE_WARNING_AUTOINDEX(SQLite3Jni.SQLITE_WARNING_AUTOINDEX),
SQLITE_AUTH_USER(SQLite3Jni.SQLITE_AUTH_USER),
SQLITE_OK_LOAD_PERMANENTLY(SQLite3Jni.SQLITE_OK_LOAD_PERMANENTLY);
SQLITE_OK(CApi.SQLITE_OK),
SQLITE_ERROR(CApi.SQLITE_ERROR),
SQLITE_INTERNAL(CApi.SQLITE_INTERNAL),
SQLITE_PERM(CApi.SQLITE_PERM),
SQLITE_ABORT(CApi.SQLITE_ABORT),
SQLITE_BUSY(CApi.SQLITE_BUSY),
SQLITE_LOCKED(CApi.SQLITE_LOCKED),
SQLITE_NOMEM(CApi.SQLITE_NOMEM),
SQLITE_READONLY(CApi.SQLITE_READONLY),
SQLITE_INTERRUPT(CApi.SQLITE_INTERRUPT),
SQLITE_IOERR(CApi.SQLITE_IOERR),
SQLITE_CORRUPT(CApi.SQLITE_CORRUPT),
SQLITE_NOTFOUND(CApi.SQLITE_NOTFOUND),
SQLITE_FULL(CApi.SQLITE_FULL),
SQLITE_CANTOPEN(CApi.SQLITE_CANTOPEN),
SQLITE_PROTOCOL(CApi.SQLITE_PROTOCOL),
SQLITE_EMPTY(CApi.SQLITE_EMPTY),
SQLITE_SCHEMA(CApi.SQLITE_SCHEMA),
SQLITE_TOOBIG(CApi.SQLITE_TOOBIG),
SQLITE_CONSTRAINT(CApi.SQLITE_CONSTRAINT),
SQLITE_MISMATCH(CApi.SQLITE_MISMATCH),
SQLITE_MISUSE(CApi.SQLITE_MISUSE),
SQLITE_NOLFS(CApi.SQLITE_NOLFS),
SQLITE_AUTH(CApi.SQLITE_AUTH),
SQLITE_FORMAT(CApi.SQLITE_FORMAT),
SQLITE_RANGE(CApi.SQLITE_RANGE),
SQLITE_NOTADB(CApi.SQLITE_NOTADB),
SQLITE_NOTICE(CApi.SQLITE_NOTICE),
SQLITE_WARNING(CApi.SQLITE_WARNING),
SQLITE_ROW(CApi.SQLITE_ROW),
SQLITE_DONE(CApi.SQLITE_DONE),
SQLITE_ERROR_MISSING_COLLSEQ(CApi.SQLITE_ERROR_MISSING_COLLSEQ),
SQLITE_ERROR_RETRY(CApi.SQLITE_ERROR_RETRY),
SQLITE_ERROR_SNAPSHOT(CApi.SQLITE_ERROR_SNAPSHOT),
SQLITE_IOERR_READ(CApi.SQLITE_IOERR_READ),
SQLITE_IOERR_SHORT_READ(CApi.SQLITE_IOERR_SHORT_READ),
SQLITE_IOERR_WRITE(CApi.SQLITE_IOERR_WRITE),
SQLITE_IOERR_FSYNC(CApi.SQLITE_IOERR_FSYNC),
SQLITE_IOERR_DIR_FSYNC(CApi.SQLITE_IOERR_DIR_FSYNC),
SQLITE_IOERR_TRUNCATE(CApi.SQLITE_IOERR_TRUNCATE),
SQLITE_IOERR_FSTAT(CApi.SQLITE_IOERR_FSTAT),
SQLITE_IOERR_UNLOCK(CApi.SQLITE_IOERR_UNLOCK),
SQLITE_IOERR_RDLOCK(CApi.SQLITE_IOERR_RDLOCK),
SQLITE_IOERR_DELETE(CApi.SQLITE_IOERR_DELETE),
SQLITE_IOERR_BLOCKED(CApi.SQLITE_IOERR_BLOCKED),
SQLITE_IOERR_NOMEM(CApi.SQLITE_IOERR_NOMEM),
SQLITE_IOERR_ACCESS(CApi.SQLITE_IOERR_ACCESS),
SQLITE_IOERR_CHECKRESERVEDLOCK(CApi.SQLITE_IOERR_CHECKRESERVEDLOCK),
SQLITE_IOERR_LOCK(CApi.SQLITE_IOERR_LOCK),
SQLITE_IOERR_CLOSE(CApi.SQLITE_IOERR_CLOSE),
SQLITE_IOERR_DIR_CLOSE(CApi.SQLITE_IOERR_DIR_CLOSE),
SQLITE_IOERR_SHMOPEN(CApi.SQLITE_IOERR_SHMOPEN),
SQLITE_IOERR_SHMSIZE(CApi.SQLITE_IOERR_SHMSIZE),
SQLITE_IOERR_SHMLOCK(CApi.SQLITE_IOERR_SHMLOCK),
SQLITE_IOERR_SHMMAP(CApi.SQLITE_IOERR_SHMMAP),
SQLITE_IOERR_SEEK(CApi.SQLITE_IOERR_SEEK),
SQLITE_IOERR_DELETE_NOENT(CApi.SQLITE_IOERR_DELETE_NOENT),
SQLITE_IOERR_MMAP(CApi.SQLITE_IOERR_MMAP),
SQLITE_IOERR_GETTEMPPATH(CApi.SQLITE_IOERR_GETTEMPPATH),
SQLITE_IOERR_CONVPATH(CApi.SQLITE_IOERR_CONVPATH),
SQLITE_IOERR_VNODE(CApi.SQLITE_IOERR_VNODE),
SQLITE_IOERR_AUTH(CApi.SQLITE_IOERR_AUTH),
SQLITE_IOERR_BEGIN_ATOMIC(CApi.SQLITE_IOERR_BEGIN_ATOMIC),
SQLITE_IOERR_COMMIT_ATOMIC(CApi.SQLITE_IOERR_COMMIT_ATOMIC),
SQLITE_IOERR_ROLLBACK_ATOMIC(CApi.SQLITE_IOERR_ROLLBACK_ATOMIC),
SQLITE_IOERR_DATA(CApi.SQLITE_IOERR_DATA),
SQLITE_IOERR_CORRUPTFS(CApi.SQLITE_IOERR_CORRUPTFS),
SQLITE_LOCKED_SHAREDCACHE(CApi.SQLITE_LOCKED_SHAREDCACHE),
SQLITE_LOCKED_VTAB(CApi.SQLITE_LOCKED_VTAB),
SQLITE_BUSY_RECOVERY(CApi.SQLITE_BUSY_RECOVERY),
SQLITE_BUSY_SNAPSHOT(CApi.SQLITE_BUSY_SNAPSHOT),
SQLITE_BUSY_TIMEOUT(CApi.SQLITE_BUSY_TIMEOUT),
SQLITE_CANTOPEN_NOTEMPDIR(CApi.SQLITE_CANTOPEN_NOTEMPDIR),
SQLITE_CANTOPEN_ISDIR(CApi.SQLITE_CANTOPEN_ISDIR),
SQLITE_CANTOPEN_FULLPATH(CApi.SQLITE_CANTOPEN_FULLPATH),
SQLITE_CANTOPEN_CONVPATH(CApi.SQLITE_CANTOPEN_CONVPATH),
SQLITE_CANTOPEN_SYMLINK(CApi.SQLITE_CANTOPEN_SYMLINK),
SQLITE_CORRUPT_VTAB(CApi.SQLITE_CORRUPT_VTAB),
SQLITE_CORRUPT_SEQUENCE(CApi.SQLITE_CORRUPT_SEQUENCE),
SQLITE_CORRUPT_INDEX(CApi.SQLITE_CORRUPT_INDEX),
SQLITE_READONLY_RECOVERY(CApi.SQLITE_READONLY_RECOVERY),
SQLITE_READONLY_CANTLOCK(CApi.SQLITE_READONLY_CANTLOCK),
SQLITE_READONLY_ROLLBACK(CApi.SQLITE_READONLY_ROLLBACK),
SQLITE_READONLY_DBMOVED(CApi.SQLITE_READONLY_DBMOVED),
SQLITE_READONLY_CANTINIT(CApi.SQLITE_READONLY_CANTINIT),
SQLITE_READONLY_DIRECTORY(CApi.SQLITE_READONLY_DIRECTORY),
SQLITE_ABORT_ROLLBACK(CApi.SQLITE_ABORT_ROLLBACK),
SQLITE_CONSTRAINT_CHECK(CApi.SQLITE_CONSTRAINT_CHECK),
SQLITE_CONSTRAINT_COMMITHOOK(CApi.SQLITE_CONSTRAINT_COMMITHOOK),
SQLITE_CONSTRAINT_FOREIGNKEY(CApi.SQLITE_CONSTRAINT_FOREIGNKEY),
SQLITE_CONSTRAINT_FUNCTION(CApi.SQLITE_CONSTRAINT_FUNCTION),
SQLITE_CONSTRAINT_NOTNULL(CApi.SQLITE_CONSTRAINT_NOTNULL),
SQLITE_CONSTRAINT_PRIMARYKEY(CApi.SQLITE_CONSTRAINT_PRIMARYKEY),
SQLITE_CONSTRAINT_TRIGGER(CApi.SQLITE_CONSTRAINT_TRIGGER),
SQLITE_CONSTRAINT_UNIQUE(CApi.SQLITE_CONSTRAINT_UNIQUE),
SQLITE_CONSTRAINT_VTAB(CApi.SQLITE_CONSTRAINT_VTAB),
SQLITE_CONSTRAINT_ROWID(CApi.SQLITE_CONSTRAINT_ROWID),
SQLITE_CONSTRAINT_PINNED(CApi.SQLITE_CONSTRAINT_PINNED),
SQLITE_CONSTRAINT_DATATYPE(CApi.SQLITE_CONSTRAINT_DATATYPE),
SQLITE_NOTICE_RECOVER_WAL(CApi.SQLITE_NOTICE_RECOVER_WAL),
SQLITE_NOTICE_RECOVER_ROLLBACK(CApi.SQLITE_NOTICE_RECOVER_ROLLBACK),
SQLITE_WARNING_AUTOINDEX(CApi.SQLITE_WARNING_AUTOINDEX),
SQLITE_AUTH_USER(CApi.SQLITE_AUTH_USER),
SQLITE_OK_LOAD_PERMANENTLY(CApi.SQLITE_OK_LOAD_PERMANENTLY);
public final int value;

View File

@@ -14,7 +14,7 @@
package org.sqlite.jni;
/**
Callback for use with {@link SQLite3Jni#sqlite3_rollback_hook}.
Callback for use with {@link CApi#sqlite3_rollback_hook}.
*/
public interface RollbackHookCallback extends CallbackProxy {
/**

View File

@@ -18,7 +18,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.nio.charset.StandardCharsets;
import java.util.regex.*;
import static org.sqlite.jni.SQLite3Jni.*;
import static org.sqlite.jni.CApi.*;
/**
Modes for how to escape (or not) column values and names from
@@ -668,7 +668,7 @@ public class SQLTester {
static {
System.loadLibrary("sqlite3-jni")
/* Interestingly, when SQLTester is the main app, we have to
load that lib from here. The same load from SQLite3Jni does
load that lib from here. The same load from CApi does
not happen early enough. Without this,
installCustomExtensions() is an unresolved symbol. */;
}

View File

@@ -0,0 +1,69 @@
/*
** 2023-10-09
**
** 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 is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni;
import static org.sqlite.jni.CApi.*;
/**
This class represents a database connection, analog to the C-side
sqlite3 class but with added argument validation, exceptions, and
similar "smoothing of sharp edges" to make the API safe to use from
Java. It also acts as a namespace for other types for which
individual instances are tied to a specific database connection.
*/
public final class Sqlite implements AutoCloseable {
private sqlite3 db = null;
//! Used only by the open() factory functions.
private Sqlite(sqlite3 db){
this.db = db;
}
/**
Returns a newly-opened db connection or throws SqliteException if
opening fails. All arguments are as documented for
sqlite3_open_v2().
*/
public static Sqlite open(String filename, int flags, String vfsName){
final OutputPointer.sqlite3 out = new OutputPointer.sqlite3();
final int rc = sqlite3_open_v2(filename, out, flags, vfsName);
final sqlite3 n = out.take();
if( 0!=rc ){
if( null==n ) throw new SqliteException(rc);
else throw new SqliteException(n);
}
return new Sqlite(n);
}
public static Sqlite open(String filename, int flags){
return open(filename, flags, null);
}
public static Sqlite open(String filename){
return open(filename, 0, null);
}
@Override public void close(){
if(null!=this.db){
this.db.close();
this.db = null;
}
}
/**
Returns this object's underlying native db handle, or null if
this instance has been closed.
*/
sqlite3 dbHandle(){ return this.db; }
}

View File

@@ -0,0 +1,73 @@
/*
** 2023-10-09
**
** 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 is part of the JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni;
import static org.sqlite.jni.CApi.*;
/**
A wrapper for communicating C-level (sqlite3*) instances with
Java. These wrappers do not own their associated pointer, they
simply provide a type-safe way to communicate it between Java
and C via JNI.
*/
public final class SqliteException extends java.lang.RuntimeException {
int errCode = SQLITE_ERROR;
int xerrCode = SQLITE_ERROR;
int errOffset = -1;
int sysErrno = 0;
/**
Records the given error string and uses SQLITE_ERROR for both the
error code and extended error code.
*/
public SqliteException(String msg){
super(msg);
}
/**
Uses sqlite3_errstr(sqlite3ResultCode) for the error string and
sets both the error code and extended error code to the given
value.
*/
public SqliteException(int sqlite3ResultCode){
super(sqlite3_errstr(sqlite3ResultCode));
errCode = xerrCode = sqlite3ResultCode;
}
/**
Records the current error state of db (which must not be null and
must refer to an opened db object) then closes it.
*/
public SqliteException(sqlite3 db){
super(sqlite3_errmsg(db));
errCode = sqlite3_errcode(db);
xerrCode = sqlite3_extended_errcode(db);
errOffset = sqlite3_error_offset(db);
sysErrno = sqlite3_system_errno(db);
db.close();
}
/**
Records the current error state of db (which must not be null and must
refer to an open database) then closes it.
*/
public SqliteException(Sqlite db){
this(db.dbHandle());
}
public int errcode(){ return errCode; }
public int extendedErrcode(){ return xerrCode; }
public int errorOffset(){ return errOffset; }
public int systemErrno(){ return sysErrno; }
}

View File

@@ -12,7 +12,7 @@
** This file contains a set of tests for the sqlite3 JNI bindings.
*/
package org.sqlite.jni;
import static org.sqlite.jni.SQLite3Jni.*;
import static org.sqlite.jni.CApi.*;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.ArrayList;
@@ -934,7 +934,7 @@ public class Tester1 implements Runnable {
private void listBoundMethods(){
if(false){
final java.lang.reflect.Field[] declaredFields =
SQLite3Jni.class.getDeclaredFields();
CApi.class.getDeclaredFields();
outln("Bound constants:\n");
for(java.lang.reflect.Field field : declaredFields) {
if(java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
@@ -943,7 +943,7 @@ public class Tester1 implements Runnable {
}
}
final java.lang.reflect.Method[] declaredMethods =
SQLite3Jni.class.getDeclaredMethods();
CApi.class.getDeclaredMethods();
final java.util.List<String> funcList = new java.util.ArrayList<>();
for(java.lang.reflect.Method m : declaredMethods){
if((m.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0){
@@ -1925,29 +1925,24 @@ public class Tester1 implements Runnable {
sqlite3_shutdown();
int nMethods = 0;
int nNatives = 0;
int nCanonical = 0;
final java.lang.reflect.Method[] declaredMethods =
SQLite3Jni.class.getDeclaredMethods();
CApi.class.getDeclaredMethods();
for(java.lang.reflect.Method m : declaredMethods){
final int mod = m.getModifiers();
if( 0!=(mod & java.lang.reflect.Modifier.STATIC) ){
final String name = m.getName();
if(name.startsWith("sqlite3_")){
++nMethods;
if( m.isAnnotationPresent( org.sqlite.jni.annotation.Canonical.class ) ){
++nCanonical;
}
if( 0!=(mod & java.lang.reflect.Modifier.NATIVE) ){
++nNatives;
}
}
}
}
outln("\tSQLite3Jni.sqlite3_*() methods: "+
outln("\tCApi.sqlite3_*() methods: "+
nMethods+" total, with "+
nNatives+" native, "+
(nMethods - nNatives)+" Java, ",
nCanonical," @Canonical"
(nMethods - nNatives)+" Java"
);
outln("\tTotal test time = "
+(timeEnd - timeStart)+"ms");

View File

@@ -0,0 +1,417 @@
/*
** 2023-10-09
**
** 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 contains a set of tests for the sqlite3 JNI bindings.
*/
package org.sqlite.jni;
import static org.sqlite.jni.CApi.*;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Tester2 implements Runnable {
//! True when running in multi-threaded mode.
private static boolean mtMode = false;
//! True to sleep briefly between tests.
private static boolean takeNaps = false;
//! True to shuffle the order of the tests.
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()
private static List<Exception> listErrors = new ArrayList<>();
private static final class Metrics {
//! Number of times createNewDb() (or equivalent) is invoked.
volatile int dbOpen = 0;
}
//! Instance ID.
private Integer tId;
Tester2(Integer id){
tId = id;
}
static final Metrics metrics = new Metrics();
public static synchronized void outln(){
if( !quietMode ){
System.out.println("");
}
}
public static synchronized void outPrefix(){
if( !quietMode ){
System.out.print(Thread.currentThread().getName()+": ");
}
}
public static synchronized void outln(Object val){
if( !quietMode ){
outPrefix();
System.out.println(val);
}
}
public static synchronized void out(Object val){
if( !quietMode ){
System.out.print(val);
}
}
@SuppressWarnings("unchecked")
public static synchronized void out(Object... vals){
if( !quietMode ){
outPrefix();
for(Object v : vals) out(v);
}
}
@SuppressWarnings("unchecked")
public static synchronized void outln(Object... vals){
if( !quietMode ){
out(vals); out("\n");
}
}
static volatile int affirmCount = 0;
public static synchronized int affirm(Boolean v, String comment){
++affirmCount;
if( false ) assert( v /* prefer assert over exception if it's enabled because
the JNI layer sometimes has to suppress exceptions,
so they might be squelched on their way back to the
top. */);
if( !v ) throw new RuntimeException(comment);
return affirmCount;
}
public static void affirm(Boolean v){
affirm(v, "Affirmation failed.");
}
@SingleThreadOnly /* because it's thread-agnostic */
private void test1(){
affirm(sqlite3_libversion_number() == 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 {
if( takeNaps ){
Thread.sleep(java.util.concurrent.ThreadLocalRandom.current().nextInt(3, 17), 0);
}
}
@ManualTest /* because we only want to run this test on demand */
private void testFail(){
affirm( false, "Intentional failure." );
}
private void runTests(boolean fromThread) throws Exception {
List<java.lang.reflect.Method> mlist = testMethods;
affirm( null!=mlist );
if( shuffle ){
mlist = new ArrayList<>( testMethods.subList(0, testMethods.size()) );
java.util.Collections.shuffle(mlist);
}
if( listRunTests ){
synchronized(this.getClass()){
if( !fromThread ){
out("Initial test"," list: ");
for(java.lang.reflect.Method m : testMethods){
out(m.getName()+" ");
}
outln();
outln("(That list excludes some which are hard-coded to run.)");
}
out("Running"," tests: ");
for(java.lang.reflect.Method m : mlist){
out(m.getName()+" ");
}
outln();
}
}
for(java.lang.reflect.Method m : mlist){
nap();
try{
m.invoke(this);
}catch(java.lang.reflect.InvocationTargetException e){
outln("FAILURE: ",m.getName(),"(): ", e.getCause());
throw e;
}
}
synchronized( this.getClass() ){
++nTestRuns;
}
}
public void run() {
try {
runTests(0!=this.tId);
}catch(Exception e){
synchronized( listErrors ){
listErrors.add(e);
}
}finally{
affirm( sqlite3_java_uncache_thread() );
affirm( !sqlite3_java_uncache_thread() );
}
}
/**
Runs the basic sqlite3 JNI binding sanity-check suite.
CLI flags:
-q|-quiet: disables most test output.
-t|-thread N: runs the tests in N threads
concurrently. Default=1.
-r|-repeat N: repeats the tests in a loop N times, each one
consisting of the -thread value's threads.
-shuffle: randomizes the order of most of the test functions.
-naps: sleep small random intervals between tests in order to add
some chaos for cross-thread contention.
-list-tests: outputs the list of tests being run, minus some
which are hard-coded. This is noisy in multi-threaded mode.
-fail: forces an exception to be thrown during the test run. Use
with -shuffle to make its appearance unpredictable.
-v: emit some developer-mode info at the end.
*/
public static void main(String[] args) throws Exception {
Integer nThread = 1;
boolean doSomethingForDev = false;
Integer nRepeat = 1;
boolean forceFail = false;
boolean sqlLog = false;
boolean configLog = false;
boolean squelchTestOutput = false;
for( int i = 0; i < args.length; ){
String arg = args[i++];
if(arg.startsWith("-")){
arg = arg.replaceFirst("-+","");
if(arg.equals("v")){
doSomethingForDev = true;
//listBoundMethods();
}else if(arg.equals("t") || arg.equals("thread")){
nThread = Integer.parseInt(args[i++]);
}else if(arg.equals("r") || arg.equals("repeat")){
nRepeat = Integer.parseInt(args[i++]);
}else if(arg.equals("shuffle")){
shuffle = true;
}else if(arg.equals("list-tests")){
listRunTests = true;
}else if(arg.equals("fail")){
forceFail = true;
}else if(arg.equals("sqllog")){
sqlLog = true;
}else if(arg.equals("configlog")){
configLog = 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);
}
}
}
if( sqlLog ){
if( sqlite3_compileoption_used("ENABLE_SQLLOG") ){
final ConfigSqllogCallback log = new ConfigSqllogCallback() {
@Override public void call(sqlite3 db, String msg, int op){
switch(op){
case 0: outln("Opening db: ",db); break;
case 1: outln("SQL ",db,": ",msg); break;
case 2: outln("Closing db: ",db); break;
}
}
};
int rc = sqlite3_config( log );
affirm( 0==rc );
rc = sqlite3_config( (ConfigSqllogCallback)null );
affirm( 0==rc );
rc = sqlite3_config( log );
affirm( 0==rc );
}else{
outln("WARNING: -sqllog is not active because library was built ",
"without SQLITE_ENABLE_SQLLOG.");
}
}
if( configLog ){
final ConfigLogCallback log = new ConfigLogCallback() {
@Override public void call(int code, String msg){
outln("ConfigLogCallback: ",ResultCode.getEntryForInt(code),": ", msg);
};
};
int rc = sqlite3_config( log );
affirm( 0==rc );
rc = sqlite3_config( (ConfigLogCallback)null );
affirm( 0==rc );
rc = sqlite3_config( log );
affirm( 0==rc );
}
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.");
{
// Build list of tests to run from the methods named test*().
testMethods = new ArrayList<>();
int nSkipped = 0;
for(final java.lang.reflect.Method m : Tester2.class.getDeclaredMethods()){
final String name = m.getName();
if( name.equals("testFail") ){
if( forceFail ){
testMethods.add(m);
}
}else if( !m.isAnnotationPresent( ManualTest.class ) ){
if( nThread>1 && m.isAnnotationPresent( SingleThreadOnly.class ) ){
if( 0==nSkipped++ ){
out("Skipping tests in multi-thread mode:");
}
out(" "+name+"()");
}else if( name.startsWith("test") ){
testMethods.add(m);
}
}
}
if( nSkipped>0 ) out("\n");
}
final long timeStart = System.currentTimeMillis();
int nLoop = 0;
switch( sqlite3_threadsafe() ){ /* Sanity checking */
case 0:
affirm( SQLITE_ERROR==sqlite3_config( SQLITE_CONFIG_SINGLETHREAD ),
"Could not switch to single-thread mode." );
affirm( SQLITE_ERROR==sqlite3_config( SQLITE_CONFIG_MULTITHREAD ),
"Could switch to multithread mode." );
affirm( SQLITE_ERROR==sqlite3_config( 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==sqlite3_config( SQLITE_CONFIG_SINGLETHREAD ),
"Could not switch to single-thread mode." );
affirm( 0==sqlite3_config( SQLITE_CONFIG_MULTITHREAD ),
"Could not switch to multithread mode." );
affirm( 0==sqlite3_config( SQLITE_CONFIG_SERIALIZED ),
"Could not switch to serialized threading mode." );
break;
default:
affirm( false, "Unhandled SQLITE_THREADSAFE value." );
}
outln("libversion_number: ",
sqlite3_libversion_number(),"\n",
sqlite3_libversion(),"\n",SQLITE_SOURCE_ID,"\n",
"SQLITE_THREADSAFE=",sqlite3_threadsafe());
final boolean showLoopCount = (nRepeat>1 && nThread>1);
if( showLoopCount ){
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 ){
++nLoop;
if( showLoopCount ) out((1==nLoop ? "" : " ")+nLoop);
if( nThread<=1 ){
new Tester2(0).runTests(false);
continue;
}
Tester2.mtMode = true;
final ExecutorService ex = Executors.newFixedThreadPool( nThread );
for( int i = 0; i < nThread; ++i ){
ex.submit( new Tester2(i), i );
}
ex.shutdown();
try{
ex.awaitTermination(nThread*200, java.util.concurrent.TimeUnit.MILLISECONDS);
ex.shutdownNow();
}catch (InterruptedException ie){
ex.shutdownNow();
Thread.currentThread().interrupt();
}
if( !listErrors.isEmpty() ){
quietMode = false;
outln("TEST ERRORS:");
Exception err = null;
for( Exception e : listErrors ){
e.printStackTrace();
if( null==err ) err = e;
}
if( null!=err ) throw err;
}
}
if( showLoopCount ) outln();
quietMode = false;
final long timeEnd = System.currentTimeMillis();
outln("Tests done. Metrics across ",nTestRuns," total iteration(s):");
outln("\tAssertions checked: ",affirmCount);
outln("\tDatabases opened: ",metrics.dbOpen);
if( doSomethingForDev ){
sqlite3_jni_internal_details();
}
affirm( 0==sqlite3_release_memory(1) );
sqlite3_shutdown();
int nMethods = 0;
int nNatives = 0;
int nCanonical = 0;
final java.lang.reflect.Method[] declaredMethods =
CApi.class.getDeclaredMethods();
for(java.lang.reflect.Method m : declaredMethods){
final int mod = m.getModifiers();
if( 0!=(mod & java.lang.reflect.Modifier.STATIC) ){
final String name = m.getName();
if(name.startsWith("sqlite3_")){
++nMethods;
if( 0!=(mod & java.lang.reflect.Modifier.NATIVE) ){
++nNatives;
}
}
}
}
outln("\tCApi.sqlite3_*() methods: "+
nMethods+" total, with "+
nNatives+" native, "+
(nMethods - nNatives)+" Java"
);
outln("\tTotal test time = "
+(timeEnd - timeStart)+"ms");
}
}

View File

@@ -12,7 +12,7 @@
** This file contains a set of tests for the sqlite3 JNI bindings.
*/
package org.sqlite.jni;
import static org.sqlite.jni.SQLite3Jni.*;
import static org.sqlite.jni.CApi.*;
import static org.sqlite.jni.Tester1.*;
import org.sqlite.jni.*;
import org.sqlite.jni.fts5.*;

View File

@@ -15,7 +15,7 @@ package org.sqlite.jni;
import org.sqlite.jni.annotation.Nullable;
/**
Callback for use with {@link SQLite3Jni#sqlite3_trace_v2}.
Callback for use with {@link CApi#sqlite3_trace_v2}.
*/
public interface TraceV2Callback extends CallbackProxy {
/**

View File

@@ -14,7 +14,7 @@
package org.sqlite.jni;
/**
Callback for use with {@link SQLite3Jni#sqlite3_update_hook}.
Callback for use with {@link CApi#sqlite3_update_hook}.
*/
public interface UpdateHookCallback extends CallbackProxy {
/**

View File

@@ -1,48 +0,0 @@
/*
** 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 Canonical annotaion for the sqlite3 C API.
*/
package org.sqlite.jni.annotation;
/**
This annotation is for marking functions as "canonical", meaning
that they map directly to a function in the core sqlite3 C API. The
intent is to distinguish them from functions added specifically to
the Java API.
<p>Canonical functions, unless specifically documented, have the
same semantics as their counterparts in <a
href="https://sqlite.org/c3ref/intro.html">the C API
documentation</a>, despite their signatures perhaps differing
slightly. Canonical forms may be native or implemented in Java.
Sometimes multiple overloads are labeled as Canonical because one
or more of them are just type- or encoding-related conversion
wrappers but provide identical semantics (e.g. from a String to a
byte[]). The Java API adds a number of convenience overloads to
simplify use, as well as a few Java-specific functions, and those
are never flagged as @Canonical.
<p>In some cases, the canonical version of a function is private
and exposed to Java via public overloads.
<p>The comment property can be used to add a comment.
*/
@java.lang.annotation.Documented
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD)
public @interface Canonical{
/**
Brief comments about the binding, e.g. noting any major
semantic differences.
*/
String comment() default "";
}

View File

@@ -33,67 +33,51 @@ public final class Fts5ExtensionApi extends NativePointerHolder<Fts5ExtensionApi
*/
public static native Fts5ExtensionApi getInstance();
@Canonical
public native int xColumnCount(@NotNull Fts5Context fcx);
@Canonical
public native int xColumnSize(@NotNull Fts5Context cx, int iCol,
@NotNull OutputPointer.Int32 pnToken);
@Canonical
public native int xColumnText(@NotNull Fts5Context cx, int iCol,
@NotNull OutputPointer.String txt);
@Canonical
public native int xColumnTotalSize(@NotNull Fts5Context fcx, int iCol,
@NotNull OutputPointer.Int64 pnToken);
@Canonical
public native Object xGetAuxdata(@NotNull Fts5Context cx, boolean clearIt);
@Canonical
public native int xInst(@NotNull Fts5Context cx, int iIdx,
@NotNull OutputPointer.Int32 piPhrase,
@NotNull OutputPointer.Int32 piCol,
@NotNull OutputPointer.Int32 piOff);
@Canonical
public native int xInstCount(@NotNull Fts5Context fcx,
@NotNull OutputPointer.Int32 pnInst);
@Canonical
public native int xPhraseCount(@NotNull Fts5Context fcx);
@Canonical
public native int xPhraseFirst(@NotNull Fts5Context cx, int iPhrase,
@NotNull Fts5PhraseIter iter,
@NotNull OutputPointer.Int32 iCol,
@NotNull OutputPointer.Int32 iOff);
@Canonical
public native int xPhraseFirstColumn(@NotNull Fts5Context cx, int iPhrase,
@NotNull Fts5PhraseIter iter,
@NotNull OutputPointer.Int32 iCol);
@Canonical
public native void xPhraseNext(@NotNull Fts5Context cx,
@NotNull Fts5PhraseIter iter,
@NotNull OutputPointer.Int32 iCol,
@NotNull OutputPointer.Int32 iOff);
@Canonical
public native void xPhraseNextColumn(@NotNull Fts5Context cx,
@NotNull Fts5PhraseIter iter,
@NotNull OutputPointer.Int32 iCol);
@Canonical
public native int xPhraseSize(@NotNull Fts5Context fcx, int iPhrase);
@Canonical
public native int xQueryPhrase(@NotNull Fts5Context cx, int iPhrase,
@NotNull XQueryPhraseCallback callback);
@Canonical
public native int xRowCount(@NotNull Fts5Context fcx,
@NotNull OutputPointer.Int64 nRow);
@Canonical
public native long xRowid(@NotNull Fts5Context cx);
/* Note that the JNI binding lacks the C version's xDelete()
callback argument. Instead, if pAux has an xDestroy() method, it
@@ -102,14 +86,11 @@ public final class Fts5ExtensionApi extends NativePointerHolder<Fts5ExtensionApi
pAux held by the JNI layer will be relinquished regardless of
whether pAux has an xDestroy() method. */
@Canonical
public native int xSetAuxdata(@NotNull Fts5Context cx, @Nullable Object pAux);
@Canonical
public native int xTokenize(@NotNull Fts5Context cx, @NotNull byte[] pText,
@NotNull XTokenizeCallback callback);
@Canonical
public native Object xUserData(Fts5Context cx);
//^^^ returns the pointer passed as the 3rd arg to the C-level
// fts5_api::xCreateFunction().

View File

@@ -33,7 +33,6 @@ public final class fts5_api extends NativePointerHolder<fts5_api> {
*/
public static synchronized native fts5_api getInstanceForDb(@NotNull sqlite3 db);
@Canonical
public synchronized native int xCreateFunction(@NotNull String name,
@Nullable Object userData,
@NotNull fts5_extension_function xFunction);

View File

@@ -2,7 +2,7 @@
This package houses a JNI binding to the SQLite3 C API.
<p>The primary interfaces are in {@link
org.sqlite.jni.SQLite3Jni}.</p>
org.sqlite.jni.CApi}.</p>
<h1>API Goals and Requirements</h1>

View File

@@ -30,19 +30,14 @@ public final class sqlite3 extends NativePointerHolder<sqlite3>
if( 0==ptr ){
return sqlite3.class.getSimpleName()+"@null";
}
final String fn = SQLite3Jni.sqlite3_db_filename(this, "main");
final String fn = CApi.sqlite3_db_filename(this, "main");
return sqlite3.class.getSimpleName()
+"@"+String.format("0x%08x",ptr)
+"["+((null == fn) ? "<unnamed>" : fn)+"]"
;
}
@Override protected void finalize(){
//System.out.println(this+".finalize()");
SQLite3Jni.sqlite3_close_v2(this.clearNativePointer());
}
@Override public void close(){
SQLite3Jni.sqlite3_close_v2(this.clearNativePointer());
CApi.sqlite3_close_v2(this.clearNativePointer());
}
}

View File

@@ -25,7 +25,7 @@ public final class sqlite3_backup extends NativePointerHolder<sqlite3_backup>
private sqlite3_backup(){}
@Override public void close(){
SQLite3Jni.sqlite3_backup_finish(this);
CApi.sqlite3_backup_finish(this);
}
}

View File

@@ -25,7 +25,7 @@ public final class sqlite3_blob extends NativePointerHolder<sqlite3_blob>
private sqlite3_blob(){}
@Override public void close(){
SQLite3Jni.sqlite3_blob_close(this.clearNativePointer());
CApi.sqlite3_blob_close(this.clearNativePointer());
}
}

View File

@@ -71,7 +71,7 @@ public final class sqlite3_context extends NativePointerHolder<sqlite3_context>
*/
public synchronized Long getAggregateContext(boolean initIfNeeded){
if( aggregateContext==null ){
aggregateContext = SQLite3Jni.sqlite3_aggregate_context(this, initIfNeeded);
aggregateContext = CApi.sqlite3_aggregate_context(this, initIfNeeded);
if( !initIfNeeded && null==aggregateContext ) aggregateContext = 0L;
}
return (null==aggregateContext || 0!=aggregateContext) ? aggregateContext : null;

View File

@@ -24,12 +24,7 @@ public final class sqlite3_stmt extends NativePointerHolder<sqlite3_stmt>
// Only invoked from JNI.
private sqlite3_stmt(){}
//For as-yet-unknown reasons, this triggers a JVM crash.
//@Override protected void finalize(){
// SQLite3Jni.sqlite3_finalize(this.clearNativePointer());
//}
@Override public void close(){
SQLite3Jni.sqlite3_finalize(this.clearNativePointer());
CApi.sqlite3_finalize(this.clearNativePointer());
}
}

View File

@@ -135,8 +135,8 @@ do_test 2.2.2 {
DROP TABLE t2;
CREATE TABLE t2(a, b PRIMARY KEY, c, d);
}
list [catch { S changeset } msg] $msg
} {1 SQLITE_SCHEMA}
catch { S changeset }
} {0}
do_test 2.2.3 {
S delete
sqlite3session S db main
@@ -167,8 +167,8 @@ do_test 2.2.4 {
CREATE TABLE t2(a, b PRIMARY KEY, c, d);
INSERT INTO t2 VALUES(4, 5, 6, 7);
}
list [catch { S changeset } msg] $msg
} {1 SQLITE_SCHEMA}
catch { S changeset }
} {0}
do_test 2.3 {
S delete

View File

@@ -0,0 +1,237 @@
# 2023 October 02
#
# 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 implements that the sessions module interacts well with
# the ALTER TABLE ADD COLUMN command.
#
if {![info exists testdir]} {
set testdir [file join [file dirname [info script]] .. .. test]
}
source [file join [file dirname [info script]] session_common.tcl]
source $testdir/tester.tcl
ifcapable !session {finish_test; return}
set testprefix sessionalter
forcedelete test.db2
sqlite3 db2 test.db2
do_execsql_test 1.0 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
}
do_execsql_test -db db2 1.1 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c DEFAULT 1234);
}
do_then_apply_sql {
INSERT INTO t1 VALUES(1, 'one');
INSERT INTO t1 VALUES(2, 'two');
}
do_execsql_test -db db2 1.2 {
SELECT * FROM t1
} {
1 one 1234
2 two 1234
}
do_then_apply_sql {
UPDATE t1 SET b='four' WHERE a=2;
}
do_execsql_test -db db2 1.3 {
SELECT * FROM t1
} {
1 one 1234
2 four 1234
}
do_then_apply_sql {
DELETE FROM t1 WHERE a=1;
}
do_execsql_test -db db2 1.4 {
SELECT * FROM t1
} {
2 four 1234
}
#--------------------------------------------------------------------------
reset_db
do_execsql_test 2.0 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
}
do_test 2.1 {
sqlite3session S db main
S attach t1
set {} {}
} {}
do_execsql_test 2.2 {
INSERT INTO t1 VALUES(1, 2);
ALTER TABLE t1 ADD COLUMN c DEFAULT 'abcd';
INSERT INTO t1 VALUES(2, 3, 4);
}
do_changeset_test 2.3 S {
{INSERT t1 0 X.. {} {i 1 i 2 t abcd}}
{INSERT t1 0 X.. {} {i 2 i 3 i 4}}
}
do_iterator_test 2.4 {} {
DELETE FROM t1 WHERE a=2;
ALTER TABLE t1 ADD COLUMN d DEFAULT 'abcd';
ALTER TABLE t1 ADD COLUMN e DEFAULT 5;
ALTER TABLE t1 ADD COLUMN f DEFAULT 7.2;
-- INSERT INTO t1 VALUES(9, 9, 9, 9);
} {
{DELETE t1 0 X..... {i 2 i 3 i 4 t abcd i 5 f 7.2} {}}
}
#-------------------------------------------------------------------------
# Tests of the sqlite3changegroup_xxx() APIs.
#
reset_db
do_execsql_test 3.0 {
CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
CREATE TABLE t2(x PRIMARY KEY, y);
CREATE TABLE t3(x, y);
CREATE TABLE t4(y PRIMARY KEY, x) WITHOUT ROWID;
INSERT INTO t1 VALUES(1, 2), (3, 4), (5, 6);
INSERT INTO t2 VALUES('one', 'two'), ('three', 'four'), ('five', 'six');
INSERT INTO t3 VALUES(1, 2), (3, 4), (5, 6);
INSERT INTO t4(x, y) VALUES(1, 2), (3, 4), (5, 6);
}
db_save_and_close
foreach {tn sql1 at sql2} {
1 {
INSERT INTO t1(x, y) VALUES(7, 8);
} {
ALTER TABLE t1 ADD COLUMN z DEFAULT 10;
} {
UPDATE t1 SET y=11 WHERE x=7;
}
2 {
UPDATE t2 SET y='two.two' WHERE x='one';
DELETE FROM t2 WHERE x='five';
INSERT INTO t2(x, y) VALUES('seven', 'eight');
} {
ALTER TABLE t2 ADD COLUMN z;
ALTER TABLE t2 ADD COLUMN zz;
} {
}
3 {
DELETE FROM t2 WHERE x='five';
} {
ALTER TABLE t2 ADD COLUMN z DEFAULT 'xyz';
} {
}
4 {
UPDATE t2 SET y='two.two' WHERE x='three';
} {
ALTER TABLE t2 ADD COLUMN z;
} {
UPDATE t2 SET z='abc' WHERE x='one';
}
5* {
UPDATE t2 SET y='two.two' WHERE x='three';
} {
ALTER TABLE t2 ADD COLUMN z DEFAULT 'defu1';
} {
}
6* {
INSERT INTO t2(x, y) VALUES('nine', 'ten');
} {
ALTER TABLE t2 ADD COLUMN z;
ALTER TABLE t2 ADD COLUMN a DEFAULT 'eelve';
ALTER TABLE t2 ADD COLUMN b DEFAULT x'1234abcd';
ALTER TABLE t2 ADD COLUMN c DEFAULT 4.2;
ALTER TABLE t2 ADD COLUMN d DEFAULT NULL;
} {
}
7 {
INSERT INTO t3(x, y) VALUES(7, 8);
UPDATE t3 SET y='fourteen' WHERE x=1;
DELETE FROM t3 WHERE x=3;
} {
ALTER TABLE t3 ADD COLUMN c;
} {
INSERT INTO t3(x, y, c) VALUES(9, 10, 11);
}
8 {
INSERT INTO t4(x, y) VALUES(7, 8);
UPDATE t4 SET y='fourteen' WHERE x=1;
DELETE FROM t4 WHERE x=3;
} {
ALTER TABLE t4 ADD COLUMN c;
} {
INSERT INTO t4(x, y, c) VALUES(9, 10, 11);
}
} {
foreach {tn2 cmd} {
1 changeset_from_sql
2 patchset_from_sql
} {
db_restore_and_reopen
set C1 [$cmd $sql1]
execsql $at
set C2 [$cmd $sql2]
sqlite3changegroup grp
grp schema db main
grp add $C1
grp add $C2
set T1 [grp output]
grp delete
db_restore_and_reopen
execsql $at
set T2 [$cmd "$sql1 ; $sql2"]
if {[string range $tn end end]!="*"} {
do_test 3.1.$tn.$tn2.1 { changeset_to_list $T1 } [changeset_to_list $T2]
set testname "$tn.$tn2"
} else {
set testname "[string range $tn 0 end-1].$tn2"
}
db_restore_and_reopen
proc xConflict {args} { return "REPLACE" }
sqlite3changeset_apply_v2 db $T1 xConflict
set S1 [scksum db main]
db_restore_and_reopen
sqlite3changeset_apply_v2 db $T2 xConflict
set S2 [scksum db main]
# if { $tn==7 } { puts [changeset_to_list $T1] }
do_test 3.1.$tn.2 { set S1 } $S2
}
}
finish_test

View File

@@ -0,0 +1,59 @@
# 2016 October 6
#
# 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.
#
#***********************************************************************
#
# The focus of this file is testing the session module.
#
if {![info exists testdir]} {
set testdir [file join [file dirname [info script]] .. .. test]
}
source [file join [file dirname [info script]] session_common.tcl]
source $testdir/tester.tcl
ifcapable !session {finish_test; return}
set testprefix sessionfault3
do_execsql_test 1.0 {
CREATE TABLE t1(a, b, PRIMARY KEY(a));
INSERT INTO t1 VALUES(1, 2);
INSERT INTO t1 VALUES(3, 4);
INSERT INTO t1 VALUES('five', 'six');
}
set C1 [changeset_from_sql {
INSERT INTO t1 VALUES('seven', 'eight');
UPDATE t1 SET b=6 WHERE a='five';
DELETE FROM t1 WHERE a=1;
}]
do_execsql_test 1.1 {
ALTER TABLE t1 ADD COLUMN d DEFAULT 123;
ALTER TABLE t1 ADD COLUMN e DEFAULT 'string';
}
set C2 [changeset_from_sql {
UPDATE t1 SET e='new value' WHERE a='seven';
INSERT INTO t1 VALUES(0, 0, 0, 0);
}]
do_faultsim_test 1 -faults oom* -prep {
sqlite3changegroup G
} -body {
G schema db main
G add $::C1
G add $::C2
G output
set {} {}
} -test {
catch { G delete }
faultsim_test_result {0 {}} {1 SQLITE_NOMEM}
}
finish_test

File diff suppressed because it is too large Load Diff

View File

@@ -884,6 +884,18 @@ int sqlite3changeset_concat(
);
/*
** CAPI3REF: Upgrade the Schema of a Changeset/Patchset
*/
int sqlite3changeset_upgrade(
sqlite3 *db,
const char *zDb,
int nIn, const void *pIn, /* Input changeset */
int *pnOut, void **ppOut /* OUT: Inverse of input */
);
/*
** CAPI3REF: Changegroup Handle
**
@@ -930,6 +942,38 @@ typedef struct sqlite3_changegroup sqlite3_changegroup;
*/
int sqlite3changegroup_new(sqlite3_changegroup **pp);
/*
** CAPI3REF: Add a Schema to a Changegroup
** METHOD: sqlite3_changegroup_schema
**
** This method may be used to optionally enforce the rule that the changesets
** added to the changegroup handle must match the schema of database zDb
** ("main", "temp", or the name of an attached database). If
** sqlite3changegroup_add() is called to add a changeset that is not compatible
** with the configured schema, SQLITE_SCHEMA is returned and the changegroup
** object is left in an undefined state.
**
** A changeset schema is considered compatible with the database schema in
** the same way as for sqlite3changeset_apply(). Specifically, for each
** table in the changeset, there exists a database table with:
**
** <ul>
** <li> The name identified by the changeset, and
** <li> at least as many columns as recorded in the changeset, and
** <li> the primary key columns in the same position as recorded in
** the changeset.
** </ul>
**
** The output of the changegroup object always has the same schema as the
** database nominated using this function. In cases where changesets passed
** to sqlite3changegroup_add() have fewer columns than the corresponding table
** in the database schema, these are filled in using the default column
** values from the database schema. This makes it possible to combined
** changesets that have different numbers of columns for a single table
** within a changegroup, provided that they are otherwise compatible.
*/
int sqlite3changegroup_schema(sqlite3_changegroup*, sqlite3*, const char *zDb);
/*
** CAPI3REF: Add A Changeset To A Changegroup
** METHOD: sqlite3_changegroup
@@ -998,13 +1042,18 @@ int sqlite3changegroup_new(sqlite3_changegroup **pp);
** If the new changeset contains changes to a table that is already present
** in the changegroup, then the number of columns and the position of the
** primary key columns for the table must be consistent. If this is not the
** case, this function fails with SQLITE_SCHEMA. If the input changeset
** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
** returned. Or, if an out-of-memory condition occurs during processing, this
** function returns SQLITE_NOMEM. In all cases, if an error occurs the state
** of the final contents of the changegroup is undefined.
** case, this function fails with SQLITE_SCHEMA. Except, if the changegroup
** object has been configured with a database schema using the
** sqlite3changegroup_schema() API, then it is possible to combine changesets
** with different numbers of columns for a single table, provided that
** they are otherwise compatible.
**
** If no error occurs, SQLITE_OK is returned.
** If the input changeset appears to be corrupt and the corruption is
** detected, SQLITE_CORRUPT is returned. Or, if an out-of-memory condition
** occurs during processing, this function returns SQLITE_NOMEM.
**
** In all cases, if an error occurs the state of the final contents of the
** changegroup is undefined. If no error occurs, SQLITE_OK is returned.
*/
int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);

View File

@@ -1452,12 +1452,144 @@ static int SQLITE_TCLAPI test_sqlite3session_config(
return TCL_OK;
}
typedef struct TestChangegroup TestChangegroup;
struct TestChangegroup {
sqlite3_changegroup *pGrp;
};
/*
** Destructor for Tcl changegroup command object.
*/
static void test_changegroup_del(void *clientData){
TestChangegroup *pGrp = (TestChangegroup*)clientData;
sqlite3changegroup_delete(pGrp->pGrp);
ckfree(pGrp);
}
/*
** Tclcmd: $changegroup schema DB DBNAME
** Tclcmd: $changegroup add CHANGESET
** Tclcmd: $changegroup output
** Tclcmd: $changegroup delete
*/
static int SQLITE_TCLAPI test_changegroup_cmd(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
TestChangegroup *p = (TestChangegroup*)clientData;
static struct ChangegroupCmd {
const char *zSub;
int nArg;
const char *zMsg;
int iSub;
} aSub[] = {
{ "schema", 2, "DB DBNAME", }, /* 0 */
{ "add", 1, "CHANGESET", }, /* 1 */
{ "output", 0, "", }, /* 2 */
{ "delete", 0, "", }, /* 3 */
{ 0 }
};
int rc = TCL_OK;
int iSub = 0;
if( objc<2 ){
Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
return TCL_ERROR;
}
rc = Tcl_GetIndexFromObjStruct(interp,
objv[1], aSub, sizeof(aSub[0]), "sub-command", 0, &iSub
);
if( rc!=TCL_OK ) return rc;
if( objc!=2+aSub[iSub].nArg ){
Tcl_WrongNumArgs(interp, 2, objv, aSub[iSub].zMsg);
return TCL_ERROR;
}
switch( iSub ){
case 0: { /* schema */
sqlite3 *db = 0;
const char *zDb = Tcl_GetString(objv[3]);
if( dbHandleFromObj(interp, objv[2], &db) ){
return TCL_ERROR;
}
rc = sqlite3changegroup_schema(p->pGrp, db, zDb);
if( rc!=SQLITE_OK ) rc = test_session_error(interp, rc, 0);
break;
};
case 1: { /* add */
int nByte = 0;
const u8 *aByte = Tcl_GetByteArrayFromObj(objv[2], &nByte);
rc = sqlite3changegroup_add(p->pGrp, nByte, (void*)aByte);
if( rc!=SQLITE_OK ) rc = test_session_error(interp, rc, 0);
break;
};
case 2: { /* output */
int nByte = 0;
u8 *aByte = 0;
rc = sqlite3changegroup_output(p->pGrp, &nByte, (void**)&aByte);
if( rc!=SQLITE_OK ){
rc = test_session_error(interp, rc, 0);
}else{
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(aByte, nByte));
}
sqlite3_free(aByte);
break;
};
default: { /* delete */
assert( iSub==3 );
Tcl_DeleteCommand(interp, Tcl_GetString(objv[0]));
break;
}
}
return rc;
}
/*
** Tclcmd: sqlite3changegroup CMD
*/
static int SQLITE_TCLAPI test_sqlite3changegroup(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
int rc; /* sqlite3changegroup_new() return code */
TestChangegroup *p; /* New wrapper object */
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "CMD");
return TCL_ERROR;
}
p = (TestChangegroup*)ckalloc(sizeof(TestChangegroup));
memset(p, 0, sizeof(TestChangegroup));
rc = sqlite3changegroup_new(&p->pGrp);
if( rc!=SQLITE_OK ){
ckfree((char*)p);
return test_session_error(interp, rc, 0);
}
Tcl_CreateObjCommand(
interp, Tcl_GetString(objv[1]), test_changegroup_cmd, (ClientData)p,
test_changegroup_del
);
Tcl_SetObjResult(interp, objv[1]);
return TCL_OK;
}
int TestSession_Init(Tcl_Interp *interp){
struct Cmd {
const char *zCmd;
Tcl_ObjCmdProc *xProc;
} aCmd[] = {
{ "sqlite3session", test_sqlite3session },
{ "sqlite3changegroup", test_sqlite3changegroup },
{ "sqlite3session_foreach", test_sqlite3session_foreach },
{ "sqlite3changeset_invert", test_sqlite3changeset_invert },
{ "sqlite3changeset_concat", test_sqlite3changeset_concat },

View File

@@ -1,5 +1,5 @@
C Remove\ssome\sunnecessary\scode.\s\sReport\serrors\sfor\sinvalid\sJSONB\sinput\son\nan\sextract.
D 2023-10-07T23:35:07.967
C Merge\sthe\slatest\strunk\sfixes\sand\senhancements\sinto\sthe\sjsonb\sbranch,\sand\nespecially\sthe\sJSON\scache\sspill\sUAF\sfix.
D 2023-10-09T12:57:03.290
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -235,59 +235,61 @@ 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 7278812b41ced95fe67a9e5823aee027d641fd26fdfabe66c62b102a3a4e0631
F ext/jni/README.md 9fceaeb17cecdc5d699dfc83c0cbc3a03fdb3b86bf676381894166c73375ee75
F ext/jni/GNUmakefile 8c44e22bad18ecc266dd8c521f215e95dc3741d9e337c51b175029abaedcfb35
F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4
F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
F ext/jni/src/c/sqlite3-jni.c 2c4948634fd7f6460b074b72328b9c885ec11333bbc98144f745e4d6203a7ac2
F ext/jni/src/c/sqlite3-jni.h 74e3da791f748f02d0d684562126cf6bfdd2a85cbb6a5d1354b14fcd46e187bc
F ext/jni/src/c/sqlite3-jni.c fb8f178d27df828e3c797b4427a0a20545b44f5147ce38d09ce9b465be5a840b
F ext/jni/src/c/sqlite3-jni.h be1fdff7ab3a2bb357197271c8ac5d2bf6ff59380c106dde3a13be88724bad22
F ext/jni/src/org/sqlite/jni/AbstractCollationCallback.java 95e88ba04f4aac51ffec65693e878e234088b2f21b387f4e4285c8b72b33e436
F ext/jni/src/org/sqlite/jni/AggregateFunction.java 7312486bc65fecdb91753c0a4515799194e031f45edbe16a6373cea18f404dc4
F ext/jni/src/org/sqlite/jni/AuthorizerCallback.java e6135be32f12bf140bffa39be7fd1a45ad83b2661ed49c08dbde04c8485feb38
F ext/jni/src/org/sqlite/jni/AutoExtensionCallback.java 5e4a75611c026730289d776469d6122cb2699d6970af5f53fe85e74d49930476
F ext/jni/src/org/sqlite/jni/BusyHandlerCallback.java d316373b12b3bf1a421f1f7eed08128fa8dd52bb98617ba28c161aaabd71d1ee
F ext/jni/src/org/sqlite/jni/AuthorizerCallback.java fde5f758ad170ca45ae00b12194c8ba8d8f3090bd64cc3e002dd9c5e7dff8568
F ext/jni/src/org/sqlite/jni/AutoExtensionCallback.java c0fbfd3779fc92982c7935325a7484dee43eeb80d716989ed31218f453addb94
F ext/jni/src/org/sqlite/jni/BusyHandlerCallback.java 4cb7fc70efd55583fed6033c34a8719da42975ca97ef4781dda0b9f6cc8ec2e8
F ext/jni/src/org/sqlite/jni/CApi.java c1dde485a3a3f43c46c8d9c527f9ba5bf303fe0409b2c0de253fb7b6e1055f7e w ext/jni/src/org/sqlite/jni/SQLite3Jni.java
F ext/jni/src/org/sqlite/jni/CallbackProxy.java 064a8a00e4c63cc501c30504f93ca996d422c5f010067f969b2d0a10f0868153
F ext/jni/src/org/sqlite/jni/CollationCallback.java df327348e1a34ee65210208d694d690e5ee0bfe901410122e07caf6c98b2b7c8
F ext/jni/src/org/sqlite/jni/CollationNeededCallback.java 07df5fa161a0b81154295258037f662e7c372735c2899c76e81cb3abd9fd3b39
F ext/jni/src/org/sqlite/jni/CommitHookCallback.java 77cf8bb4f5548113e9792978f3f8a454614f420fa0ad73939421cbff4e7776f2
F ext/jni/src/org/sqlite/jni/ConfigLogCallback.java 636ed6b89ed03f15bc2a6f6f47bf7853b8328e5a8269e52e80630708efa703a6
F ext/jni/src/org/sqlite/jni/ConfigSqllogCallback.java e3656909eab7ed0f7e457c5b82df160ca22dd5e954c0a306ec1fca61b0d266b4
F ext/jni/src/org/sqlite/jni/CollationCallback.java 8cf57cb014a645ecc12609eed17308852a597bc5e83d82a4fdb90f7fadc25f9d
F ext/jni/src/org/sqlite/jni/CollationNeededCallback.java 0c62245e000d5db52576c728cac20f6a31f31f5cf40ca4cbcd64b22964e82ae5
F ext/jni/src/org/sqlite/jni/CommitHookCallback.java d15bd87ca6159a48b281966cf7a6e67dd17e2fabf974a797c9e3a66a74f361e8
F ext/jni/src/org/sqlite/jni/ConfigLogCallback.java 16bb391d8d4ae89cc43baa3cfa0c80c988003627b7ea872deb41156a76f7e867
F ext/jni/src/org/sqlite/jni/ConfigSqllogCallback.java 6d6b64638123acb70ffefcd5d2345b1bea3d3b528727d1684cc20cc2357f03a0
F ext/jni/src/org/sqlite/jni/NativePointerHolder.java 3eb36b5e81993a847f5ec03d23ab219a92671f817547b6a85d312667faeedd8b
F ext/jni/src/org/sqlite/jni/OutputPointer.java 2f57c05672ddc9b38e3f8eed11759896cf0bf01107ffd24d5182b99f6e7254b6
F ext/jni/src/org/sqlite/jni/PrepareMultiCallback.java 878ed9cc8000def1a4e6d7113d52bba6fce0aa6733b4eb216d68dfbe096776ac
F ext/jni/src/org/sqlite/jni/PreupdateHookCallback.java eccaed8dc9c6289f07ef3fc109891c6be1e7cc6c88723d90174b68706fc21cda
F ext/jni/src/org/sqlite/jni/ProgressHandlerCallback.java 7b9ff2218129ece98ba60c57eeedcd8447e9e3b6e5d0f5e5d3eb0f0c5037d48d
F ext/jni/src/org/sqlite/jni/ResultCode.java ba701f20213a5f259e94cfbfdd36eb7ac7ce7797f2c6c7fca2004ff12ce20f86
F ext/jni/src/org/sqlite/jni/RollbackHookCallback.java d12352c0e22840de484ffa9b11ed5058bb0daca2e9f218055d3c54c947a273c4
F ext/jni/src/org/sqlite/jni/PrepareMultiCallback.java 6f051951fecab41f2e842b1ac1d3c498706de9387c86f62564e2afbe03d026cb
F ext/jni/src/org/sqlite/jni/PreupdateHookCallback.java 242dc2afea13c45b4809d41b6a919e0a4003508713ceffe5f6545270138c6a7b
F ext/jni/src/org/sqlite/jni/ProgressHandlerCallback.java 247a47f49a1dd54fda28201c27796d2600a5c904f47fa21697a5377d49febe56
F ext/jni/src/org/sqlite/jni/ResultCode.java dc7400b8b18df10027525d8d0f04300b2c6afc617d4d980923f8b5bb14412f3a
F ext/jni/src/org/sqlite/jni/RollbackHookCallback.java ec6cd96bff5d3bc5af079cbf1469ae7fb34c50583a23581a58d6b2f8b55bafd3
F ext/jni/src/org/sqlite/jni/SQLFunction.java 544a875d33fd160467d82e2397ac33157b29971d715a821a4fad3c899113ee8c
F ext/jni/src/org/sqlite/jni/SQLTester.java da42be06a2d644e0b915b40508934c1f32391e5308ab8767c1e2e65a281a198f
F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 9860c1cebd8a38041306f2ee7563f2898fcbdf77e4bfa393fba25b4924edcb5d
F ext/jni/src/org/sqlite/jni/SQLTester.java d246c67f93e2fa2603bd106dbb3246ea725c987dffd6e5d42214ae262f750c68
F ext/jni/src/org/sqlite/jni/ScalarFunction.java 6d387bb499fbe3bc13c53315335233dbf6a0c711e8fa7c521683219b041c614c
F ext/jni/src/org/sqlite/jni/Sqlite.java 44b23a929e5d625b35c83fd49a80ada944bdd8b2bdece3ca7d400b33a2652fbd
F ext/jni/src/org/sqlite/jni/SqliteException.java f5d17a10202c0983fb074f66a0b48cf1e573b1da2eaeda679825e3edc1829706
F ext/jni/src/org/sqlite/jni/TableColumnMetadata.java 54511b4297fa28dcb3f49b24035e34ced10e3fd44fd0e458e784f4d6b0096dab
F ext/jni/src/org/sqlite/jni/Tester1.java ced62ed417c3326f93d2e90b3bb64ac2db58ac42a7ad7a5965b24545434e3200
F ext/jni/src/org/sqlite/jni/TesterFts5.java 854c737bb5c9463ee92a8ee230013e924236dd4b74d4688dd62c17f38d5837db
F ext/jni/src/org/sqlite/jni/TraceV2Callback.java beb0b064c1a5f8bfe585a324ed39a4e33edbe379a3fc60f1401661620d3ca7c0
F ext/jni/src/org/sqlite/jni/UpdateHookCallback.java 8376f4a931f2d5612b295c003c9515ba933ee76d8f95610e89c339727376e36c
F ext/jni/src/org/sqlite/jni/Tester1.java f7b85fe24cf6c3e43bdf7e390617657e8137359f804d76921829c2a8c41b6df1
F ext/jni/src/org/sqlite/jni/Tester2.java 75aa079e2baf8f73d95299da092e611656be0f6e12fe2fa051fdd984657857e2
F ext/jni/src/org/sqlite/jni/TesterFts5.java d60fe9944a81156b3b5325dd1b0e8e92a1547468f39fd1266d06f7bb6a95fa70
F ext/jni/src/org/sqlite/jni/TraceV2Callback.java f157edd9c72e7d2243c169061487cd7bb51a0d50f3ac976dbcbbacf748ab1fc2
F ext/jni/src/org/sqlite/jni/UpdateHookCallback.java 959d4677a857c9079c6e96ddd10918b946d68359af6252b6f284379069ea3d27
F ext/jni/src/org/sqlite/jni/WindowFunction.java 488980f4dbb6bdd7067d6cb9c43e4075475e51c54d9b74a5834422654b126246
F ext/jni/src/org/sqlite/jni/XDestroyCallback.java 50c5ca124ef6c6b735a7e136e7a23a557be367e61b56d4aab5777a614ab46cc2
F ext/jni/src/org/sqlite/jni/annotation/Canonical.java 44ea75a3c6c39513be9052eaa845b258a953f6af59e61002d715363fa52a7175
F ext/jni/src/org/sqlite/jni/annotation/NotNull.java a99341e88154e70447596b1af6a27c586317df41a7e0f246fd41370cd7b723b2
F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 0b1879852707f752512d4db9d7edd0d8db2f0c2612316ce1c832715e012ff6ba
F ext/jni/src/org/sqlite/jni/annotation/package-info.java 977b374aed9d5853cbf3438ba3b0940abfa2ea4574f702a2448ee143b98ac3ca
F ext/jni/src/org/sqlite/jni/fts5/Fts5.java e94681023785f1eff5399f0ddc82f46b035977d350f14838db659236ebdf6b41
F ext/jni/src/org/sqlite/jni/fts5/Fts5Context.java 7058da97059b8e156c17561a47ecd7faa0fc3e2d8c2588b9a28dbff8d06202dd
F ext/jni/src/org/sqlite/jni/fts5/Fts5ExtensionApi.java e2680721bd83129d0d650ba845b44d7634a9489a90a56c5ce3c54508bf470743
F ext/jni/src/org/sqlite/jni/fts5/Fts5ExtensionApi.java c8e06475a6172a7cd61b2bad9cfb18b6f059ffdd2935e62856f95785a14fe0e5
F ext/jni/src/org/sqlite/jni/fts5/Fts5PhraseIter.java 2a7f3d76a1206e6a43d4c4ed9609b294d5431cc7d8fb875d8419f76efa6e56dc
F ext/jni/src/org/sqlite/jni/fts5/Fts5Tokenizer.java cc9a53846a168a215238af224c31cef0e8379780e36e8a5e743b00c08145cf19
F ext/jni/src/org/sqlite/jni/fts5/XTokenizeCallback.java 1efd1220ea328a32f2d2a1b16c735864159e929480f71daad4de9d5944839167
F ext/jni/src/org/sqlite/jni/fts5/fts5_api.java e2ad9bc06a9d307e0a6221c11645783898906455a92b1f7d5ec9b9ff1af1b8ea
F ext/jni/src/org/sqlite/jni/fts5/fts5_api.java 90f09477331c371a8abe0a6504cfe094bc075b29a800be9d72a2c92a7bb49db1
F ext/jni/src/org/sqlite/jni/fts5/fts5_extension_function.java 1fe0f5692c1d67475d12b067f0469949073446f18c56eba5ee5da6ddd06db9b9
F ext/jni/src/org/sqlite/jni/fts5/fts5_tokenizer.java ea993738b851038c16d98576abd0db3d6028a231f075a394fb8a78c7834d0f6c
F ext/jni/src/org/sqlite/jni/package-info.java a3946db2504de747a1993c4f6e8ce604bec5a8e5a134b292c3b07527bc321a99
F ext/jni/src/org/sqlite/jni/sqlite3.java 5cd95c182a38b874ad973b3c16a70a69786fe82a6793abf147639803dec7ecac
F ext/jni/src/org/sqlite/jni/sqlite3_backup.java 12182124c4d4928d78db5a07ea285f1d7af04c7a148f0759a1972d5bfa87311e
F ext/jni/src/org/sqlite/jni/sqlite3_blob.java fc631ad52feea6e3d1d62b0d0e769ac107c01bc0ddd20eb512aff07b428cda6d
F ext/jni/src/org/sqlite/jni/sqlite3_context.java 66ca95ce904044263a4aff684abe262d56f73e6b06bca6cf650761d79d7779ad
F ext/jni/src/org/sqlite/jni/sqlite3_stmt.java cf7f076d8b0f2a23faebbd64e12e8b3dd1977378ca828245d186f1b98458127d
F ext/jni/src/org/sqlite/jni/package-info.java 7d465cbdf9050761db0db6d0c542afaaad7dc67f61510860592159c48bfc40e8
F ext/jni/src/org/sqlite/jni/sqlite3.java 4fa76f9c618264ed17ab613570076002c0b78717261b263350cd92d6d6b01242
F ext/jni/src/org/sqlite/jni/sqlite3_backup.java 42db8b2f9cd8e9e16217273890e5d4afbb102603d7130a2cb1651f1c69c1cfa4
F ext/jni/src/org/sqlite/jni/sqlite3_blob.java 7c341bca1856475fc3bf3697251e0cf1d737ddcb099c65d90afdc164aaddcc51
F ext/jni/src/org/sqlite/jni/sqlite3_context.java ba8da75eaaeb557c986af3fb4dbc69501cf2b083ca33497f2c0c70dbc0a53f2c
F ext/jni/src/org/sqlite/jni/sqlite3_stmt.java fa0703004721c49d6d08a0c1e99439fadb8cebaebf42b81ee3f427d7f950d1eb
F ext/jni/src/org/sqlite/jni/sqlite3_value.java 3d1d4903e267bc0bc81d57d21f5e85978eff389a1a6ed46726dbe75f85e6914a
F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe59004a1485311c50a13edbf18c79a6ff9160030e
F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745
@@ -513,7 +515,7 @@ F ext/session/changesetfuzz.c 227076ab0ae4447d742c01ee88a564da6478bbf26b65108bf8
F ext/session/changesetfuzz1.test 2e1b90d888fbf0eea5e1bd2f1e527a48cc85f8e0ff75df1ec4e320b21f580b3a
F ext/session/session1.test e94f764fbfb672147c0ef7026b195988133b371dc8cf9e52423eba6cad69717e
F ext/session/session2.test ee83bb973b9ce17ccce4db931cdcdae65eb40bbb22089b2fe6aa4f6be3b9303f
F ext/session/session3.test ce9ce3dfa489473987f899e9f6a0f2db9bde3479
F ext/session/session3.test 2cc1629cfb880243aec1a7251145e07b78411d851b39b2aa1390704550db8e6a
F ext/session/session4.test 6778997065b44d99c51ff9cece047ff9244a32856b328735ae27ddef68979c40
F ext/session/session5.test 716bc6fafd625ce60dfa62ae128971628c1a1169
F ext/session/session6.test 35279f2ec45448cd2e24a61688219dc6cf7871757716063acf4a8b5455e1e926
@@ -529,11 +531,13 @@ F ext/session/sessionG.test 3efe388282d641b65485b5462e67851002cd91a282dc95b685d0
F ext/session/sessionH.test 71bbff6b1abb2c4ac62b84dee53273c37e0b21e5fde3aed80929403e091ef859
F ext/session/session_common.tcl e5598096425486b363718e2cda48ee85d660c96b4f8ea9d9d7a4c3ef514769da
F ext/session/session_speed_test.c dcf0ef58d76b70c8fbd9eab3be77cf9deb8bc1638fed8be518b62d6cbdef88b3
F ext/session/sessionalter.test 72722f6f971c7cb6302a1a3c43ff256c0db1aaf19ae625ecdf710d53f08b1237
F ext/session/sessionat.test 00c8badb35e43a2f12a716d2734a44d614ff62361979b6b85419035bc04b45ee
F ext/session/sessionbig.test 47c381e7acfabeef17d98519a3080d69151723354d220afa2053852182ca7adf
F ext/session/sessiondiff.test ad13dd65664bae26744e1f18eb3cbd5588349b7e9118851d8f9364248d67bcec
F ext/session/sessionfault.test 573bf027fb870d57bd4e7cf50822a3e4b17b2b923407438747aaa918dec57a09
F ext/session/sessionfault2.test b0d6a7c1d7398a7e800d84657404909c7d385965ea8576dc79ed344c46fbf41c
F ext/session/sessionfault3.test 7c7547202775de268f3fe6f074c4d0d165151829710b4e64f90d4a01645ba9e7
F ext/session/sessioninvert.test 04075517a9497a80d39c495ba6b44f3982c7371129b89e2c52219819bc105a25
F ext/session/sessionmem.test f2a735db84a3e9e19f571033b725b0b2daf847f3f28b1da55a0c1a4e74f1de09
F ext/session/sessionnoop.test a9366a36a95ef85f8a3687856ebef46983df399541174cb1ede2ee53b8011bc7
@@ -543,9 +547,9 @@ F ext/session/sessionrowid.test 85187c2f1b38861a5844868126f69f9ec62223a03449a98a
F ext/session/sessionsize.test 8fcf4685993c3dbaa46a24183940ab9f5aa9ed0d23e5fb63bfffbdb56134b795
F ext/session/sessionstat1.test b039e38e2ba83767b464baf39b297cc0b1cc6f3292255cb467ea7e12d0d0280c
F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc
F ext/session/sqlite3session.c 0fe9107318140cefa1b50f2e1e0f330ab359022599e5976820db349f33efae11
F ext/session/sqlite3session.h 653e9d49c4edae231df8a4c8d69c2145195aedb32462d4b44229dbee7d2680fb
F ext/session/test_session.c 5285482f83cd92b4c1fe12fcf88210566a18312f4f2aa110f6399dae46aeccbb
F ext/session/sqlite3session.c ea28d07a280dc82efd4e98417a10b582058dc11a0f2a6ac3b194aa20d233d758
F ext/session/sqlite3session.h 4d1f69f1d8bfd4798e8f6431de301d17bb2e4097de2f77ca4dad494bb6c60dc0
F ext/session/test_session.c be0610a8ab717c3f9c898576d8b4c43e5eb75384a47fed0a0b22768067552778
F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb
@@ -670,7 +674,7 @@ F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
F src/json.c e97d03f1c19e403bfe0f0a1deaf50b3e3d657bb8addd5dfe7f9dcf72bcfa3109
F src/json.c 8717fe7a6461f24ba7b92ccd323c8e2417f44f2a959704c5a05a7aac1ca0df12
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 98cfba10989b3da6f1807ad42444017742db7f100a54f1032af7a8b1295912c0
F src/main.c 618aeb399e993cf561864f4b0cf6a331ee4f355cf663635f8d9da3193a46aa40
@@ -1303,7 +1307,7 @@ F test/json/json-generator.tcl dc0dd0f393800c98658fc4c47eaa6af29d4e17527380cd286
F test/json/json-q1-b.txt 606818a5fba6d9e418c9f4ea7d8418af026775042dad81439b72447a147a462c
F test/json/json-q1.txt 65f9d1cdcc4cffa9823fb73ed936aae5658700cd001fde448f68bfb91c807307
F test/json/json-speed-check.sh b060a9a6c696c0a807d8929400fa11bd7113edc58b0d66b9795f424f8d0db326 x
F test/json101.test e8ccd09f965c594f38ef486ddf7913f0fcac97be20a785a41c3d7cd4289e82de
F test/json101.test abb5a0cfde077a6f1124604e75806fbe889bc1c0acc11d32897f191e1f9c6b2c
F test/json102.test 557a46e16df1aa9bdbc4076a71a45814ea0e7503d6621d87d42a8c04cbc2b0ef
F test/json103.test 53df87f83a4e5fa0c0a56eb29ff6c94055c6eb919f33316d62161a8880112dbe
F test/json104.test 1b844a70cddcfa2e4cd81a5db0657b2e61e7f00868310f24f56a9ba0114348c1
@@ -2124,8 +2128,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 7b52b266b066f1385144c1103a3a411306db5f44568366ae1e93cd8cce799bbc
R 878d86e1e87a30f2fb868ea5f585d29f
P cbea16c29eb0507f39b5a1cf744a3bb9bb7c71ac156e84a19d03a37cb1816891 a163fecca90cab9d1b7bf8ebac78d498775eed7b6d81e7920e3401633c3a4b60
R 1dd322f61ae3b783d06705b01094df38
U drh
Z 509d9208ad89eff1e0f2ca5c213ed021
Z 41e410a665a938a0454df231f95bd4b4
# Remove this line to create a well-formed Fossil manifest.

View File

@@ -1 +1 @@
cbea16c29eb0507f39b5a1cf744a3bb9bb7c71ac156e84a19d03a37cb1816891
9422c24f4a8b290dcae61e50ec81be5b314b22c61a2bca1e194e47da1316b6e6

View File

@@ -4766,6 +4766,7 @@ static void jsonReplaceFunc(
}
pParse = jsonParseCached(ctx, argv[0], ctx, argc>1);
if( pParse==0 ) return;
pParse->nJPRef++;
for(i=1; i<(u32)argc; i+=2){
zPath = (const char*)sqlite3_value_text(argv[i]);
pParse->useMod = 1;
@@ -4778,6 +4779,7 @@ static void jsonReplaceFunc(
jsonReturnNodeAsJson(pParse, pParse->aNode, ctx, 1);
replace_err:
jsonDebugPrintParse(pParse);
jsonParseFree(pParse);
}
@@ -4813,6 +4815,7 @@ static void jsonSetFunc(
}
pParse = jsonParseCached(ctx, argv[0], ctx, argc>1);
if( pParse==0 ) return;
pParse->nJPRef++;
for(i=1; i<(u32)argc; i+=2){
zPath = (const char*)sqlite3_value_text(argv[i]);
bApnd = 0;
@@ -4829,9 +4832,8 @@ static void jsonSetFunc(
}
jsonDebugPrintParse(pParse);
jsonReturnNodeAsJson(pParse, pParse->aNode, ctx, 1);
jsonSetDone:
/* no cleanup required */;
jsonParseFree(pParse);
}
/*

View File

@@ -1098,4 +1098,30 @@ do_execsql_test json101-21.27 {
SELECT json_group_object(x,y) FROM c;
} {{{"a":1,"b":2.0,"c":null,:"three","e":"four"}}}
# 2023-10-09 https://sqlite.org/forum/forumpost/b25edc1d46
# UAF due to JSON cache overflow
#
do_execsql_test json101-22.1 {
SELECT json_set(
'{}',
'$.a', json('1'),
'$.a', json('2'),
'$.b', json('3'),
'$.b', json('4'),
'$.c', json('5'),
'$.c', json('6')
);
} {{{"a":2,"b":4,"c":6}}}
do_execsql_test json101-22.2 {
SELECT json_replace(
'{"a":7,"b":8,"c":9}',
'$.a', json('1'),
'$.a', json('2'),
'$.b', json('3'),
'$.b', json('4'),
'$.c', json('5'),
'$.c', json('6')
);
} {{{"a":2,"b":4,"c":6}}}
finish_test