Index: Makefile.in ================================================================== --- Makefile.in +++ Makefile.in @@ -587,12 +587,11 @@ # TESTOPTS = --verbose=file --output=test-out.txt # Extra compiler options for various shell tools # -SHELL_OPT += -DSQLITE_DQS=0 -SHELL_OPT += -DSQLITE_ENABLE_FTS4 +SHELL_OPT = -DSQLITE_ENABLE_FTS4 #SHELL_OPT += -DSQLITE_ENABLE_FTS5 SHELL_OPT += -DSQLITE_ENABLE_RTREE SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB @@ -601,59 +600,34 @@ SHELL_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC FUZZERSHELL_OPT = FUZZCHECK_OPT += -I$(TOP)/test FUZZCHECK_OPT += -I$(TOP)/ext/recover -FUZZCHECK_OPT += \ - -DSQLITE_OSS_FUZZ \ - -DSQLITE_ENABLE_BYTECODE_VTAB \ - -DSQLITE_ENABLE_DBPAGE_VTAB \ - -DSQLITE_ENABLE_DBSTAT_VTAB \ - -DSQLITE_ENABLE_BYTECODE_VTAB \ - -DSQLITE_ENABLE_DESERIALIZE \ - -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ - -DSQLITE_ENABLE_FTS3_PARENTHESIS \ - -DSQLITE_ENABLE_FTS4 \ - -DSQLITE_ENABLE_FTS5 \ - -DSQLITE_ENABLE_GEOPOLY \ - -DSQLITE_ENABLE_MATH_FUNCTIONS \ - -DSQLITE_ENABLE_MEMSYS5 \ - -DSQLITE_ENABLE_NORMALIZE \ - -DSQLITE_ENABLE_OFFSET_SQL_FUNC \ - -DSQLITE_ENABLE_PREUPDATE_HOOK \ - -DSQLITE_ENABLE_RTREE \ - -DSQLITE_ENABLE_SESSION \ - -DSQLITE_ENABLE_STMTVTAB \ - -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION \ - -DSQLITE_ENABLE_STAT4 \ - -DSQLITE_ENABLE_STMT_SCANSTATUS \ - -DSQLITE_MAX_MEMORY=50000000 \ - -DSQLITE_MAX_MMAP_SIZE=0 \ - -DSQLITE_OMIT_LOAD_EXTENSION \ - -DSQLITE_PRINTF_PRECISION_LIMIT=1000 \ - -DSQLITE_PRIVATE="" - +FUZZCHECK_OPT += -DSQLITE_OMIT_LOAD_EXTENSION +FUZZCHECK_OPT += -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ +FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000 +FUZZCHECK_OPT += -DSQLITE_PRINTF_PRECISION_LIMIT=1000 +FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS4 +FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS3_PARENTHESIS +FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS5 +FUZZCHECK_OPT += -DSQLITE_ENABLE_RTREE +FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY +FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB +FUZZCHECK_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB FUZZCHECK_SRC += $(TOP)/test/fuzzcheck.c FUZZCHECK_SRC += $(TOP)/test/ossfuzz.c FUZZCHECK_SRC += $(TOP)/test/fuzzinvariants.c FUZZCHECK_SRC += $(TOP)/ext/recover/dbdata.c FUZZCHECK_SRC += $(TOP)/ext/recover/sqlite3recover.c FUZZCHECK_SRC += $(TOP)/test/vt02.c DBFUZZ_OPT = ST_OPT = -DSQLITE_OS_KV_OPTIONAL - -# In wasi-sdk builds, disable the CLI shell build in the "all" target. -SQLITE3_SHELL_TARGET_ = sqlite3$(TEXE) -SQLITE3_SHELL_TARGET_1 = -SQLITE3_SHELL_TARGET = $(SQLITE3_SHELL_TARGET_@HAVE_WASI_SDK@) - # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. # -all: sqlite3.h libsqlite3.la $(SQLITE3_SHELL_TARGET) \ - $(HAVE_TCL:1=libtclsqlite3.la) +all: sqlite3.h libsqlite3.la sqlite3$(TEXE) $(HAVE_TCL:1=libtclsqlite3.la) Makefile: $(TOP)/Makefile.in ./config.status sqlite3.pc: $(TOP)/sqlite3.pc.in @@ -696,13 +670,10 @@ $(TOP)/tool/fuzzershell.c sqlite3.c $(TLIBS) fuzzcheck$(TEXE): $(FUZZCHECK_SRC) sqlite3.c sqlite3.h $(FUZZCHECK_DEP) $(LTLINK) -o $@ $(FUZZCHECK_OPT) $(FUZZCHECK_SRC) sqlite3.c $(TLIBS) -fuzzcheck-asan$(TEXE): $(FUZZCHECK_SRC) sqlite3.c sqlite3.h $(FUZZCHECK_DEP) - $(LTLINK) -o $@ -fsanitize=address $(FUZZCHECK_OPT) $(FUZZCHECK_SRC) sqlite3.c $(TLIBS) - ossshell$(TEXE): $(TOP)/test/ossfuzz.c $(TOP)/test/ossshell.c sqlite3.c sqlite3.h $(LTLINK) -o $@ $(FUZZCHECK_OPT) $(TOP)/test/ossshell.c \ $(TOP)/test/ossfuzz.c sqlite3.c $(TLIBS) sessionfuzz$(TEXE): $(TOP)/test/sessionfuzz.c sqlite3.c sqlite3.h Index: Makefile.msc ================================================================== --- Makefile.msc +++ Makefile.msc @@ -1524,11 +1524,11 @@ $(TOP)\src\test_window.c \ $(TOP)\src\test_wsd.c \ $(TOP)\ext\fts3\fts3_term.c \ $(TOP)\ext\fts3\fts3_test.c \ $(TOP)\ext\rbu\test_rbu.c \ - $(TOP)\ext\session\test_session.c + $(TOP)\ext\session\test_session.c # Statically linked extensions. # TESTEXT = \ $(TOP)\ext\expert\sqlite3expert.c \ @@ -1656,11 +1656,10 @@ # Additional compiler options for the shell. These are only effective # when the shell is not being dynamically linked. # !IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0 -SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_DQS=0 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1 !ENDIF @@ -1670,37 +1669,10 @@ MPTESTER_COMPILE_OPTS = -DSQLITE_ENABLE_FTS5 FUZZERSHELL_COMPILE_OPTS = FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -I$(TOP)\test -I$(TOP)\ext\recover FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_MEMSYS5 FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_OSS_FUZZ -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_BYTECODE_VTAB -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_DBPAGE_VTAB -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_DBSTAT_VTAB -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_BYTECODE_VTAB -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_DESERIALIZE -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_FTS3_PARENTHESIS -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_FTS4 -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_FTS5 -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_GEOPOLY -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_MATH_FUNCTIONS -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_MEMSYS5 -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_NORMALIZE -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_PREUPDATE_HOOK -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_RTREE -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_SESSION -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_STMTVTAB -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_STAT4 -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_STMT_SCANSTATUS -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_MAX_MEMORY=50000000 -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_MAX_MMAP_SIZE=0 -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_OMIT_LOAD_EXTENSION -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_PRINTF_PRECISION_LIMIT=1000 -FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_PRIVATE="" - FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_MAX_MEMORY=50000000 FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_PRINTF_PRECISION_LIMIT=1000 FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_OMIT_LOAD_EXTENSION FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_FTS4 FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_FTS5 @@ -1815,13 +1787,10 @@ $(LTLINK) $(NO_WARN) $(DBFUZZ_COMPILE_OPTS) $(TOP)\test\dbfuzz.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) fuzzcheck.exe: $(FUZZCHECK_SRC) $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(FUZZCHECK_OPTS) $(FUZZCHECK_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) -fuzzcheck-asan.exe: $(FUZZCHECK_SRC) $(SQLITE3C) $(SQLITE3H) - $(LTLINK) $(NO_WARN) /fsanitize=address $(FUZZCHECK_OPTS) $(FUZZCHECK_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) - ossshell.exe: $(OSSSHELL_SRC) $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(FUZZCHECK_OPTS) $(OSSSHELL_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) sessionfuzz.exe: zlib $(TOP)\test\sessionfuzz.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) -I$(ZLIBINCDIR) $(TOP)\test\sessionfuzz.c /link $(LDFLAGS) $(LTLINKOPTS) /LIBPATH:$(ZLIBLIBDIR) $(ZLIBLIB) Index: README.md ================================================================== --- README.md +++ README.md @@ -5,11 +5,11 @@ are also included. However, many other test scripts and most of the documentation are managed separately. ## Version Control -SQLite sources are managed using +SQLite sources are managed using the [Fossil](https://www.fossil-scm.org/), a distributed version control system that was specifically designed and written to support SQLite development. The [Fossil repository](https://sqlite.org/src/timeline) contains the urtext. If you are reading this on GitHub or some other Git repository or service, Index: VERSION ================================================================== --- VERSION +++ VERSION @@ -1,1 +1,1 @@ -3.42.0 +3.41.0 Index: autoconf/Makefile.msc ================================================================== --- autoconf/Makefile.msc +++ autoconf/Makefile.msc @@ -953,11 +953,10 @@ # Additional compiler options for the shell. These are only effective # when the shell is not being dynamically linked. # !IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0 -SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_DQS=0 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1 !ENDIF Index: autoconf/tea/configure.ac ================================================================== --- autoconf/tea/configure.ac +++ autoconf/tea/configure.ac @@ -17,11 +17,11 @@ # so you can encode the package version directly into the source files. # This will also define a special symbol for Windows (BUILD_ # so that we create the export library with the dll. #----------------------------------------------------------------------- -AC_INIT([sqlite],[3.42.0]) +AC_INIT([sqlite],[3.40.0]) #-------------------------------------------------------------------- # Call TEA_INIT as the first TEA_ macro to set up initial vars. # This will define a ${TEA_PLATFORM} variable == "unix" or "windows" # as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE. Index: configure ================================================================== --- configure +++ configure @@ -1,8 +1,8 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for sqlite 3.42.0. +# Generated by GNU Autoconf 2.69 for sqlite 3.41.0. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # @@ -724,12 +724,12 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' -PACKAGE_VERSION='3.42.0' -PACKAGE_STRING='sqlite 3.42.0' +PACKAGE_VERSION='3.41.0' +PACKAGE_STRING='sqlite 3.41.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ @@ -798,11 +798,10 @@ BUILD_EXEEXT TEMP_STORE ALLOWRELEASE SQLITE_THREADSAFE BUILD_CC -HAVE_WASI_SDK RELEASE VERSION program_prefix TCLLIBDIR TCLSH_CMD @@ -891,11 +890,10 @@ with_pic enable_fast_install with_gnu_ld enable_libtool_lock enable_largefile -with_wasi_sdk enable_threadsafe enable_releasemode enable_tempstore enable_tcl with_tcl @@ -1468,11 +1466,11 @@ # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures sqlite 3.42.0 to adapt to many kinds of systems. +\`configure' configures sqlite 3.41.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. @@ -1533,11 +1531,11 @@ _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of sqlite 3.42.0:";; + short | recursive ) echo "Configuration of sqlite 3.41.0:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options @@ -1579,12 +1577,10 @@ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] - --with-wasi-sdk=DIR directory containing the WASI SDK. Triggers - cross-compile to WASM. --with-tcl=DIR directory containing tcl configuration (tclConfig.sh) --with-readline-lib specify readline library --with-readline-inc specify readline include paths @@ -1663,11 +1659,11 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -sqlite configure 3.42.0 +sqlite configure 3.41.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. @@ -2082,11 +2078,11 @@ } # ac_fn_c_check_header_mongrel cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by sqlite $as_me 3.42.0, which was +It was created by sqlite $as_me 3.41.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF @@ -3940,17 +3936,17 @@ if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:3945: $ac_compile\"" >&5) + (eval echo "\"\$as_me:3941: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 - (eval echo "\"\$as_me:3948: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval echo "\"\$as_me:3944: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 - (eval echo "\"\$as_me:3951: output\"" >&5) + (eval echo "\"\$as_me:3947: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* @@ -5152,11 +5148,11 @@ fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 5157 "configure"' > conftest.$ac_ext + echo '#line 5153 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then @@ -6677,15 +6673,15 @@ # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:6682: $lt_compile\"" >&5) + (eval echo "\"\$as_me:6678: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:6686: \$? = $ac_status" >&5 + echo "$as_me:6682: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 @@ -7016,15 +7012,15 @@ # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7021: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7017: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7025: \$? = $ac_status" >&5 + echo "$as_me:7021: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 @@ -7121,15 +7117,15 @@ # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7126: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7122: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7130: \$? = $ac_status" >&5 + echo "$as_me:7126: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp @@ -7176,15 +7172,15 @@ # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7181: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7177: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7185: \$? = $ac_status" >&5 + echo "$as_me:7181: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp @@ -9556,11 +9552,11 @@ lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 9561 "configure" +#line 9557 "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif @@ -9652,11 +9648,11 @@ lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 9657 "configure" +#line 9653 "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif @@ -10393,72 +10389,10 @@ $as_echo "$as_me: Version set to $VERSION" >&6;} RELEASE=`cat $srcdir/VERSION` { $as_echo "$as_me:${as_lineno-$LINENO}: Release set to $RELEASE" >&5 $as_echo "$as_me: Release set to $RELEASE" >&6;} - - -########## -# Handle --with-wasi-sdk=DIR -# -# This must be early because it changes the toolchain. -# - -# Check whether --with-wasi-sdk was given. -if test "${with_wasi_sdk+set}" = set; then : - withval=$with_wasi_sdk; with_wasisdk=${withval} -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for WASI SDK directory" >&5 -$as_echo_n "checking for WASI SDK directory... " >&6; } -if ${ac_cv_c_wasi_sdk+:} false; then : - $as_echo_n "(cached) " >&6 -else - - # First check to see if --with-tcl was specified. - if test x"${with_wasi_sdk}" != x ; then - if ! test -d "${with_wasi_sdk}" ; then - as_fn_error $? "${with_wasi_sdk} directory doesn't exist" "$LINENO" 5 - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_wasi_sdk}: using wasi-sdk clang, disabling: tcl, CLI shell, DLL" >&5 -$as_echo "${with_wasi_sdk}: using wasi-sdk clang, disabling: tcl, CLI shell, DLL" >&6; } - use_wasi_sdk=yes - else - use_wasi_sdk=no - fi - -fi - -if test "${use_wasi_sdk}" = "no" ; then - HAVE_WASI_SDK="" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -else - HAVE_WASI_SDK=1 -# Changing --host and --target have no effect here except to possibly -# cause confusion. autoconf has finished processing them by this -# point. -# -# host_alias=wasm32-wasi -# target=wasm32-wasi -# -# Merely changing CC and LD to the wasi-sdk's is enough to get -# sqlite3.o building in WASM format. - CC="${with_wasi_sdk}/bin/clang" - LD="${with_wasi_sdk}/bin/wasm-ld" - RANLIB="${with_wasi_sdk}/bin/llvm-ranlib" - cross_compiling=yes - enable_threadsafe=no - use_tcl=no - enable_tcl=no - # libtool is apparently hard-coded to use gcc for linking DLLs, so - # we disable the DLL build... - enable_shared=no - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -fi - ######### # Locate a compiler for the build machine. This compiler should # generate command-line programs that run on the build machine. @@ -11331,11 +11265,10 @@ fi ######### # See whether we should use the amalgamation to build - # Check whether --enable-amalgamation was given. if test "${enable_amalgamation+set}" = set; then : enableval=$enable_amalgamation; fi @@ -12455,11 +12388,11 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by sqlite $as_me 3.42.0, which was +This file was extended by sqlite $as_me 3.41.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS @@ -12521,11 +12454,11 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -sqlite config.status 3.42.0 +sqlite config.status 3.41.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -68,15 +68,15 @@ # # The filename extension for executables on the # target platform. "" for Unix and ".exe" for windows. # # This configure.in file is easy to reuse on other projects. Just -# change the argument to AC_INIT. And disable any features that +# change the argument to AC_INIT(). And disable any features that # you don't need (for example BLT) by erasing or commenting out # the corresponding code. # -AC_INIT([sqlite],[m4_esyscmd(cat VERSION | tr -d '\n')]) +AC_INIT(sqlite, m4_esyscmd([cat VERSION | tr -d '\n'])) dnl Make sure the local VERSION file matches this configure script sqlite_version_sanity_check=`cat $srcdir/VERSION | tr -d '\n'` if test "$PACKAGE_VERSION" != "$sqlite_version_sanity_check" ; then AC_MSG_ERROR([configure script is out of date: @@ -86,11 +86,11 @@ fi ######### # Programs needed # -LT_INIT +AC_PROG_LIBTOOL AC_PROG_INSTALL ######### # Enable large file support (if special flags are necessary) # @@ -155,60 +155,10 @@ AC_MSG_NOTICE(Version set to $VERSION) AC_SUBST(VERSION) RELEASE=`cat $srcdir/VERSION` AC_MSG_NOTICE(Release set to $RELEASE) AC_SUBST(RELEASE) - -########## -# Handle --with-wasi-sdk=DIR -# -# This must be early because it changes the toolchain. -# -AC_ARG_WITH(wasi-sdk, -AS_HELP_STRING([--with-wasi-sdk=DIR], - [directory containing the WASI SDK. Triggers cross-compile to WASM.]), with_wasisdk=${withval}) -AC_MSG_CHECKING([for WASI SDK directory]) -AC_CACHE_VAL(ac_cv_c_wasi_sdk,[ - # First check to see if --with-tcl was specified. - if test x"${with_wasi_sdk}" != x ; then - if ! test -d "${with_wasi_sdk}" ; then - AC_MSG_ERROR([${with_wasi_sdk} directory doesn't exist]) - fi - AC_MSG_RESULT([${with_wasi_sdk}: using wasi-sdk clang, disabling: tcl, CLI shell, DLL]) - use_wasi_sdk=yes - else - use_wasi_sdk=no - fi -]) -if test "${use_wasi_sdk}" = "no" ; then - HAVE_WASI_SDK="" - AC_MSG_RESULT([no]) -else - HAVE_WASI_SDK=1 -# Changing --host and --target have no effect here except to possibly -# cause confusion. autoconf has finished processing them by this -# point. -# -# host_alias=wasm32-wasi -# target=wasm32-wasi -# -# Merely changing CC and LD to the wasi-sdk's is enough to get -# sqlite3.o building in WASM format. - CC="${with_wasi_sdk}/bin/clang" - LD="${with_wasi_sdk}/bin/wasm-ld" - RANLIB="${with_wasi_sdk}/bin/llvm-ranlib" - cross_compiling=yes - enable_threadsafe=no - use_tcl=no - enable_tcl=no - # libtool is apparently hard-coded to use gcc for linking DLLs, so - # we disable the DLL build... - enable_shared=no - AC_MSG_RESULT([yes]) -fi -AC_SUBST(HAVE_WASI_SDK) - ######### # Locate a compiler for the build machine. This compiler should # generate command-line programs that run on the build machine. # @@ -227,11 +177,11 @@ ########## # Do we want to support multithreaded use of sqlite # AC_ARG_ENABLE(threadsafe, -AS_HELP_STRING([--disable-threadsafe],[Disable mutexing])) +AC_HELP_STRING([--disable-threadsafe],[Disable mutexing])) AC_MSG_CHECKING([whether to support threadsafe operation]) if test "$enable_threadsafe" = "no"; then SQLITE_THREADSAFE=0 AC_MSG_RESULT([no]) else @@ -247,11 +197,11 @@ ########## # Do we want to support release # AC_ARG_ENABLE(releasemode, -AS_HELP_STRING([--enable-releasemode],[Support libtool link to release mode]),,enable_releasemode=no) +AC_HELP_STRING([--enable-releasemode],[Support libtool link to release mode]),,enable_releasemode=no) AC_MSG_CHECKING([whether to support shared library linked as release mode or not]) if test "$enable_releasemode" = "no"; then ALLOWRELEASE="" AC_MSG_RESULT([no]) else @@ -262,11 +212,11 @@ ########## # Do we want temporary databases in memory # AC_ARG_ENABLE(tempstore, -AS_HELP_STRING([--enable-tempstore],[Use an in-ram database for temporary tables (never,no,yes,always)]),,enable_tempstore=no) +AC_HELP_STRING([--enable-tempstore],[Use an in-ram database for temporary tables (never,no,yes,always)]),,enable_tempstore=no) AC_MSG_CHECKING([whether to use an in-ram database for temporary tables]) case "$enable_tempstore" in never ) TEMP_STORE=0 AC_MSG_RESULT([never]) @@ -302,19 +252,11 @@ AC_MSG_RESULT(yes) else AC_MSG_RESULT(unknown) fi if test "$CYGWIN" != "yes"; then - m4_warn([obsolete], -[AC_CYGWIN is obsolete: use AC_CANONICAL_HOST and check if $host_os -matches *cygwin*])dnl -AC_CANONICAL_HOST -case $host_os in - *cygwin* ) CYGWIN=yes;; - * ) CYGWIN=no;; -esac - + AC_CYGWIN fi if test "$CYGWIN" = "yes"; then BUILD_EXEEXT=.exe else BUILD_EXEEXT=$EXEEXT @@ -345,14 +287,14 @@ # This code is derived from the SC_PATH_TCLCONFIG and SC_LOAD_TCLCONFIG # macros in the in the tcl.m4 file of the standard TCL distribution. # Those macros could not be used directly since we have to make some # minor changes to accomodate systems that do not have TCL installed. # -AC_ARG_ENABLE(tcl, AS_HELP_STRING([--disable-tcl],[do not build TCL extension]), +AC_ARG_ENABLE(tcl, AC_HELP_STRING([--disable-tcl],[do not build TCL extension]), [use_tcl=$enableval],[use_tcl=yes]) if test "${use_tcl}" = "yes" ; then - AC_ARG_WITH(tcl, AS_HELP_STRING([--with-tcl=DIR],[directory containing tcl configuration (tclConfig.sh)]), with_tclconfig=${withval}) + AC_ARG_WITH(tcl, AC_HELP_STRING([--with-tcl=DIR],[directory containing tcl configuration (tclConfig.sh)]), with_tclconfig=${withval}) AC_MSG_CHECKING([for Tcl configuration]) AC_CACHE_VAL(ac_cv_c_tclconfig,[ # First check to see if --with-tcl was specified. if test x"${with_tclconfig}" != x ; then if test -f "${with_tclconfig}/tclConfig.sh" ; then @@ -530,15 +472,15 @@ TARGET_READLINE_LIBS="" TARGET_READLINE_INC="" TARGET_HAVE_READLINE=0 TARGET_HAVE_EDITLINE=0 AC_ARG_ENABLE([editline], - [AS_HELP_STRING([--enable-editline],[enable BSD editline support])], + [AC_HELP_STRING([--enable-editline],[enable BSD editline support])], [with_editline=$enableval], [with_editline=auto]) AC_ARG_ENABLE([readline], - [AS_HELP_STRING([--disable-readline],[disable readline support])], + [AC_HELP_STRING([--disable-readline],[disable readline support])], [with_readline=$enableval], [with_readline=auto]) if test x"$with_editline" != xno; then sLIBS=$LIBS @@ -550,11 +492,11 @@ fi if test x"$with_readline" != xno; then found="yes" AC_ARG_WITH([readline-lib], - [AS_HELP_STRING([--with-readline-lib],[specify readline library])], + [AC_HELP_STRING([--with-readline-lib],[specify readline library])], [with_readline_lib=$withval], [with_readline_lib="auto"]) if test "x$with_readline_lib" = xauto; then save_LIBS="$LIBS" LIBS="" @@ -565,11 +507,11 @@ else TARGET_READLINE_LIBS="$with_readline_lib" fi AC_ARG_WITH([readline-inc], - [AS_HELP_STRING([--with-readline-inc],[specify readline include paths])], + [AC_HELP_STRING([--with-readline-inc],[specify readline include paths])], [with_readline_inc=$withval], [with_readline_inc="auto"]) if test "x$with_readline_inc" = xauto; then AC_CHECK_HEADER(readline.h, [found="yes"], [ found="no" @@ -610,11 +552,11 @@ # AC_SEARCH_LIBS(fdatasync, [rt]) ######### # check for debug enabled -AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug],[enable debugging & verbose explain])) +AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],[enable debugging & verbose explain])) AC_MSG_CHECKING([build type]) if test "${enable_debug}" = "yes" ; then TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0" AC_MSG_RESULT([debug]) else @@ -623,12 +565,11 @@ fi AC_SUBST(TARGET_DEBUG) ######### # See whether we should use the amalgamation to build - -AC_ARG_ENABLE(amalgamation, AS_HELP_STRING([--disable-amalgamation], +AC_ARG_ENABLE(amalgamation, AC_HELP_STRING([--disable-amalgamation], [Disable the amalgamation and instead build all files separately])) if test "${enable_amalgamation}" = "no" ; then USE_AMALGAMATION=0 fi AC_SUBST(USE_AMALGAMATION) @@ -639,11 +580,11 @@ AC_SEARCH_LIBS(deflate, z, [HAVE_ZLIB="-DSQLITE_HAVE_ZLIB=1"], [HAVE_ZLIB=""]) AC_SUBST(HAVE_ZLIB) ######### # See whether we should allow loadable extensions -AC_ARG_ENABLE(load-extension, AS_HELP_STRING([--disable-load-extension], +AC_ARG_ENABLE(load-extension, AC_HELP_STRING([--disable-load-extension], [Disable loading of external extensions]),,[enable_load_extension=yes]) if test "${enable_load_extension}" = "yes" ; then OPT_FEATURE_FLAGS="" AC_SEARCH_LIBS(dlopen, dl) else @@ -652,11 +593,11 @@ ########## # Do we want to support math functions # AC_ARG_ENABLE(math, -AS_HELP_STRING([--disable-math],[Disable math functions])) +AC_HELP_STRING([--disable-math],[Disable math functions])) AC_MSG_CHECKING([whether to support math functions]) if test "$enable_math" = "no"; then AC_MSG_RESULT([no]) else AC_MSG_RESULT([yes]) @@ -666,11 +607,11 @@ ########## # Do we want to support JSON functions # AC_ARG_ENABLE(json, -AS_HELP_STRING([--disable-json],[Disable JSON functions])) +AC_HELP_STRING([--disable-json],[Disable JSON functions])) AC_MSG_CHECKING([whether to support JSON functions]) if test "$enable_json" = "no"; then AC_MSG_RESULT([no]) OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_OMIT_JSON" else @@ -678,27 +619,27 @@ fi ######## # The --enable-all argument is short-hand to enable # multiple extensions. -AC_ARG_ENABLE(all, AS_HELP_STRING([--enable-all], +AC_ARG_ENABLE(all, AC_HELP_STRING([--enable-all], [Enable FTS4, FTS5, Geopoly, RTree, Sessions])) ########## # Do we want to support memsys3 and/or memsys5 # AC_ARG_ENABLE(memsys5, - AS_HELP_STRING([--enable-memsys5],[Enable MEMSYS5])) + AC_HELP_STRING([--enable-memsys5],[Enable MEMSYS5])) AC_MSG_CHECKING([whether to support MEMSYS5]) if test "${enable_memsys5}" = "yes"; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_MEMSYS5" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi AC_ARG_ENABLE(memsys3, - AS_HELP_STRING([--enable-memsys3],[Enable MEMSYS3])) + AC_HELP_STRING([--enable-memsys3],[Enable MEMSYS3])) AC_MSG_CHECKING([whether to support MEMSYS3]) if test "${enable_memsys3}" = "yes" -a "${enable_memsys5}" = "no"; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_MEMSYS3" AC_MSG_RESULT([yes]) else @@ -705,30 +646,30 @@ AC_MSG_RESULT([no]) fi ######### # See whether we should enable Full Text Search extensions -AC_ARG_ENABLE(fts3, AS_HELP_STRING([--enable-fts3], +AC_ARG_ENABLE(fts3, AC_HELP_STRING([--enable-fts3], [Enable the FTS3 extension])) AC_MSG_CHECKING([whether to support FTS3]) if test "${enable_fts3}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS3" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi -AC_ARG_ENABLE(fts4, AS_HELP_STRING([--enable-fts4], +AC_ARG_ENABLE(fts4, AC_HELP_STRING([--enable-fts4], [Enable the FTS4 extension])) AC_MSG_CHECKING([whether to support FTS4]) if test "${enable_fts4}" = "yes" -o "${enable_all}" = "yes" ; then AC_MSG_RESULT([yes]) OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS4" AC_SEARCH_LIBS([log],[m]) else AC_MSG_RESULT([no]) fi -AC_ARG_ENABLE(fts5, AS_HELP_STRING([--enable-fts5], +AC_ARG_ENABLE(fts5, AC_HELP_STRING([--enable-fts5], [Enable the FTS5 extension])) AC_MSG_CHECKING([whether to support FTS5]) if test "${enable_fts5}" = "yes" -o "${enable_all}" = "yes" ; then AC_MSG_RESULT([yes]) OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS5" @@ -738,11 +679,11 @@ fi ######### # See whether we should enable the LIMIT clause on UPDATE and DELETE # statements. -AC_ARG_ENABLE(update-limit, AS_HELP_STRING([--enable-update-limit], +AC_ARG_ENABLE(update-limit, AC_HELP_STRING([--enable-update-limit], [Enable the UPDATE/DELETE LIMIT clause])) AC_MSG_CHECKING([whether to support LIMIT on UPDATE and DELETE statements]) if test "${enable_update_limit}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT" AC_MSG_RESULT([yes]) @@ -750,11 +691,11 @@ AC_MSG_RESULT([no]) fi ######### # See whether we should enable GEOPOLY -AC_ARG_ENABLE(geopoly, AS_HELP_STRING([--enable-geopoly], +AC_ARG_ENABLE(geopoly, AC_HELP_STRING([--enable-geopoly], [Enable the GEOPOLY extension]), [enable_geopoly=yes],[enable_geopoly=no]) AC_MSG_CHECKING([whether to support GEOPOLY]) if test "${enable_geopoly}" = "yes" -o "${enable_all}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_GEOPOLY" @@ -764,11 +705,11 @@ AC_MSG_RESULT([no]) fi ######### # See whether we should enable RTREE -AC_ARG_ENABLE(rtree, AS_HELP_STRING([--enable-rtree], +AC_ARG_ENABLE(rtree, AC_HELP_STRING([--enable-rtree], [Enable the RTREE extension])) AC_MSG_CHECKING([whether to support RTREE]) if test "${enable_rtree}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_RTREE" AC_MSG_RESULT([yes]) @@ -776,11 +717,11 @@ AC_MSG_RESULT([no]) fi ######### # See whether we should enable the SESSION extension -AC_ARG_ENABLE(session, AS_HELP_STRING([--enable-session], +AC_ARG_ENABLE(session, AC_HELP_STRING([--enable-session], [Enable the SESSION extension])) AC_MSG_CHECKING([whether to support SESSION]) if test "${enable_session}" = "yes" -o "${enable_all}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_SESSION" OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_PREUPDATE_HOOK" @@ -840,11 +781,11 @@ BUILD_CFLAGS=$ac_temp_BUILD_CFLAGS ######### # See whether we should use GCOV -AC_ARG_ENABLE(gcov, AS_HELP_STRING([--enable-gcov], +AC_ARG_ENABLE(gcov, AC_HELP_STRING([--enable-gcov], [Enable coverage testing using gcov])) if test "${use_gcov}" = "yes" ; then USE_GCOV=1 else USE_GCOV=0 @@ -869,10 +810,9 @@ ######### # Generate the output files. # AC_SUBST(BUILD_CFLAGS) -AC_CONFIG_FILES([ +AC_OUTPUT([ Makefile sqlite3.pc ]) -AC_OUTPUT Index: ext/fts3/fts3_write.c ================================================================== --- ext/fts3/fts3_write.c +++ ext/fts3/fts3_write.c @@ -2665,22 +2665,20 @@ static int fts3MsrBufferData( Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */ char *pList, i64 nList ){ - if( (nList+FTS3_NODE_PADDING)>pMsr->nBuffer ){ + if( nList>pMsr->nBuffer ){ char *pNew; - int nNew = nList*2 + FTS3_NODE_PADDING; - pNew = (char *)sqlite3_realloc64(pMsr->aBuffer, nNew); + pMsr->nBuffer = nList*2; + pNew = (char *)sqlite3_realloc64(pMsr->aBuffer, pMsr->nBuffer); if( !pNew ) return SQLITE_NOMEM; pMsr->aBuffer = pNew; - pMsr->nBuffer = nNew; } assert( nList>0 ); memcpy(pMsr->aBuffer, pList, nList); - memset(&pMsr->aBuffer[nList], 0, FTS3_NODE_PADDING); return SQLITE_OK; } int sqlite3Fts3MsrIncrNext( Fts3Table *p, /* Virtual table handle */ Index: ext/fts5/fts5Int.h ================================================================== --- ext/fts5/fts5Int.h +++ ext/fts5/fts5Int.h @@ -197,34 +197,29 @@ fts5_tokenizer *pTokApi; int bLock; /* True when table is preparing statement */ int ePattern; /* FTS_PATTERN_XXX constant */ /* Values loaded from the %_config table */ - int iVersion; /* fts5 file format 'version' */ int iCookie; /* Incremented when %_config is modified */ int pgsz; /* Approximate page size used in %_data */ int nAutomerge; /* 'automerge' setting */ int nCrisisMerge; /* Maximum allowed segments per level */ int nUsermerge; /* 'usermerge' setting */ int nHashSize; /* Bytes of memory for in-memory hash */ char *zRank; /* Name of rank function */ char *zRankArgs; /* Arguments to rank function */ - int bSecureDelete; /* 'secure-delete' */ /* If non-NULL, points to sqlite3_vtab.base.zErrmsg. Often NULL. */ char **pzErrmsg; #ifdef SQLITE_DEBUG int bPrefixIndex; /* True to use prefix-indexes */ #endif }; -/* Current expected value of %_config table 'version' field. And -** the expected version if the 'secure-delete' option has ever been -** set on the table. */ -#define FTS5_CURRENT_VERSION 4 -#define FTS5_CURRENT_VERSION_SECUREDELETE 5 +/* Current expected value of %_config table 'version' field */ +#define FTS5_CURRENT_VERSION 4 #define FTS5_CONTENT_NORMAL 0 #define FTS5_CONTENT_NONE 1 #define FTS5_CONTENT_EXTERNAL 2 @@ -386,11 +381,10 @@ /* The following are used internally by the fts5_index.c module. They are ** defined here only to make it easier to avoid clashes with the flags ** above. */ #define FTS5INDEX_QUERY_SKIPEMPTY 0x0010 #define FTS5INDEX_QUERY_NOOUTPUT 0x0020 -#define FTS5INDEX_QUERY_SKIPHASH 0x0040 /* ** Create/destroy an Fts5Index object. */ int sqlite3Fts5IndexOpen(Fts5Config *pConfig, int bCreate, Fts5Index**, char**); @@ -541,11 +535,11 @@ int sqlite3Fts5GetVarint32(const unsigned char *p, u32 *v); int sqlite3Fts5GetVarintLen(u32 iVal); u8 sqlite3Fts5GetVarint(const unsigned char*, u64*); int sqlite3Fts5PutVarint(unsigned char *p, u64 v); -#define fts5GetVarint32(a,b) sqlite3Fts5GetVarint32(a,(u32*)&(b)) +#define fts5GetVarint32(a,b) sqlite3Fts5GetVarint32(a,(u32*)&b) #define fts5GetVarint sqlite3Fts5GetVarint #define fts5FastGetVarint32(a, iOff, nVal) { \ nVal = (a)[iOff++]; \ if( nVal & 0x80 ){ \ Index: ext/fts5/fts5_aux.c ================================================================== --- ext/fts5/fts5_aux.c +++ ext/fts5/fts5_aux.c @@ -161,11 +161,11 @@ UNUSED_PARAM2(pToken, nToken); if( tflags & FTS5_TOKEN_COLOCATED ) return SQLITE_OK; iPos = p->iPos++; - if( p->iRangeEnd>=0 ){ + if( p->iRangeEnd>0 ){ if( iPosiRangeStart || iPos>p->iRangeEnd ) return SQLITE_OK; if( p->iRangeStart && iPos==p->iRangeStart ) p->iOff = iStartOff; } if( iPos==p->iter.iStart ){ @@ -173,11 +173,11 @@ fts5HighlightAppend(&rc, p, p->zOpen, -1); p->iOff = iStartOff; } if( iPos==p->iter.iEnd ){ - if( p->iRangeEnd>=0 && p->iter.iStartiRangeStart ){ + if( p->iRangeEnd && p->iter.iStartiRangeStart ){ fts5HighlightAppend(&rc, p, p->zOpen, -1); } fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff); fts5HighlightAppend(&rc, p, p->zClose, -1); p->iOff = iEndOff; @@ -184,11 +184,11 @@ if( rc==SQLITE_OK ){ rc = fts5CInstIterNext(&p->iter); } } - if( p->iRangeEnd>=0 && iPos==p->iRangeEnd ){ + if( p->iRangeEnd>0 && iPos==p->iRangeEnd ){ fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff); p->iOff = iEndOff; if( iPos>=p->iter.iStart && iPositer.iEnd ){ fts5HighlightAppend(&rc, p, p->zClose, -1); } @@ -219,11 +219,10 @@ iCol = sqlite3_value_int(apVal[0]); memset(&ctx, 0, sizeof(HighlightContext)); ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]); ctx.zClose = (const char*)sqlite3_value_text(apVal[2]); - ctx.iRangeEnd = -1; rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn); if( ctx.zIn ){ if( rc==SQLITE_OK ){ rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter); @@ -405,11 +404,10 @@ nCol = pApi->xColumnCount(pFts); memset(&ctx, 0, sizeof(HighlightContext)); iCol = sqlite3_value_int(apVal[0]); ctx.zOpen = fts5ValueToText(apVal[1]); ctx.zClose = fts5ValueToText(apVal[2]); - ctx.iRangeEnd = -1; zEllips = fts5ValueToText(apVal[3]); nToken = sqlite3_value_int(apVal[4]); iBestCol = (iCol>=0 ? iCol : 0); nPhrase = pApi->xPhraseCount(pFts); Index: ext/fts5/fts5_config.c ================================================================== --- ext/fts5/fts5_config.c +++ ext/fts5/fts5_config.c @@ -548,11 +548,10 @@ if( rc==SQLITE_OK && sqlite3_stricmp(pRet->zName, FTS5_RANK_NAME)==0 ){ *pzErr = sqlite3_mprintf("reserved fts5 table name: %s", pRet->zName); rc = SQLITE_ERROR; } - assert( (pRet->abUnindexed && pRet->azCol) || rc!=SQLITE_OK ); for(i=3; rc==SQLITE_OK && izRankArgs = zRankArgs; }else if( rc==SQLITE_ERROR ){ rc = SQLITE_OK; *pbBadkey = 1; } - } - - else if( 0==sqlite3_stricmp(zKey, "secure-delete") ){ - int bVal = -1; - if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ - bVal = sqlite3_value_int(pVal); - } - if( bVal<0 ){ - *pbBadkey = 1; - }else{ - pConfig->bSecureDelete = (bVal ? 1 : 0); - } }else{ *pbBadkey = 1; } return rc; } @@ -958,26 +945,21 @@ } } rc = sqlite3_finalize(p); } - if( rc==SQLITE_OK - && iVersion!=FTS5_CURRENT_VERSION - && iVersion!=FTS5_CURRENT_VERSION_SECUREDELETE - ){ + if( rc==SQLITE_OK && iVersion!=FTS5_CURRENT_VERSION ){ rc = SQLITE_ERROR; if( pConfig->pzErrmsg ){ assert( 0==*pConfig->pzErrmsg ); - *pConfig->pzErrmsg = sqlite3_mprintf("invalid fts5 file format " - "(found %d, expected %d or %d) - run 'rebuild'", - iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE + *pConfig->pzErrmsg = sqlite3_mprintf( + "invalid fts5 file format (found %d, expected %d) - run 'rebuild'", + iVersion, FTS5_CURRENT_VERSION ); } - }else{ - pConfig->iVersion = iVersion; } if( rc==SQLITE_OK ){ pConfig->iCookie = iCookie; } return rc; } Index: ext/fts5/fts5_expr.c ================================================================== --- ext/fts5/fts5_expr.c +++ ext/fts5/fts5_expr.c @@ -287,23 +287,10 @@ sqlite3_free(sParse.apPhrase); *pzErr = sParse.zErr; return sParse.rc; } -/* -** Assuming that buffer z is at least nByte bytes in size and contains a -** valid utf-8 string, return the number of characters in the string. -*/ -static int fts5ExprCountChar(const char *z, int nByte){ - int nRet = 0; - int ii; - for(ii=0; ii=3 ){ + if( i-iFirst>=3 ){ int jj; zExpr[iOut++] = '"'; for(jj=iFirst; jjnPhrase + p2->nPhrase; p1->pRoot = sqlite3Fts5ParseNode(&sParse, FTS5_AND, p1->pRoot, p2->pRoot,0); p2->pRoot = 0; @@ -430,11 +416,11 @@ p1->apExprPhrase = ap; } } sqlite3_free(p2->apExprPhrase); sqlite3_free(p2); - }else if( p2 ){ + }else{ *pp1 = p2; } return sParse.rc; } Index: ext/fts5/fts5_index.c ================================================================== --- ext/fts5/fts5_index.c +++ ext/fts5/fts5_index.c @@ -300,12 +300,10 @@ sqlite3_stmt *pIdxWriter; /* "INSERT ... %_idx VALUES(?,?,?,?)" */ sqlite3_stmt *pIdxDeleter; /* "DELETE FROM %_idx WHERE segid=?" */ sqlite3_stmt *pIdxSelect; int nRead; /* Total number of blocks read */ - sqlite3_stmt *pDeleteFromIdx; - sqlite3_stmt *pDataVersion; i64 iStructVersion; /* data_version when pStruct read */ Fts5Structure *pStruct; /* Current db structure (or NULL) */ }; @@ -394,10 +392,13 @@ ** Current leaf page number within segment. ** ** iLeafOffset: ** Byte offset within the current leaf that is the first byte of the ** position list data (one byte passed the position-list size field). +** rowid field of the current entry. Usually this is the size field of the +** position list data. The exception is if the rowid for the current entry +** is the last thing on the leaf page. ** ** pLeaf: ** Buffer containing current leaf page data. Set to NULL at EOF. ** ** iTermLeafPgno, iTermLeafOffset: @@ -952,11 +953,10 @@ Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg]; if( i>=nData ){ rc = FTS5_CORRUPT; break; } - assert( pSeg!=0 ); i += fts5GetVarint32(&pData[i], pSeg->iSegid); i += fts5GetVarint32(&pData[i], pSeg->pgnoFirst); i += fts5GetVarint32(&pData[i], pSeg->pgnoLast); if( pSeg->pgnoLastpgnoFirst ){ rc = FTS5_CORRUPT; @@ -983,11 +983,10 @@ ** Add a level to the Fts5Structure.aLevel[] array of structure object ** (*ppStruct). */ static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){ fts5StructureMakeWritable(pRc, ppStruct); - assert( (ppStruct!=0 && (*ppStruct)!=0) || (*pRc)!=SQLITE_OK ); if( *pRc==SQLITE_OK ){ Fts5Structure *pStruct = *ppStruct; int nLevel = pStruct->nLevel; sqlite3_int64 nByte = ( sizeof(Fts5Structure) + /* Main structure */ @@ -1442,29 +1441,46 @@ assert( pLvl->bEof==0 ); if( iOff<=pLvl->iFirstOff ){ pLvl->bEof = 1; }else{ u8 *a = pLvl->pData->p; - - pLvl->iOff = 0; - fts5DlidxLvlNext(pLvl); - while( 1 ){ - int nZero = 0; - int ii = pLvl->iOff; - u64 delta = 0; - - while( a[ii]==0 ){ - nZero++; - ii++; - } - ii += sqlite3Fts5GetVarint(&a[ii], &delta); - - if( ii>=iOff ) break; - pLvl->iLeafPgno += nZero+1; - pLvl->iRowid += delta; - pLvl->iOff = ii; - } + i64 iVal; + int iLimit; + int ii; + int nZero = 0; + + /* Currently iOff points to the first byte of a varint. This block + ** decrements iOff until it points to the first byte of the previous + ** varint. Taking care not to read any memory locations that occur + ** before the buffer in memory. */ + iLimit = (iOff>9 ? iOff-9 : 0); + for(iOff--; iOff>iLimit; iOff--){ + if( (a[iOff-1] & 0x80)==0 ) break; + } + + fts5GetVarint(&a[iOff], (u64*)&iVal); + pLvl->iRowid -= iVal; + pLvl->iLeafPgno--; + + /* Skip backwards past any 0x00 varints. */ + for(ii=iOff-1; ii>=pLvl->iFirstOff && a[ii]==0x00; ii--){ + nZero++; + } + if( ii>=pLvl->iFirstOff && (a[ii] & 0x80) ){ + /* The byte immediately before the last 0x00 byte has the 0x80 bit + ** set. So the last 0x00 is only a varint 0 if there are 8 more 0x80 + ** bytes before a[ii]. */ + int bZero = 0; /* True if last 0x00 counts */ + if( (ii-8)>=pLvl->iFirstOff ){ + int j; + for(j=1; j<=8 && (a[ii-j] & 0x80); j++); + bZero = (j>8); + } + if( bZero==0 ) nZero--; + } + pLvl->iLeafPgno -= nZero; + pLvl->iOff = iOff - nZero; } return pLvl->bEof; } @@ -1656,11 +1672,11 @@ static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){ u8 *a = pIter->pLeaf->p; /* Buffer to read data from */ i64 iOff = pIter->iLeafOffset; ASSERT_SZLEAF_OK(pIter->pLeaf); - while( iOff>=pIter->pLeaf->szLeaf ){ + if( iOff>=pIter->pLeaf->szLeaf ){ fts5SegIterNextPage(p, pIter); if( pIter->pLeaf==0 ){ if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT; return; } @@ -1755,16 +1771,14 @@ if( p->rc==SQLITE_OK ){ memset(pIter, 0, sizeof(*pIter)); fts5SegIterSetNext(p, pIter); pIter->pSeg = pSeg; pIter->iLeafPgno = pSeg->pgnoFirst-1; - do { - fts5SegIterNextPage(p, pIter); - }while( p->rc==SQLITE_OK && pIter->pLeaf && pIter->pLeaf->nn==4 ); + fts5SegIterNextPage(p, pIter); } - if( p->rc==SQLITE_OK && pIter->pLeaf ){ + if( p->rc==SQLITE_OK ){ pIter->iLeafOffset = 4; assert( pIter->pLeaf!=0 ); assert_nc( pIter->pLeaf->nn>4 ); assert_nc( fts5LeafFirstTermOff(pIter->pLeaf)==4 ); pIter->iPgidxOff = pIter->pLeaf->szLeaf+1; @@ -1954,11 +1968,11 @@ ASSERT_SZLEAF_OK(pIter->pLeaf); iOff = pIter->iLeafOffset; /* Next entry is on the next page */ - while( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){ + if( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){ fts5SegIterNextPage(p, pIter); if( p->rc || pIter->pLeaf==0 ) return; pIter->iRowid = 0; iOff = 4; } @@ -2147,11 +2161,11 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){ Fts5DlidxIter *pDlidx = pIter->pDlidx; Fts5Data *pLast = 0; int pgnoLast = 0; - if( pDlidx && p->pConfig->iVersion==FTS5_CURRENT_VERSION ){ + if( pDlidx ){ int iSegid = pIter->pSeg->iSegid; pgnoLast = fts5DlidxIterPgno(pDlidx); pLast = fts5LeafRead(p, FTS5_SEGMENT_ROWID(iSegid, pgnoLast)); }else{ Fts5Data *pLeaf = pIter->pLeaf; /* Current leaf data */ @@ -2708,12 +2722,11 @@ return 0; } /* ** Move the seg-iter so that it points to the first rowid on page iLeafPgno. -** It is an error if leaf iLeafPgno does not exist. Unless the db is -** a 'secure-delete' db, if it contains no rowids then this is also an error. +** It is an error if leaf iLeafPgno does not exist or contains no rowids. */ static void fts5SegIterGotoPage( Fts5Index *p, /* FTS5 backend object */ Fts5SegIter *pIter, /* Iterator to advance */ int iLeafPgno @@ -2724,27 +2737,25 @@ p->rc = FTS5_CORRUPT; }else{ fts5DataRelease(pIter->pNextLeaf); pIter->pNextLeaf = 0; pIter->iLeafPgno = iLeafPgno-1; + fts5SegIterNextPage(p, pIter); + assert( p->rc!=SQLITE_OK || pIter->iLeafPgno==iLeafPgno ); - while( p->rc==SQLITE_OK ){ + if( p->rc==SQLITE_OK && ALWAYS(pIter->pLeaf!=0) ){ int iOff; - fts5SegIterNextPage(p, pIter); - if( pIter->pLeaf==0 ) break; + u8 *a = pIter->pLeaf->p; + int n = pIter->pLeaf->szLeaf; + iOff = fts5LeafFirstRowidOff(pIter->pLeaf); - if( iOff>0 ){ - u8 *a = pIter->pLeaf->p; - int n = pIter->pLeaf->szLeaf; - if( iOff<4 || iOff>=n ){ - p->rc = FTS5_CORRUPT; - }else{ - iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid); - pIter->iLeafOffset = iOff; - fts5SegIterLoadNPos(p, pIter); - } - break; + if( iOff<4 || iOff>=n ){ + p->rc = FTS5_CORRUPT; + }else{ + iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid); + pIter->iLeafOffset = iOff; + fts5SegIterLoadNPos(p, pIter); } } } } @@ -3455,11 +3466,11 @@ /* Allocate space for the new multi-seg-iterator. */ if( p->rc==SQLITE_OK ){ if( iLevel<0 ){ assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) ); nSeg = pStruct->nSegment; - nSeg += (p->pHash && 0==(flags & FTS5INDEX_QUERY_SKIPHASH)); + nSeg += (p->pHash ? 1 : 0); }else{ nSeg = MIN(pStruct->aLevel[iLevel].nSeg, nSegment); } } *ppOut = pNew = fts5MultiIterAlloc(p, nSeg); @@ -3476,11 +3487,11 @@ /* Initialize each of the component segment iterators. */ if( p->rc==SQLITE_OK ){ if( iLevel<0 ){ Fts5StructureLevel *pEnd = &pStruct->aLevel[pStruct->nLevel]; - if( p->pHash && 0==(flags & FTS5INDEX_QUERY_SKIPHASH) ){ + if( p->pHash ){ /* Add a segment iterator for the current contents of the hash table. */ Fts5SegIter *pIter = &pNew->aSeg[iIter++]; fts5SegIterHashInit(p, pTerm, nTerm, flags, pIter); } for(pLvl=&pStruct->aLevel[0]; pLvlrc, &buf, pData->nn); fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr); fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n); fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p); - fts5BufferAppendBlob(&p->rc, &buf,pData->szLeaf-iOff,&pData->p[iOff]); + fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff,&pData->p[iOff]); if( p->rc==SQLITE_OK ){ /* Set the szLeaf field */ fts5PutU16(&buf.p[2], (u16)buf.n); } @@ -4509,20 +4520,20 @@ Fts5Index *p, /* FTS5 backend object */ Fts5Structure **ppStruct /* IN/OUT: Current structure of index */ ){ const int nCrisis = p->pConfig->nCrisisMerge; Fts5Structure *pStruct = *ppStruct; - if( pStruct && pStruct->nLevel>0 ){ - int iLvl = 0; - while( p->rc==SQLITE_OK && pStruct->aLevel[iLvl].nSeg>=nCrisis ){ - fts5IndexMergeLevel(p, &pStruct, iLvl, 0); - assert( p->rc!=SQLITE_OK || pStruct->nLevel>(iLvl+1) ); - fts5StructurePromote(p, iLvl+1, pStruct); - iLvl++; - } - *ppStruct = pStruct; - } + int iLvl = 0; + + assert( p->rc!=SQLITE_OK || pStruct->nLevel>0 ); + while( p->rc==SQLITE_OK && pStruct->aLevel[iLvl].nSeg>=nCrisis ){ + fts5IndexMergeLevel(p, &pStruct, iLvl, 0); + assert( p->rc!=SQLITE_OK || pStruct->nLevel>(iLvl+1) ); + fts5StructurePromote(p, iLvl+1, pStruct); + iLvl++; + } + *ppStruct = pStruct; } static int fts5IndexReturn(Fts5Index *p){ int rc = p->rc; p->rc = SQLITE_OK; @@ -4551,417 +4562,10 @@ ret += i; } } return ret; } - -/* -** Execute the SQL statement: -** -** DELETE FROM %_idx WHERE (segid, (pgno/2)) = ($iSegid, $iPgno); -** -** This is used when a secure-delete operation removes the last term -** from a segment leaf page. In that case the %_idx entry is removed -** too. This is done to ensure that if all instances of a token are -** removed from an fts5 database in secure-delete mode, no trace of -** the token itself remains in the database. -*/ -static void fts5SecureDeleteIdxEntry( - Fts5Index *p, /* FTS5 backend object */ - int iSegid, /* Id of segment to delete entry for */ - int iPgno /* Page number within segment */ -){ - if( iPgno!=1 ){ - assert( p->pConfig->iVersion==FTS5_CURRENT_VERSION_SECUREDELETE ); - if( p->pDeleteFromIdx==0 ){ - fts5IndexPrepareStmt(p, &p->pDeleteFromIdx, sqlite3_mprintf( - "DELETE FROM '%q'.'%q_idx' WHERE (segid, (pgno/2)) = (?1, ?2)", - p->pConfig->zDb, p->pConfig->zName - )); - } - if( p->rc==SQLITE_OK ){ - sqlite3_bind_int(p->pDeleteFromIdx, 1, iSegid); - sqlite3_bind_int(p->pDeleteFromIdx, 2, iPgno); - sqlite3_step(p->pDeleteFromIdx); - p->rc = sqlite3_reset(p->pDeleteFromIdx); - } - } -} - -/* -** This is called when a secure-delete operation removes a position-list -** that overflows onto segment page iPgno of segment pSeg. This function -** rewrites node iPgno, and possibly one or more of its right-hand peers, -** to remove this portion of the position list. -** -** Output variable (*pbLastInDoclist) is set to true if the position-list -** removed is followed by a new term or the end-of-segment, or false if -** it is followed by another rowid/position list. -*/ -static void fts5SecureDeleteOverflow( - Fts5Index *p, - Fts5StructureSegment *pSeg, - int iPgno, - int *pbLastInDoclist -){ - const int bDetailNone = (p->pConfig->eDetail==FTS5_DETAIL_NONE); - int pgno; - Fts5Data *pLeaf = 0; - assert( iPgno!=1 ); - - *pbLastInDoclist = 1; - for(pgno=iPgno; p->rc==SQLITE_OK && pgno<=pSeg->pgnoLast; pgno++){ - i64 iRowid = FTS5_SEGMENT_ROWID(pSeg->iSegid, pgno); - int iNext = 0; - u8 *aPg = 0; - - pLeaf = fts5DataRead(p, iRowid); - if( pLeaf==0 ) break; - aPg = pLeaf->p; - - iNext = fts5GetU16(&aPg[0]); - if( iNext!=0 ){ - *pbLastInDoclist = 0; - } - if( iNext==0 && pLeaf->szLeaf!=pLeaf->nn ){ - fts5GetVarint32(&aPg[pLeaf->szLeaf], iNext); - } - - if( iNext==0 ){ - /* The page contains no terms or rowids. Replace it with an empty - ** page and move on to the right-hand peer. */ - const u8 aEmpty[] = {0x00, 0x00, 0x00, 0x04}; - assert_nc( bDetailNone==0 || pLeaf->nn==4 ); - if( bDetailNone==0 ) fts5DataWrite(p, iRowid, aEmpty, sizeof(aEmpty)); - fts5DataRelease(pLeaf); - pLeaf = 0; - }else if( bDetailNone ){ - break; - }else if( iNext>=pLeaf->szLeaf || iNext<4 ){ - p->rc = FTS5_CORRUPT; - break; - }else{ - int nShift = iNext - 4; - int nPg; - - int nIdx = 0; - u8 *aIdx = 0; - - /* Unless the current page footer is 0 bytes in size (in which case - ** the new page footer will be as well), allocate and populate a - ** buffer containing the new page footer. Set stack variables aIdx - ** and nIdx accordingly. */ - if( pLeaf->nn>pLeaf->szLeaf ){ - int iFirst = 0; - int i1 = pLeaf->szLeaf; - int i2 = 0; - - aIdx = sqlite3Fts5MallocZero(&p->rc, (pLeaf->nn-pLeaf->szLeaf)+2); - if( aIdx==0 ) break; - i1 += fts5GetVarint32(&aPg[i1], iFirst); - i2 = sqlite3Fts5PutVarint(aIdx, iFirst-nShift); - if( i1nn ){ - memcpy(&aIdx[i2], &aPg[i1], pLeaf->nn-i1); - i2 += (pLeaf->nn-i1); - } - nIdx = i2; - } - - /* Modify the contents of buffer aPg[]. Set nPg to the new size - ** in bytes. The new page is always smaller than the old. */ - nPg = pLeaf->szLeaf - nShift; - memmove(&aPg[4], &aPg[4+nShift], nPg-4); - fts5PutU16(&aPg[2], nPg); - if( fts5GetU16(&aPg[0]) ) fts5PutU16(&aPg[0], 4); - if( nIdx>0 ){ - memcpy(&aPg[nPg], aIdx, nIdx); - nPg += nIdx; - } - sqlite3_free(aIdx); - - /* Write the new page to disk and exit the loop */ - assert( nPg>4 || fts5GetU16(aPg)==0 ); - fts5DataWrite(p, iRowid, aPg, nPg); - break; - } - } - fts5DataRelease(pLeaf); -} - -/* -** Completely remove the entry that pSeg currently points to from -** the database. -*/ -static void fts5DoSecureDelete( - Fts5Index *p, - Fts5SegIter *pSeg -){ - const int bDetailNone = (p->pConfig->eDetail==FTS5_DETAIL_NONE); - int iSegid = pSeg->pSeg->iSegid; - u8 *aPg = pSeg->pLeaf->p; - int nPg = pSeg->pLeaf->nn; - int iPgIdx = pSeg->pLeaf->szLeaf; - - u64 iDelta = 0; - u64 iNextDelta = 0; - int iNextOff = 0; - int iOff = 0; - int nIdx = 0; - u8 *aIdx = 0; - int bLastInDoclist = 0; - int iIdx = 0; - int iStart = 0; - int iKeyOff = 0; - int iPrevKeyOff = 0; - int iDelKeyOff = 0; /* Offset of deleted key, if any */ - - nIdx = nPg-iPgIdx; - aIdx = sqlite3Fts5MallocZero(&p->rc, nIdx+16); - if( p->rc ) return; - memcpy(aIdx, &aPg[iPgIdx], nIdx); - - /* At this point segment iterator pSeg points to the entry - ** this function should remove from the b-tree segment. - ** - ** In detail=full or detail=column mode, pSeg->iLeafOffset is the - ** offset of the first byte in the position-list for the entry to - ** remove. Immediately before this comes two varints that will also - ** need to be removed: - ** - ** + the rowid or delta rowid value for the entry, and - ** + the size of the position list in bytes. - ** - ** Or, in detail=none mode, there is a single varint prior to - ** pSeg->iLeafOffset - the rowid or delta rowid value. - ** - ** This block sets the following variables: - ** - ** iStart: - ** iDelta: - */ - { - int iSOP; - if( pSeg->iLeafPgno==pSeg->iTermLeafPgno ){ - iStart = pSeg->iTermLeafOffset; - }else{ - iStart = fts5GetU16(&aPg[0]); - } - - iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta); - assert_nc( iSOP<=pSeg->iLeafOffset ); - - if( bDetailNone ){ - while( iSOPiLeafOffset ){ - if( aPg[iSOP]==0x00 ) iSOP++; - if( aPg[iSOP]==0x00 ) iSOP++; - iStart = iSOP; - iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta); - } - - iNextOff = iSOP; - if( iNextOffiEndofDoclist && aPg[iNextOff]==0x00 ) iNextOff++; - if( iNextOffiEndofDoclist && aPg[iNextOff]==0x00 ) iNextOff++; - - }else{ - int nPos = 0; - iSOP += fts5GetVarint32(&aPg[iSOP], nPos); - while( iSOPiLeafOffset ){ - iStart = iSOP + (nPos/2); - iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta); - iSOP += fts5GetVarint32(&aPg[iSOP], nPos); - } - assert_nc( iSOP==pSeg->iLeafOffset ); - iNextOff = pSeg->iLeafOffset + pSeg->nPos; - } - } - - iOff = iStart; - if( iNextOff>=iPgIdx ){ - int pgno = pSeg->iLeafPgno+1; - fts5SecureDeleteOverflow(p, pSeg->pSeg, pgno, &bLastInDoclist); - iNextOff = iPgIdx; - }else{ - /* Set bLastInDoclist to true if the entry being removed is the last - ** in its doclist. */ - for(iIdx=0, iKeyOff=0; iIdxiTermLeafOffset && pSeg->iLeafPgno==pSeg->iTermLeafPgno - ){ - /* The entry being removed was the only position list in its - ** doclist. Therefore the term needs to be removed as well. */ - int iKey = 0; - for(iIdx=0, iKeyOff=0; iIdx(u32)iStart ) break; - iKeyOff += iVal; - } - - iDelKeyOff = iOff = iKeyOff; - if( iNextOff!=iPgIdx ){ - int nPrefix = 0; - int nSuffix = 0; - int nPrefix2 = 0; - int nSuffix2 = 0; - - iDelKeyOff = iNextOff; - iNextOff += fts5GetVarint32(&aPg[iNextOff], nPrefix2); - iNextOff += fts5GetVarint32(&aPg[iNextOff], nSuffix2); - - if( iKey!=1 ){ - iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nPrefix); - } - iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nSuffix); - - nPrefix = MIN(nPrefix, nPrefix2); - nSuffix = (nPrefix2 + nSuffix2) - nPrefix; - - if( (iKeyOff+nSuffix)>iPgIdx || (iNextOff+nSuffix2)>iPgIdx ){ - p->rc = FTS5_CORRUPT; - }else{ - if( iKey!=1 ){ - iOff += sqlite3Fts5PutVarint(&aPg[iOff], nPrefix); - } - iOff += sqlite3Fts5PutVarint(&aPg[iOff], nSuffix); - if( nPrefix2>nPrefix ){ - memcpy(&aPg[iOff], &pSeg->term.p[nPrefix], nPrefix2-nPrefix); - iOff += (nPrefix2-nPrefix); - } - memmove(&aPg[iOff], &aPg[iNextOff], nSuffix2); - iOff += nSuffix2; - iNextOff += nSuffix2; - } - } - }else if( iStart==4 ){ - int iPgno; - - assert_nc( pSeg->iLeafPgno>pSeg->iTermLeafPgno ); - /* The entry being removed may be the only position list in - ** its doclist. */ - for(iPgno=pSeg->iLeafPgno-1; iPgno>pSeg->iTermLeafPgno; iPgno-- ){ - Fts5Data *pPg = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, iPgno)); - int bEmpty = (pPg && pPg->nn==4); - fts5DataRelease(pPg); - if( bEmpty==0 ) break; - } - - if( iPgno==pSeg->iTermLeafPgno ){ - i64 iId = FTS5_SEGMENT_ROWID(iSegid, pSeg->iTermLeafPgno); - Fts5Data *pTerm = fts5DataRead(p, iId); - if( pTerm && pTerm->szLeaf==pSeg->iTermLeafOffset ){ - u8 *aTermIdx = &pTerm->p[pTerm->szLeaf]; - int nTermIdx = pTerm->nn - pTerm->szLeaf; - int iTermIdx = 0; - int iTermOff = 0; - - while( 1 ){ - u32 iVal = 0; - int nByte = fts5GetVarint32(&aTermIdx[iTermIdx], iVal); - iTermOff += iVal; - if( (iTermIdx+nByte)>=nTermIdx ) break; - iTermIdx += nByte; - } - nTermIdx = iTermIdx; - - memmove(&pTerm->p[iTermOff], &pTerm->p[pTerm->szLeaf], nTermIdx); - fts5PutU16(&pTerm->p[2], iTermOff); - - fts5DataWrite(p, iId, pTerm->p, iTermOff+nTermIdx); - if( nTermIdx==0 ){ - fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iTermLeafPgno); - } - } - fts5DataRelease(pTerm); - } - } - - if( p->rc==SQLITE_OK ){ - const int nMove = nPg - iNextOff; - int nShift = 0; - - memmove(&aPg[iOff], &aPg[iNextOff], nMove); - iPgIdx -= (iNextOff - iOff); - nPg = iPgIdx; - fts5PutU16(&aPg[2], iPgIdx); - - nShift = iNextOff - iOff; - for(iIdx=0, iKeyOff=0, iPrevKeyOff=0; iIdxiOff ){ - iKeyOff -= nShift; - nShift = 0; - } - nPg += sqlite3Fts5PutVarint(&aPg[nPg], iKeyOff - iPrevKeyOff); - iPrevKeyOff = iKeyOff; - } - } - - if( iPgIdx==nPg && nIdx>0 && pSeg->iLeafPgno!=1 ){ - fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iLeafPgno); - } - - assert_nc( nPg>4 || fts5GetU16(aPg)==0 ); - fts5DataWrite(p, FTS5_SEGMENT_ROWID(iSegid,pSeg->iLeafPgno), aPg,nPg); - } - sqlite3_free(aIdx); -} - -/* -** This is called as part of flushing a delete to disk in 'secure-delete' -** mode. It edits the segments within the database described by argument -** pStruct to remove the entries for term zTerm, rowid iRowid. -*/ -static void fts5FlushSecureDelete( - Fts5Index *p, - Fts5Structure *pStruct, - const char *zTerm, - i64 iRowid -){ - const int f = FTS5INDEX_QUERY_SKIPHASH; - int nTerm = (int)strlen(zTerm); - Fts5Iter *pIter = 0; /* Used to find term instance */ - - fts5MultiIterNew(p, pStruct, f, 0, (const u8*)zTerm, nTerm, -1, 0, &pIter); - if( fts5MultiIterEof(p, pIter)==0 ){ - i64 iThis = fts5MultiIterRowid(pIter); - if( iThisrc==SQLITE_OK - && fts5MultiIterEof(p, pIter)==0 - && iRowid==fts5MultiIterRowid(pIter) - ){ - Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst]; - fts5DoSecureDelete(p, pSeg); - } - } - - fts5MultiIterFree(pIter); -} - /* ** Flush the contents of in-memory hash table iHash to a new level-0 ** segment on disk. Also update the corresponding structure record. ** @@ -4981,11 +4585,10 @@ fts5StructureInvalidate(p); if( iSegid ){ const int pgsz = p->pConfig->pgsz; int eDetail = p->pConfig->eDetail; - int bSecureDelete = p->pConfig->bSecureDelete; Fts5StructureSegment *pSeg; /* New segment within pStruct */ Fts5Buffer *pBuf; /* Buffer in which to assemble leaf page */ Fts5Buffer *pPgidx; /* Buffer in which to assemble pgidx */ Fts5SegWriter writer; @@ -5004,81 +4607,44 @@ if( p->rc==SQLITE_OK ){ p->rc = sqlite3Fts5HashScanInit(pHash, 0, 0); } while( p->rc==SQLITE_OK && 0==sqlite3Fts5HashScanEof(pHash) ){ const char *zTerm; /* Buffer containing term */ - int nTerm; /* Size of zTerm in bytes */ const u8 *pDoclist; /* Pointer to doclist for this term */ int nDoclist; /* Size of doclist in bytes */ - /* Get the term and doclist for this entry. */ + /* Write the term for this entry to disk. */ sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist); - nTerm = (int)strlen(zTerm); - if( bSecureDelete==0 ){ - fts5WriteAppendTerm(p, &writer, nTerm, (const u8*)zTerm); - if( p->rc!=SQLITE_OK ) break; - assert( writer.bFirstRowidInPage==0 ); - } - - if( !bSecureDelete && pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){ + fts5WriteAppendTerm(p, &writer, (int)strlen(zTerm), (const u8*)zTerm); + if( p->rc!=SQLITE_OK ) break; + + assert( writer.bFirstRowidInPage==0 ); + if( pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){ /* The entire doclist will fit on the current leaf. */ fts5BufferSafeAppendBlob(pBuf, pDoclist, nDoclist); }else{ - int bTermWritten = !bSecureDelete; i64 iRowid = 0; - i64 iPrev = 0; + u64 iDelta = 0; int iOff = 0; /* The entire doclist will not fit on this leaf. The following ** loop iterates through the poslists that make up the current ** doclist. */ while( p->rc==SQLITE_OK && iOffrc!=SQLITE_OK || pDoclist[iOff]==0x01 ){ - iOff++; - continue; - } - } - } - - if( p->rc==SQLITE_OK && bTermWritten==0 ){ - fts5WriteAppendTerm(p, &writer, nTerm, (const u8*)zTerm); - bTermWritten = 1; - assert( p->rc!=SQLITE_OK || writer.bFirstRowidInPage==0 ); - } if( writer.bFirstRowidInPage ){ fts5PutU16(&pBuf->p[0], (u16)pBuf->n); /* first rowid on page */ pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid); writer.bFirstRowidInPage = 0; fts5WriteDlidxAppend(p, &writer, iRowid); + if( p->rc!=SQLITE_OK ) break; }else{ - pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid-iPrev); + pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta); } - if( p->rc!=SQLITE_OK ) break; assert( pBuf->n<=pBuf->nSpace ); - iPrev = iRowid; if( eDetail==FTS5_DETAIL_NONE ){ if( iOffp[pBuf->n++] = 0; iOff++; @@ -5133,27 +4699,24 @@ if( p->rc==SQLITE_OK ) sqlite3Fts5HashScanNext(pHash); } sqlite3Fts5HashClear(pHash); fts5WriteFinish(p, &writer, &pgnoLast); - assert( p->rc!=SQLITE_OK || bSecureDelete || pgnoLast>0 ); - if( pgnoLast>0 ){ - /* Update the Fts5Structure. It is written back to the database by the - ** fts5StructureRelease() call below. */ - if( pStruct->nLevel==0 ){ - fts5StructureAddLevel(&p->rc, &pStruct); - } - fts5StructureExtendLevel(&p->rc, pStruct, 0, 1, 0); - if( p->rc==SQLITE_OK ){ - pSeg = &pStruct->aLevel[0].aSeg[ pStruct->aLevel[0].nSeg++ ]; - pSeg->iSegid = iSegid; - pSeg->pgnoFirst = 1; - pSeg->pgnoLast = pgnoLast; - pStruct->nSegment++; - } - fts5StructurePromote(p, 0, pStruct); - } + /* Update the Fts5Structure. It is written back to the database by the + ** fts5StructureRelease() call below. */ + if( pStruct->nLevel==0 ){ + fts5StructureAddLevel(&p->rc, &pStruct); + } + fts5StructureExtendLevel(&p->rc, pStruct, 0, 1, 0); + if( p->rc==SQLITE_OK ){ + pSeg = &pStruct->aLevel[0].aSeg[ pStruct->aLevel[0].nSeg++ ]; + pSeg->iSegid = iSegid; + pSeg->pgnoFirst = 1; + pSeg->pgnoLast = pgnoLast; + pStruct->nSegment++; + } + fts5StructurePromote(p, 0, pStruct); } fts5IndexAutomerge(p, &pStruct, pgnoLast); fts5IndexCrisismerge(p, &pStruct); fts5StructureWrite(p, pStruct); @@ -5205,14 +4768,14 @@ pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte); if( pNew ){ Fts5StructureLevel *pLvl; nByte = nSeg * sizeof(Fts5StructureSegment); - pNew->nLevel = MIN(pStruct->nLevel+1, FTS5_MAX_LEVEL); + pNew->nLevel = pStruct->nLevel+1; pNew->nRef = 1; pNew->nWriteCounter = pStruct->nWriteCounter; - pLvl = &pNew->aLevel[pNew->nLevel-1]; + pLvl = &pNew->aLevel[MIN(pStruct->nLevel, FTS5_MAX_LEVEL-1)]; pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&p->rc, nByte); if( pLvl->aSeg ){ int iLvl, iSeg; int iSegOut = 0; /* Iterate through all segments, from oldest to newest. Add them to @@ -5890,11 +5453,10 @@ sqlite3_finalize(p->pDeleter); sqlite3_finalize(p->pIdxWriter); sqlite3_finalize(p->pIdxDeleter); sqlite3_finalize(p->pIdxSelect); sqlite3_finalize(p->pDataVersion); - sqlite3_finalize(p->pDeleteFromIdx); sqlite3Fts5HashFree(p->pHash); sqlite3_free(p->zDataTbl); sqlite3_free(p); } return rc; @@ -6521,11 +6083,10 @@ static void fts5IndexIntegrityCheckSegment( Fts5Index *p, /* FTS5 backend object */ Fts5StructureSegment *pSeg /* Segment to check internal consistency */ ){ Fts5Config *pConfig = p->pConfig; - int bSecureDelete = (pConfig->iVersion==FTS5_CURRENT_VERSION_SECUREDELETE); sqlite3_stmt *pStmt = 0; int rc2; int iIdxPrevLeaf = pSeg->pgnoFirst-1; int iDlidxPrevLeaf = pSeg->pgnoLast; @@ -6557,23 +6118,11 @@ /* Check that the leaf contains at least one term, and that it is equal ** to or larger than the split-key in zIdxTerm. Also check that if there ** is also a rowid pointer within the leaf page header, it points to a ** location before the term. */ if( pLeaf->nn<=pLeaf->szLeaf ){ - - if( nIdxTerm==0 - && pConfig->iVersion==FTS5_CURRENT_VERSION_SECUREDELETE - && pLeaf->nn==pLeaf->szLeaf - && pLeaf->nn==4 - ){ - /* special case - the very first page in a segment keeps its %_idx - ** entry even if all the terms are removed from it by secure-delete - ** operations. */ - }else{ - p->rc = FTS5_CORRUPT; - } - + p->rc = FTS5_CORRUPT; }else{ int iOff; /* Offset of first term on leaf */ int iRowidOff; /* Offset of first rowid on leaf */ int nTerm; /* Size of term on leaf in bytes */ int res; /* Comparison of term and split-key */ @@ -6633,16 +6182,13 @@ i64 iRowid; int iRowidOff = fts5LeafFirstRowidOff(pLeaf); ASSERT_SZLEAF_OK(pLeaf); if( iRowidOff>=pLeaf->szLeaf ){ p->rc = FTS5_CORRUPT; - }else if( bSecureDelete==0 || iRowidOff>0 ){ - i64 iDlRowid = fts5DlidxIterRowid(pDlidx); + }else{ fts5GetVarint(&pLeaf->p[iRowidOff], (u64*)&iRowid); - if( iRowidrc = FTS5_CORRUPT; - } + if( iRowid!=fts5DlidxIterRowid(pDlidx) ) p->rc = FTS5_CORRUPT; } fts5DataRelease(pLeaf); } } Index: ext/fts5/fts5_main.c ================================================================== --- ext/fts5/fts5_main.c +++ ext/fts5/fts5_main.c @@ -1621,12 +1621,10 @@ ){ Fts5FullTable *pTab = (Fts5FullTable*)pVtab; Fts5Config *pConfig = pTab->p.pConfig; int eType0; /* value_type() of apVal[0] */ int rc = SQLITE_OK; /* Return code */ - int bUpdateOrDelete = 0; - /* A transaction must be open when this is called. */ assert( pTab->ts.eState==1 || pTab->ts.eState==2 ); assert( pVtab->zErrMsg==0 ); @@ -1633,15 +1631,10 @@ assert( nArg==1 || nArg==(2+pConfig->nCol+2) ); assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER || sqlite3_value_type(apVal[0])==SQLITE_NULL ); assert( pTab->p.pConfig->pzErrmsg==0 ); - if( pConfig->pgsz==0 ){ - rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex); - if( rc!=SQLITE_OK ) return rc; - } - pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg; /* Put any active cursors into REQUIRE_SEEK state. */ fts5TripCursors(pTab); @@ -1690,11 +1683,10 @@ /* DELETE */ else if( nArg==1 ){ i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0); - bUpdateOrDelete = 1; } /* INSERT or UPDATE */ else{ int eType1 = sqlite3_value_numeric_type(apVal[1]); @@ -1706,11 +1698,10 @@ else if( eType0!=SQLITE_INTEGER ){ /* If this is a REPLACE, first remove the current entry (if any) */ if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){ i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); - bUpdateOrDelete = 1; } fts5StorageInsert(&rc, pTab, apVal, pRowid); } /* UPDATE */ @@ -1735,25 +1726,11 @@ } }else{ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); fts5StorageInsert(&rc, pTab, apVal, pRowid); } - bUpdateOrDelete = 1; - } - } - } - - if( rc==SQLITE_OK - && bUpdateOrDelete - && pConfig->bSecureDelete - && pConfig->iVersion==FTS5_CURRENT_VERSION - ){ - rc = sqlite3Fts5StorageConfigValue( - pTab->pStorage, "version", 0, FTS5_CURRENT_VERSION_SECUREDELETE - ); - if( rc==SQLITE_OK ){ - pConfig->iVersion = FTS5_CURRENT_VERSION_SECUREDELETE; + } } } pTab->p.pConfig->pzErrmsg = 0; return rc; @@ -2612,11 +2589,10 @@ static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ Fts5FullTable *pTab = (Fts5FullTable*)pVtab; UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint); fts5TripCursors(pTab); - pTab->p.pConfig->pgsz = 0; return sqlite3Fts5StorageRollback(pTab->pStorage); } /* ** Register a new auxiliary function with global context pGlobal. Index: ext/fts5/test/fts5_common.tcl ================================================================== --- ext/fts5/test/fts5_common.tcl +++ ext/fts5/test/fts5_common.tcl @@ -592,14 +592,10 @@ set ::expr_not_ok 1 } list } -proc dump {tname} { - execsql_pp "SELECT * FROM ${tname}_idx" - execsql_pp "SELECT id, quote(block), fts5_decode(id,block) FROM ${tname}_data" -} #------------------------------------------------------------------------- # Code for a simple Tcl tokenizer that supports synonyms at query time. # proc tclnum_tokenize {mode tflags text} { Index: ext/fts5/test/fts5af.test ================================================================== --- ext/fts5/test/fts5af.test +++ ext/fts5/test/fts5af.test @@ -190,37 +190,7 @@ do_execsql_test 5.6 { SELECT snippet(p1, 0, '[', NULL, '...', 6) FROM p1('x OR ' || x'DB'); } {{[x a a a a a...}} } ;# foreach_detail_mode - -reset_db -do_execsql_test 6.0 { - CREATE VIRTUAL TABLE t1 USING fts5(colA, colB); - INSERT INTO t1 VALUES('A B C', 'D E F'); -} - -do_execsql_test 6.1 { - SELECT colA, colB, snippet(t1,0,'[', ']','...',1) FROM t1 WHERE t1 MATCH 'B'; -} {{A B C} {D E F} ...[B]...} -breakpoint -do_execsql_test 6.2 { - SELECT colA, colB, snippet(t1, 1,'[',']','...',2) FROM t1 WHERE t1 MATCH 'B'; -} {{A B C} {D E F} {D E...}} -do_execsql_test 6.3 { - SELECT colA, colB, snippet(t1, 1,'[',']','...',1) FROM t1 WHERE t1 MATCH 'B'; -} {{A B C} {D E F} {D...}} - -do_execsql_test 6.1 { - SELECT colA, colB, snippet(t1,0,'[', ']','...',1) FROM t1 WHERE t1 MATCH 'A'; -} {{A B C} {D E F} [A]...} -breakpoint -do_execsql_test 6.2 { - SELECT colA, colB, snippet(t1, 1,'[',']','...',2) FROM t1 WHERE t1 MATCH 'A'; -} {{A B C} {D E F} {D E...}} -do_execsql_test 6.3 { - SELECT colA, colB, snippet(t1, 1,'[',']','...',1) FROM t1 WHERE t1 MATCH 'A'; -} {{A B C} {D E F} {D...}} - - finish_test Index: ext/fts5/test/fts5ak.test ================================================================== --- ext/fts5/test/fts5ak.test +++ ext/fts5/test/fts5ak.test @@ -152,32 +152,6 @@ {a b c d e} } } -# 2023-04-06 https://sqlite.org/forum/forumpost/cae4367d9b -# -# This is not a test of FTS5, but rather a test of the of what happens to -# prepared statements that encounter SQLITE_SCHEMA while other prepared -# statements are running. The original problem POC used FTS5, and so -# is seems reasonable to put the test here. -# -# The vdbeaux24.test module in TH3 also tests this same behavior but -# without requiring FTS5 or an other extension. -# -reset_db -db null NULL -do_execsql_test 4.0 { - CREATE TABLE t5(a PRIMARY KEY); - INSERT INTO t5 VALUES(0); - CREATE VIRTUAL TABLE t6 USING fts5(0); - DELETE FROM t6; - CREATE TABLE t7(x); - WITH cte(a) AS ( - SELECT a FROM t5 - WHERE ((0,0) IN (SELECT 0, LAG(0) OVER (PARTITION BY 0) FROM t6), 0) - < (a,0) - ) - SELECT max(a) FROM cte; -} NULL - finish_test DELETED ext/fts5/test/fts5corrupt7.test Index: ext/fts5/test/fts5corrupt7.test ================================================================== --- ext/fts5/test/fts5corrupt7.test +++ /dev/null @@ -1,99 +0,0 @@ -# 2023 April 30 -# -# 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. -# -#*********************************************************************** -# - -source [file join [file dirname [info script]] fts5_common.tcl] -set testprefix fts5corrupt7 - -# If SQLITE_ENABLE_FTS5 is defined, omit this file. -ifcapable !fts5 { - finish_test - return -} -sqlite3_fts5_may_be_corrupt 1 - -do_execsql_test 1.0 { - CREATE VIRTUAL TABLE t1 USING fts5(x); - INSERT INTO t1(t1, rank) VALUES('pgsz', 32); -} - -set doc [string repeat "a b " 30] - -do_execsql_test 1.1 { - BEGIN; - INSERT INTO t1(rowid, x) VALUES(123, $doc); - INSERT INTO t1(rowid, x) VALUES(124, $doc); - COMMIT; -} - -execsql_pp { - SELECT id, fts5_decode(id, block), quote(block) FROM t1_data -} - -set rows [db eval { SELECT rowid FROM t1_data }] -db_save_and_close - -foreach r $rows { - db_restore_and_reopen - - proc edit_block {b} { - binary scan $b c* in - set out [lreplace $in 0 1 255 255] - binary format c* $out - } - db func edit_block edit_block - - do_execsql_test 1.2.$r.1 { - UPDATE t1_data SET block = edit_block(block) WHERE rowid=$r; - } - - do_execsql_test 1.2.$r.2 { - INSERT INTO t1(t1, rank) VALUES('secure-delete', 1); - } - - do_test 1.2.$r.3 { - catchsql { DELETE FROM t1 WHERE rowid=123; } - catchsql { DELETE FROM t1 WHERE rowid=124; } - set {} {} - } {} - - db close -} - -foreach r $rows { -set r 137438953475 - db_restore_and_reopen - - proc edit_block {b} { - binary scan $b c* in - set out [lreplace $in end end 127] - binary format c* $out - } - db func edit_block edit_block - - do_execsql_test 1.2.$r.1 { - UPDATE t1_data SET block = edit_block(block) WHERE rowid=$r; - } - - do_execsql_test 1.2.$r.2 { - INSERT INTO t1(t1, rank) VALUES('secure-delete', 1); - } - - do_test 1.2.$r.3 { - catchsql { DELETE FROM t1 WHERE rowid=124; } - catchsql { DELETE FROM t1 WHERE rowid=123; } - set {} {} - } {} - - db close -} - -finish_test Index: ext/fts5/test/fts5misc.test ================================================================== --- ext/fts5/test/fts5misc.test +++ ext/fts5/test/fts5misc.test @@ -440,36 +440,8 @@ } do_execsql_test -db db2 16.6 { SELECT * FROM x1 } {abc def} - -#------------------------------------------------------------------------- -reset_db -do_execsql_test 17.1 { - CREATE VIRTUAL TABLE ft USING fts5(x, tokenize="unicode61 separators 'X'"); -} -do_execsql_test 17.2 { - SELECT 0 FROM ft WHERE ft MATCH 'X' AND ft MATCH 'X' -} -do_execsql_test 17.3 { - SELECT 0 FROM ft('X') -} - -do_execsql_test 17.4 { - CREATE VIRTUAL TABLE t0 USING fts5(c0, t="trigram"); - INSERT INTO t0 VALUES('assertionfaultproblem'); -} -do_execsql_test 17.5 { - SELECT 0 FROM t0(0) WHERE c0 GLOB 0; -} {} - -do_execsql_test 17.5 { - SELECT c0 FROM t0 WHERE c0 GLOB '*f*'; -} {assertionfaultproblem} -do_execsql_test 17.5 { - SELECT c0 FROM t0 WHERE c0 GLOB '*faul*'; -} {assertionfaultproblem} - finish_test Index: ext/fts5/test/fts5optimize2.test ================================================================== --- ext/fts5/test/fts5optimize2.test +++ ext/fts5/test/fts5optimize2.test @@ -19,19 +19,17 @@ ifcapable !fts5 { finish_test return } -set nLoop 2500 - do_execsql_test 1.0 { CREATE VIRTUAL TABLE t1 USING fts5(x); INSERT INTO t1(t1, rank) VALUES('pgsz', 32); } do_test 1.1 { - for {set ii 0} {$ii < $nLoop} {incr ii} { + for {set ii 0} {$ii < 1500} {incr ii} { execsql { INSERT INTO t1 VALUES('abc def ghi'); INSERT INTO t1 VALUES('jkl mno pqr'); INSERT INTO t1(t1) VALUES('optimize'); } @@ -38,19 +36,19 @@ } } {} do_execsql_test 1.2 { SELECT count(*) FROM t1('mno') -} $nLoop +} {1500} do_execsql_test 2.0 { CREATE VIRTUAL TABLE t2 USING fts5(x); INSERT INTO t2(t2, rank) VALUES('pgsz', 32); } do_test 2.1 { - for {set ii 0} {$ii < $nLoop} {incr ii} { + for {set ii 0} {$ii < 1500} {incr ii} { execsql { INSERT INTO t2 VALUES('abc def ghi'); INSERT INTO t2 VALUES('jkl mno pqr'); INSERT INTO t2(t2, rank) VALUES('merge', -1); } @@ -57,8 +55,8 @@ } } {} do_execsql_test 2.2 { SELECT count(*) FROM t2('mno') -} $nLoop +} {1500} finish_test DELETED ext/fts5/test/fts5secure.test Index: ext/fts5/test/fts5secure.test ================================================================== --- ext/fts5/test/fts5secure.test +++ /dev/null @@ -1,278 +0,0 @@ -# 2023 Feb 17 -# -# 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. -# -#************************************************************************* -# - -source [file join [file dirname [info script]] fts5_common.tcl] -ifcapable !fts5 { finish_test ; return } -set ::testprefix fts5secure - -proc dump {tname} { - execsql_pp "SELECT * FROM ${tname}_idx" - execsql_pp "SELECT id, quote(block), fts5_decode(id,block) FROM ${tname}_data" -} - - -do_execsql_test 0.0 { - CREATE VIRTUAL TABLE t1 USING fts5(ab); - CREATE VIRTUAL TABLE v1 USING fts5vocab('t1', 'instance'); - INSERT INTO t1(rowid, ab) VALUES - (0,'abc'), (1,'abc'), (2,'abc'), (3,'abc'), (4,'def'); -} - -do_execsql_test 0.1 { - INSERT INTO t1(t1, rank) VALUES('secure-delete', 1); -} - -do_execsql_test 0.2 { - DELETE FROM t1 WHERE rowid=2; -} - -do_execsql_test 0.3 { - SELECT count(*) FROM t1_data -} 3 - -do_execsql_test 0.4 { - INSERT INTO t1(t1) VALUES('integrity-check'); -} - -do_execsql_test 0.5 { - DELETE FROM t1 WHERE rowid=3; -} - -do_execsql_test 0.6 { - INSERT INTO t1(t1) VALUES('integrity-check'); -} - -do_execsql_test 0.7 { - DELETE FROM t1 WHERE rowid=0; -} - -do_execsql_test 0.8 { - INSERT INTO t1(t1) VALUES('integrity-check'); -} - -#---------------------------------- - -do_execsql_test 1.0 { - CREATE VIRTUAL TABLE t2 USING fts5(ab); - INSERT INTO t2(rowid, ab) VALUES (5, 'key'), (6, 'value'); - INSERT INTO t2(t2, rank) VALUES('secure-delete', 1); -} - -#execsql_pp { SELECT id, quote(block) FROM t1_data } -#execsql_pp { SELECT segid, quote(term), pgno FROM t1_idx } - -do_execsql_test 1.1 { - DELETE FROM t2 WHERE rowid = 5; -} - -do_execsql_test 1.2 { - INSERT INTO t2(t2) VALUES('integrity-check'); -} - -do_execsql_test 1.3 { - DELETE FROM t2 WHERE rowid = 6; -} - -do_execsql_test 1.4 { - INSERT INTO t2(t2) VALUES('integrity-check'); -} - -do_execsql_test 1.5 { - SELECT * FROM t2('value'); - SELECT * FROM t2('v*'); -} - -do_execsql_test 1.6 { - SELECT * FROM t2('value') ORDER BY rowid DESC; - SELECT * FROM t2('v*') ORDER BY rowid DESC; -} -execsql_pp { - SELECT id, quote(block) FROM t2_data; -} - -#---------------------------------- - -do_execsql_test 2.0 { - CREATE VIRTUAL TABLE ft USING fts5(ab); - CREATE VIRTUAL TABLE vocab USING fts5vocab('ft', 'instance'); - INSERT INTO ft(rowid, ab) VALUES - (1, 'one'), - (2, 'two'), - (3, 'three'), - (4, 'four'), - (5, 'one one'), - (6, 'one two'), - (7, 'one three'), - (8, 'one four'), - (9, 'two one'), - (10, 'two two'), - (11, 'two three'), - (12, 'two four'), - (13, 'three one'), - (14, 'three two'), - (15, 'three three'), - (16, 'three four'); -} - -do_execsql_test 2.1 { - SELECT count(*) FROM ft_data; -} {3} - -do_execsql_test 2.2 { - INSERT INTO ft(ft, rank) VALUES('secure-delete', 1); -} - -do_execsql_test 2.3 { - DELETE FROM ft WHERE rowid=9; -} - -do_execsql_test 2.4 { - INSERT INTO ft(ft) VALUES('integrity-check'); -} - -do_execsql_test 2.5 { - DELETE FROM ft WHERE ab LIKE '%two%' -} - -do_execsql_test 2.6 { - INSERT INTO ft(ft) VALUES('integrity-check'); -} - -do_execsql_test 2.7 { - SELECT count(*) FROM ft_data; -} {3} - -#---------------------------------- -reset_db - -set ::vocab { - one two three four five six seven eight nine ten - eleven twelve thirteen fourteen fifteen sixteen - seventeen eighteen nineteen twenty -} -proc rnddoc {} { - set nVocab [llength $::vocab] - set ret [list] - for {set ii 0} {$ii < 8} {incr ii} { - lappend ret [lindex $::vocab [expr int(abs(rand()) * $nVocab)]] - } - set ret -} - -proc contains {list val} { - expr {[lsearch $list $val]>=0} -} - -foreach {tn pgsz} { - 2 64 - 1 1000 -} { - reset_db - db function rnddoc rnddoc - db function contains contains - - expr srand(1) - - do_execsql_test 3.$tn.0 { - CREATE VIRTUAL TABLE t1 USING fts5(x); - INSERT INTO t1(t1, rank) VALUES('pgsz', $pgsz); - WITH s(i) AS ( - VALUES(1) UNION SELECT i+1 FROM s WHERE i<20 - ) - INSERT INTO t1 SELECT rnddoc() FROM s; - } - - do_execsql_test 3.$tn.1 { - INSERT INTO t1(t1, rank) VALUES('secure-delete', 1); - } - - foreach {rowid} { - 6 16 3 4 9 14 13 7 20 15 19 10 11 2 5 18 17 1 12 8 - } { - - do_execsql_test 3.$tn.2.$rowid { - DELETE FROM t1 WHERE rowid=$rowid; - } - do_execsql_test 3.$tn.2.$rowid.ic { - INSERT INTO t1(t1) VALUES('integrity-check'); - } - - foreach v $::vocab { - do_execsql_test 3.$tn.2.$rowid.q.$v { - SELECT rowid FROM t1($v) - } [db eval {SELECT rowid FROM t1 WHERE contains(x, $v)}] - - do_execsql_test 3.$tn.2.$rowid.q.$v.DESC { - SELECT rowid FROM t1($v) ORDER BY 1 DESC - } [db eval {SELECT rowid FROM t1 WHERE contains(x, $v) ORDER BY 1 DESC}] - } - } -} - -do_execsql_test 3.3 { - INSERT INTO t1(x) VALUES('optimize'); - INSERT INTO t1(t1) VALUES('optimize'); - SELECT count(*) FROM t1_data; -} {3} - -#---------------------------------- -reset_db -do_execsql_test 4.0 { - CREATE VIRTUAL TABLE t1 USING fts5(x); - INSERT INTO t1(t1, rank) VALUES('pgsz', 32); - INSERT INTO t1(t1, rank) VALUES('secure-delete', 1); -} - -set L1 [string repeat abcdefghij 10] -set L2 [string repeat 1234567890 10] - -do_execsql_test 4.1 { - INSERT INTO t1 VALUES('aa' || $L1 || ' ' || $L2); -} -do_execsql_test 4.2 { - DELETE FROM t1 WHERE rowid=1 -} -do_execsql_test 4.3 { - INSERT INTO t1(t1) VALUES('integrity-check'); -} - -#---------------------------------- -reset_db -do_execsql_test 5.0 { - CREATE VIRTUAL TABLE t1 USING fts5(x); - INSERT INTO t1(t1, rank) VALUES('pgsz', 32); - INSERT INTO t1(t1, rank) VALUES('secure-delete', 1); -} - -set doc "aa [string repeat {abc } 60]" - -do_execsql_test 5.1 { - BEGIN; - INSERT INTO t1 VALUES($doc); - INSERT INTO t1 VALUES('aa abc'); - COMMIT; -} - -do_execsql_test 5.2 { - DELETE FROM t1 WHERE rowid = 1; -} - -do_execsql_test 5.3 { - INSERT INTO t1(t1) VALUES('integrity-check'); -} - -do_execsql_test 5.4 { SELECT rowid FROM t1('abc'); } 2 -do_execsql_test 5.5 { SELECT rowid FROM t1('aa'); } 2 - - -finish_test - DELETED ext/fts5/test/fts5secure2.test Index: ext/fts5/test/fts5secure2.test ================================================================== --- ext/fts5/test/fts5secure2.test +++ /dev/null @@ -1,87 +0,0 @@ -# 2023 Feb 17 -# -# 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. -# -#************************************************************************* -# - -source [file join [file dirname [info script]] fts5_common.tcl] -ifcapable !fts5 { finish_test ; return } -set ::testprefix fts5secure2 - -do_execsql_test 1.0 { - CREATE VIRTUAL TABLE ft USING fts5(col); - INSERT INTO ft VALUES('data for the table'); - INSERT INTO ft VALUES('more of the same'); - INSERT INTO ft VALUES('and extra data'); -} - -do_execsql_test 1.1 { - SELECT * FROM ft_config -} {version 4} - -do_execsql_test 1.2 { - INSERT INTO ft(ft, rank) VALUES('secure-delete', 1); - SELECT * FROM ft_config; -} {secure-delete 1 version 4} - -do_execsql_test 1.3 { - INSERT INTO ft(ft, rank) VALUES('secure-delete', 1); - SELECT * FROM ft_config; -} {secure-delete 1 version 4} - -do_execsql_test 1.4 { - DELETE FROM ft WHERE rowid=2; - SELECT * FROM ft_config; -} {secure-delete 1 version 5} - -do_execsql_test 1.5 { - SELECT rowid, col FROM ft('data'); -} {1 {data for the table} 3 {and extra data}} - -db close -sqlite3 db test.db - -do_execsql_test 1.6 { - SELECT rowid, col FROM ft('data'); -} {1 {data for the table} 3 {and extra data}} - -#------------------------------------------------------------------------ - -reset_db -do_execsql_test 2.0 { - CREATE VIRTUAL TABLE ft USING fts5(col); - INSERT INTO ft VALUES('one zero one one zero'); - INSERT INTO ft(ft, rank) VALUES('secure-delete', 1); -} - -do_execsql_test 2.1 { - SELECT count(*) FROM ft_data WHERE block=X'00000004'; -} {0} - -do_execsql_test 2.2 { - UPDATE ft SET col = 'zero one zero zero one' WHERE rowid=1; -} - -do_execsql_test 2.3 { - SELECT count(*) FROM ft_data WHERE block=X'00000004'; -} {1} - -do_execsql_test 2.4 { - INSERT INTO ft VALUES('one zero zero one'); - DELETE FROM ft WHERE rowid=1; -} - -do_execsql_test 2.5 { - SELECT count(*) FROM ft_data WHERE block=X'00000004'; -} {2} - - -finish_test - - DELETED ext/fts5/test/fts5secure3.test Index: ext/fts5/test/fts5secure3.test ================================================================== --- ext/fts5/test/fts5secure3.test +++ /dev/null @@ -1,166 +0,0 @@ -# 2023 Feb 17 -# -# 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. -# -#************************************************************************* -# -# TESTRUNNER: slow -# - -source [file join [file dirname [info script]] fts5_common.tcl] -ifcapable !fts5 { finish_test ; return } -set ::testprefix fts5secure3 - -do_execsql_test 1.0 { - CREATE VIRTUAL TABLE ft USING fts5(col); - INSERT INTO ft VALUES('data for the table'); - INSERT INTO ft VALUES('more of the same'); - INSERT INTO ft VALUES('and extra data'); - - INSERT INTO ft(ft, rank) VALUES('secure-delete', 1); -} - -do_execsql_test 1.1 { - BEGIN; - INSERT INTO ft(rowid, col) VALUES(0, 'the next data'); - DELETE FROM ft WHERE rowid=1; - DELETE FROM ft WHERE rowid=2; - INSERT INTO ft(rowid, col) VALUES(6, 'with some more of the same data'); - COMMIT; -} - -do_execsql_test 1.2 { - INSERT INTO ft(ft) VALUES('integrity-check'); -} - -#------------------------------------------------------------------------- - -reset_db -do_execsql_test 2.0 { - CREATE VIRTUAL TABLE t1 USING fts5(x); - INSERT INTO t1(t1, rank) VALUES('pgsz', 64); - INSERT INTO t1(t1, rank) VALUES('secure-delete', 1); - BEGIN; - INSERT INTO t1 VALUES('the start'); -} -do_test 2.1 { - for {set i 0} {$i < 1000} {incr i} { - execsql { INSERT INTO t1 VALUES('the ' || hex(randomblob(3))) } - } - execsql { - INSERT INTO t1 VALUES('the end'); - COMMIT; - } -} {} - -do_execsql_test 2.2 { - DELETE FROM t1 WHERE rowid BETWEEN 2 AND 1000; -} - -do_execsql_test 2.3 { - INSERT INTO t1(t1) VALUES('integrity-check'); -} - -do_execsql_test 2.6 { - INSERT INTO t1(rowid, x) VALUES(500, 'middle'); - INSERT INTO t1(rowid, x) VALUES(501, 'value'); - SELECT * FROM t1('the middle'); -} - -do_execsql_test 2.7 { - INSERT INTO t1(t1) VALUES('optimize'); -} - -do_execsql_test 2.8 { - SELECT count(*) FROM t1_data -} 4 - -#execsql_pp { SELECT id, quote(block), fts5_decode(id, block) FROM t1_data; } - -#------------------------------------------------------------------------- -# Tests with large/small rowid values. -# - -reset_db - -expr srand(0) - -set vocab { - Popper Poppins Popsicle Porfirio Porrima Porsche - Porter Portia Portland Portsmouth Portugal Portuguese - Poseidon Post PostgreSQL Potemkin Potomac Potsdam - Pottawatomie Potter Potts Pound Poussin Powell - PowerPC PowerPoint Powers Powhatan Poznan Prada - Prado Praetorian Prague Praia Prakrit Pratchett - Pratt Pravda Praxiteles Preakness Precambrian Preminger - Premyslid Prensa Prentice Pres Presbyterian Presbyterianism -} -proc newdoc {} { - for {set i 0} {$i<8} {incr i} { - lappend ret [lindex $::vocab [expr int(abs(rand()) * [llength $::vocab])]] - } - set ret -} -db func newdoc newdoc - -do_execsql_test 3.0 { - CREATE VIRTUAL TABLE fff USING fts5(y); - INSERT INTO fff(fff, rank) VALUES('pgsz', 64); - - WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 ) - INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s; - - WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 ) - INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s; - - WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 ) - INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s; - - INSERT INTO fff(fff, rank) VALUES('secure-delete', 1); -} - -proc lshuffle {in} { - set out [list] - while {[llength $in]>0} { - set idx [expr int(abs(rand()) * [llength $in])] - lappend out [lindex $in $idx] - set in [lreplace $in $idx $idx] - } - set out -} - -#dump fff - -set iTest 1 -foreach ii [lshuffle [db eval {SELECT rowid FROM fff}]] { - #if {$iTest==1} { dump fff } - #if {$iTest==1} { breakpoint } - do_execsql_test 3.1.$iTest.$ii { - DELETE FROM fff WHERE rowid=$ii; - } - #if {$iTest==1} { dump fff } - if {($iTest % 20)==0} { - do_execsql_test 3.1.$iTest.$ii.ic { - INSERT INTO fff(fff) VALUES('integrity-check'); - } - } - #if {$iTest==1} { break } - incr iTest -} - -#execsql_pp { SELECT rowid FROM fff('post') ORDER BY rowid ASC } -#breakpoint -#execsql_pp { -# SELECT rowid FROM fff('post') ORDER BY rowid DESC -#} -# -#dump fff - - -finish_test - DELETED ext/fts5/test/fts5secure4.test Index: ext/fts5/test/fts5secure4.test ================================================================== --- ext/fts5/test/fts5secure4.test +++ /dev/null @@ -1,170 +0,0 @@ -# 2023 April 14 -# -# 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. -# -#************************************************************************* -# - -source [file join [file dirname [info script]] fts5_common.tcl] -return_if_no_fts5 -set ::testprefix fts5secure4 - -#------------------------------------------------------------------------- -# Test using the 'delete' command to attempt to delete a token that -# is not present in the index in secure-delete mode. -# -do_execsql_test 1.0 { - CREATE VIRTUAL TABLE t1 USING fts5(a, b, content=x1); - - CREATE TABLE x1(rowid INTEGER PRIMARY KEY, a, b); - INSERT INTO x1 VALUES - (1, 'hello world', 'today xyz'), - (2, 'not the day', 'crunch crumble and chomp'), - (3, 'one', 'two'); - INSERT INTO t1(t1) VALUES('rebuild'); -} - -do_execsql_test 1.1 { - INSERT INTO t1(t1, rank) VALUES('secure-delete', 1); -} - -do_execsql_test 1.2 { - INSERT INTO t1(t1, rowid, a, b) VALUES('delete', 4, 'nosuchtoken', ''); -} - -do_execsql_test 1.3 { - INSERT INTO t1(t1) VALUES('integrity-check'); -} - -do_execsql_test 1.4 { - INSERT INTO t1(t1, rowid, a, b) VALUES('delete', 1, 'crunch', ''); -} - -do_execsql_test 1.5 { - INSERT INTO t1(t1, rowid, a, b) VALUES('delete', 3, 'crunch', ''); -} - -do_execsql_test 1.6 { - INSERT INTO t1(t1) VALUES('integrity-check'); -} - -do_execsql_test 1.7 { -CREATE VIRTUAL TABLE y1 USING fts5(xx, prefix='1,2'); -INSERT INTO y1(y1, rank) VALUES('pgsz', 64); -INSERT INTO y1(y1, rank) VALUES('secure-delete', 1); -} -do_execsql_test 1.8 { - BEGIN; - INSERT INTO y1(rowid, xx) VALUES(1, 'abc def'); - INSERT INTO y1(rowid, xx) VALUES(2, 'reallyreallylongtoken'); - COMMIT; -} -do_execsql_test 1.9 { - DELETE FROM y1 WHERE rowid=1; - INSERT INTO y1(y1) VALUES('integrity-check'); -} - -do_execsql_test 1.10 { - CREATE VIRTUAL TABLE w1 USING fts5(ww, content=""); - INSERT INTO w1(rowid, ww) VALUES(123, ''); -} -do_catchsql_test 1.11 { - INSERT INTO w1(w1, rowid, ww) VALUES('delete', 123, 'xyz'); -} {1 {database disk image is malformed}} -do_catchsql_test 1.12 { - DROP TABLE w1; - CREATE VIRTUAL TABLE w1 USING fts5(ww, content=""); - INSERT INTO w1(rowid, ww) VALUES(123, ''); - DELETE FROM w1_data WHERE id>10; - INSERT INTO w1(w1, rowid, ww) VALUES('delete', 123, 'xyz'); -} {1 {database disk image is malformed}} - -#------------------------------------------------------------------------- -# Test using secure-delete with detail=none or detail=col. -# -foreach {tn d} {1 full 2 none 3 column} { - reset_db - do_execsql_test 2.$tn.1 " - CREATE VIRTUAL TABLE x1 USING fts5(xx, yy, zz, detail=$d, prefix='10,20'); - INSERT INTO x1(x1, rank) VALUES('pgsz', 64); - INSERT INTO x1(x1, rank) VALUES('secure-delete', 1); - " - - do_execsql_test 2.$tn.2 { - BEGIN; - INSERT INTO x1(xx, yy, zz) VALUES('a b c', 'd e f', 'a b c'); - INSERT INTO x1(xx, yy, zz) VALUES('a b c', 'd e f', 'a b c'); - INSERT INTO x1(xx, yy, zz) VALUES('a b c', 'd e f', 'a b c'); - INSERT INTO x1(xx, yy, zz) VALUES('a b c', 'd e f', 'a b c'); - INSERT INTO x1(xx, yy, zz) VALUES('a b c', 'd e f', 'a b c'); - COMMIT; - INSERT INTO x1(x1) VALUES('integrity-check'); - } - - do_execsql_test 2.$tn.3 { - DELETE FROM x1 WHERE rowid IN (2, 4, 6); - INSERT INTO x1(x1) VALUES('integrity-check'); - } - - do_execsql_test 2.$tn.4 { - DELETE FROM x1 WHERE rowid IN (1, 3, 5); - INSERT INTO x1(x1) VALUES('integrity-check'); - } - - do_execsql_test 2.$tn.5 { - WITH s(i) AS ( - SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100 - ) - INSERT INTO x1 - SELECT 'seems to be', 'used brew to', 'everything is working' FROM s - UNION ALL - SELECT 'used brew to', 'everything is working', 'seems to be' FROM s - UNION ALL - SELECT 'everything is working', 'seems to be', 'used brew to' FROM s - UNION ALL - SELECT 'abc', 'zzz', 'a b c d' - UNION ALL - SELECT 'z', 'z', 'z' FROM s - } - - do_test 2.$tn.6 { - for {set i 300} {$i > 200} {incr i -1} { - execsql { - DELETE FROM x1 WHERE rowid=$i; - INSERT INTO x1(x1) VALUES('integrity-check'); - } - } - } {} - - do_test 2.$tn.7 { - for {set i 1} {$i < 100} {incr i} { - execsql { - DELETE FROM x1 WHERE rowid=$i; - INSERT INTO x1(x1) VALUES('integrity-check'); - } - } - } {} - - do_test 2.$tn.8 { - foreach i [db eval {SELECT rowid FROM x1}] { - execsql { - DELETE FROM x1 WHERE rowid=$i; - INSERT INTO x1(x1) VALUES('integrity-check'); - } - } - } {} - - do_execsql_test 2.$tn.9 { - SELECT * FROM x1 - } {} -} - - - -finish_test - DELETED ext/fts5/test/fts5secure5.test Index: ext/fts5/test/fts5secure5.test ================================================================== --- ext/fts5/test/fts5secure5.test +++ /dev/null @@ -1,129 +0,0 @@ -# 2023 April 14 -# -# 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. -# -#************************************************************************* -# - -source [file join [file dirname [info script]] fts5_common.tcl] -return_if_no_fts5 -set ::testprefix fts5secure5 -return_if_no_fts5 - -proc dump {} { - execsql_pp { - SELECT id, quote(block), fts5_decode_none(id, block) FROM ft1_data - } -} - -do_execsql_test 1.0 { - CREATE VIRTUAL TABLE ft1 USING fts5(a, detail=none); - INSERT INTO ft1(ft1, rank) VALUES('secure-delete', 1); -} - -do_execsql_test 1.1 { - BEGIN; - INSERT INTO ft1(rowid, a) VALUES(1, 'abcd'); - INSERT INTO ft1(rowid, a) VALUES(2, 'abcd'); - INSERT INTO ft1(rowid, a) VALUES(3, 'abcd'); - COMMIT; -} -do_execsql_test 1.2 { - DELETE FROM ft1 WHERE rowid=1; -} -do_execsql_test 1.3 { - INSERT INTO ft1(ft1) VALUES('integrity-check'); -} -do_execsql_test 1.4 { - DELETE FROM ft1 WHERE rowid=3; -} -do_execsql_test 1.5 { - INSERT INTO ft1(ft1) VALUES('integrity-check'); -} -do_execsql_test 1.6 { - DELETE FROM ft1 WHERE rowid=3; -} -do_execsql_test 1.7 { - INSERT INTO ft1(ft1) VALUES('integrity-check'); -} - -#------------------------------------------------------------------------- -reset_db -do_execsql_test 2.0 { - CREATE VIRTUAL TABLE ft1 USING fts5(a, detail=none); - INSERT INTO ft1(ft1, rank) VALUES('secure-delete', 1); -} - -do_execsql_test 2.1 { - BEGIN; - INSERT INTO ft1(rowid, a) VALUES(1, 'abcd one'); - INSERT INTO ft1(rowid, a) VALUES(2, 'abcd two'); - INSERT INTO ft1(rowid, a) VALUES(3, 'abcd two'); - INSERT INTO ft1(rowid, a) VALUES(4, 'abcd two'); - INSERT INTO ft1(rowid, a) VALUES(5, 'abcd three'); - COMMIT; -} - -do_execsql_test 2.2a { - DELETE FROM ft1 WHERE rowid=3; -} -do_execsql_test 2.2b { - INSERT INTO ft1(ft1) VALUES('integrity-check'); -} -do_execsql_test 2.3a { - DELETE FROM ft1 WHERE rowid=2; -} -do_execsql_test 2.3b { - INSERT INTO ft1(ft1) VALUES('integrity-check'); -} -do_execsql_test 2.4a { - DELETE FROM ft1 WHERE rowid=4; -} -do_execsql_test 2.4b { - INSERT INTO ft1(ft1) VALUES('integrity-check'); -} - -#------------------------------------------------------------------------- -reset_db -do_execsql_test 3.0 { - CREATE VIRTUAL TABLE ft1 USING fts5(a, detail=none, prefix=1); - INSERT INTO ft1(ft1, rank) VALUES('secure-delete', 1); - INSERT INTO ft1(ft1, rank) VALUES('pgsz', 64); -} -do_execsql_test 3.1 { - BEGIN; - INSERT INTO ft1(a) VALUES('c'); - COMMIT; -} -do_execsql_test 3.2 { - DELETE FROM ft1 WHERE rowid IN (1); - INSERT INTO ft1(ft1) VALUES('integrity-check'); -} - -#------------------------------------------------------------------------- -reset_db -do_execsql_test 4.0 { - CREATE VIRTUAL TABLE ft1 USING fts5(a, detail=none); - INSERT INTO ft1(ft1, rank) VALUES('secure-delete', 1); - INSERT INTO ft1(ft1, rank) VALUES('pgsz', 64); - - WITH s(i) AS ( - SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<500 - ) - INSERT INTO ft1 SELECT 'abcdefg' FROM s; -} - -do_test 4.1 { - for {set i 500} {$i > 0} {incr i -1} { - execsql { DELETE FROM ft1 WHERE rowid=$i } - execsql { INSERT INTO ft1(ft1) VALUES('integrity-check') } - } -} {} - -finish_test - DELETED ext/fts5/test/fts5secure6.test Index: ext/fts5/test/fts5secure6.test ================================================================== --- ext/fts5/test/fts5secure6.test +++ /dev/null @@ -1,55 +0,0 @@ -# 2023 Feb 17 -# -# 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. -# -#************************************************************************* -# - -source [file join [file dirname [info script]] fts5_common.tcl] -ifcapable !fts5 { finish_test ; return } -set ::testprefix fts5secure6 - -db progress 1 progress_handler -set ::PHC 0 -proc progress_handler {args} { - incr ::PHC - if {($::PHC % 100000)==0} breakpoint - return 0 -} - -proc setup {} { - db eval { - DROP TABLE IF EXISTS t1; - CREATE VIRTUAL TABLE t1 USING fts5(x); - WITH s(i) AS ( - VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<1000 - ) - INSERT INTO t1 SELECT 'a b c d e f g h i j k' FROM s; - } -} - -foreach {tn sd} { - 1 0 - 2 1 -} { - setup - do_execsql_test 1.$tn.0 { - INSERT INTO t1(t1, rank) VALUES('secure-delete', $sd) - } - set PHC 0 - do_execsql_test 1.$tn.1 { DELETE FROM t1; } - set phc($tn) $PHC -} - -do_test 1.3 { - expr $phc(1)*5 < $phc(2) -} {1} - - -finish_test - DELETED ext/fts5/test/fts5securefault.test Index: ext/fts5/test/fts5securefault.test ================================================================== --- ext/fts5/test/fts5securefault.test +++ /dev/null @@ -1,225 +0,0 @@ -# 2023 April 14 -# -# 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 regression tests for SQLite library. The -# focus of this script is testing the FTS5 module. -# - -source [file join [file dirname [info script]] fts5_common.tcl] -source $testdir/malloc_common.tcl -set testprefix fts5securefault - -# If SQLITE_ENABLE_FTS5 is defined, omit this file. -return_if_no_fts5 - -do_execsql_test 1.0 { - CREATE VIRTUAL TABLE t1 USING fts5(ab); - INSERT INTO t1(rowid, ab) VALUES - (0, 'abc'), (1, 'abc'), (2, 'abc'), (3, 'abc'), (4, 'def'); -} -faultsim_save_and_close - -do_faultsim_test 1.1 -faults oom* -prep { - faultsim_restore_and_reopen - execsql { - INSERT INTO t1(t1, rank) VALUES('secure-delete', 1); - } -} -body { - execsql { DELETE FROM t1 WHERE rowid=2 } -} -test { - faultsim_test_result {0 {}} -} -do_faultsim_test 1.2 -faults oom* -prep { - faultsim_restore_and_reopen - execsql { - INSERT INTO t1(t1, rank) VALUES('secure-delete', 1); - } -} -body { - execsql { DELETE FROM t1 WHERE rowid IN(0, 1, 2, 3, 4) } -} -test { - faultsim_test_result {0 {}} -} - -#------------------------------------------------------------------------- -# -reset_db -set big [string repeat abcdefghij 5] -set big2 [string repeat klmnopqrst 5] -set doc "$big $big2" - -do_execsql_test 2.0 { - CREATE VIRTUAL TABLE t1 USING fts5(ab); - INSERT INTO t1(t1, rank) VALUES('pgsz', 64); - WITH s(i) AS ( - SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<4 - ) - INSERT INTO t1(rowid, ab) SELECT i, $doc FROM s; -} -faultsim_save_and_close - -do_faultsim_test 2.1 -faults oom* -prep { - faultsim_restore_and_reopen - execsql { - INSERT INTO t1(t1, rank) VALUES('secure-delete', 1); - } -} -body { - execsql { DELETE FROM t1 WHERE rowid = 3 } - execsql { DELETE FROM t1 WHERE rowid = 4 } -} -test { - faultsim_test_result {0 {}} -} - -#------------------------------------------------------------------------- -# -reset_db -set big [string repeat abcdefghij 5] -set big2 [string repeat klmnopqrst 5] -set doc "$big $big2" - -do_execsql_test 3.0 { - CREATE VIRTUAL TABLE t1 USING fts5(ab); - INSERT INTO t1(t1, rank) VALUES('pgsz', 64); - WITH s(i) AS ( - SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<25 - ) - INSERT INTO t1(rowid, ab) SELECT i, $doc FROM s; - - INSERT INTO t1(t1, rank) VALUES('secure-delete', 1); - DELETE FROM t1 WHERE rowid BETWEEN 3 AND 23; -} -faultsim_save_and_close - -do_faultsim_test 3.1 -faults oom* -prep { - faultsim_restore_and_reopen - execsql { - INSERT INTO t1(t1, rank) VALUES('secure-delete', 1); - } -} -body { - execsql { DELETE FROM t1 WHERE rowid = 24 } - execsql { DELETE FROM t1 WHERE rowid = 25 } -} -test { - faultsim_test_result {0 {}} -} - -#------------------------------------------------------------------------- -# -reset_db -set doc [string repeat "tok " 400] - -do_execsql_test 4.0 { - CREATE VIRTUAL TABLE t1 USING fts5(ab); - INSERT INTO t1(t1, rank) VALUES('pgsz', 64); - INSERT INTO t1(rowid, ab) VALUES(1, $doc), (2, $doc), (3, $doc); -} -faultsim_save_and_close - -do_faultsim_test 4.1 -faults oom* -prep { - faultsim_restore_and_reopen - execsql { - INSERT INTO t1(t1, rank) VALUES('secure-delete', 1); - } -} -body { - execsql { DELETE FROM t1 WHERE rowid = 2 } -} -test { - faultsim_test_result {0 {}} -} - -#------------------------------------------------------------------------- -# -reset_db - -set doc1 [string repeat "abc " 10] -set doc2 [string repeat "def " 10] - -do_test 5.0 { - execsql { - CREATE VIRTUAL TABLE t1 USING fts5(ab); - INSERT INTO t1(t1, rank) VALUES('pgsz', 64); - BEGIN; - } - for {set i 0} {$i < 50} {incr i} { - execsql { - INSERT INTO t1(rowid, ab) VALUES($i, 'abcdefg'); - } - } - execsql { - INSERT INTO t1(rowid, ab) VALUES(105, 'def'); - COMMIT; - } -} {} -faultsim_save_and_close - -do_faultsim_test 5.1 -faults oom* -prep { - faultsim_restore_and_reopen - execsql { - INSERT INTO t1(t1, rank) VALUES('secure-delete', 1); - } -} -body { - execsql { DELETE FROM t1 WHERE rowid = 105 } -} -test { - faultsim_test_result {0 {}} -} - -#------------------------------------------------------------------------- -# -reset_db -do_test 6.0 { - execsql { - CREATE VIRTUAL TABLE t1 USING fts5(ab); - INSERT INTO t1(t1, rank) VALUES('pgsz', 64); - BEGIN; - INSERT INTO t1(rowid, ab) VALUES(1, 'abcdefg'); - INSERT INTO t1(rowid, ab) VALUES(2, 'abcdefg'); - INSERT INTO t1(rowid, ab) VALUES(3, 'abcdefg'); - COMMIT; - } -} {} -faultsim_save_and_close - -do_faultsim_test 6.1 -faults oom* -prep { - faultsim_restore_and_reopen - execsql { - INSERT INTO t1(t1, rank) VALUES('secure-delete', 1); - } -} -body { - execsql { - UPDATE t1 SET ab='abcdefg' WHERE rowid=2; - } -} -test { - faultsim_test_result {0 {}} -} - -#------------------------------------------------------------------------- -# -reset_db -do_test 7.0 { - execsql { - CREATE VIRTUAL TABLE t1 USING fts5(ab); - INSERT INTO t1(t1, rank) VALUES('pgsz', 32); - INSERT INTO t1(t1, rank) VALUES('secure-delete', 1); - } -} {} -faultsim_save_and_close - -do_faultsim_test 7.1 -faults oom* -prep { - faultsim_restore_and_reopen - set big1 "[string repeat x 50] [string repeat y 50] [string repeat z 50]" - execsql { - BEGIN; - INSERT INTO t1 VALUES($big1); - } -} -body { - execsql { COMMIT } -} -test { - faultsim_test_result {0 {}} -} - - -finish_test Index: ext/fts5/test/fts5trigram.test ================================================================== --- ext/fts5/test/fts5trigram.test +++ ext/fts5/test/fts5trigram.test @@ -53,11 +53,10 @@ 4 {%f_h%} 1 5 {%f_g%} {} 6 {abc%klm} 1 7 {ABCDEFG%} 1 8 {%รุงเ%} 2 - 9 {%งเ%} 2 } { do_execsql_test 1.3.$tn { SELECT rowid FROM t1 WHERE y LIKE $like } $res } @@ -196,23 +195,6 @@ } {{SCAN ci1 VIRTUAL TABLE INDEX 0:}} do_eqp_test 6.4 { SELECT * FROM ci1 WHERE x GLOB ? } {VIRTUAL TABLE INDEX 0:G0} -reset_db -do_execsql_test 7.0 { - CREATE VIRTUAL TABLE f USING FTS5(filename, tokenize="trigram"); - INSERT INTO f (rowid, filename) VALUES - (10, "giraffe.png"), - (20, "жираф.png"), - (30, "cat.png"), - (40, "кот.png"), - (50, "misic-🎵-.mp3"); -} -do_execsql_test 7.1 { - SELECT rowid FROM f WHERE +filename GLOB '*ир*'; -} {20} -do_execsql_test 7.2 { - SELECT rowid FROM f WHERE filename GLOB '*ир*'; -} {20} - finish_test Index: ext/fts5/test/fts5version.test ================================================================== --- ext/fts5/test/fts5version.test +++ ext/fts5/test/fts5version.test @@ -36,98 +36,30 @@ SELECT rowid FROM t1 WHERE t1 MATCH 'a'; } {1} sqlite3_db_config db DEFENSIVE 0 do_execsql_test 1.4 { - UPDATE t1_config set v=6 WHERE k='version'; + UPDATE t1_config set v=5 WHERE k='version'; } do_test 1.5 { db close sqlite3 db test.db catchsql { SELECT * FROM t1 WHERE t1 MATCH 'a' } -} {1 {invalid fts5 file format (found 6, expected 4 or 5) - run 'rebuild'}} +} {1 {invalid fts5 file format (found 5, expected 4) - run 'rebuild'}} do_test 1.6 { db close sqlite3 db test.db catchsql { INSERT INTO t1 VALUES('x y z') } -} {1 {invalid fts5 file format (found 6, expected 4 or 5) - run 'rebuild'}} +} {1 {invalid fts5 file format (found 5, expected 4) - run 'rebuild'}} do_test 1.7 { sqlite3_db_config db DEFENSIVE 0 execsql { DELETE FROM t1_config WHERE k='version' } db close sqlite3 db test.db catchsql { SELECT * FROM t1 WHERE t1 MATCH 'a' } -} {1 {invalid fts5 file format (found 0, expected 4 or 5) - run 'rebuild'}} - -do_test 1.8 { - sqlite3_db_config db DEFENSIVE 0 - execsql { INSERT INTO t1_config VALUES('version', 4) } - execsql { INSERT INTO t1(t1, rank) VALUES('secure-delete', 1) } -} {} - -do_execsql_test 1.10 { - SELECT * FROM t1_config -} {secure-delete 1 version 4} - -do_execsql_test 1.11 { - INSERT INTO t1(rowid, one) VALUES(123, 'one two three'); - DELETE FROM t1 WHERE rowid=123; - SELECT * FROM t1_config -} {secure-delete 1 version 5} - -do_execsql_test 1.11 { - INSERT INTO t1(t1) VALUES('rebuild'); - SELECT * FROM t1_config -} {secure-delete 1 version 4} - -do_execsql_test 1.12 { - SELECT * FROM t1_config -} {secure-delete 1 version 4} - -#------------------------------------------------------------------------- -reset_db - -do_execsql_test 2.0 { - CREATE VIRTUAL TABLE xyz USING fts5(x); - INSERT INTO xyz(rowid, x) VALUES - (1, 'one document'), - (2, 'two document'), - (3, 'three document'), - (4, 'four document'), - (5, 'five document'), - (6, 'six document'); - - INSERT INTO xyz(xyz, rank) VALUES('secure-delete', 1); - SELECT v FROM xyz_config WHERE k='version'; -} {4} - -do_execsql_test 2.1 { - BEGIN; - INSERT INTO xyz(rowid, x) VALUES(7, 'seven document'); - SAVEPOINT one; - DELETE FROM xyz WHERE rowid = 4; -} - -do_execsql_test 2.2 { - SELECT v FROM xyz_config WHERE k='version'; -} {5} - -do_execsql_test 2.3 { - ROLLBACK TO one; - SELECT v FROM xyz_config WHERE k='version'; -} {4} - - -do_execsql_test 2.4 { - DELETE FROM xyz WHERE rowid = 3; - COMMIT; - SELECT v FROM xyz_config WHERE k='version'; -} {5} - - +} {1 {invalid fts5 file format (found 0, expected 4) - run 'rebuild'}} finish_test - Index: ext/misc/base64.c ================================================================== --- ext/misc/base64.c +++ ext/misc/base64.c @@ -74,11 +74,10 @@ #ifndef U8_TYPEDEF typedef unsigned char u8; #define U8_TYPEDEF #endif -/* Decoding table, ASCII (7-bit) value to base 64 digit value or other */ static const u8 b64DigitValues[128] = { /* HT LF VT FF CR */ ND,ND,ND,ND, ND,ND,ND,ND, ND,WS,WS,WS, WS,WS,ND,ND, /* US */ ND,ND,ND,ND, ND,ND,ND,ND, ND,ND,ND,ND, ND,ND,ND,ND, @@ -146,22 +145,22 @@ *pOut = 0; return pOut; } /* Skip over text which is not base64 numeral(s). */ -static char * skipNonB64( char *s, int nc ){ +static char * skipNonB64( char *s ){ char c; - while( nc-- > 0 && (c = *s) && !IS_BX_DIGIT(BX_DV_PROTO(c)) ) ++s; + while( (c = *s) && !IS_BX_DIGIT(BX_DV_PROTO(c)) ) ++s; return s; } /* Decode base64 text into a byte buffer. */ static u8* fromBase64( char *pIn, int ncIn, u8 *pOut ){ if( ncIn>0 && pIn[ncIn-1]=='\n' ) --ncIn; while( ncIn>0 && *pIn!=PAD_CHAR ){ static signed char nboi[] = { 0, 0, 1, 2, 3 }; - char *pUse = skipNonB64(pIn, ncIn); + char *pUse = skipNonB64(pIn); unsigned long qv = 0L; int nti, nbo, nac; ncIn -= (pUse - pIn); pIn = pUse; nti = (ncIn>4)? 4 : ncIn; @@ -217,20 +216,13 @@ nc += (nc+(B64_DARK_MAX-1))/B64_DARK_MAX + 1; /* LFs and a 0-terminator */ if( nvMax < nc ){ sqlite3_result_error(context, "blob expanded to base64 too big", -1); return; } - bBuf = (u8*)sqlite3_value_blob(av[0]); - if( !bBuf ){ - if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){ - goto memFail; - } - sqlite3_result_text(context,"",-1,SQLITE_STATIC); - break; - } cBuf = sqlite3_malloc(nc); if( !cBuf ) goto memFail; + bBuf = (u8*)sqlite3_value_blob(av[0]); nc = (int)(toBase64(bBuf, nb, cBuf) - cBuf); sqlite3_result_text(context, cBuf, nc, sqlite3_free); break; case SQLITE_TEXT: nc = nv; @@ -239,20 +231,13 @@ sqlite3_result_error(context, "blob from base64 may be too big", -1); return; }else if( nb<1 ){ nb = 1; } - cBuf = (char *)sqlite3_value_text(av[0]); - if( !cBuf ){ - if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){ - goto memFail; - } - sqlite3_result_zeroblob(context, 0); - break; - } bBuf = sqlite3_malloc(nb); if( !bBuf ) goto memFail; + cBuf = (char *)sqlite3_value_text(av[0]); nb = (int)(fromBase64(cBuf, nc, bBuf) - bBuf); sqlite3_result_blob(context, bBuf, nb, sqlite3_free); break; default: sqlite3_result_error(context, "base64 accepts only blob or text", -1); Index: ext/misc/base85.c ================================================================== --- ext/misc/base85.c +++ ext/misc/base85.c @@ -138,13 +138,13 @@ /* Width of base64 lines. Should be an integer multiple of 5. */ #define B85_DARK_MAX 80 -static char * skipNonB85( char *s, int nc ){ +static char * skipNonB85( char *s ){ char c; - while( nc-- > 0 && (c = *s) && !IS_B85(c) ) ++s; + while( (c = *s) && !IS_B85(c) ) ++s; return s; } /* Convert small integer, known to be in 0..84 inclusive, to base85 numeral. * Do not use the macro form with argument expression having a side-effect.*/ @@ -210,11 +210,11 @@ /* Decode base85 text into a byte buffer. */ static u8* fromBase85( char *pIn, int ncIn, u8 *pOut ){ if( ncIn>0 && pIn[ncIn-1]=='\n' ) --ncIn; while( ncIn>0 ){ static signed char nboi[] = { 0, 0, 1, 2, 3, 4 }; - char *pUse = skipNonB85(pIn, ncIn); + char *pUse = skipNonB85(pIn); unsigned long qv = 0L; int nti, nbo; ncIn -= (pUse - pIn); pIn = pUse; nti = (ncIn>5)? 5 : ncIn; @@ -295,20 +295,13 @@ nc = 5*(nv/4) + nv%4 + nv/64+1 + 2; if( nvMax < nc ){ sqlite3_result_error(context, "blob expanded to base85 too big", -1); return; } - bBuf = (u8*)sqlite3_value_blob(av[0]); - if( !bBuf ){ - if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){ - goto memFail; - } - sqlite3_result_text(context,"",-1,SQLITE_STATIC); - break; - } cBuf = sqlite3_malloc(nc); if( !cBuf ) goto memFail; + bBuf = (u8*)sqlite3_value_blob(av[0]); nc = (int)(toBase85(bBuf, nb, cBuf, "\n") - cBuf); sqlite3_result_text(context, cBuf, nc, sqlite3_free); break; case SQLITE_TEXT: nc = nv; @@ -317,20 +310,13 @@ sqlite3_result_error(context, "blob from base85 may be too big", -1); return; }else if( nb<1 ){ nb = 1; } - cBuf = (char *)sqlite3_value_text(av[0]); - if( !cBuf ){ - if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){ - goto memFail; - } - sqlite3_result_zeroblob(context, 0); - break; - } bBuf = sqlite3_malloc(nb); if( !bBuf ) goto memFail; + cBuf = (char *)sqlite3_value_text(av[0]); nb = (int)(fromBase85(cBuf, nc, bBuf) - bBuf); sqlite3_result_blob(context, bBuf, nb, sqlite3_free); break; default: sqlite3_result_error(context, "base85 accepts only blob or text.", -1); DELETED ext/misc/randomjson.c Index: ext/misc/randomjson.c ================================================================== --- ext/misc/randomjson.c +++ /dev/null @@ -1,202 +0,0 @@ -/* -** 2023-04-28 -** -** 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 SQLite extension implements a the random_json(SEED) and -** random_json5(SEED) functions. Given a numeric SEED value, these -** routines generate pseudo-random JSON or JSON5, respectively. The -** same value is always generated for the same seed. -** -** These SQL functions are intended for testing. They do not have any -** practical real-world use, that we know of. -** -** COMPILE: -** -** gcc --shared -fPIC -o randomjson.so -I. ext/misc/randomjson.c -** -** USING FROM THE CLI: -** -** .load ./randomjson -** SELECT random_json(1); -*/ -#include "sqlite3ext.h" -SQLITE_EXTENSION_INIT1 -#include -#include -#include - -/* Pseudo-random number generator */ -typedef struct Prng { - unsigned int x, y; -} Prng; - -/* Reseed the PRNG */ -static void prngSeed(Prng *p, unsigned int iSeed){ - p->x = iSeed | 1; - p->y = iSeed; -} - -/* Extract a random number */ -static unsigned int prngInt(Prng *p){ - p->x = (p->x>>1) ^ ((1+~(p->x&1)) & 0xd0000001); - p->y = p->y*1103515245 + 12345; - return p->x ^ p->y; -} - -static const char *azJsonAtoms[] = { - /* JSON /* JSON-5 */ - "0", "0", - "1", "1", - "-1", "-1", - "2", "+2", - "3", "3", - "2.5", "2.5", - "0.75", ".75", - "-4.0e2", "-4.e2", - "5.0e-3", "+5e-3", - "0", "0x0", - "512", "0x200", - "256", "+0x100", - "-2748", "-0xabc", - "true", "true", - "false", "false", - "null", "null", - "9.0e999", "Infinity", - "-9.0e999", "-Infinity", - "9.0e999", "+Infinity", - "null", "NaN", - "-0.0005123", "-0.0005123", - "4.35e-3", "+4.35e-3", - "\"gem\\\"hay\"", "\"gem\\\"hay\"", - "\"icy'joy\"", "'icy\\'joy\'", - "\"keylog\"", "\"key\\\nlog\"", - "\"mix\\\\\\tnet\"", "\"mix\\\\\\tnet\"", - "{}", "{}", - "[]", "[]", - "[]", "[/*empty*/]", - "{}", "{//empty\n}", - "\"ask\"", "\"ask\"", - "\"bag\"", "\"bag\"", - "\"can\"", "\"can\"", - "\"day\"", "\"day\"", - "\"end\"", "'end'", - "\"fly\"", "\"fly\"", - "\"\"", "\"\"", -}; -static const char *azJsonTemplate[] = { - /* JSON JSON-5 */ - "{\"a\":%,\"b\":%,\"c\":%}", "{a:%,b:%,c:%}", - "{\"a\":%,\"b\":%,\"c\":%,\"d\":%,\"e\":%}", "{a:%,b:%,c:%,d:%,e:%}", - "{\"a\":%,\"b\":%,\"c\":%,\"d\":%,\"\":%}", "{a:%,b:%,c:%,d:%,\"\":%}", - "{\"d\":%}", "{d:%}", - "{\"eeee\":%, \"ffff\":%}", "{eeee:% /*and*/, ffff:%}", - "{\"$g\":%,\"_h_\":%}", "{$g:%,_h_:%,}", - "{\"x\":%,\n \"y\":%}", "{\"x\":%,\n \"y\":%}", - "{\"a b c d\":%,\"e\":%,\"f\":%,\"x\":%,\"y\":%}", - "{\"a b c d\":%,e:%,f:%,x:%,y:%}", - "{\"Z\":%}", "{Z:%,}", - "[%]", "[%,]", - "[%,%]", "[%,%]", - "[%,%,%]", "[%,%,%,]", - "[%,%,%,%]", "[%,%,%,%]", - "[%,%,%,%,%]", "[%,%,%,%,%]", -}; - -#define count(X) (sizeof(X)/sizeof(X[0])) - -#define STRSZ 10000 - -static void jsonExpand( - const char *zSrc, - char *zDest, - Prng *p, - int eType, /* 0 for JSON, 1 for JSON5 */ - unsigned int r /* Growth probability 0..1000. 0 means no growth */ -){ - unsigned int i, j, k; - const char *z; - size_t n; - - j = 0; - if( zSrc==0 ){ - k = prngInt(p)%(count(azJsonTemplate)/2); - k = k*2 + eType; - zSrc = azJsonTemplate[k]; - } - if( strlen(zSrc)>=STRSZ/10 ) r = 0; - for(i=0; zSrc[i]; i++){ - if( zSrc[i]!='%' ){ - if( j= 0 ) -** for each produced value (independent of production time ordering.) -** -** All parameters must be either integer or convertable to integer. -** The start parameter is required. -** The stop parameter defaults to (1<<32)-1 (aka 4294967295 or 0xffffffff) -** The step parameter defaults to 1 and 0 is treated as 1. -** +** which gives similar results to the eponymous function in PostgreSQL. ** Examples: ** ** SELECT * FROM generate_series(0,100,5); ** ** The query above returns integers from 0 through 100 counting by steps @@ -38,18 +26,10 @@ ** ** SELECT * FROM generate_series(20) LIMIT 10; ** ** Integers 20 through 29. ** -** SELECT * FROM generate_series(0,-100,-5); -** -** Integers 0 -5 -10 ... -100. -** -** SELECT * FROM generate_series(0,-1); -** -** Empty sequence. -** ** HOW IT WORKS ** ** The generate_series "function" is really a virtual table with the ** following schema: ** @@ -58,13 +38,10 @@ ** start HIDDEN, ** stop HIDDEN, ** step HIDDEN ** ); ** -** The virtual table also has a rowid, logically equivalent to n+1 where -** "n" is the ascending integer in the aforesaid production definition. -** ** Function arguments in queries against this virtual table are translated ** into equality constraints against successive hidden columns. In other ** words, the following pairs of queries are equivalent to each other: ** ** SELECT * FROM generate_series(0,100,5); @@ -93,109 +70,27 @@ */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include #include -#include #ifndef SQLITE_OMIT_VIRTUALTABLE -/* -** Return that member of a generate_series(...) sequence whose 0-based -** index is ix. The 0th member is given by smBase. The sequence members -** progress per ix increment by smStep. -*/ -static sqlite3_int64 genSeqMember(sqlite3_int64 smBase, - sqlite3_int64 smStep, - sqlite3_uint64 ix){ - if( ix>=(sqlite3_uint64)LLONG_MAX ){ - /* Get ix into signed i64 range. */ - ix -= (sqlite3_uint64)LLONG_MAX; - smBase += LLONG_MAX * smStep; - } - return smBase + ((sqlite3_int64)ix)*smStep; -} - -typedef unsigned char u8; - -typedef struct SequenceSpec { - sqlite3_int64 iBase; /* Starting value ("start") */ - sqlite3_int64 iTerm; /* Given terminal value ("stop") */ - sqlite3_int64 iStep; /* Increment ("step") */ - sqlite3_uint64 uSeqIndexMax; /* maximum sequence index (aka "n") */ - sqlite3_uint64 uSeqIndexNow; /* Current index during generation */ - sqlite3_int64 iValueNow; /* Current value during generation */ - u8 isNotEOF; /* Sequence generation not exhausted */ - u8 isReversing; /* Sequence is being reverse generated */ -} SequenceSpec; - -/* -** Prepare a SequenceSpec for use in generating an integer series -** given initialized iBase, iTerm and iStep values. Sequence is -** initialized per given isReversing. Other members are computed. -*/ -void setupSequence( SequenceSpec *pss ){ - pss->uSeqIndexMax = 0; - pss->isNotEOF = 0; - if( pss->iTerm < pss->iBase ){ - sqlite3_uint64 nuspan = (sqlite3_uint64)(pss->iBase-pss->iTerm); - if( pss->iStep<0 ){ - pss->isNotEOF = 1; - if( nuspan==ULONG_MAX ){ - pss->uSeqIndexMax = ( pss->iStep>LLONG_MIN )? nuspan/-pss->iStep : 1; - }else if( pss->iStep>LLONG_MIN ){ - pss->uSeqIndexMax = nuspan/-pss->iStep; - } - } - }else if( pss->iTerm > pss->iBase ){ - sqlite3_uint64 puspan = (sqlite3_uint64)(pss->iTerm-pss->iBase); - if( pss->iStep>0 ){ - pss->isNotEOF = 1; - pss->uSeqIndexMax = puspan/pss->iStep; - } - }else if( pss->iTerm == pss->iBase ){ - pss->isNotEOF = 1; - pss->uSeqIndexMax = 0; - } - pss->uSeqIndexNow = (pss->isReversing)? pss->uSeqIndexMax : 0; - pss->iValueNow = (pss->isReversing) - ? genSeqMember(pss->iBase, pss->iStep, pss->uSeqIndexMax) - : pss->iBase; -} - -/* -** Progress sequence generator to yield next value, if any. -** Leave its state to either yield next value or be at EOF. -** Return whether there is a next value, or 0 at EOF. -*/ -int progressSequence( SequenceSpec *pss ){ - if( !pss->isNotEOF ) return 0; - if( pss->isReversing ){ - if( pss->uSeqIndexNow > 0 ){ - pss->uSeqIndexNow--; - pss->iValueNow -= pss->iStep; - }else{ - pss->isNotEOF = 0; - } - }else{ - if( pss->uSeqIndexNow < pss->uSeqIndexMax ){ - pss->uSeqIndexNow++; - pss->iValueNow += pss->iStep; - }else{ - pss->isNotEOF = 0; - } - } - return pss->isNotEOF; -} + /* series_cursor is a subclass of sqlite3_vtab_cursor which will ** serve as the underlying representation of a cursor that scans ** over rows of the result */ typedef struct series_cursor series_cursor; struct series_cursor { sqlite3_vtab_cursor base; /* Base class - must be first */ - SequenceSpec ss; /* (this) Derived class data */ + int isDesc; /* True to count down rather than up */ + sqlite3_int64 iRowid; /* The rowid */ + sqlite3_int64 iValue; /* Current value ("value") */ + sqlite3_int64 mnValue; /* Mimimum value ("start") */ + sqlite3_int64 mxValue; /* Maximum value ("stop") */ + sqlite3_int64 iStep; /* Increment ("step") */ }; /* ** The seriesConnect() method is invoked to create a new ** series_vtab that describes the generate_series virtual table. @@ -273,11 +168,16 @@ /* ** Advance a series_cursor to its next row of output. */ static int seriesNext(sqlite3_vtab_cursor *cur){ series_cursor *pCur = (series_cursor*)cur; - progressSequence( & pCur->ss ); + if( pCur->isDesc ){ + pCur->iValue -= pCur->iStep; + }else{ + pCur->iValue += pCur->iStep; + } + pCur->iRowid++; return SQLITE_OK; } /* ** Return values of columns for the row at which the series_cursor @@ -289,14 +189,14 @@ int i /* Which column to return */ ){ series_cursor *pCur = (series_cursor*)cur; sqlite3_int64 x = 0; switch( i ){ - case SERIES_COLUMN_START: x = pCur->ss.iBase; break; - case SERIES_COLUMN_STOP: x = pCur->ss.iTerm; break; - case SERIES_COLUMN_STEP: x = pCur->ss.iStep; break; - default: x = pCur->ss.iValueNow; break; + case SERIES_COLUMN_START: x = pCur->mnValue; break; + case SERIES_COLUMN_STOP: x = pCur->mxValue; break; + case SERIES_COLUMN_STEP: x = pCur->iStep; break; + default: x = pCur->iValue; break; } sqlite3_result_int64(ctx, x); return SQLITE_OK; } @@ -305,24 +205,28 @@ ** first row returned is assigned rowid value 1, and each subsequent ** row a value 1 more than that of the previous. */ static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ series_cursor *pCur = (series_cursor*)cur; - *pRowid = ((sqlite3_int64)pCur->ss.uSeqIndexNow + 1); + *pRowid = pCur->iRowid; return SQLITE_OK; } /* ** Return TRUE if the cursor has been moved off of the last ** row of output. */ static int seriesEof(sqlite3_vtab_cursor *cur){ series_cursor *pCur = (series_cursor*)cur; - return !pCur->ss.isNotEOF; + if( pCur->isDesc ){ + return pCur->iValue < pCur->mnValue; + }else{ + return pCur->iValue > pCur->mxValue; + } } -/* True to cause run-time checking of the start=, stop=, and/or step= +/* True to cause run-time checking of the start=, stop=, and/or step= ** parameters. The only reason to do this is for testing the ** constraint checking logic for virtual tables in the SQLite core. */ #ifndef SQLITE_SERIES_CONSTRAINT_VERIFY # define SQLITE_SERIES_CONSTRAINT_VERIFY 0 @@ -329,11 +233,11 @@ #endif /* ** This method is called to "rewind" the series_cursor object back ** to the first row of output. This method is always called at least -** once prior to any call to seriesColumn() or seriesRowid() or +** once prior to any call to seriesColumn() or seriesRowid() or ** seriesEof(). ** ** The query plan selected by seriesBestIndex is passed in the idxNum ** parameter. (idxStr is not used in this implementation.) idxNum ** is a bitmask showing which constraints are available: @@ -349,53 +253,58 @@ ** This routine should initialize the cursor and position it so that it ** is pointing at the first row, or pointing off the end of the table ** (so that seriesEof() will return true) if the table is empty. */ static int seriesFilter( - sqlite3_vtab_cursor *pVtabCursor, + sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStrUnused, int argc, sqlite3_value **argv ){ series_cursor *pCur = (series_cursor *)pVtabCursor; int i = 0; (void)idxStrUnused; if( idxNum & 1 ){ - pCur->ss.iBase = sqlite3_value_int64(argv[i++]); + pCur->mnValue = sqlite3_value_int64(argv[i++]); }else{ - pCur->ss.iBase = 0; + pCur->mnValue = 0; } if( idxNum & 2 ){ - pCur->ss.iTerm = sqlite3_value_int64(argv[i++]); + pCur->mxValue = sqlite3_value_int64(argv[i++]); }else{ - pCur->ss.iTerm = 0xffffffff; + pCur->mxValue = 0xffffffff; } if( idxNum & 4 ){ - pCur->ss.iStep = sqlite3_value_int64(argv[i++]); - if( pCur->ss.iStep==0 ){ - pCur->ss.iStep = 1; - }else if( pCur->ss.iStep<0 ){ + pCur->iStep = sqlite3_value_int64(argv[i++]); + if( pCur->iStep==0 ){ + pCur->iStep = 1; + }else if( pCur->iStep<0 ){ + pCur->iStep = -pCur->iStep; if( (idxNum & 16)==0 ) idxNum |= 8; } }else{ - pCur->ss.iStep = 1; + pCur->iStep = 1; } for(i=0; iss.iBase = 1; - pCur->ss.iTerm = 0; - pCur->ss.iStep = 1; + pCur->mnValue = 1; + pCur->mxValue = 0; break; } } if( idxNum & 8 ){ - pCur->ss.isReversing = pCur->ss.iStep > 0; + pCur->isDesc = 1; + pCur->iValue = pCur->mxValue; + if( pCur->iStep>0 ){ + pCur->iValue -= (pCur->mxValue - pCur->mnValue)%pCur->iStep; + } }else{ - pCur->ss.isReversing = pCur->ss.iStep < 0; + pCur->isDesc = 0; + pCur->iValue = pCur->mnValue; } - setupSequence( &pCur->ss ); + pCur->iRowid = 1; return SQLITE_OK; } /* ** SQLite will invoke this method one or more times while planning a query Index: ext/misc/shathree.c ================================================================== --- ext/misc/shathree.c +++ ext/misc/shathree.c @@ -8,12 +8,11 @@ ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** -** This SQLite extension implements functions that compute SHA3 hashes -** in the way described by the (U.S.) NIST FIPS 202 SHA-3 Standard. +** This SQLite extension implements functions that compute SHA3 hashes. ** Two SQL functions are implemented: ** ** sha3(X,SIZE) ** sha3_query(Y,SIZE) ** Index: ext/misc/zipfile.c ================================================================== --- ext/misc/zipfile.c +++ ext/misc/zipfile.c @@ -1095,14 +1095,11 @@ }else{ /* Figure out if this is a directory or a zero-sized file. Consider ** it to be a directory either if the mode suggests so, or if ** the final character in the name is '/'. */ u32 mode = pCDS->iExternalAttr >> 16; - if( !(mode & S_IFDIR) - && pCDS->nFile>=1 - && pCDS->zFile[pCDS->nFile-1]!='/' - ){ + if( !(mode & S_IFDIR) && pCDS->zFile[pCDS->nFile-1]!='/' ){ sqlite3_result_blob(ctx, "", 0, SQLITE_STATIC); } } } break; @@ -1535,23 +1532,13 @@ ** Unless it is NULL, entry pOld is currently part of the pTab->pFirstEntry ** linked list. Remove it from the list and free the object. */ static void zipfileRemoveEntryFromList(ZipfileTab *pTab, ZipfileEntry *pOld){ if( pOld ){ - if( pTab->pFirstEntry==pOld ){ - pTab->pFirstEntry = pOld->pNext; - if( pTab->pLastEntry==pOld ) pTab->pLastEntry = 0; - }else{ - ZipfileEntry *p; - for(p=pTab->pFirstEntry; p; p=p->pNext){ - if( p->pNext==pOld ){ - p->pNext = pOld->pNext; - if( pTab->pLastEntry==pOld ) pTab->pLastEntry = p; - break; - } - } - } + ZipfileEntry **pp; + for(pp=&pTab->pFirstEntry; (*pp)!=pOld; pp=&((*pp)->pNext)); + *pp = (*pp)->pNext; zipfileEntryFree(pOld); } } /* Index: ext/rbu/rbu_common.tcl ================================================================== --- ext/rbu/rbu_common.tcl +++ ext/rbu/rbu_common.tcl @@ -18,13 +18,12 @@ proc if_no_rbu_support {tcl} { set bOk 1 ifcapable !rbu { set bOk 0 } if {[permutation]=="journaltest"} { set bOk 0 } if {$bOk==0} { - set c [catch {uplevel 1 $tcl} r] - return -code $c $r - } + uplevel $tcl + } } proc check_prestep_state {target state} { set oal_exists [file exists $target-oal] set wal_exists [file exists $target-wal] Index: ext/rbu/rbuexlock.test ================================================================== --- ext/rbu/rbuexlock.test +++ ext/rbu/rbuexlock.test @@ -205,88 +205,7 @@ sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=0 rbu1.db rbu step } SQLITE_OK rbu close -#------------------------------------------------------------------------- -reset_db -forcedelete rbu1.db -forcedelete rbu2.db - -sqlite3 rbu rbu1.db -do_execsql_test -db rbu 4.1 { - CREATE TABLE data_t1(a, b, rbu_control); - INSERT INTO data_t1 VALUES(1, 'one', 0); -} -rbu close -sqlite3 rbu rbu2.db -do_execsql_test -db rbu 4.2 { - CREATE TABLE data_t1(a, b, rbu_control); - INSERT INTO data_t1 VALUES(2, 'two', 0); -} -rbu close - -do_execsql_test 4.3 { - CREATE TABLE t1(a PRIMARY KEY, b); -} -db close - -do_test 4.4 { - sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=1 rbu1.db - rbu step - rbu state -} {oal} - -sqlite3 cons test.db -do_execsql_test -db cons 4.5 { - SELECT * FROM t1 -} {} - -do_test 4.6 { rbu step ; rbu state } {oal} -do_test 4.7 { rbu step ; rbu state } {move} -do_execsql_test -db cons 4.8 { - SELECT * FROM t1 -} {} -do_test 4.9 { rbu step ; rbu state } {checkpoint} -do_test 4.10 { - catchsql { SELECT * FROM t1 } cons -} {1 {database is locked}} -do_test 4.11 { rbu step ; rbu state } {checkpoint} -do_test 4.11 { rbu step ; rbu state } {done} -rbu close - -do_test 4.12 { - catchsql { SELECT * FROM t1 } cons -} {0 {1 one}} - -do_test 4.13 { - sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=1 rbu2.db - rbu step - rbu state -} {oal} - -do_test 4.14 { - catchsql { SELECT * FROM t1 } cons -} {0 {1 one}} - -do_test 4.15 { rbu step ; rbu state } {oal} -do_test 4.16 { rbu step ; rbu state } {move} - -do_test 4.17 { - catchsql { SELECT * FROM t1 } cons -} {0 {1 one}} - -do_test 4.18 { rbu step ; rbu state } {checkpoint} -do_test 4.19 { - catchsql { SELECT * FROM t1 } cons -} {1 {database is locked}} -do_test 4.20 { rbu step ; rbu state } {checkpoint} -do_test 4.21 { rbu step ; rbu state } {done} -rbu close - -do_test 4.22 { - catchsql { SELECT * FROM t1 } cons -} {0 {1 one 2 two}} - -cons close finish_test Index: ext/rbu/rbufault4.test ================================================================== --- ext/rbu/rbufault4.test +++ ext/rbu/rbufault4.test @@ -22,11 +22,10 @@ CREATE INDEX i1b ON t1(b); CREATE INDEX i1c ON t1(c); INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t1 VALUES(4, 5, 6); } - db close forcedelete test.db2 sqlite3rbu_vacuum rbu test.db test.db2 for {set i 0} {$i < $tn} {incr i} { rbu step } set rc [rbu close] @@ -52,15 +51,13 @@ sqlite3rbu_vacuum rbu test.db test.db2 while {[rbu step]=="SQLITE_OK"} {} set trc [rbu close] if {$trc!="SQLITE_DONE"} { error "Got $trc instead of SQLITE_DONE!" } - sqlite3 db test.db set rc [db one {PRAGMA integrity_check}] if {$rc!="ok"} { error "Got $rc instead of ok!" } - db close } } finish_test Index: ext/rbu/rburesume.test ================================================================== --- ext/rbu/rburesume.test +++ ext/rbu/rburesume.test @@ -98,11 +98,11 @@ if {$rc == "SQLITE_DONE"} { rbu close break } - foreach f {test.db test.db-oal test.db-wal test.db-vacuum} { + foreach f {test.db test.db-oal test.db-wal test.db-shm test.db-vacuum} { set f2 [string map [list test.db test.db2] $f] if {[file exists $f]} { forcecopy $f $f2 } else { forcedelete $f2 @@ -157,11 +157,11 @@ if {$rc == "SQLITE_DONE"} { rbu close break } - foreach f {test.db test.db-oal test.db-wal test.db-vacuum} { + foreach f {test.db test.db-oal test.db-wal test.db-shm test.db-vacuum} { set f2 [string map [list test.db test.db2] $f] if {[file exists $f]} { forcecopy $f $f2 } else { forcedelete $f2 @@ -224,11 +224,11 @@ if {$rc == "SQLITE_DONE"} { rbu close break } - foreach f {test.db test.db-oal test.db-wal test.db-vacuum} { + foreach f {test.db test.db-oal test.db-wal test.db-shm test.db-vacuum} { set f2 [string map [list test.db test.db2] $f] if {[file exists $f]} { forcecopy $f $f2 } else { forcedelete $f2 Index: ext/rbu/sqlite3rbu.c ================================================================== --- ext/rbu/sqlite3rbu.c +++ ext/rbu/sqlite3rbu.c @@ -3139,28 +3139,19 @@ iOff = (i64)(pFrame->iDbPage-1) * p->pgsz; p->rc = pDb->pMethods->xWrite(pDb, p->aBuf, p->pgsz, iOff); } -/* -** This value is copied from the definition of ZIPVFS_CTRL_FILE_POINTER -** in zipvfs.h. -*/ -#define RBU_ZIPVFS_CTRL_FILE_POINTER 230439 /* ** Take an EXCLUSIVE lock on the database file. Return SQLITE_OK if ** successful, or an SQLite error code otherwise. */ static int rbuLockDatabase(sqlite3 *db){ int rc = SQLITE_OK; sqlite3_file *fd = 0; - - sqlite3_file_control(db, "main", RBU_ZIPVFS_CTRL_FILE_POINTER, &fd); - if( fd==0 ){ - sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd); - } + sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd); if( fd->pMethods ){ rc = fd->pMethods->xLock(fd, SQLITE_LOCK_SHARED); if( rc==SQLITE_OK ){ rc = fd->pMethods->xLock(fd, SQLITE_LOCK_EXCLUSIVE); Index: ext/recover/dbdata.c ================================================================== --- ext/recover/dbdata.c +++ ext/recover/dbdata.c @@ -165,11 +165,10 @@ int rc = sqlite3_declare_vtab(db, pAux ? DBPTR_SCHEMA : DBDATA_SCHEMA); (void)argc; (void)argv; (void)pzErr; - sqlite3_vtab_config(db, SQLITE_VTAB_USES_ALL_SCHEMAS); if( rc==SQLITE_OK ){ pTab = (DbdataTable*)sqlite3_malloc64(sizeof(DbdataTable)); if( pTab==0 ){ rc = SQLITE_NOMEM; }else{ @@ -511,18 +510,14 @@ if( pCsr->aPage==0 ){ while( 1 ){ if( pCsr->bOnePage==0 && pCsr->iPgno>pCsr->szDb ) return SQLITE_OK; rc = dbdataLoadPage(pCsr, pCsr->iPgno, &pCsr->aPage, &pCsr->nPage); if( rc!=SQLITE_OK ) return rc; - if( pCsr->aPage && pCsr->nPage>=256 ) break; - sqlite3_free(pCsr->aPage); - pCsr->aPage = 0; + if( pCsr->aPage ) break; if( pCsr->bOnePage ) return SQLITE_OK; pCsr->iPgno++; } - - assert( iOff+3+2<=pCsr->nPage ); pCsr->iCell = pTab->bPtr ? -2 : 0; pCsr->nCell = get_uint16(&pCsr->aPage[iOff+3]); } if( pTab->bPtr ){ @@ -753,11 +748,12 @@ static int dbdataGetEncoding(DbdataCursor *pCsr){ int rc = SQLITE_OK; int nPg1 = 0; u8 *aPg1 = 0; rc = dbdataLoadPage(pCsr, 1, &aPg1, &nPg1); - if( rc==SQLITE_OK && nPg1>=(56+4) ){ + assert( rc!=SQLITE_OK || nPg1==0 || nPg1>=512 ); + if( rc==SQLITE_OK && nPg1>0 ){ pCsr->enc = get_uint32(&aPg1[56]); } sqlite3_free(aPg1); return rc; } @@ -811,22 +807,20 @@ ); } } if( rc==SQLITE_OK ){ rc = sqlite3_bind_text(pCsr->pStmt, 1, zSchema, -1, SQLITE_TRANSIENT); + }else{ + pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db)); } /* Try to determine the encoding of the db by inspecting the header ** field on page 1. */ if( rc==SQLITE_OK ){ rc = dbdataGetEncoding(pCsr); } - if( rc!=SQLITE_OK ){ - pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db)); - } - if( rc==SQLITE_OK ){ rc = dbdataNext(pCursor); } return rc; } Index: ext/recover/recover1.test ================================================================== --- ext/recover/recover1.test +++ ext/recover/recover1.test @@ -314,20 +314,7 @@ do_execsql_test 16.9 { SELECT * FROM t1; COMMIT; } {1 2 3 4} -#------------------------------------------------------------------------- -reset_db -do_execsql_test 17.1 { - CREATE TABLE t(a, PRIMARY KEY(a, a COLLATE NOCASE)) WITHOUT ROWID; - INSERT INTO t VALUES('abc'); - INSERT INTO t VALUES('def'); -} -do_test 17.2 { - set R [sqlite3_recover_init db main test.db2] - $R run - list [catch { $R finish } msg] $msg -} {0 {}} - finish_test DELETED ext/recover/recoverbuild.test Index: ext/recover/recoverbuild.test ================================================================== --- ext/recover/recoverbuild.test +++ /dev/null @@ -1,42 +0,0 @@ -# 2023 February 28 -# -# 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. -# -#*********************************************************************** -# - -source [file join [file dirname [info script]] recover_common.tcl] -set testprefix recoverbuild - - -# The following tests verify that if the recovery extension is used with -# a build that does not support the sqlite_dbpage table, the error message -# is "no such table: sqlite_dbpage", and not something more generic. -# -reset_db -create_null_module db sqlite_dbpage -do_execsql_test 1.0 { - CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT); - INSERT INTO t1 VALUES(123, 'one hundred and twenty three'); -} - -forcedelete test.db2 -do_test 1.1 { - set R [sqlite3_recover_init db main test.db2] -} {/sqlite_recover.*/} - -do_test 1.2 { - $R run -} {1} - -do_test 1.3 { - list [catch { $R finish } msg] $msg -} {1 {no such table: sqlite_dbpage}} - -finish_test - Index: ext/recover/sqlite3recover.c ================================================================== --- ext/recover/sqlite3recover.c +++ ext/recover/sqlite3recover.c @@ -1104,11 +1104,11 @@ pStmt = recoverPreparePrintf(p, p->dbOut, "PRAGMA index_xinfo(%Q)", zName); while( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){ int iField = sqlite3_column_int(pStmt, 0); int iCol = sqlite3_column_int(pStmt, 1); - assert( iColnCol ); + assert( iFieldnCol && iColnCol ); pNew->aCol[iCol].iField = iField; pNew->bIntkey = 0; iPk = -2; } Index: ext/rtree/rtree.c ================================================================== --- ext/rtree/rtree.c +++ ext/rtree/rtree.c @@ -469,21 +469,20 @@ ** using C-preprocessor macros. If that is unsuccessful, or if ** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined ** at run-time. */ #ifndef SQLITE_BYTEORDER -# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ - defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ - defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ - defined(__ARMEL__) || defined(__AARCH64EL__) || defined(_M_ARM64) -# define SQLITE_BYTEORDER 1234 -# elif defined(sparc) || defined(__ppc__) || \ - defined(__ARMEB__) || defined(__AARCH64EB__) -# define SQLITE_BYTEORDER 4321 -# else -# define SQLITE_BYTEORDER 0 -# endif +#if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ + defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ + defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ + defined(__arm__) +# define SQLITE_BYTEORDER 1234 +#elif defined(sparc) || defined(__ppc__) +# define SQLITE_BYTEORDER 4321 +#else +# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */ +#endif #endif /* What version of MSVC is being used. 0 means MSVC is not being used */ #ifndef MSVC_VERSION Index: ext/rtree/rtree6.test ================================================================== --- ext/rtree/rtree6.test +++ ext/rtree/rtree6.test @@ -102,19 +102,17 @@ do_eqp_test rtree6.2.4.1 { SELECT * FROM t1,t2 WHERE v=+ii and x1<10 and x2>10 } { QUERY PLAN |--SCAN t1 VIRTUAL TABLE INDEX 2:C0E1 - |--BLOOM FILTER ON t2 (v=?) `--SEARCH t2 USING AUTOMATIC COVERING INDEX (v=?) } do_eqp_test rtree6.2.4.2 { SELECT * FROM t1,t2 WHERE v=10 and x1<10 and x2>10 } { QUERY PLAN |--SCAN t1 VIRTUAL TABLE INDEX 2:C0E1 - |--BLOOM FILTER ON t2 (v=?) `--SEARCH t2 USING AUTOMATIC PARTIAL COVERING INDEX (v=?) } do_eqp_test rtree6.2.5 { SELECT * FROM t1,t2 WHERE k=ii AND x11 && [string first $a1 -ignorenoop]==0} { - set bIgnoreNoop 1 - set args [lrange $args 1 end] - } - - if {[llength $args]!=1 && [llength $args]!=2} { - error "usage: do_then_apply_sql ?-ignorenoop? SQL ?DBNAME?" - } - - set sql [lindex $args 0] - if {[llength $args]==1} { - set dbname main - } else { - set dbname [lindex $args 1] - } - - set ::n_conflict 0 - proc xConflict args { incr ::n_conflict ; return "OMIT" } +proc do_then_apply_sql {sql {dbname main}} { + proc xConflict args { return "OMIT" } set rc [catch { sqlite3session S db $dbname - S object_config rowid 1 db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" { S attach $name } db eval $sql - set ::changeset [S changeset] - sqlite3changeset_apply db2 $::changeset xConflict + sqlite3changeset_apply db2 [S changeset] xConflict } msg] catch { S delete } - if {$rc} {error $msg} - - if {$bIgnoreNoop} { - set nSave $::n_conflict - set ::n_conflict 0 - proc xConflict args { incr ::n_conflict ; return "OMIT" } - sqlite3changeset_apply_v2 -ignorenoop db2 $::changeset xConflict - if {$::n_conflict!=$nSave} { - error "-ignorenoop problem ($::n_conflict $nSave)..." - } - } + + if {$rc} {error $msg} } proc do_iterator_test {tn tbl_list sql res} { sqlite3session S db main - S object_config rowid 1 - if {[llength $tbl_list]==0} { S attach * } foreach t $tbl_list {S attach $t} execsql $sql set r [list] foreach v $res { lappend r $v } set x [list] -# set ::c [S changeset] ; execsql_pp { SELECT quote($::c) } sqlite3session_foreach c [S changeset] { lappend x $c } uplevel do_test $tn [list [list set {} $x]] [list $r] S delete } @@ -249,51 +211,5 @@ } set txt [string trim $txt] if {$txt==""} {set txt zero} return $txt } - -proc scksum {db dbname} { - - if {$dbname=="temp"} { - set master sqlite_temp_master - } else { - set master $dbname.sqlite_master - } - - set alltab [$db eval "SELECT name FROM $master WHERE type='table'"] - set txt [$db eval "SELECT * FROM $master ORDER BY type,name,sql"] - foreach tab $alltab { - set cols [list] - db eval "PRAGMA $dbname.table_info = $tab" x { - lappend cols "quote($x(name))" - } - set cols [join $cols ,] - append txt [db eval "SELECT $cols FROM $dbname.$tab ORDER BY $cols"] - } - return [md5 $txt] -} - -proc do_diff_test {tn setup} { - reset_db - forcedelete test.db2 - execsql { ATTACH 'test.db2' AS aux } - execsql $setup - - sqlite3session S db main - S object_config rowid 1 - foreach tbl [db eval {SELECT name FROM sqlite_master WHERE type='table'}] { - S attach $tbl - S diff aux $tbl - } - - set C [S changeset] - S delete - - sqlite3 db2 test.db2 - sqlite3changeset_apply db2 $C "" - uplevel do_test $tn.1 [list {execsql { PRAGMA integrity_check } db2}] ok - db2 close - - set cksum [scksum db main] - uplevel do_test $tn.2 [list {scksum db aux}] [list $cksum] -} Index: ext/session/sessionat.test ================================================================== --- ext/session/sessionat.test +++ ext/session/sessionat.test @@ -108,19 +108,19 @@ } do_execsql_test -db db2 $tn.3.1 { CREATE TABLE t3(a, b, c DEFAULT 'D', PRIMARY KEY(b)) %WR%; } do_test $tn.3.2 { - do_then_apply_sql -ignorenoop { + do_then_apply_sql { INSERT INTO t3 VALUES(1, 2); INSERT INTO t3 VALUES(3, 4); INSERT INTO t3 VALUES(5, 6); }; db2 eval {SELECT * FROM t3} } {1 2 D 3 4 D 5 6 D} do_test $tn.3.3 { - do_then_apply_sql -ignorenoop { + do_then_apply_sql { UPDATE t3 SET a=45 WHERE b=4; DELETE FROM t3 WHERE a=5; }; db2 eval {SELECT * FROM t3} } {1 2 D 45 4 D} @@ -251,11 +251,11 @@ } do_execsql_test -db db2 $tn.7.1 { CREATE TABLE t8(a PRIMARY KEY, b, c, d DEFAULT 'D', e DEFAULT 'E'); } - do_then_apply_sql -ignorenoop { + do_then_apply_sql { INSERT INTO t8 VALUES(1, 2, 3); INSERT INTO t8 VALUES(4, 5, 6); } do_execsql_test $tn.7.2.1 { SELECT * FROM t8 @@ -262,11 +262,11 @@ } {1 2 3 4 5 6} do_execsql_test -db db2 $tn.7.2.2 { SELECT * FROM t8 } {1 2 3 D E 4 5 6 D E} - do_then_apply_sql -ignorenoop { + do_then_apply_sql { UPDATE t8 SET c=45 WHERE a=4; } do_execsql_test $tn.7.3.1 { SELECT * FROM t8 } {1 2 3 4 5 45} @@ -280,20 +280,20 @@ CREATE TABLE t9(a PRIMARY KEY, b, c, d, e, f, g, h); } do_execsql_test -db db2 $tn.8.1 { CREATE TABLE t9(a PRIMARY KEY, b, c, d, e, f, g, h, i, j, k, l); } - do_then_apply_sql -ignorenoop { + do_then_apply_sql { INSERT INTO t9 VALUES(1, 2, 3, 4, 5, 6, 7, 8); } do_then_apply_sql { UPDATE t9 SET h=450 WHERE a=1 } do_execsql_test -db db2 $tn.8.2 { SELECT * FROM t9 } {1 2 3 4 5 6 7 450 {} {} {} {}} - do_then_apply_sql -ignorenoop { + do_then_apply_sql { UPDATE t9 SET h=NULL } do_execsql_test -db db2 $tn.8.2 { SELECT * FROM t9 } {1 2 3 4 5 6 7 {} {} {} {} {}} Index: ext/session/sessionbig.test ================================================================== --- ext/session/sessionbig.test +++ ext/session/sessionbig.test @@ -41,11 +41,11 @@ do_execsql_test -db db2 1.1 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); } do_test 1.2 { - do_then_apply_sql -ignorenoop { + do_then_apply_sql { INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); @@ -69,11 +69,11 @@ execsql2 { DELETE FROM t1 } } {} do_test 1.4 { set rc [catch { - do_then_apply_sql -ignorenoop { + do_then_apply_sql { INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); INSERT INTO t1(b) VALUES( zeroblob(100*1000*1000) ); Index: ext/session/sessionfault.test ================================================================== --- ext/session/sessionfault.test +++ ext/session/sessionfault.test @@ -42,11 +42,11 @@ catch {db2 close} catch {db close} faultsim_restore_and_reopen sqlite3 db2 test.db2 } -body { - do_then_apply_sql -ignorenoop { + do_then_apply_sql { INSERT INTO t1 VALUES('a string value', 8, 9); UPDATE t1 SET c = 10 WHERE a = 1; DELETE FROM t1 WHERE a = 4; } } -test { Index: ext/session/sessionfault2.test ================================================================== --- ext/session/sessionfault2.test +++ ext/session/sessionfault2.test @@ -130,11 +130,11 @@ catch {db2 close} catch {db close} faultsim_restore_and_reopen sqlite3 db2 test.db2 } -body { - do_then_apply_sql -ignorenoop { + do_then_apply_sql { INSERT INTO sqlite_stat1 VALUES('x', 'y', 45); UPDATE sqlite_stat1 SET stat = 123 WHERE tbl='t1' AND idx='i1'; UPDATE sqlite_stat1 SET stat = 456 WHERE tbl='t2'; } } -test { DELETED ext/session/sessionnoop2.test Index: ext/session/sessionnoop2.test ================================================================== --- ext/session/sessionnoop2.test +++ /dev/null @@ -1,180 +0,0 @@ -# 2011 March 07 -# -# 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 regression tests for SQLite library. -# - -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 sessionnoop - -foreach {tn wo} { - 1 "" - 2 " WITHOUT ROWID " -} { - reset_db - eval [string map [list %WO% $wo] { -do_execsql_test $tn.1.0 { - CREATE TABLE t1(a PRIMARY KEY, b, c) %WO%; - INSERT INTO t1 VALUES('a', 'A', 'AAA'); - INSERT INTO t1 VALUES('b', 'B', 'BBB'); - INSERT INTO t1 VALUES('c', 'C', 'CCC'); - INSERT INTO t1 VALUES('d', 'D', 'DDD'); - INSERT INTO t1 VALUES('e', 'E', 'EEE'); -} - -forcedelete test.db2 -sqlite3 db2 test.db2 - -do_execsql_test -db db2 $tn.1.1 { - CREATE TABLE t1(a PRIMARY KEY, b, c) %WO%; - INSERT INTO t1 VALUES('a', 'A', 'AAA'); - INSERT INTO t1 VALUES('b', 'B', '123'); - INSERT INTO t1 VALUES('c', 'C', 'CCC'); - INSERT INTO t1 VALUES('e', 'E', 'EEE'); - INSERT INTO t1 VALUES('f', 'F', 'FFF'); -} - -set C [changeset_from_sql { - UPDATE t1 SET c='123' WHERE a='b'; - DELETE FROM t1 WHERE a='d'; - INSERT INTO t1 VALUES('f', 'F', 'FFF'); -}] - - -set ::conflict_list [list] -proc xConflict {args} { - lappend ::conflict_list $args - return "OMIT" -} -do_test $tn.1.2 { - sqlite3changeset_apply_v2 db2 $C xConflict - set ::conflict_list -} [list {*}{ - {UPDATE t1 DATA {t b {} {} t BBB} {{} {} {} {} t 123} {t b t B t 123}} - {INSERT t1 CONFLICT {t f t F t FFF} {t f t F t FFF}} - {DELETE t1 NOTFOUND {t d t D t DDD}} -}] -do_test $tn.1.3 { - set ::conflict_list [list] - sqlite3changeset_apply_v2 db2 $C xConflict - set ::conflict_list -} [list {*}{ - {UPDATE t1 DATA {t b {} {} t BBB} {{} {} {} {} t 123} {t b t B t 123}} - {INSERT t1 CONFLICT {t f t F t FFF} {t f t F t FFF}} - {DELETE t1 NOTFOUND {t d t D t DDD}} -}] - -do_test $tn.1.4 { - set ::conflict_list [list] - sqlite3changeset_apply_v2 -ignorenoop db2 $C xConflict - set ::conflict_list -} {} - -do_execsql_test -db db2 1.5 { - UPDATE t1 SET b='G' WHERE a='f'; - UPDATE t1 SET c='456' WHERE a='b'; -} - -do_test $tn.1.6 { - set ::conflict_list [list] - sqlite3changeset_apply_v2 -ignorenoop db2 $C xConflict - set ::conflict_list -} [list {*}{ - {UPDATE t1 DATA {t b {} {} t BBB} {{} {} {} {} t 123} {t b t B t 456}} - {INSERT t1 CONFLICT {t f t F t FFF} {t f t G t FFF}} -}] - -db2 close - -#-------------------------------------------------------------------------- - -reset_db -forcedelete test.db2 -sqlite3 db2 test.db2 -do_execsql_test $tn.2.0 { - CREATE TABLE t1(a PRIMARY KEY, b) %WO%; -} -do_execsql_test -db db2 $tn.2.1 { - CREATE TABLE t1(a PRIMARY KEY, b, c DEFAULT 'val') %WO%; -} - -do_test $tn.2.2 { - do_then_apply_sql -ignorenoop { - INSERT INTO t1 VALUES(1, 2); - } - do_then_apply_sql -ignorenoop { - UPDATE t1 SET b=2 WHERE a=1 - } -} {} - - -}] -} - -db2 close - -#------------------------------------------------------------------------- -reset_db -forcedelete test.db2 -do_execsql_test 3.0 { - CREATE TABLE xyz(a, b, c, PRIMARY KEY(a, b), UNIQUE(c)); - ANALYZE; - WITH s(i) AS ( - VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100 - ) - INSERT INTO xyz SELECT i, i, i FROM s; - VACUUM INTO 'test.db2'; -} - -set C [changeset_from_sql { ANALYZE }] -sqlite3 db2 test.db2 - -set ::conflict_list [list] -proc xConflict {args} { lappend ::conflict_list $args ; return "OMIT" } -do_test 3.1 { - sqlite3changeset_apply_v2 db2 $C xConflict - set ::conflict_list -} {} - -do_test 3.2 { - sqlite3changeset_apply_v2 -ignorenoop db2 $C xConflict - set ::conflict_list -} {} - -do_test 3.3 { - sqlite3changeset_apply_v2 db2 $C xConflict - set ::conflict_list -} [list {*}{ - {INSERT sqlite_stat1 CONFLICT {t xyz t sqlite_autoindex_xyz_1 t {100 1 1}} {t xyz t sqlite_autoindex_xyz_1 t {100 1 1}}} - {INSERT sqlite_stat1 CONFLICT {t xyz t sqlite_autoindex_xyz_2 t {100 1}} {t xyz t sqlite_autoindex_xyz_2 t {100 1}}} -}] - -do_execsql_test -db db2 3.4 { - UPDATE sqlite_stat1 SET stat='200 1 1' WHERE idx='sqlite_autoindex_xyz_1'; -} - -do_test 3.5 { - set ::conflict_list [list] - sqlite3changeset_apply_v2 -ignorenoop db2 $C xConflict - set ::conflict_list -} [list {*}{ - {INSERT sqlite_stat1 CONFLICT {t xyz t sqlite_autoindex_xyz_1 t {100 1 1}} {t xyz t sqlite_autoindex_xyz_1 t {200 1 1}}} -}] - - - -finish_test - Index: ext/session/sessionrebase.test ================================================================== --- ext/session/sessionrebase.test +++ ext/session/sessionrebase.test @@ -82,29 +82,26 @@ sqlite3 db2 test.db2 db eval BEGIN sqlite3session S1 db main - S1 object_config rowid 1 S1 attach * execsql $sql1 db set c1 [S1 changeset] S1 delete if {$i==1} { sqlite3session S2 db2 main - S2 object_config rowid 1 S2 attach * execsql $sql2 db2 set c2 [S2 changeset] S2 delete } else { set c2 [list] foreach sql [split $sql2 ";"] { if {[string is space $sql]} continue sqlite3session S2 db2 main - S2 object_config rowid 1 S2 attach * execsql $sql db2 lappend c2 [S2 changeset] S2 delete } @@ -341,83 +338,10 @@ } { UPDATE t2 SET y='two' WHERE z='B'; } { OMIT } { SELECT * FROM t2 WHERE z='B' } { 1 one B } - - -reset_db -do_execsql_test 2.3.0 { - CREATE TABLE t1 (b TEXT); - INSERT INTO t1(rowid, b) VALUES(1, 'one'); - INSERT INTO t1(rowid, b) VALUES(2, 'two'); - INSERT INTO t1(rowid, b) VALUES(3, 'three'); -} -do_rebase_test 2.3.1 { - UPDATE t1 SET b = 'two.1' WHERE rowid=2 -} { - UPDATE t1 SET b = 'two.2' WHERE rowid=2; -} { - OMIT -} { SELECT rowid, * FROM t1 } {1 one 2 two.1 3 three} - -do_rebase_test 2.3.2 { - UPDATE t1 SET b = 'two.1' WHERE rowid=2 -} { - UPDATE t1 SET b = 'two.2' WHERE rowid=2; -} { - REPLACE -} { SELECT rowid, * FROM t1 } {1 one 2 two.2 3 three} - -do_rebase_test 2.3.3 { - DELETE FROM t1 WHERE rowid=3 -} { - DELETE FROM t1 WHERE rowid=3; -} { - OMIT -} { SELECT rowid, * FROM t1 } {1 one 2 two} - -do_rebase_test 2.3.4 { - DELETE FROM t1 WHERE rowid=1 -} { - UPDATE t1 SET b='one.2' WHERE rowid=1 -} { - OMIT -} { SELECT rowid, * FROM t1 } {2 two 3 three} - -do_rebase_test 2.3.6 { - UPDATE t1 SET b='three.1' WHERE rowid=3 -} { - DELETE FROM t1 WHERE rowid=3; -} { - OMIT -} { SELECT rowid, * FROM t1 } {1 one 2 two 3 three.1} - -do_rebase_test 2.3.7 { - UPDATE t1 SET b='three.1' WHERE rowid=3 -} { - DELETE FROM t1 WHERE rowid=3; -} { - REPLACE -} { SELECT rowid, * FROM t1 } {1 one 2 two} - -do_rebase_test 2.3.8 { - INSERT INTO t1(rowid, b) VALUES(4, 'four.1') -} { - INSERT INTO t1(rowid, b) VALUES(4, 'four.2'); -} { - REPLACE -} { SELECT rowid, * FROM t1 } {1 one 2 two 3 three 4 four.2} - -do_rebase_test 2.3.9 { - INSERT INTO t1(rowid, b) VALUES(4, 'four.1') -} { - INSERT INTO t1(rowid, b) VALUES(4, 'four.2'); -} { - OMIT -} { SELECT rowid, * FROM t1 } {1 one 2 two 3 three 4 four.1} - #------------------------------------------------------------------------- reset_db do_execsql_test 3.0 { CREATE TABLE t3(a, b, c, PRIMARY KEY(b, c)); DELETED ext/session/sessionrowid.test Index: ext/session/sessionrowid.test ================================================================== --- ext/session/sessionrowid.test +++ /dev/null @@ -1,281 +0,0 @@ -# 2011 Mar 16 -# -# 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 sessionrowid - -do_execsql_test 0.0 { - CREATE TABLE t1(a, b); -} - -foreach {tn rowid bEmpty} { - 1 0 1 - 2 1 0 - 3 -1 1 -} { - do_test 0.$tn { - sqlite3session S db main - if {$rowid>=0} { S object_config rowid $rowid } - S attach t1 - execsql { INSERT INTO t1 VALUES(1, 2); } - expr [string length [S changeset]]==0 - } $bEmpty - S delete -} - -#------------------------------------------------------------------------- -reset_db -do_execsql_test 1.0 { - CREATE TABLE t1(a, b); -} - -do_iterator_test 1.1 t1 { - INSERT INTO t1 VALUES('i', 'one'); -} { - {INSERT t1 0 X.. {} {i 1 t i t one}} -} - -do_execsql_test 1.2 { - SELECT rowid, * FROM t1 -} {1 i one} - -do_iterator_test 1.3 t1 { - UPDATE t1 SET b='two' -} { - {UPDATE t1 0 X.. {i 1 {} {} t one} {{} {} {} {} t two}} -} - -do_iterator_test 1.4 t1 { - DELETE FROM t1; -} { - {DELETE t1 0 X.. {i 1 t i t two} {}} -} - -do_iterator_test 1.5 t1 { - INSERT INTO t1(rowid, a, b) VALUES(14, 'hello', 'world'); - INSERT INTO t1(rowid, a, b) VALUES(NULL, 'yes', 'no'); - INSERT INTO t1(rowid, a, b) VALUES(-123, 'ii', 'iii'); -} { - {INSERT t1 0 X.. {} {i -123 t ii t iii}} - {INSERT t1 0 X.. {} {i 15 t yes t no}} - {INSERT t1 0 X.. {} {i 14 t hello t world}} -} - -do_iterator_test 1.6 t1 { - UPDATE t1 SET a='deluxe' WHERE rowid=14; - DELETE FROM t1 WHERE rowid=-123; - INSERT INTO t1 VALUES('x', 'xi'); -} { - {DELETE t1 0 X.. {i -123 t ii t iii} {}} - {UPDATE t1 0 X.. {i 14 t hello {} {}} {{} {} t deluxe {} {}}} - {INSERT t1 0 X.. {} {i 16 t x t xi}} -} - -#------------------------------------------------------------------------- -reset_db -forcedelete test.db2 -sqlite3 db2 test.db2 - -do_execsql_test 2.0 { - CREATE TABLE t1(a, b); -} -do_execsql_test -db db2 2.0.1 { - CREATE TABLE t1(a, b); -} - -proc xConflict {args} { - puts "CONFLICT!" - return "OMIT" -} - -do_test 2.1 { - set C [changeset_from_sql { - INSERT INTO t1 VALUES('abc', 'def'); - }] - sqlite3changeset_apply db2 $C xConflict - execsql { SELECT * FROM t1 } db2 -} {abc def} -do_test 2.2 { - set C [changeset_from_sql { - UPDATE t1 SET b='hello' - }] - sqlite3changeset_apply db2 $C xConflict - execsql { SELECT * FROM t1 } db2 -} {abc hello} -do_test 2.3 { - set C [changeset_from_sql { - DELETE FROM t1 WHERE b='hello' - }] - sqlite3changeset_apply db2 $C xConflict - execsql { SELECT * FROM t1 } db2 -} {} - -do_test 2.4 { - do_then_apply_sql { - INSERT INTO t1 VALUES('i', 'one'); - INSERT INTO t1 VALUES('ii', 'two'); - INSERT INTO t1 VALUES('iii', 'three'); - INSERT INTO t1 VALUES('iv', 'four'); - } - compare_db db db2 -} {} - -do_test 2.5 { - do_then_apply_sql { - DELETE FROM t1 WHERE a='ii'; - UPDATE t1 SET b='THREE' WHERE a='iii'; - UPDATE t1 SET a='III' WHERE a='iii'; - INSERT INTO t1 VALUES('v', 'five'); - } - compare_db db db2 -} {} - -do_execsql_test 2.6 {SELECT * FROM t1} {i one III THREE iv four v five} -do_execsql_test -db db2 2.7 {SELECT * FROM t1} {i one III THREE iv four v five} - -#------------------------------------------------------------------------- -db2 close -reset_db -forcedelete test.db2 -sqlite3 db2 test.db2 - -set init_sql { - CREATE TABlE t4(a, b); - CREATE INDEX t4a ON t4(a); - CREATE UNIQUE INDEX t4b ON t4(b); -} - -do_execsql_test 3.0 $init_sql -do_execsql_test -db db2 3.0a $init_sql - -do_execsql_test -db db2 3.1 { - INSERT INTO t4(rowid, a, b) VALUES(43, 'hello', 'world'); -} -do_conflict_test 3.2 -sql { - INSERT INTO t4(rowid, a, b) VALUES(43, 'abc', 'def'); -} -tables t4 -conflicts { - {INSERT t4 CONFLICT {i 43 t abc t def} {i 43 t hello t world}} -} -do_execsql_test -db db2 3.3 { - SELECT * FROM t4 -} {hello world} - -do_execsql_test 3.4 { DELETE FROM t4 } -do_conflict_test 3.5 -sql { - INSERT INTO t4(rowid, a, b) VALUES(43, 'abc', 'def'); -} -tables t4 -conflicts { - {INSERT t4 CONFLICT {i 43 t abc t def} {i 43 t hello t world}} -} -policy REPLACE -do_execsql_test -db db2 3.6 { - SELECT * FROM t4 -} {abc def} - -do_execsql_test 3.7 { DELETE FROM t4 } -do_conflict_test 3.8 -sql { - INSERT INTO t4(rowid, a, b) VALUES(45, 'xyz', 'def'); -} -tables t4 -conflicts { - {INSERT t4 CONSTRAINT {i 45 t xyz t def}} -} -do_execsql_test -db db2 3.9 { - SELECT * FROM t4 -} {abc def} - - -do_execsql_test -db db 3.10a { DELETE FROM t4 } -do_execsql_test -db db2 3.10b { DELETE FROM t4 } - -do_execsql_test -db db 3.11a { - INSERT INTO t4(rowid, a, b) VALUES(111, 'one', 'one'); - INSERT INTO t4(rowid, a, b) VALUES(222, 'two', 'two'); -} -do_execsql_test -db db2 3.11b { - INSERT INTO t4(rowid, a, b) VALUES(111, 'one', 'blip'); -} - -do_conflict_test 3.12 -sql { - DELETE FROM t4 WHERE a='one'; -} -tables t4 -conflicts { - {DELETE t4 DATA {i 111 t one t one} {i 111 t one t blip}} -} -do_execsql_test -db db2 3.13 { - SELECT * FROM t4 -} {one blip} - -do_conflict_test 3.14 -sql { - DELETE FROM t4 WHERE a='two'; -} -tables t4 -conflicts { - {DELETE t4 NOTFOUND {i 222 t two t two}} -} -do_execsql_test -db db2 3.15 { - SELECT * FROM t4 -} {one blip} - -do_execsql_test -db db 3.16a { DELETE FROM t4 } -do_execsql_test -db db2 3.16b { DELETE FROM t4 } - -do_execsql_test -db db 3.17a { - INSERT INTO t4(rowid, a, b) VALUES(111, 'one', 'one'); - INSERT INTO t4(rowid, a, b) VALUES(222, 'two', 'two'); -} -do_execsql_test -db db2 3.17b { - INSERT INTO t4(rowid, a, b) VALUES(111, 'one', 'blip'); -} - -do_conflict_test 3.18 -sql { - UPDATE t4 SET b='xyz' WHERE a='one' -} -tables t4 -conflicts { - {UPDATE t4 DATA {i 111 {} {} t one} {{} {} {} {} t xyz} {i 111 t one t blip}} -} -do_execsql_test -db db2 3.19 { - SELECT * FROM t4 -} {one blip} - -do_conflict_test 3.20 -sql { - UPDATE t4 SET b='123' WHERE a='two' -} -tables t4 -conflicts { - {UPDATE t4 NOTFOUND {i 222 {} {} t two} {{} {} {} {} t 123}} -} -do_execsql_test -db db2 3.21 { - SELECT * FROM t4 -} {one blip} - -#-------------------------------------------------------------------------- -breakpoint -do_diff_test 4.0 { - CREATE TABLE t1(x, y); - CREATE TABLE aux.t1(x, y); - INSERT INTO t1 VALUES(1, 2); -} - -do_diff_test 4.1 { - CREATE TABLE t1(x, y); - CREATE TABLE aux.t1(x, y); - INSERT INTO aux.t1 VALUES(1, 2); -} - -do_diff_test 4.2 { - CREATE TABLE t1(x, y); - CREATE TABLE aux.t1(x, y); - INSERT INTO t1(rowid, x, y) VALUES(413, 'hello', 'there'); - INSERT INTO aux.t1(rowid, x, y) VALUES(413, 'hello', 'world'); -} - -finish_test - Index: ext/session/sessionsize.test ================================================================== --- ext/session/sessionsize.test +++ ext/session/sessionsize.test @@ -111,21 +111,21 @@ CREATE TABLE t1(a INTEGER PRIMARY KEY, b); } do_test 3.1 { sqlite3session S db main - S object_config size -1 + S object_config_size -1 } 1 -do_test 3.2.1 { S object_config size 0 } 0 -do_test 3.2.2 { S object_config size -1 } 0 -do_test 3.2.3 { S object_config size 1 } 1 -do_test 3.2.4 { S object_config size -1 } 1 +do_test 3.2.1 { S object_config_size 0 } 0 +do_test 3.2.2 { S object_config_size -1 } 0 +do_test 3.2.3 { S object_config_size 1 } 1 +do_test 3.2.4 { S object_config_size -1 } 1 do_test 3.3 { S attach t1 } {} -do_test 3.4 { S object_config size 1 } {SQLITE_MISUSE} -do_test 3.4 { S object_config size -1 } {1} +do_test 3.4 { S object_config_size 1 } {SQLITE_MISUSE} +do_test 3.4 { S object_config_size -1 } {1} S delete finish_test Index: ext/session/sessionstat1.test ================================================================== --- ext/session/sessionstat1.test +++ ext/session/sessionstat1.test @@ -80,11 +80,11 @@ ANALYZE; } } {} do_test 2.1 { - do_then_apply_sql -ignorenoop { + do_then_apply_sql { WITH s(i) AS ( SELECT 0 UNION ALL SELECT i+1 FROM s WHERE (i+1)<32 ) INSERT INTO t1 SELECT i, i%8, i%2 FROM s; ANALYZE; @@ -98,11 +98,11 @@ t1 t1b {32 4} t1 t1c {32 16} } do_test 2.3 { - do_then_apply_sql -ignorenoop { DROP INDEX t1c } + do_then_apply_sql { DROP INDEX t1c } } {} do_execsql_test -db db2 2.4 { SELECT * FROM sqlite_stat1 } { @@ -109,11 +109,11 @@ t1 sqlite_autoindex_t1_1 {32 1} t1 t1b {32 4} } do_test 2.3 { - do_then_apply_sql -ignorenoop { DROP TABLE t1 } + do_then_apply_sql { DROP TABLE t1 } } {} do_execsql_test -db db2 2.4 { SELECT * FROM sqlite_stat1 } { @@ -151,20 +151,20 @@ do_execsql_test 3.2 { SELECT * FROM sqlite_stat1; } {t1 null 4} do_test 3.3 { execsql { DELETE FROM sqlite_stat1 } - do_then_apply_sql -ignorenoop { ANALYZE } + do_then_apply_sql { ANALYZE } execsql { SELECT * FROM sqlite_stat1 } db2 } {t1 null 4} do_test 3.4 { execsql { INSERT INTO t1 VALUES(5,5,5) } - do_then_apply_sql -ignorenoop { ANALYZE } + do_then_apply_sql { ANALYZE } execsql { SELECT * FROM sqlite_stat1 } db2 } {t1 null 5} do_test 3.5 { - do_then_apply_sql -ignorenoop { DROP TABLE t1 } + do_then_apply_sql { DROP TABLE t1 } execsql { SELECT * FROM sqlite_stat1 } db2 } {} do_test 3.6.1 { execsql { Index: ext/session/sqlite3session.c ================================================================== --- ext/session/sqlite3session.c +++ ext/session/sqlite3session.c @@ -23,12 +23,10 @@ # else # define SESSIONS_STRM_CHUNK_SIZE 1024 # endif #endif -#define SESSIONS_ROWID "_rowid_" - static int sessions_strm_chunk_size = SESSIONS_STRM_CHUNK_SIZE; typedef struct SessionHook SessionHook; struct SessionHook { void *pCtx; @@ -46,11 +44,10 @@ char *zDb; /* Name of database session is attached to */ int bEnableSize; /* True if changeset_size() enabled */ int bEnable; /* True if currently recording */ int bIndirect; /* True if all changes are indirect */ int bAutoAttach; /* True to auto-attach tables */ - int bImplicitPK; /* True to handle tables with implicit PK */ int rc; /* Non-zero if an error has occurred */ void *pFilterCtx; /* First argument to pass to xTableFilter */ int (*xTableFilter)(void *pCtx, const char *zTab); i64 nMalloc; /* Number of bytes of data allocated */ i64 nMaxChangesetSize; @@ -123,11 +120,10 @@ struct SessionTable { SessionTable *pNext; char *zName; /* Local name of table */ int nCol; /* Number of columns in table zName */ int bStat1; /* True if this is sqlite_stat1 */ - int bRowid; /* True if this table uses rowid for PK */ const char **azCol; /* Column names */ u8 *abPK; /* Array of primary key flags */ int nEntry; /* Total number of entries in hash table */ int nChange; /* Size of apChange[] array */ SessionChange **apChange; /* Hash table buckets */ @@ -516,66 +512,60 @@ ** of *piHash asn *pbNullPK are undefined. Otherwise, SQLITE_OK is returned ** and the output variables are set as described above. */ static int sessionPreupdateHash( sqlite3_session *pSession, /* Session object that owns pTab */ - i64 iRowid, SessionTable *pTab, /* Session table handle */ int bNew, /* True to hash the new.* PK */ int *piHash, /* OUT: Hash value */ int *pbNullPK /* OUT: True if there are NULL values in PK */ ){ unsigned int h = 0; /* Hash value to return */ int i; /* Used to iterate through columns */ - if( pTab->bRowid ){ - assert( pTab->nCol-1==pSession->hook.xCount(pSession->hook.pCtx) ); - h = sessionHashAppendI64(h, iRowid); - }else{ - assert( *pbNullPK==0 ); - assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) ); - for(i=0; inCol; i++){ - if( pTab->abPK[i] ){ - int rc; - int eType; - sqlite3_value *pVal; - - if( bNew ){ - rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal); - }else{ - rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal); - } - if( rc!=SQLITE_OK ) return rc; - - eType = sqlite3_value_type(pVal); - h = sessionHashAppendType(h, eType); - if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ - i64 iVal; - if( eType==SQLITE_INTEGER ){ - iVal = sqlite3_value_int64(pVal); - }else{ - double rVal = sqlite3_value_double(pVal); - assert( sizeof(iVal)==8 && sizeof(rVal)==8 ); - memcpy(&iVal, &rVal, 8); - } - h = sessionHashAppendI64(h, iVal); - }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ - const u8 *z; - int n; - if( eType==SQLITE_TEXT ){ - z = (const u8 *)sqlite3_value_text(pVal); - }else{ - z = (const u8 *)sqlite3_value_blob(pVal); - } - n = sqlite3_value_bytes(pVal); - if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM; - h = sessionHashAppendBlob(h, n, z); - }else{ - assert( eType==SQLITE_NULL ); - assert( pTab->bStat1==0 || i!=1 ); - *pbNullPK = 1; - } + assert( *pbNullPK==0 ); + assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) ); + for(i=0; inCol; i++){ + if( pTab->abPK[i] ){ + int rc; + int eType; + sqlite3_value *pVal; + + if( bNew ){ + rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal); + }else{ + rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal); + } + if( rc!=SQLITE_OK ) return rc; + + eType = sqlite3_value_type(pVal); + h = sessionHashAppendType(h, eType); + if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ + i64 iVal; + if( eType==SQLITE_INTEGER ){ + iVal = sqlite3_value_int64(pVal); + }else{ + double rVal = sqlite3_value_double(pVal); + assert( sizeof(iVal)==8 && sizeof(rVal)==8 ); + memcpy(&iVal, &rVal, 8); + } + h = sessionHashAppendI64(h, iVal); + }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ + const u8 *z; + int n; + if( eType==SQLITE_TEXT ){ + z = (const u8 *)sqlite3_value_text(pVal); + }else{ + z = (const u8 *)sqlite3_value_blob(pVal); + } + n = sqlite3_value_bytes(pVal); + if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM; + h = sessionHashAppendBlob(h, n, z); + }else{ + assert( eType==SQLITE_NULL ); + assert( pTab->bStat1==0 || i!=1 ); + *pbNullPK = 1; } } } *piHash = (h % pTab->nChange); @@ -854,23 +844,17 @@ ** if the pre-update-hook does not affect the same row as pChange, it returns ** false. */ static int sessionPreupdateEqual( sqlite3_session *pSession, /* Session object that owns SessionTable */ - i64 iRowid, /* Rowid value if pTab->bRowid */ SessionTable *pTab, /* Table associated with change */ SessionChange *pChange, /* Change to compare to */ int op /* Current pre-update operation */ ){ int iCol; /* Used to iterate through columns */ u8 *a = pChange->aRecord; /* Cursor used to scan change record */ - if( pTab->bRowid ){ - if( a[0]!=SQLITE_INTEGER ) return 0; - return sessionGetI64(&a[1])==iRowid; - } - assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE ); for(iCol=0; iColnCol; iCol++){ if( !pTab->abPK[iCol] ){ a += sessionSerialLen(a); }else{ @@ -1011,12 +995,11 @@ const char *zDb, /* Name of attached database (e.g. "main") */ const char *zThis, /* Table name */ int *pnCol, /* OUT: number of columns */ const char **pzTab, /* OUT: Copy of zThis */ const char ***pazCol, /* OUT: Array of column names for table */ - u8 **pabPK, /* OUT: Array of booleans - true for PK col */ - int *pbRowid /* OUT: True if only PK is a rowid */ + u8 **pabPK /* OUT: Array of booleans - true for PK col */ ){ char *zPragma; sqlite3_stmt *pStmt; int rc; sqlite3_int64 nByte; @@ -1024,11 +1007,10 @@ int nThis; int i; u8 *pAlloc = 0; char **azCol = 0; u8 *abPK = 0; - int bRowid = 0; /* Set to true to use rowid as PK */ assert( pazCol && pabPK ); nThis = sqlite3Strlen30(zThis); if( nThis==12 && 0==sqlite3_stricmp("sqlite_stat1", zThis) ){ @@ -1069,19 +1051,14 @@ if( pzTab ) *pzTab = 0; return rc; } nByte = nThis + 1; - bRowid = (pbRowid!=0); while( SQLITE_ROW==sqlite3_step(pStmt) ){ nByte += sqlite3_column_bytes(pStmt, 1); nDbCol++; - if( sqlite3_column_int(pStmt, 5) ) bRowid = 0; } - if( nDbCol==0 ) bRowid = 0; - nDbCol += bRowid; - nByte += strlen(SESSIONS_ROWID); rc = sqlite3_reset(pStmt); if( rc==SQLITE_OK ){ nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1); pAlloc = sessionMalloc64(pSession, nByte); @@ -1099,18 +1076,10 @@ *pzTab = (char *)pAlloc; pAlloc += nThis+1; } i = 0; - if( bRowid ){ - size_t nName = strlen(SESSIONS_ROWID); - memcpy(pAlloc, SESSIONS_ROWID, nName+1); - azCol[i] = (char*)pAlloc; - pAlloc += nName+1; - abPK[i] = 1; - i++; - } while( SQLITE_ROW==sqlite3_step(pStmt) ){ int nName = sqlite3_column_bytes(pStmt, 1); const unsigned char *zName = sqlite3_column_text(pStmt, 1); if( zName==0 ) break; memcpy(pAlloc, zName, nName+1); @@ -1118,10 +1087,11 @@ pAlloc += nName+1; abPK[i] = sqlite3_column_int(pStmt, 5); i++; } rc = sqlite3_reset(pStmt); + } /* If successful, populate the output variables. Otherwise, zero them and ** free any allocation made. An error code will be returned in this case. */ @@ -1134,11 +1104,10 @@ *pabPK = 0; *pnCol = 0; if( pzTab ) *pzTab = 0; sessionFree(pSession, azCol); } - if( pbRowid ) *pbRowid = bRowid; sqlite3_finalize(pStmt); return rc; } /* @@ -1156,12 +1125,11 @@ static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){ if( pTab->nCol==0 ){ u8 *abPK; assert( pTab->azCol==0 || pTab->abPK==0 ); pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb, - pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK, - (pSession->bImplicitPK ? &pTab->bRowid : 0) + pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK ); if( pSession->rc==SQLITE_OK ){ int i; for(i=0; inCol; i++){ if( abPK[i] ){ @@ -1229,11 +1197,10 @@ SessionTable *pTab, /* Table that change applies to */ SessionChange *pC /* Update pC->nMaxSize */ ){ i64 nNew = 2; if( pC->op==SQLITE_INSERT ){ - if( pTab->bRowid ) nNew += 9; if( op!=SQLITE_DELETE ){ int ii; for(ii=0; iinCol; ii++){ sqlite3_value *p = 0; pSession->hook.xNew(pSession->hook.pCtx, ii, &p); @@ -1246,20 +1213,16 @@ nNew += pC->nRecord; } }else{ int ii; u8 *pCsr = pC->aRecord; - if( pTab->bRowid ){ - nNew += 9 + 1; - pCsr += 9; - } - for(ii=pTab->bRowid; iinCol; ii++){ + for(ii=0; iinCol; ii++){ int bChanged = 1; int nOld = 0; int eType; sqlite3_value *p = 0; - pSession->hook.xNew(pSession->hook.pCtx, ii-pTab->bRowid, &p); + pSession->hook.xNew(pSession->hook.pCtx, ii, &p); if( p==0 ){ return SQLITE_NOMEM; } eType = *pCsr++; @@ -1334,11 +1297,10 @@ ** Unless one is already present or an error occurs, an entry is added ** to the changed-rows hash table associated with table pTab. */ static void sessionPreupdateOneChange( int op, /* One of SQLITE_UPDATE, INSERT, DELETE */ - i64 iRowid, sqlite3_session *pSession, /* Session object pTab is attached to */ SessionTable *pTab /* Table that change applies to */ ){ int iHash; int bNull = 0; @@ -1350,11 +1312,11 @@ /* Load table details if required */ if( sessionInitTable(pSession, pTab) ) return; /* Check the number of columns in this xPreUpdate call matches the ** number of columns in the table. */ - if( (pTab->nCol-pTab->bRowid)!=pSession->hook.xCount(pSession->hook.pCtx) ){ + if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){ pSession->rc = SQLITE_SCHEMA; return; } /* Grow the hash table if required */ @@ -1383,20 +1345,18 @@ } /* Calculate the hash-key for this change. If the primary key of the row ** includes a NULL value, exit early. Such changes are ignored by the ** session module. */ - rc = sessionPreupdateHash( - pSession, iRowid, pTab, op==SQLITE_INSERT, &iHash, &bNull - ); + rc = sessionPreupdateHash(pSession, pTab, op==SQLITE_INSERT, &iHash, &bNull); if( rc!=SQLITE_OK ) goto error_out; if( bNull==0 ){ /* Search the hash table for an existing record for this row. */ SessionChange *pC; for(pC=pTab->apChange[iHash]; pC; pC=pC->pNext){ - if( sessionPreupdateEqual(pSession, iRowid, pTab, pC, op) ) break; + if( sessionPreupdateEqual(pSession, pTab, pC, op) ) break; } if( pC==0 ){ /* Create a new change object containing all the old values (if ** this is an SQLITE_UPDATE or SQLITE_DELETE), or just the PK @@ -1407,11 +1367,11 @@ assert( rc==SQLITE_OK ); pTab->nEntry++; /* Figure out how large an allocation is required */ nByte = sizeof(SessionChange); - for(i=0; i<(pTab->nCol-pTab->bRowid); i++){ + for(i=0; inCol; i++){ sqlite3_value *p = 0; if( op!=SQLITE_INSERT ){ TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p); assert( trc==SQLITE_OK ); }else if( pTab->abPK[i] ){ @@ -1422,13 +1382,10 @@ /* This may fail if SQLite value p contains a utf-16 string that must ** be converted to utf-8 and an OOM error occurs while doing so. */ rc = sessionSerializeValue(0, p, &nByte); if( rc!=SQLITE_OK ) goto error_out; } - if( pTab->bRowid ){ - nByte += 9; /* Size of rowid field - an integer */ - } /* Allocate the change object */ pC = (SessionChange *)sessionMalloc64(pSession, nByte); if( !pC ){ rc = SQLITE_NOMEM; @@ -1441,16 +1398,11 @@ /* Populate the change object. None of the preupdate_old(), ** preupdate_new() or SerializeValue() calls below may fail as all ** required values and encodings have already been cached in memory. ** It is not possible for an OOM to occur in this block. */ nByte = 0; - if( pTab->bRowid ){ - pC->aRecord[0] = SQLITE_INTEGER; - sessionPutI64(&pC->aRecord[1], iRowid); - nByte = 9; - } - for(i=0; i<(pTab->nCol-pTab->bRowid); i++){ + for(i=0; inCol; i++){ sqlite3_value *p = 0; if( op!=SQLITE_INSERT ){ pSession->hook.xOld(pSession->hook.pCtx, i, &p); }else if( pTab->abPK[i] ){ pSession->hook.xNew(pSession->hook.pCtx, i, &p); @@ -1561,14 +1513,13 @@ if( sqlite3_strnicmp(zDb, pSession->zDb, nDb+1) ) continue; pSession->rc = sessionFindTable(pSession, zName, &pTab); if( pTab ){ assert( pSession->rc==SQLITE_OK ); - assert( op==SQLITE_UPDATE || iKey1==iKey2 ); - sessionPreupdateOneChange(op, iKey1, pSession, pTab); + sessionPreupdateOneChange(op, pSession, pTab); if( op==SQLITE_UPDATE ){ - sessionPreupdateOneChange(SQLITE_INSERT, iKey2, pSession, pTab); + sessionPreupdateOneChange(SQLITE_INSERT, pSession, pTab); } } } } @@ -1603,30 +1554,29 @@ } typedef struct SessionDiffCtx SessionDiffCtx; struct SessionDiffCtx { sqlite3_stmt *pStmt; - int bRowid; int nOldOff; }; /* ** The diff hook implementations. */ static int sessionDiffOld(void *pCtx, int iVal, sqlite3_value **ppVal){ SessionDiffCtx *p = (SessionDiffCtx*)pCtx; - *ppVal = sqlite3_column_value(p->pStmt, iVal+p->nOldOff+p->bRowid); + *ppVal = sqlite3_column_value(p->pStmt, iVal+p->nOldOff); return SQLITE_OK; } static int sessionDiffNew(void *pCtx, int iVal, sqlite3_value **ppVal){ SessionDiffCtx *p = (SessionDiffCtx*)pCtx; - *ppVal = sqlite3_column_value(p->pStmt, iVal+p->bRowid); + *ppVal = sqlite3_column_value(p->pStmt, iVal); return SQLITE_OK; } static int sessionDiffCount(void *pCtx){ SessionDiffCtx *p = (SessionDiffCtx*)pCtx; - return (p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt)) - p->bRowid; + return p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt); } static int sessionDiffDepth(void *pCtx){ (void)pCtx; return 0; } @@ -1701,20 +1651,18 @@ } static char *sessionSelectFindNew( const char *zDb1, /* Pick rows in this db only */ const char *zDb2, /* But not in this one */ - int bRowid, const char *zTbl, /* Table name */ const char *zExpr ){ - const char *zSel = (bRowid ? SESSIONS_ROWID ", *" : "*"); char *zRet = sqlite3_mprintf( - "SELECT %s FROM \"%w\".\"%w\" WHERE NOT EXISTS (" + "SELECT * FROM \"%w\".\"%w\" WHERE NOT EXISTS (" " SELECT 1 FROM \"%w\".\"%w\" WHERE %s" ")", - zSel, zDb1, zTbl, zDb2, zTbl, zExpr + zDb1, zTbl, zDb2, zTbl, zExpr ); return zRet; } static int sessionDiffFindNew( @@ -1724,13 +1672,11 @@ const char *zDb1, const char *zDb2, char *zExpr ){ int rc = SQLITE_OK; - char *zStmt = sessionSelectFindNew( - zDb1, zDb2, pTab->bRowid, pTab->zName, zExpr - ); + char *zStmt = sessionSelectFindNew(zDb1, zDb2, pTab->zName,zExpr); if( zStmt==0 ){ rc = SQLITE_NOMEM; }else{ sqlite3_stmt *pStmt; @@ -1737,44 +1683,21 @@ rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0); if( rc==SQLITE_OK ){ SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx; pDiffCtx->pStmt = pStmt; pDiffCtx->nOldOff = 0; - pDiffCtx->bRowid = pTab->bRowid; while( SQLITE_ROW==sqlite3_step(pStmt) ){ - i64 iRowid = (pTab->bRowid ? sqlite3_column_int64(pStmt, 0) : 0); - sessionPreupdateOneChange(op, iRowid, pSession, pTab); + sessionPreupdateOneChange(op, pSession, pTab); } rc = sqlite3_finalize(pStmt); } sqlite3_free(zStmt); } return rc; } -/* -** Return a comma-separated list of the fully-qualified (with both database -** and table name) column names from table pTab. e.g. -** -** "main"."t1"."a", "main"."t1"."b", "main"."t1"."c" -*/ -static char *sessionAllCols( - const char *zDb, - SessionTable *pTab -){ - int ii; - char *zRet = 0; - for(ii=0; iinCol; ii++){ - zRet = sqlite3_mprintf("%z%s\"%w\".\"%w\".\"%w\"", - zRet, (zRet ? ", " : ""), zDb, pTab->zName, pTab->azCol[ii] - ); - if( !zRet ) break; - } - return zRet; -} - static int sessionDiffFindModified( sqlite3_session *pSession, SessionTable *pTab, const char *zFrom, const char *zExpr @@ -1785,17 +1708,15 @@ pSession->zDb, zFrom, pTab->zName, pTab->azCol, pTab->abPK ); if( zExpr2==0 ){ rc = SQLITE_NOMEM; }else{ - char *z1 = sessionAllCols(pSession->zDb, pTab); - char *z2 = sessionAllCols(zFrom, pTab); char *zStmt = sqlite3_mprintf( - "SELECT %s,%s FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)", - z1, z2, pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2 + "SELECT * FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)", + pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2 ); - if( zStmt==0 || z1==0 || z2==0 ){ + if( zStmt==0 ){ rc = SQLITE_NOMEM; }else{ sqlite3_stmt *pStmt; rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0); @@ -1802,19 +1723,16 @@ if( rc==SQLITE_OK ){ SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx; pDiffCtx->pStmt = pStmt; pDiffCtx->nOldOff = pTab->nCol; while( SQLITE_ROW==sqlite3_step(pStmt) ){ - i64 iRowid = (pTab->bRowid ? sqlite3_column_int64(pStmt, 0) : 0); - sessionPreupdateOneChange(SQLITE_UPDATE, iRowid, pSession, pTab); + sessionPreupdateOneChange(SQLITE_UPDATE, pSession, pTab); } rc = sqlite3_finalize(pStmt); } + sqlite3_free(zStmt); } - sqlite3_free(zStmt); - sqlite3_free(z1); - sqlite3_free(z2); } return rc; } @@ -1849,16 +1767,13 @@ /* Check the table schemas match */ if( rc==SQLITE_OK ){ int bHasPk = 0; int bMismatch = 0; int nCol; /* Columns in zFrom.zTbl */ - int bRowid = 0; u8 *abPK; const char **azCol = 0; - rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, &abPK, - pSession->bImplicitPK ? &bRowid : 0 - ); + rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, &abPK); if( rc==SQLITE_OK ){ if( pTo->nCol!=nCol ){ bMismatch = 1; }else{ int i; @@ -2196,14 +2111,13 @@ SessionBuffer *p, const char *zStr, int *pRc ){ int nStr = sqlite3Strlen30(zStr); - if( 0==sessionBufferGrow(p, nStr+1, pRc) ){ + if( 0==sessionBufferGrow(p, nStr, pRc) ){ memcpy(&p->aBuf[p->nBuf], zStr, nStr); p->nBuf += nStr; - p->aBuf[p->nBuf] = 0x00; } } /* ** This function is a no-op if *pRc is other than SQLITE_OK when it is @@ -2221,31 +2135,10 @@ char aBuf[24]; sqlite3_snprintf(sizeof(aBuf)-1, aBuf, "%d", iVal); sessionAppendStr(p, aBuf, pRc); } -static void sessionAppendPrintf( - SessionBuffer *p, /* Buffer to append to */ - int *pRc, - const char *zFmt, - ... -){ - if( *pRc==SQLITE_OK ){ - char *zApp = 0; - va_list ap; - va_start(ap, zFmt); - zApp = sqlite3_vmprintf(zFmt, ap); - if( zApp==0 ){ - *pRc = SQLITE_NOMEM; - }else{ - sessionAppendStr(p, zApp, pRc); - } - va_end(ap); - sqlite3_free(zApp); - } -} - /* ** This function is a no-op if *pRc is other than SQLITE_OK when it is ** called. Otherwise, append the string zStr enclosed in quotes (") and ** with any embedded quote characters escaped to the buffer. No ** nul-terminator byte is written. @@ -2256,11 +2149,11 @@ static void sessionAppendIdent( SessionBuffer *p, /* Buffer to a append to */ const char *zStr, /* String to quote, escape and append */ int *pRc /* IN/OUT: Error code */ ){ - int nStr = sqlite3Strlen30(zStr)*2 + 2 + 2; + int nStr = sqlite3Strlen30(zStr)*2 + 2 + 1; if( 0==sessionBufferGrow(p, nStr, pRc) ){ char *zOut = (char *)&p->aBuf[p->nBuf]; const char *zIn = zStr; *zOut++ = '"'; while( *zIn ){ @@ -2267,11 +2160,10 @@ if( *zIn=='"' ) *zOut++ = '"'; *zOut++ = *(zIn++); } *zOut++ = '"'; p->nBuf = (int)((u8 *)zOut - p->aBuf); - p->aBuf[p->nBuf] = 0x00; } } /* ** This function is a no-op if *pRc is other than SQLITE_OK when it is @@ -2403,11 +2295,11 @@ } /* If at least one field has been modified, this is not a no-op. */ if( bChanged ) bNoop = 0; - /* Add a field to the old.* record. This is omitted if this module is + /* Add a field to the old.* record. This is omitted if this modules is ** currently generating a patchset. */ if( bPatchset==0 ){ if( bChanged || abPK[i] ){ sessionAppendBlob(pBuf, pCsr, nAdvance, &rc); }else{ @@ -2492,82 +2384,33 @@ /* ** Formulate and prepare a SELECT statement to retrieve a row from table ** zTab in database zDb based on its primary key. i.e. ** -** SELECT *, FROM zDb.zTab WHERE (pk1, pk2,...) IS (?1, ?2,...) -** -** where is: -** -** 1 AND (?A OR ?1 IS ) AND ... -** -** for each non-pk . +** SELECT * FROM zDb.zTab WHERE pk1 = ? AND pk2 = ? AND ... */ static int sessionSelectStmt( sqlite3 *db, /* Database handle */ - int bIgnoreNoop, const char *zDb, /* Database name */ const char *zTab, /* Table name */ - int bRowid, int nCol, /* Number of columns in table */ const char **azCol, /* Names of table columns */ u8 *abPK, /* PRIMARY KEY array */ sqlite3_stmt **ppStmt /* OUT: Prepared SELECT statement */ ){ int rc = SQLITE_OK; char *zSql = 0; - const char *zSep = ""; - const char *zCols = bRowid ? SESSIONS_ROWID ", *" : "*"; int nSql = -1; - int i; - - SessionBuffer nooptest = {0, 0, 0}; - SessionBuffer pkfield = {0, 0, 0}; - SessionBuffer pkvar = {0, 0, 0}; - - sessionAppendStr(&nooptest, ", 1", &rc); - - if( 0==sqlite3_stricmp("sqlite_stat1", zTab) ){ - sessionAppendStr(&nooptest, " AND (?6 OR ?3 IS stat)", &rc); - sessionAppendStr(&pkfield, "tbl, idx", &rc); - sessionAppendStr(&pkvar, - "?1, (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", &rc - ); - zCols = "tbl, ?2, stat"; - }else{ - for(i=0; izDb, zName, &nCol, 0, &azCol, &abPK, - (pSession->bImplicitPK ? &bRowid : 0) - ); - if( rc==SQLITE_OK && ( - pTab->nCol!=nCol - || pTab->bRowid!=bRowid - || memcmp(abPK, pTab->abPK, nCol) - )){ + rc = sessionTableInfo(0, db, pSession->zDb, zName, &nCol, 0,&azCol,&abPK); + if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){ rc = SQLITE_SCHEMA; } /* Write a table header */ sessionAppendTableHdr(&buf, bPatchset, pTab, &rc); /* Build and compile a statement to execute: */ if( rc==SQLITE_OK ){ rc = sessionSelectStmt( - db, 0, pSession->zDb, zName, bRowid, nCol, azCol, abPK, &pSel - ); + db, pSession->zDb, zName, nCol, azCol, abPK, &pSel); } nNoop = buf.nBuf; for(i=0; inChange && rc==SQLITE_OK; i++){ SessionChange *p; /* Used to iterate through changes */ @@ -2844,11 +2674,11 @@ void **ppChangeset /* OUT: Buffer containing changeset */ ){ int rc; if( pnChangeset==0 || ppChangeset==0 ) return SQLITE_MISUSE; - rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset, ppChangeset); + rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset,ppChangeset); assert( rc || pnChangeset==0 || pSession->bEnableSize==0 || *pnChangeset<=pSession->nMaxChangesetSize ); return rc; } @@ -2962,23 +2792,10 @@ } *(int*)pArg = pSession->bEnableSize; break; } - case SQLITE_SESSION_OBJCONFIG_ROWID: { - int iArg = *(int*)pArg; - if( iArg>=0 ){ - if( pSession->pTable ){ - rc = SQLITE_MISUSE; - }else{ - pSession->bImplicitPK = (iArg!=0); - } - } - *(int*)pArg = pSession->bImplicitPK; - break; - } - default: rc = SQLITE_MISUSE; } return rc; @@ -3963,12 +3780,10 @@ int bInvertConstraints; /* Invert when iterating constraints buffer */ SessionBuffer constraints; /* Deferred constraints are stored here */ SessionBuffer rebase; /* Rebase information (if any) here */ u8 bRebaseStarted; /* If table header is already in rebase */ u8 bRebase; /* True to collect rebase information */ - u8 bIgnoreNoop; /* True to ignore no-op conflicts */ - int bRowid; }; /* Number of prepared UPDATE statements to cache. */ #define SESSION_UPDATE_CACHE_SZ 12 @@ -4215,14 +4030,12 @@ static int sessionSelectRow( sqlite3 *db, /* Database handle */ const char *zTab, /* Table name */ SessionApplyCtx *p /* Session changeset-apply context */ ){ - /* TODO */ - return sessionSelectStmt(db, p->bIgnoreNoop, - "main", zTab, p->bRowid, p->nCol, p->azCol, p->abPK, &p->pSelect - ); + return sessionSelectStmt( + db, "main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect); } /* ** Formulate and prepare an INSERT statement to add a record to table zTab. ** For example: @@ -4377,37 +4190,24 @@ ** new.* record to the SELECT statement. Or, if it points to a DELETE or ** UPDATE, bind values from the old.* record. */ static int sessionSeekToRow( sqlite3_changeset_iter *pIter, /* Changeset iterator */ - SessionApplyCtx *p + u8 *abPK, /* Primary key flags array */ + sqlite3_stmt *pSelect /* SELECT statement from sessionSelectRow() */ ){ - sqlite3_stmt *pSelect = p->pSelect; int rc; /* Return code */ int nCol; /* Number of columns in table */ int op; /* Changset operation (SQLITE_UPDATE etc.) */ const char *zDummy; /* Unused */ - sqlite3_clear_bindings(pSelect); sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0); rc = sessionBindRow(pIter, op==SQLITE_INSERT ? sqlite3changeset_new : sqlite3changeset_old, - nCol, p->abPK, pSelect + nCol, abPK, pSelect ); - if( op!=SQLITE_DELETE && p->bIgnoreNoop ){ - int ii; - for(ii=0; rc==SQLITE_OK && iiabPK[ii]==0 ){ - sqlite3_value *pVal = 0; - sqlite3changeset_new(pIter, ii, &pVal); - sqlite3_bind_int(pSelect, ii+1+nCol, (pVal==0)); - if( pVal ) rc = sessionBindValue(pSelect, ii+1, pVal); - } - } - } - if( rc==SQLITE_OK ){ rc = sqlite3_step(pSelect); if( rc!=SQLITE_ROW ) rc = sqlite3_reset(pSelect); } @@ -4518,26 +4318,20 @@ assert( SQLITE_CHANGESET_CONFLICT+1==SQLITE_CHANGESET_CONSTRAINT ); assert( SQLITE_CHANGESET_DATA+1==SQLITE_CHANGESET_NOTFOUND ); /* Bind the new.* PRIMARY KEY values to the SELECT statement. */ if( pbReplace ){ - rc = sessionSeekToRow(pIter, p); + rc = sessionSeekToRow(pIter, p->abPK, p->pSelect); }else{ rc = SQLITE_OK; } if( rc==SQLITE_ROW ){ /* There exists another row with the new.* primary key. */ - if( p->bIgnoreNoop - && sqlite3_column_int(p->pSelect, sqlite3_column_count(p->pSelect)-1) - ){ - res = SQLITE_CHANGESET_OMIT; - }else{ - pIter->pConflict = p->pSelect; - res = xConflict(pCtx, eType, pIter); - pIter->pConflict = 0; - } + pIter->pConflict = p->pSelect; + res = xConflict(pCtx, eType, pIter); + pIter->pConflict = 0; rc = sqlite3_reset(p->pSelect); }else if( rc==SQLITE_OK ){ if( p->bDeferConstraints && eType==SQLITE_CHANGESET_CONFLICT ){ /* Instead of invoking the conflict handler, append the change blob ** to the SessionApplyCtx.constraints buffer. */ @@ -4641,11 +4435,11 @@ } if( rc!=SQLITE_OK ) return rc; sqlite3_step(p->pDelete); rc = sqlite3_reset(p->pDelete); - if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 && p->bIgnoreNoop==0 ){ + if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){ rc = sessionConflictHandler( SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry ); }else if( (rc&0xff)==SQLITE_CONSTRAINT ){ rc = sessionConflictHandler( @@ -4698,11 +4492,11 @@ assert( op==SQLITE_INSERT ); if( p->bStat1 ){ /* Check if there is a conflicting row. For sqlite_stat1, this needs ** to be done using a SELECT, as there is no PRIMARY KEY in the ** database schema to throw an exception if a duplicate is inserted. */ - rc = sessionSeekToRow(pIter, p); + rc = sessionSeekToRow(pIter, p->abPK, p->pSelect); if( rc==SQLITE_ROW ){ rc = SQLITE_CONSTRAINT; sqlite3_reset(p->pSelect); } } @@ -4875,11 +4669,10 @@ pIter->in.bNoDiscard = 1; memset(&sApply, 0, sizeof(sApply)); sApply.bRebase = (ppRebase && pnRebase); sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); - sApply.bIgnoreNoop = !!(flags & SQLITE_CHANGESETAPPLY_IGNORENOOP); sqlite3_mutex_enter(sqlite3_db_mutex(db)); if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){ rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0); } if( rc==SQLITE_OK ){ @@ -4913,11 +4706,10 @@ sApply.azCol = 0; sApply.abPK = 0; sApply.bStat1 = 0; sApply.bDeferConstraints = 1; sApply.bRebaseStarted = 0; - sApply.bRowid = 0; memset(&sApply.constraints, 0, sizeof(SessionBuffer)); /* If an xFilter() callback was specified, invoke it now. If the ** xFilter callback returns zero, skip this table. If it returns ** non-zero, proceed. */ @@ -4933,12 +4725,12 @@ }else{ int nMinCol = 0; int i; sqlite3changeset_pk(pIter, &abPK, 0); - rc = sessionTableInfo(0, db, "main", zNew, - &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK, &sApply.bRowid + rc = sessionTableInfo(0, + db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK ); if( rc!=SQLITE_OK ) break; for(i=0; iSQLITE_SESSION_OBJCONFIG_SIZE
** This option is used to set, clear or query the flag that enables ** the [sqlite3session_changeset_size()] API. Because it imposes some @@ -107,25 +103,16 @@ ** variable is set to 1 if the sqlite3session_changeset_size() API is ** enabled following the current call, or 0 otherwise. ** ** It is an error (SQLITE_MISUSE) to attempt to modify this setting after ** the first table has been attached to the session object. -** -**
SQLITE_SESSION_OBJCONFIG_ROWID
-** This option is used to set, clear or query the flag that enables -** collection of data for tables with no explicit PRIMARY KEY. -** -** Normally, tables with no explicit PRIMARY KEY are simply ignored -** by the sessions module. However, if this flag is set, it behaves -** as if such tables have a column "_rowid_ INTEGER PRIMARY KEY" inserted -** as their leftmost columns. -** -** It is an error (SQLITE_MISUSE) to attempt to modify this setting after -** the first table has been attached to the session object. +*/ +int sqlite3session_object_config(sqlite3_session*, int op, void *pArg); + +/* */ -#define SQLITE_SESSION_OBJCONFIG_SIZE 1 -#define SQLITE_SESSION_OBJCONFIG_ROWID 2 +#define SQLITE_SESSION_OBJCONFIG_SIZE 1 /* ** CAPI3REF: Enable Or Disable A Session Object ** METHOD: sqlite3_session ** @@ -1254,27 +1241,13 @@ ** **
SQLITE_CHANGESETAPPLY_INVERT
** Invert the changeset before applying it. This is equivalent to inverting ** a changeset using sqlite3changeset_invert() before applying it. It is ** an error to specify this flag with a patchset. -** -**
SQLITE_CHANGESETAPPLY_IGNORENOOP
-** Do not invoke the conflict handler callback for any changes that -** would not actually modify the database even if they were applied. -** Specifically, this means that the conflict handler is not invoked -** for: -**
    -**
  • a delete change if the row being deleted cannot be found, -**
  • an update change if the modified fields are already set to -** their new values in the conflicting row, or -**
  • an insert change if all fields of the conflicting row match -** the row being inserted. -**
*/ #define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 #define SQLITE_CHANGESETAPPLY_INVERT 0x0002 -#define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004 /* ** CAPI3REF: Constants Passed To The Conflict Handler ** ** Values that may be passed as the second argument to a conflict-handler. Index: ext/session/test_session.c ================================================================== --- ext/session/test_session.c +++ ext/session/test_session.c @@ -74,15 +74,13 @@ int *pnChangeset, /* OUT: Size of changeset blob in bytes */ void **ppChangeset /* OUT: Pointer to changeset blob */ ){ sqlite3_session *pSession = 0; int rc; - int val = 1; /* Create a new session object */ rc = sqlite3session_create(db, "main", &pSession); - sqlite3session_object_config(pSession, SQLITE_SESSION_OBJCONFIG_ROWID, &val); /* Configure the session object to record changes to all tables */ if( rc==SQLITE_OK ) rc = sqlite3session_attach(pSession, NULL); /* Execute the SQL script */ @@ -260,11 +258,11 @@ { "table_filter", 1, "SCRIPT", }, /* 6 */ { "patchset", 0, "", }, /* 7 */ { "diff", 2, "FROMDB TBL", }, /* 8 */ { "memory_used", 0, "", }, /* 9 */ { "changeset_size", 0, "", }, /* 10 */ - { "object_config", 2, "OPTION INTEGER", }, /* 11 */ + { "object_config_size", 1, "INTEGER", }, /* 11 */ { 0 } }; int iSub; int rc; @@ -379,31 +377,19 @@ case 10: { sqlite3_int64 nSize = sqlite3session_changeset_size(pSession); Tcl_SetObjResult(interp, Tcl_NewWideIntObj(nSize)); break; } - case 11: { /* object_config */ - struct ObjConfOpt { - const char *zName; - int opt; - } aOpt[] = { - { "size", SQLITE_SESSION_OBJCONFIG_SIZE }, - { "rowid", SQLITE_SESSION_OBJCONFIG_ROWID }, - { 0, 0 } - }; - size_t sz = sizeof(aOpt[0]); - + case 11: { int rc; int iArg; - int iOpt; - if( Tcl_GetIndexFromObjStruct(interp,objv[2],aOpt,sz,"option",0,&iOpt) ){ + if( Tcl_GetIntFromObj(interp, objv[2], &iArg) ){ return TCL_ERROR; } - if( Tcl_GetIntFromObj(interp, objv[3], &iArg) ){ - return TCL_ERROR; - } - rc = sqlite3session_object_config(pSession, aOpt[iOpt].opt, &iArg); + rc = sqlite3session_object_config( + pSession, SQLITE_SESSION_OBJCONFIG_SIZE, &iArg + ); if( rc!=SQLITE_OK ){ extern const char *sqlite3ErrName(int); Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); }else{ Tcl_SetObjResult(interp, Tcl_NewIntObj(iArg)); @@ -805,35 +791,36 @@ int flags = 0; /* Flags for apply_v2() */ memset(&sStr, 0, sizeof(sStr)); sStr.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR); - /* Check for the -nosavepoint, -invert or -ignorenoop switches */ + /* Check for the -nosavepoint flag */ if( bV2 ){ - while( objc>1 ){ + if( objc>1 ){ const char *z1 = Tcl_GetString(objv[1]); int n = strlen(z1); if( n>1 && n<=12 && 0==sqlite3_strnicmp("-nosavepoint", z1, n) ){ flags |= SQLITE_CHANGESETAPPLY_NOSAVEPOINT; + objc--; + objv++; } - else if( n>2 && n<=7 && 0==sqlite3_strnicmp("-invert", z1, n) ){ + } + if( objc>1 ){ + const char *z1 = Tcl_GetString(objv[1]); + int n = strlen(z1); + if( n>1 && n<=7 && 0==sqlite3_strnicmp("-invert", z1, n) ){ flags |= SQLITE_CHANGESETAPPLY_INVERT; - } - else if( n>2 && n<=11 && 0==sqlite3_strnicmp("-ignorenoop", z1, n) ){ - flags |= SQLITE_CHANGESETAPPLY_IGNORENOOP; - }else{ - break; - } - objc--; - objv++; + objc--; + objv++; + } } } if( objc!=4 && objc!=5 ){ const char *zMsg; if( bV2 ){ - zMsg = "?-nosavepoint? ?-inverse? ?-ignorenoop? " + zMsg = "?-nosavepoint? ?-inverse? " "DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?"; }else{ zMsg = "DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?"; } Tcl_WrongNumArgs(interp, 1, objv, zMsg); Index: ext/wasm/GNUmakefile ================================================================== --- ext/wasm/GNUmakefile +++ ext/wasm/GNUmakefile @@ -42,21 +42,19 @@ # limited to: # # 1) Consolidate the code generation for sqlite3*.*js into a script # which generates the makefile code, rather than using $(call) and # $(eval), or at least centralize the setup of the numerous vars -# related to each build variant $(JS_BUILD_MODES). +# related to each build variant (vanilla, esm, bundler-friendly). # SHELL := $(shell which bash 2>/dev/null) MAKEFILE := $(lastword $(MAKEFILE_LIST)) CLEAN_FILES := DISTCLEAN_FILES := ./--dummy-- default: all release: oz -# JS_BUILD_MODES exists solely to reduce repetition in documentation -# below. -JS_BUILD_MODES := vanilla esm bunder-friendly node + # Emscripten SDK home dir and related binaries... EMSDK_HOME ?= $(word 1,$(wildcard $(HOME)/emsdk $(HOME)/src/emsdk)) emcc.bin ?= $(word 1,$(wildcard $(EMSDK_HOME)/upstream/emscripten/emcc) $(shell which emcc)) ifeq (,$(emcc.bin)) $(error Cannot find emcc.) @@ -145,31 +143,12 @@ endif ifeq (,$(wildcard $(dir.tmp))) dir._tmp := $(shell mkdir -p $(dir.tmp)) endif -######################################################################## -# Set up sqlite3.c and sqlite3.h... -# -# To build with SEE (https://sqlite.org/see), either put sqlite3-see.c -# in the top of this build tree or pass -# sqlite3.c=PATH_TO_sqlite3-see.c to the build. Note that only -# encryption modules with no 3rd-party dependencies will currently -# work here: AES256-OFB, AES128-OFB, and AES128-CCM. Not -# coincidentally, those 3 modules are included in the sqlite3-see.c -# bundle. -# -# A custom sqlite3.c must not have any spaces in its name. -sqlite3.canonical.c := $(dir.top)/sqlite3.c -sqlite3.c ?= $(firstword $(wildcard $(dir.top)/sqlite3-see.c) $(sqlite3.canonical.c)) +sqlite3.c := $(dir.top)/sqlite3.c sqlite3.h := $(dir.top)/sqlite3.h -ifeq (,$(shell grep sqlite3_activate_see $(sqlite3.c) 2>/dev/null)) - SQLITE_C_IS_SEE := 0 -else - SQLITE_C_IS_SEE := 1 - $(info This is an SEE build.) -endif # Most SQLITE_OPT flags are set in sqlite3-wasm.c but we need them # made explicit here for building speedtest1.c. SQLITE_OPT = \ -DSQLITE_ENABLE_FTS5 \ -DSQLITE_ENABLE_RTREE \ @@ -188,17 +167,14 @@ -DSQLITE_THREADSAFE=0 \ -DSQLITE_TEMP_STORE=3 \ -DSQLITE_OS_KV_OPTIONAL=1 \ '-DSQLITE_DEFAULT_UNIX_VFS="unix-none"' \ -DSQLITE_USE_URI=1 \ - -DSQLITE_WASM_ENABLE_C_TESTS \ - -DSQLITE_C=$(sqlite3.c) + -DSQLITE_WASM_ENABLE_C_TESTS -.NOTPARALLEL: $(sqlite3.h) -$(sqlite3.h): +$(sqlite3.c) $(sqlite3.h): $(MAKE) -C $(dir.top) sqlite3.c -$(sqlite3.c): $(sqlite3.h) .PHONY: clean distclean clean: -rm -f $(CLEAN_FILES) distclean: clean @@ -211,46 +187,17 @@ endif else $(info Development build. Use '$(MAKE) release' for a smaller release build.) endif -######################################################################## -# Adding custom C code via sqlite3_wasm_extra_init.c: -# -# If the canonical build process finds the file -# sqlite3_wasm_extra_init.c in the main wasm build directory, it -# arranges to include that file in the build of sqlite3.wasm and -# defines SQLITE_EXTRA_INIT=sqlite3_wasm_extra_init. -# -# sqlite3_wasm_extra_init() must be a function with this signature: -# -# int sqlite3_wasm_extra_init(const char *) -# -# and the sqlite3 library will call it with an argument of NULL one -# time during sqlite3_initialize(). If it returns non-0, -# initialization of the library will fail. -# -# The filename can be overridden with: -# -# make sqlite3_wasm_extra_init.c=my_custom_stuff.c -# -# See example_extra_init.c for an example implementation. -######################################################################## -sqlite3_wasm_extra_init.c ?= $(wildcard sqlite3_wasm_extra_init.c) -cflags.wasm_extra_init := -ifneq (,$(sqlite3_wasm_extra_init.c)) - $(info Enabling SQLITE_EXTRA_INIT via $(sqlite3_wasm_extra_init.c).) - cflags.wasm_extra_init := -DSQLITE_WASM_EXTRA_INIT -endif - # bin.version-info = binary to output various sqlite3 version info for # embedding in the JS files and in building the distribution zip file. # It must NOT be in $(dir.tmp) because we need it to survive the # cleanup process for the dist build to work properly. bin.version-info := $(dir.wasm)/version-info $(bin.version-info): $(dir.wasm)/version-info.c $(sqlite3.h) $(MAKEFILE) - $(CC) -O0 -I$(dir $(sqlite3.c)) -o $@ $< + $(CC) -O0 -I$(dir.top) -o $@ $< DISTCLEAN_FILES += $(bin.version-info) # bin.stripcomments is used for stripping C/C++-style comments from JS # files. The JS files contain large chunks of documentation which we # don't need for all builds. That app's -k flag is of particular @@ -304,11 +251,11 @@ endef # /end C-PP.FILTER ######################################################################## # cflags.common = C compiler flags for all builds -cflags.common := -I. -I$(dir $(sqlite3.c)) +cflags.common := -I. -I.. -I$(dir.top) # emcc.WASM_BIGINT = 1 for BigInt (C int64) support, else 0. The API # disables certain features if BigInt is not enabled and such builds # _are not tested_ on any regular basis. emcc.WASM_BIGINT ?= 1 @@ -347,18 +294,14 @@ # -Oz when small deliverable size is a priority. ######################################################################## # EXPORTED_FUNCTIONS.* = files for use with Emscripten's # -sEXPORTED_FUNCTION flag. -EXPORTED_FUNCTIONS.api.main := $(abspath $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-api) -EXPORTED_FUNCTIONS.api.in := $(EXPORTED_FUNCTIONS.api.main) -ifeq (1,$(SQLITE_C_IS_SEE)) - EXPORTED_FUNCTIONS.api.in += $(abspath $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-see) -endif +EXPORTED_FUNCTIONS.api.in := $(abspath $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-api) EXPORTED_FUNCTIONS.api := $(dir.tmp)/EXPORTED_FUNCTIONS.api -$(EXPORTED_FUNCTIONS.api): $(EXPORTED_FUNCTIONS.api.in) $(sqlite3.c) $(MAKEFILE) - cat $(EXPORTED_FUNCTIONS.api.in) > $@ +$(EXPORTED_FUNCTIONS.api): $(EXPORTED_FUNCTIONS.api.in) $(MAKEFILE) + cp $(EXPORTED_FUNCTIONS.api.in) $@ # sqlite3-license-version.js = generated JS file with the license # header and version info. sqlite3-license-version.js := $(dir.tmp)/sqlite3-license-version.js # sqlite3-license-version-header.js = JS file containing only the @@ -457,24 +400,18 @@ -sEXPORTED_RUNTIME_METHODS=wasmMemory # wasmMemory ==> required by our code for use with -sIMPORTED_MEMORY emcc.jsflags += $(emcc.exportedRuntimeMethods) emcc.jsflags += -sUSE_CLOSURE_COMPILER=0 emcc.jsflags += -sIMPORTED_MEMORY -emcc.jsflags += -sSTRICT_JS=0 -# STRICT_JS disabled due to: -# https://github.com/emscripten-core/emscripten/issues/18610 -# TL;DR: does not work with MODULARIZE or EXPORT_ES6 as of version 3.1.31. - -# -sENVIRONMENT values for the various build modes: -emcc.environment.vanilla := web,worker -emcc.environment.bundler-friendly := $(emcc.environment.vanilla) -emcc.environment.esm := $(emcc.environment.vanilla) -emcc.environment.node := node -# Note that adding "node" to the list for the other builds causes -# Emscripten to generate code which confuses node: it cannot reliably -# determine whether the build is for a browser or for node. - +ifeq (3.1.31,$(emcc.version)) + emcc.jsflags += -sSTRICT_JS=0 + $(warning Disabling -sSTRICT_JS for emcc $(emcc.version): \ + https://github.com/emscripten-core/emscripten/issues/18610) +else + emcc.jsflags += -sSTRICT_JS=1 +endif +emcc.environment := -sENVIRONMENT=web,worker ######################################################################## # -sINITIAL_MEMORY: How much memory we need to start with is governed # at least in part by whether -sALLOW_MEMORY_GROWTH is enabled. If so, # we can start with less. If not, we need as much as we'll ever # possibly use (which, of course, we can't know for sure). Note, @@ -483,13 +420,13 @@ # at runtime. e.g. OPFS-backed (speedtest1 --size 75) take MAY take X # time with 16mb+ memory and 3X time when starting with 8MB. However, # such test results are inconsistent due to browser internals which # are opaque to us. emcc.jsflags += -sALLOW_MEMORY_GROWTH -emcc.INITIAL_MEMORY.128 := 134217728 +emcc.INITIAL_MEMORY.128 := 13107200 emcc.INITIAL_MEMORY.96 := 100663296 -emcc.INITIAL_MEMORY.64 := 67108864 +emcc.INITIAL_MEMORY.64 := 64225280 emcc.INITIAL_MEMORY.32 := 33554432 emcc.INITIAL_MEMORY.16 := 16777216 emcc.INITIAL_MEMORY.8 := 8388608 emcc.INITIAL_MEMORY ?= 16 ifeq (,$(emcc.INITIAL_MEMORY.$(emcc.INITIAL_MEMORY))) @@ -502,12 +439,10 @@ emcc.jsflags += $(emcc.environment) emcc.jsflags += -sSTACK_SIZE=512KB # ^^^ ACHTUNG: emsdk 3.1.27 reduced the default stack size from 5MB to # a mere 64KB, which leads to silent memory corruption via the kvvfs # VFS, which requires twice that for its xRead() and xWrite() methods. -# 2023-03: those methods have since been adapted to use a malloc()'d -# buffer. ######################################################################## # $(sqlite3.js.init-func) is the name Emscripten assigns our exported # module init/load function. This symbol name is hard-coded in # $(extern-post-js.js) as well as in numerous docs. # @@ -572,11 +507,11 @@ ######################################################################## $(sqlite3-api-build-version.js): $(bin.version-info) $(MAKEFILE) @echo "Making $@..." @{ \ - echo 'globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){'; \ + echo 'self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){'; \ echo -n ' sqlite3.version = '; \ $(bin.version-info) --json; \ echo ';'; \ echo '});'; \ } > $@ @@ -614,15 +549,14 @@ ######################################################################## # call-make-pre-post is a $(call)able which creates rules for # pre-js-$(1).js. $1 = the base name of the JS file on whose behalf -# this pre-js is for (one of: sqlite3, sqlite3-wasmfs). $2 is the -# build mode: one of $(JS_BUILD_MODES). This -# sets up --[extern-][pre/post]-js flags in -# $(pre-post-$(1).flags.$(2)) and dependencies in -# $(pre-post-$(1).deps.$(2)). +# this pre-js is for (one of: sqlite3, sqlite3-wasmfs). $2 is the build +# mode: one of (vanilla, esm, bundler-friendly). This sets up +# --[extern-][pre/post]-js flags in $(pre-post-$(1).flags.$(2)) and +# dependencies in $(pre-post-$(1).deps.$(2)). define call-make-pre-post pre-post-$(1).flags.$(2) ?= $$(dir.tmp)/pre-js-$(1)-$(2).js: $$(pre-js.js.$(2)) $$(MAKEFILE) cp $$(pre-js.js.$(2)) $$@ @if [ sqlite3-wasmfs = $(1) ]; then \ @@ -643,11 +577,10 @@ # Undocumented Emscripten feature: if the target file extension is # "mjs", it defaults to ES6 module builds: # https://github.com/emscripten-core/emscripten/issues/14383 sqlite3.wasm := $(dir.dout)/sqlite3.wasm sqlite3-wasm.c := $(dir.api)/sqlite3-wasm.c -sqlite3-wasm.cses := $(sqlite3-wasm.c) $(sqlite3_wasm_extra_init.c) # sqlite3-wasm.o vs sqlite3-wasm.c: building against the latter # (predictably) results in a slightly faster binary. We're close # enough to the target speed requirements that the 500ms makes a # difference, so we build all binaries against sqlite3-wasm.c instead # of building a shared copy of sqlite3-wasm.o to link against. @@ -691,24 +624,22 @@ # pre-post-jses.deps.* = a list of dependencies for the # --[extern-][pre/post]-js files. pre-post-jses.deps.common := $(extern-pre-js.js) $(sqlite3-license-version.js) ######################################################################## # SETUP_LIB_BUILD_MODE is a $(call)'able which sets up numerous pieces -# for one of the build modes. +# for one of the build modes (vanilla, esm, bundler-friendly). # -# $1 = build mode name: one of $(JS_BUILD_MODES) +# $1 = build mode name # $2 = 1 for ESM build mode, else 0 # $3 = resulting sqlite-api JS/MJS file # $4 = resulting JS/MJS file # $5 = -D... flags for $(bin.c-pp) -# $6 = emcc -sXYZ flags (CURRENTLY UNUSED - was factored out) -# -# emcc.environment.$(1) must be set to a value for the -sENVIRONMENT flag. +# $6 = emcc -sXYZ flags define SETUP_LIB_BUILD_MODE $(info Setting up build [$(1)]: $(4)) c-pp.D.$(1) := $(5) -pre-js.js.$(1) := $$(dir.tmp)/pre-js.$(1).js +pre-js.js.$(1) := $$(dir.api)/pre-js.$(1).js $$(eval $$(call C-PP.FILTER,$$(pre-js.js.in),$$(pre-js.js.$(1)),$$(c-pp.D.$(1)))) post-js.js.$(1) := $$(dir.tmp)/post-js.$(1).js $$(eval $$(call C-PP.FILTER,$$(post-js.js.in),$$(post-js.js.$(1)),$$(c-pp.D.$(1)))) extern-post-js.js.$(1) := $$(dir.tmp)/extern-post-js.$(1).js $$(eval $$(call C-PP.FILTER,$$(extern-post-js.js.in),$$(extern-post-js.js.$(1)),$$(c-pp.D.$(1)))) @@ -719,25 +650,23 @@ pre-post-jses.deps.$(1) := $$(pre-post-jses.deps.common) \ $$(post-js.js.$(1)) $$(extern-post-js.js.$(1)) $$(eval $$(call call-make-pre-post,sqlite3,$(1))) emcc.flags.sqlite3.$(1) := $(6) $$(eval $$(call C-PP.FILTER, $$(sqlite3-api.js.in), $(3), $(5))) -$(4): $(3) $$(MAKEFILE) $$(sqlite3-wasm.cses) $$(EXPORTED_FUNCTIONS.api) $$(pre-post-sqlite3.deps.$(1)) +$(4): $(3) +$(4): $(3) $$(MAKEFILE) $$(sqlite3-wasm.c) $$(EXPORTED_FUNCTIONS.api) $$(pre-post-sqlite3.deps.$(1)) @echo "Building $$@ ..." $$(emcc.bin) -o $$@ $$(emcc_opt_full) $$(emcc.flags) \ $$(emcc.jsflags) \ - -sENVIRONMENT=$$(emcc.environment.$(1)) \ $$(pre-post-sqlite3.flags.$(1)) $$(emcc.flags.sqlite3.$(1)) \ - $$(cflags.common) $$(SQLITE_OPT) $$(cflags.wasm_extra_init) $$(sqlite3-wasm.cses) + $$(cflags.common) $$(SQLITE_OPT) $$(sqlite3-wasm.c) @$$(call SQLITE3.xJS.ESM-EXPORT-DEFAULT,$(2)) - @case $(1) in \ - bundler-friendly|node) \ - echo "Patching $(3) for sqlite3.wasm..."; \ - rm -f $$(dir.dout)/sqlite3-$(1).wasm; \ - sed -i -e 's/sqlite3-$(1).wasm/sqlite3.wasm/g' $$@ || exit $$$$?; \ - ;; \ - esac + @if [ bundler-friendly = $(1) ]; then \ + echo "Patching $(3) for sqlite3.wasm..."; \ + rm -f $$(dir.dout)/sqlite3-bundler-friendly.wasm; \ + sed -i -e 's/sqlite3-bundler-friendly.wasm/sqlite3.wasm/g' $$@ || exit $$$$?; \ + fi chmod -x $$(sqlite3.wasm) $$(maybe-wasm-strip) $$(sqlite3.wasm) @ls -la $@ $$(sqlite3.wasm) all: $(4) quick: $(4) @@ -749,23 +678,18 @@ sqlite3.js := $(dir.dout)/sqlite3.js sqlite3-api.mjs := $(dir.dout)/sqlite3-api.mjs sqlite3.mjs := $(dir.dout)/sqlite3.mjs sqlite3-api-bundler-friendly.mjs := $(dir.dout)/sqlite3-api-bundler-friendly.mjs sqlite3-bundler-friendly.mjs := $(dir.dout)/sqlite3-bundler-friendly.mjs -sqlite3-api-node.mjs := $(dir.dout)/sqlite3-api-node.mjs -sqlite3-node.mjs := $(dir.dout)/sqlite3-node.mjs # Maintenance reminder: careful not to introduce spaces around args $1, $2 #$(info $(call SETUP_LIB_BUILD_MODE,vanilla,0, $(sqlite3-api.js), $(sqlite3.js))) $(eval $(call SETUP_LIB_BUILD_MODE,vanilla,0, $(sqlite3-api.js), $(sqlite3.js))) $(eval $(call SETUP_LIB_BUILD_MODE,esm,1, $(sqlite3-api.mjs), $(sqlite3.mjs), \ -Dtarget=es6-module, -sEXPORT_ES6 -sUSE_ES6_IMPORT_META)) $(eval $(call SETUP_LIB_BUILD_MODE,bundler-friendly,1,\ $(sqlite3-api-bundler-friendly.mjs),$(sqlite3-bundler-friendly.mjs),\ - $(c-pp.D.esm) -Dtarget=es6-bundler-friendly)) -$(eval $(call SETUP_LIB_BUILD_MODE,node,1,\ - $(sqlite3-api-node.mjs),$(sqlite3-node.mjs),\ - $(c-pp.D.bundler-friendly) -Dtarget=node)) + $(c-pp.D.esm) -Dtarget=es6-bundler-friendly, $(emcc.flags.sqlite3.esm))) # The various -D... values used by *.c-pp.js include: # # -Dtarget=es6-module: for all ESM module builds # # -Dtarget=es6-module -Dtarget=es6-bundler-friendly: intended for @@ -773,30 +697,22 @@ # on how URL() objects are constructed in some contexts: URLs which # refer to files which are part of this project must be references # as string literals so that bundlers' static-analysis tools can # find those files and include them in their bundles. # -# -Dtarget=es6-module -Dtarget=es6-bundler-friendly -Dtarget=node: is -# intended for use by node.js for node.js, as opposed to by -# node.js on behalf of a browser. Mixing -sENVIRONMENT=web and -# -sENVIRONMENT=node leads to ambiguity and confusion on node's -# part, as it's unable to reliably determine whether the target is -# a browser or node. -# ######################################################################## ######################################################################## -# We have to ensure that we do not build $(sqlite3*.*js) in parallel -# because they all result in the creation of $(sqlite3.wasm). We have -# no way to build just a .[m]js file without also building the .wasm -# file because the generated .[m]js file has to include info about the -# imports needed by the wasm file, so they have to be built +# We have to ensure that we do not build both $(sqlite3*.*js) in +# parallel because both result in the creation of $(sqlite3.wasm). We +# have no way to build just the .mjs file without also building the +# .wasm file because the generated .mjs file has to include info about +# the imports needed by the wasm file, so they have to be built # together. i.e. we're building $(sqlite3.wasm) multiple times, but # that's unavoidable (and harmless, just a waste of build time). $(sqlite3.wasm): $(sqlite3.js) $(sqlite3.mjs): $(sqlite3.js) $(sqlite3-bundler-friendly.mjs): $(sqlite3.mjs) -$(sqlite3-node.mjs): $(sqlite3.mjs) CLEAN_FILES += $(sqlite3.wasm) ######################################################################## # We need separate copies of certain supplementary JS files for the # bundler-friendly build. Concretely, any supplemental JS files which @@ -805,11 +721,11 @@ # copy. sqlite3-worker1.js.in := $(dir.api)/sqlite3-worker1.c-pp.js sqlite3-worker1-promiser.js.in := $(dir.api)/sqlite3-worker1-promiser.c-pp.js sqlite3-worker1.js := $(dir.dout)/sqlite3-worker1.js sqlite3-worker1-promiser.js := $(dir.dout)/sqlite3-worker1-promiser.js -sqlite3-worker1-bundler-friendly.js := $(dir.dout)/sqlite3-worker1-bundler-friendly.mjs +sqlite3-worker1-bundler-friendly.js := $(dir.dout)/sqlite3-worker1-bundler-friendly.js sqlite3-worker1-promiser-bundler-friendly.js := $(dir.dout)/sqlite3-worker1-promiser-bundler-friendly.js $(eval $(call C-PP.FILTER,$(sqlite3-worker1.js.in),$(sqlite3-worker1.js))) $(eval $(call C-PP.FILTER,$(sqlite3-worker1.js.in),$(sqlite3-worker1-bundler-friendly.js),\ $(c-pp.D.bundler-friendly))) $(eval $(call C-PP.FILTER,$(sqlite3-worker1-promiser.js.in),$(sqlite3-worker1-promiser.js))) @@ -854,11 +770,11 @@ emcc.speedtest1 += -sALLOW_MEMORY_GROWTH emcc.speedtest1 += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.$(emcc.INITIAL_MEMORY)) emcc.speedtest1.common += -sINVOKE_RUN=0 emcc.speedtest1.common += --no-entry emcc.speedtest1.common += -sABORTING_MALLOC -emcc.speedtest1.common += -sSTRICT_JS=0 +emcc.speedtest1.common += -sSTRICT_JS emcc.speedtest1.common += -sMODULARIZE emcc.speedtest1.common += -Wno-limited-postlink-optimizations EXPORTED_FUNCTIONS.speedtest1 := $(abspath $(dir.tmp)/EXPORTED_FUNCTIONS.speedtest1) emcc.speedtest1.common += -sSTACK_SIZE=512KB emcc.speedtest1.common += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.speedtest1) @@ -885,13 +801,13 @@ # and pending output is not flushed because it didn't end with a # newline (by design). The lesser of the two evils seems to be # -sEXIT_RUNTIME=1 but we need EXIT_RUNTIME=0 for the worker-based app # which runs speedtest1 multiple times. -$(EXPORTED_FUNCTIONS.speedtest1): $(EXPORTED_FUNCTIONS.api.main) +$(EXPORTED_FUNCTIONS.speedtest1): $(EXPORTED_FUNCTIONS.api) @echo "Making $@ ..." - @{ echo _wasm_main; cat $(EXPORTED_FUNCTIONS.api.main); } > $@ + @{ echo _wasm_main; cat $(EXPORTED_FUNCTIONS.api); } > $@ speedtest1.js := $(dir.dout)/speedtest1.js speedtest1.wasm := $(dir.dout)/speedtest1.wasm cflags.speedtest1 := $(cflags.common) -DSQLITE_SPEEDTEST1_WASM speedtest1.cses := $(speedtest1.c) $(sqlite3-wasm.c) $(eval $(call call-make-pre-post,speedtest1,vanilla)) @@ -898,15 +814,13 @@ $(speedtest1.js): $(MAKEFILE) $(speedtest1.cses) \ $(pre-post-speedtest1.deps.vanilla) \ $(EXPORTED_FUNCTIONS.speedtest1) @echo "Building $@ ..." $(emcc.bin) \ - $(emcc.speedtest1) -I$(dir $(sqlite3.canonical.c)) \ - $(emcc.speedtest1.common) \ + $(emcc.speedtest1) $(emcc.speedtest1.common) \ $(cflags.speedtest1) $(pre-post-speedtest1.flags.vanilla) \ $(SQLITE_OPT) \ - -USQLITE_C -DSQLITE_C=$(sqlite3.canonical.c) \ $(speedtest1.exit-runtime0) \ -o $@ $(speedtest1.cses) -lm $(maybe-wasm-strip) $(speedtest1.wasm) ls -la $@ $(speedtest1.wasm) DELETED ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-see Index: ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-see ================================================================== --- ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-see +++ /dev/null @@ -1,5 +0,0 @@ -_sqlite3_key -_sqlite3_key_v2 -_sqlite3_rekey -_sqlite3_rekey_v2 -_sqlite3_activate_see Index: ext/wasm/api/extern-post-js.c-pp.js ================================================================== --- ext/wasm/api/extern-post-js.c-pp.js +++ ext/wasm/api/extern-post-js.c-pp.js @@ -26,11 +26,11 @@ const originalInit = /* Maintenance reminder: DO NOT use `self.` here. It's correct for non-ES6 Module cases but wrong for ES6 modules because those resolve this symbol differently. */ sqlite3InitModule; if(!originalInit){ - throw new Error("Expecting globalThis.sqlite3InitModule to be defined by the Emscripten build."); + throw new Error("Expecting self.sqlite3InitModule to be defined by the Emscripten build."); } /** We need to add some state which our custom Module.locateFile() can see, but an Emscripten limitation currently prevents us from attaching it to the sqlite3InitModule function object: @@ -39,17 +39,15 @@ The only(?) current workaround is to temporarily stash this state into the global scope and delete it when sqlite3InitModule() is called. */ - const initModuleState = globalThis.sqlite3InitModuleState = Object.assign(Object.create(null),{ - moduleScript: globalThis?.document?.currentScript, + const initModuleState = self.sqlite3InitModuleState = Object.assign(Object.create(null),{ + moduleScript: self?.document?.currentScript, isWorker: ('undefined' !== typeof WorkerGlobalScope), - location: globalThis.location, - urlParams: globalThis?.location?.href - ? new URL(globalThis.location.href).searchParams - : new URLSearchParams() + location: self.location, + urlParams: new URL(self.location.href).searchParams }); initModuleState.debugModule = initModuleState.urlParams.has('sqlite3.debugModule') ? (...args)=>console.warn('sqlite3.debugModule:',...args) : ()=>{}; @@ -60,18 +58,18 @@ const li = initModuleState.moduleScript.src.split('/'); li.pop(); initModuleState.sqlite3Dir = li.join('/') + '/'; } - globalThis.sqlite3InitModule = function ff(...args){ - //console.warn("Using replaced sqlite3InitModule()",globalThis.location); + self.sqlite3InitModule = function ff(...args){ + //console.warn("Using replaced sqlite3InitModule()",self.location); return originalInit(...args).then((EmscriptenModule)=>{ - if('undefined'!==typeof WorkerGlobalScope && + if(self.window!==self && (EmscriptenModule['ENVIRONMENT_IS_PTHREAD'] || EmscriptenModule['_pthread_self'] || 'function'===typeof threadAlert - || globalThis?.location?.pathname?.endsWith?.('.worker.js') + || self.location.pathname.endsWith('.worker.js') )){ /** Workaround for wasmfs-generated worker, which calls this routine from each individual thread and requires that its argument be returned. All of the criteria above are fragile, based solely on inspection of the offending code, not public @@ -88,22 +86,22 @@ }).catch((e)=>{ console.error("Exception loading sqlite3 module:",e); throw e; }); }; - globalThis.sqlite3InitModule.ready = originalInit.ready; + self.sqlite3InitModule.ready = originalInit.ready; - if(globalThis.sqlite3InitModuleState.moduleScript){ - const sim = globalThis.sqlite3InitModuleState; + if(self.sqlite3InitModuleState.moduleScript){ + const sim = self.sqlite3InitModuleState; let src = sim.moduleScript.src.split('/'); src.pop(); sim.scriptDir = src.join('/') + '/'; } initModuleState.debugModule('sqlite3InitModuleState =',initModuleState); if(0){ console.warn("Replaced sqlite3InitModule()"); - console.warn("globalThis.location.href =",globalThis.location.href); + console.warn("self.location.href =",self.location.href); if('undefined' !== typeof document){ console.warn("document.currentScript.src =", document?.currentScript?.src); } } @@ -119,10 +117,10 @@ exports["sqlite3InitModule"] = sqlite3InitModule; } /* AMD modules get injected in a way we cannot override, so we can't handle those here. */ //#endif // !target=es6-module - return globalThis.sqlite3InitModule /* required for ESM */; + return self.sqlite3InitModule /* required for ESM */; })(); //#if target=es6-module export default toExportForESM; //#endif Index: ext/wasm/api/pre-js.c-pp.js ================================================================== --- ext/wasm/api/pre-js.c-pp.js +++ ext/wasm/api/pre-js.c-pp.js @@ -4,16 +4,16 @@ This file is intended to be prepended to the sqlite3.js build using Emscripten's --pre-js=THIS_FILE flag (or equivalent). */ // See notes in extern-post-js.js -const sqlite3InitModuleState = globalThis.sqlite3InitModuleState +const sqlite3InitModuleState = self.sqlite3InitModuleState || Object.assign(Object.create(null),{ debugModule: ()=>{} }); -delete globalThis.sqlite3InitModuleState; -sqlite3InitModuleState.debugModule('globalThis.location =',globalThis.location); +delete self.sqlite3InitModuleState; +sqlite3InitModuleState.debugModule('self.location =',self.location); //#ifnot target=es6-bundler-friendly /** This custom locateFile() tries to figure out where to load `path` from. The intent is to provide a way for foo/bar/X.js loaded from a Index: ext/wasm/api/sqlite3-api-cleanup.js ================================================================== --- ext/wasm/api/sqlite3-api-cleanup.js +++ ext/wasm/api/sqlite3-api-cleanup.js @@ -23,39 +23,39 @@ const SABC = Object.assign( Object.create(null), { exports: Module['asm'], memory: Module.wasmMemory /* gets set if built with -sIMPORT_MEMORY */ }, - globalThis.sqlite3ApiConfig || {} + self.sqlite3ApiConfig || {} ); /** For current (2022-08-22) purposes, automatically call sqlite3ApiBootstrap(). That decision will be revisited at some point, as we really want client code to be able to call this to configure certain parts. Clients may modify - globalThis.sqlite3ApiBootstrap.defaultConfig to tweak the default + self.sqlite3ApiBootstrap.defaultConfig to tweak the default configuration used by a no-args call to sqlite3ApiBootstrap(), but must have first loaded their WASM module in order to be able to provide the necessary configuration state. */ - //console.warn("globalThis.sqlite3ApiConfig = ",globalThis.sqlite3ApiConfig); - globalThis.sqlite3ApiConfig = SABC; + //console.warn("self.sqlite3ApiConfig = ",self.sqlite3ApiConfig); + self.sqlite3ApiConfig = SABC; let sqlite3; try{ - sqlite3 = globalThis.sqlite3ApiBootstrap(); + sqlite3 = self.sqlite3ApiBootstrap(); }catch(e){ console.error("sqlite3ApiBootstrap() error:",e); throw e; }finally{ - delete globalThis.sqlite3ApiBootstrap; - delete globalThis.sqlite3ApiConfig; + delete self.sqlite3ApiBootstrap; + delete self.sqlite3ApiConfig; } Module.sqlite3 = sqlite3 /* Needed for customized sqlite3InitModule() to be able to pass the sqlite3 object off to the client. */; }else{ console.warn("This is not running in an Emscripten module context, so", - "globalThis.sqlite3ApiBootstrap() is _not_ being called due to lack", + "self.sqlite3ApiBootstrap() is _not_ being called due to lack", "of config info for the WASM environment.", "It must be called manually."); } Index: ext/wasm/api/sqlite3-api-glue.js ================================================================== --- ext/wasm/api/sqlite3-api-glue.js +++ ext/wasm/api/sqlite3-api-glue.js @@ -14,17 +14,17 @@ previous steps of the sqlite3-api.js bootstrapping process: sqlite3-api-prologue.js, whwasmutil.js, and jaccwabyt.js. It initializes the main API pieces so that the downstream components (e.g. sqlite3-api-oo1.js) have all that they need. */ -globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ +self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ 'use strict'; const toss = (...args)=>{throw new Error(args.join(' '))}; const toss3 = sqlite3.SQLite3Error.toss; const capi = sqlite3.capi, wasm = sqlite3.wasm, util = sqlite3.util; - globalThis.WhWasmUtilInstaller(wasm); - delete globalThis.WhWasmUtilInstaller; + self.WhWasmUtilInstaller(wasm); + delete self.WhWasmUtilInstaller; if(0){ /** Please keep this block around as a maintenance reminder that we cannot rely on this type of check. @@ -325,19 +325,10 @@ build-time function-export list does not currently take optional features into account. */ wasm.bindingSignatures.push(["sqlite3_normalized_sql", "string", "sqlite3_stmt*"]); } - if(wasm.exports.sqlite3_activate_see instanceof Function){ - wasm.bindingSignatures.push( - ["sqlite3_key", "int", "sqlite3*", "string", "int"], - ["sqlite3_key_v2","int","sqlite3*","string","*","int"], - ["sqlite3_rekey", "int", "sqlite3*", "string", "int"], - ["sqlite3_rekey_v2", "int", "sqlite3*", "string", "*", "int"], - ["sqlite3_activate_see", undefined, "string"] - ); - } /** Functions which require BigInt (int64) support are separated from the others because we need to conditionally bind them or apply dummy impls, depending on the capabilities of the environment. @@ -612,19 +603,19 @@ ]; /** Install JS<->C struct bindings for the non-opaque struct types we need... */ - sqlite3.StructBinder = globalThis.Jaccwabyt({ + sqlite3.StructBinder = self.Jaccwabyt({ heap: 0 ? wasm.memory : wasm.heap8u, alloc: wasm.alloc, dealloc: wasm.dealloc, bigIntEnabled: wasm.bigIntEnabled, memberPrefix: /* Never change this: this prefix is baked into any amount of code and client-facing docs. */ '$' }); - delete globalThis.Jaccwabyt; + delete self.Jaccwabyt; {// wasm.xWrap() bindings... /* Convert Arrays and certain TypedArrays to strings for 'string:flexible'-type arguments */ Index: ext/wasm/api/sqlite3-api-oo1.js ================================================================== --- ext/wasm/api/sqlite3-api-oo1.js +++ ext/wasm/api/sqlite3-api-oo1.js @@ -10,13 +10,13 @@ *********************************************************************** This file contains the so-called OO #1 API wrapper for the sqlite3 WASM build. It requires that sqlite3-api-glue.js has already run - and it installs its deliverable as globalThis.sqlite3.oo1. + and it installs its deliverable as self.sqlite3.oo1. */ -globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ +self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ const toss = (...args)=>{throw new Error(args.join(' '))}; const toss3 = (...args)=>{throw new sqlite3.SQLite3Error(...args)}; const capi = sqlite3.capi, wasm = sqlite3.wasm, util = sqlite3.util; /* What follows is colloquially known as "OO API #1". It is a Index: ext/wasm/api/sqlite3-api-prologue.js ================================================================== --- ext/wasm/api/sqlite3-api-prologue.js +++ ext/wasm/api/sqlite3-api-prologue.js @@ -27,11 +27,11 @@ /** sqlite3ApiBootstrap() is the only global symbol persistently exposed by this API. It is intended to be called one time at the end of the API amalgamation process, passed configuration details for the current environment, and then optionally be removed from - the global object using `delete globalThis.sqlite3ApiBootstrap`. + the global object using `delete self.sqlite3ApiBootstrap`. This function is not intended for client-level use. It is intended for use in creating bundles configured for specific WASM environments. @@ -56,11 +56,11 @@ to `Module.wasmMemory` if the build uses `-sIMPORT_MEMORY`, or be left undefined/falsy to default to `exports.memory` when using WASM-exported memory. - `bigIntEnabled`: true if BigInt support is enabled. Defaults to - true if `globalThis.BigInt64Array` is available, else false. Some APIs + true if `self.BigInt64Array` is available, else false. Some APIs will throw exceptions if called without BigInt support, as BigInt is required for marshalling C-side int64 into and out of JS. (Sidebar: it is technically possible to add int64 support via marshalling of int32 pairs, but doing so is unduly invasive.) @@ -98,12 +98,12 @@ The returned object is the top-level sqlite3 namespace object. */ 'use strict'; -globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( - apiConfig = (globalThis.sqlite3ApiConfig || sqlite3ApiBootstrap.defaultConfig) +self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( + apiConfig = (self.sqlite3ApiConfig || sqlite3ApiBootstrap.defaultConfig) ){ if(sqlite3ApiBootstrap.sqlite3){ /* already initalized */ console.warn("sqlite3ApiBootstrap() called multiple times.", "Config and external initializers are ignored on calls after the first."); return sqlite3ApiBootstrap.sqlite3; @@ -115,11 +115,11 @@ if('undefined'!==typeof Module){ /* Emscripten module will contain HEAPU64 when built with -sWASM_BIGINT=1, else it will not. */ return !!Module.HEAPU64; } - return !!globalThis.BigInt64Array; + return !!self.BigInt64Array; })(), debug: console.debug.bind(console), warn: console.warn.bind(console), error: console.error.bind(console), log: console.log.bind(console), @@ -770,11 +770,11 @@ affirmBindableTypedArray, flexibleString, bigIntFits32, bigIntFits64, bigIntFitsDouble, isBindableTypedArray, isInt32, isSQLableTypedArray, isTypedArray, typedArrayToString, - isUIThread: ()=>(globalThis.window===globalThis && !!globalThis.document), + isUIThread: ()=>(self.window===self && !!self.document), // is this true for ESM?: 'undefined'===typeof WorkerGlobalScope isSharedTypedArray, toss: function(...args){throw new Error(args.join(' '))}, toss3, typedArrayPart @@ -1201,13 +1201,13 @@ // If we have no OPFS, there is no persistent dir const pdir = config.wasmfsOpfsDir; console.error("sqlite3_wasmfs_opfs_dir() can no longer work due "+ "to incompatible WASMFS changes. It will be removed."); if(!pdir - || !globalThis.FileSystemHandle - || !globalThis.FileSystemDirectoryHandle - || !globalThis.FileSystemFileHandle){ + || !self.FileSystemHandle + || !self.FileSystemDirectoryHandle + || !self.FileSystemFileHandle){ return __wasmfsOpfsDir = ""; } try{ if(pdir && 0===wasm.xCallWrapped( 'sqlite3_wasm_init_wasmfs', 'i32', ['string'], pdir @@ -1459,12 +1459,12 @@ */ const __kvvfsInfo = function(which){ const rc = Object.create(null); rc.prefix = 'kvvfs-'+which; rc.stores = []; - if('session'===which || ""===which) rc.stores.push(globalThis.sessionStorage); - if('local'===which || ""===which) rc.stores.push(globalThis.localStorage); + if('session'===which || ""===which) rc.stores.push(self.sessionStorage); + if('local'===which || ""===which) rc.stores.push(self.localStorage); return rc; }; /** Clears all storage used by the kvvfs DB backend, deleting any @@ -1535,50 +1535,46 @@ sqlite3_db_config(). Full docs: https://sqlite.org/c3ref/db_config.html Returns capi.SQLITE_MISUSE if op is not a valid operation ID. - - The variants which take `(int, int*)` arguments treat a - missing or falsy pointer argument as 0. */ - capi.sqlite3_db_config = function(pDb, op, ...args){ + capi.sqlite3_db_config = function f(pDb, op, ...args){ if(!this.s){ this.s = wasm.xWrap('sqlite3_wasm_db_config_s','int', ['sqlite3*', 'int', 'string:static'] /* MAINDBNAME requires a static string */); this.pii = wasm.xWrap('sqlite3_wasm_db_config_pii', 'int', ['sqlite3*', 'int', '*','int', 'int']); this.ip = wasm.xWrap('sqlite3_wasm_db_config_ip','int', ['sqlite3*', 'int', 'int','*']); } + const c = capi; switch(op){ - case capi.SQLITE_DBCONFIG_ENABLE_FKEY: - case capi.SQLITE_DBCONFIG_ENABLE_TRIGGER: - case capi.SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER: - case capi.SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION: - case capi.SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE: - case capi.SQLITE_DBCONFIG_ENABLE_QPSG: - case capi.SQLITE_DBCONFIG_TRIGGER_EQP: - case capi.SQLITE_DBCONFIG_RESET_DATABASE: - case capi.SQLITE_DBCONFIG_DEFENSIVE: - case capi.SQLITE_DBCONFIG_WRITABLE_SCHEMA: - case capi.SQLITE_DBCONFIG_LEGACY_ALTER_TABLE: - case capi.SQLITE_DBCONFIG_DQS_DML: - case capi.SQLITE_DBCONFIG_DQS_DDL: - case capi.SQLITE_DBCONFIG_ENABLE_VIEW: - case capi.SQLITE_DBCONFIG_LEGACY_FILE_FORMAT: - case capi.SQLITE_DBCONFIG_TRUSTED_SCHEMA: - case capi.SQLITE_DBCONFIG_STMT_SCANSTATUS: - case capi.SQLITE_DBCONFIG_REVERSE_SCANORDER: + case c.SQLITE_DBCONFIG_ENABLE_FKEY: + case c.SQLITE_DBCONFIG_ENABLE_TRIGGER: + case c.SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER: + case c.SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION: + case c.SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE: + case c.SQLITE_DBCONFIG_ENABLE_QPSG: + case c.SQLITE_DBCONFIG_TRIGGER_EQP: + case c.SQLITE_DBCONFIG_RESET_DATABASE: + case c.SQLITE_DBCONFIG_DEFENSIVE: + case c.SQLITE_DBCONFIG_WRITABLE_SCHEMA: + case c.SQLITE_DBCONFIG_LEGACY_ALTER_TABLE: + case c.SQLITE_DBCONFIG_DQS_DML: + case c.SQLITE_DBCONFIG_DQS_DDL: + case c.SQLITE_DBCONFIG_ENABLE_VIEW: + case c.SQLITE_DBCONFIG_LEGACY_FILE_FORMAT: + case c.SQLITE_DBCONFIG_TRUSTED_SCHEMA: return this.ip(pDb, op, args[0], args[1] || 0); - case capi.SQLITE_DBCONFIG_LOOKASIDE: + case c.SQLITE_DBCONFIG_LOOKASIDE: return this.pii(pDb, op, args[0], args[1], args[2]); - case capi.SQLITE_DBCONFIG_MAINDBNAME: + case c.SQLITE_DBCONFIG_MAINDBNAME: return this.s(pDb, op, args[0]); default: - return capi.SQLITE_MISUSE; + return c.SQLITE_MISUSE; } }.bind(Object.create(null)); /** Given a (sqlite3_value*), this function attempts to convert it @@ -1964,11 +1960,11 @@ delete sqlite3ApiBootstrap.initializers; sqlite3ApiBootstrap.sqlite3 = sqlite3; return sqlite3; }/*sqlite3ApiBootstrap()*/; /** - globalThis.sqlite3ApiBootstrap.initializers is an internal detail used by + self.sqlite3ApiBootstrap.initializers is an internal detail used by the various pieces of the sqlite3 API's amalgamation process. It must not be modified by client code except when plugging such code into the amalgamation process. Each component of the amalgamation is expected to append a function @@ -1982,18 +1978,18 @@ Note that the order of insertion into this array is significant for some pieces. e.g. sqlite3.capi and sqlite3.wasm cannot be fully utilized until the whwasmutil.js part is plugged in via sqlite3-api-glue.js. */ -globalThis.sqlite3ApiBootstrap.initializers = []; +self.sqlite3ApiBootstrap.initializers = []; /** - globalThis.sqlite3ApiBootstrap.initializersAsync is an internal detail + self.sqlite3ApiBootstrap.initializersAsync is an internal detail used by the sqlite3 API's amalgamation process. It must not be modified by client code except when plugging such code into the amalgamation process. - The counterpart of globalThis.sqlite3ApiBootstrap.initializers, + The counterpart of self.sqlite3ApiBootstrap.initializers, specifically for initializers which are asynchronous. All entries in this list must be either async functions, non-async functions which return a Promise, or a Promise. Each function in the list is called with the sqlite3 ojbect as its only argument. @@ -2001,27 +1997,28 @@ the asyncPostInit() process (at an indeterminate point because all of them are run asynchronously in parallel). This list is not processed until the client calls sqlite3.asyncPostInit(). This means, for example, that intializers - added to globalThis.sqlite3ApiBootstrap.initializers may push entries to + added to self.sqlite3ApiBootstrap.initializers may push entries to this list. */ -globalThis.sqlite3ApiBootstrap.initializersAsync = []; +self.sqlite3ApiBootstrap.initializersAsync = []; /** Client code may assign sqlite3ApiBootstrap.defaultConfig an object-type value before calling sqlite3ApiBootstrap() (without arguments) in order to tell that call to use this object as its default config value. The intention of this is to provide downstream clients with a reasonably flexible approach for plugging in an environment-suitable configuration without having to define a new global-scope symbol. */ -globalThis.sqlite3ApiBootstrap.defaultConfig = Object.create(null); +self.sqlite3ApiBootstrap.defaultConfig = Object.create(null); /** Placeholder: gets installed by the first call to - globalThis.sqlite3ApiBootstrap(). However, it is recommended that the + self.sqlite3ApiBootstrap(). However, it is recommended that the caller of sqlite3ApiBootstrap() capture its return value and delete - globalThis.sqlite3ApiBootstrap after calling it. It returns the same + self.sqlite3ApiBootstrap after calling it. It returns the same value which will be stored here. */ -globalThis.sqlite3ApiBootstrap.sqlite3 = undefined; +self.sqlite3ApiBootstrap.sqlite3 = undefined; + Index: ext/wasm/api/sqlite3-api-worker1.js ================================================================== --- ext/wasm/api/sqlite3-api-worker1.js +++ ext/wasm/api/sqlite3-api-worker1.js @@ -311,15 +311,15 @@ The response is the input options object (or a synthesized one if passed only a string), noting that options.resultRows and options.columnNames may be populated by the call to db.exec(). */ -globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ +self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ sqlite3.initWorker1API = function(){ 'use strict'; const toss = (...args)=>{throw new Error(args.join(' '))}; - if(!(globalThis.WorkerGlobalScope instanceof Function)){ + if('function' !== typeof importScripts){ toss("initWorker1API() must be run from a Worker thread."); } const self = this.self; const sqlite3 = this.sqlite3 || toss("Missing this.sqlite3 object."); const DB = sqlite3.oo1.DB; @@ -380,14 +380,14 @@ postMessage()'s second argument and xferList.length is set to 0. */ post: function(msg,xferList){ if(xferList && xferList.length){ - globalThis.postMessage( msg, Array.from(xferList) ); + self.postMessage( msg, Array.from(xferList) ); xferList.length = 0; }else{ - globalThis.postMessage(msg); + self.postMessage(msg); } }, /** Map of DB IDs to DBs. */ dbs: Object.create(null), /** Fetch the DB for the given id. Throw if require=true and the @@ -587,11 +587,11 @@ const response = await sqlite3.opfs.treeList(); return response; } }/*wMsgHandler*/; - globalThis.onmessage = async function(ev){ + self.onmessage = async function(ev){ ev = ev.data; let result, dbId = ev.dbId, evType = ev.type; const arrivalTime = performance.now(); try { if(wMsgHandler.hasOwnProperty(evType) && @@ -635,8 +635,8 @@ // workerResponse: performance.now(); //}, result: result }, wState.xfer); }; - globalThis.postMessage({type:'sqlite3-api',result:'worker1-ready'}); + self.postMessage({type:'sqlite3-api',result:'worker1-ready'}); }.bind({self, sqlite3}); }); Index: ext/wasm/api/sqlite3-license-version-header.js ================================================================== --- ext/wasm/api/sqlite3-license-version-header.js +++ ext/wasm/api/sqlite3-license-version-header.js @@ -1,9 +1,9 @@ /* ** LICENSE for the sqlite3 WebAssembly/JavaScript APIs. ** -** This bundle (typically released as sqlite3.js or sqlite3.mjs) +** This bundle (typically released as sqlite3.js or sqlite3-wasmfs.js) ** is an amalgamation of JavaScript source code from two projects: ** ** 1) https://emscripten.org: the Emscripten "glue code" is covered by ** the terms of the MIT license and University of Illinois/NCSA ** Open Source License, as described at: Index: ext/wasm/api/sqlite3-opfs-async-proxy.js ================================================================== --- ext/wasm/api/sqlite3-opfs-async-proxy.js +++ ext/wasm/api/sqlite3-opfs-async-proxy.js @@ -48,14 +48,14 @@ */ "use strict"; const wPost = (type,...args)=>postMessage({type, payload:args}); const installAsyncProxy = function(self){ const toss = function(...args){throw new Error(args.join(' '))}; - if(globalThis.window === globalThis){ + if(self.window === self){ toss("This code cannot run from the main thread.", "Load it as a Worker from a separate Worker."); - }else if(!navigator?.storage?.getDirectory){ + }else if(!navigator.storage.getDirectory){ toss("This API requires navigator.storage.getDirectory."); } /** Will hold state copied to this object from the syncronous side of @@ -72,13 +72,13 @@ 3 = debug, warnings, and errors */ state.verbose = 1; const loggers = { - 0:console.error.bind(console), - 1:console.warn.bind(console), - 2:console.log.bind(console) + 0:sqlite3.config.error.bind(console), + 1:sqlite3.config.warn.bind(console), + 2:sqlite3.config.log.bind(console) }; const logImpl = (level,...args)=>{ if(state.verbose>level) loggers[level]("OPFS asyncer:",...args); }; const log = (...args)=>logImpl(2, ...args); @@ -104,16 +104,16 @@ n += m.count; t += m.time; w += m.wait; m.avgTime = (m.count && m.time) ? (m.time / m.count) : 0; } - console.log(globalThis?.location?.href, - "metrics for",globalThis?.location?.href,":\n", + sqlite3.config.log(self.location.href, + "metrics for",self.location.href,":\n", metrics, "\nTotal of",n,"op(s) for",t,"ms", "approx",w,"ms spent waiting on OPFS APIs."); - console.log("Serialization metrics:",metrics.s11n); + sqlite3.config.log("Serialization metrics:",metrics.s11n); }; /** __openFiles is a map of sqlite3_file pointers (integers) to metadata related to a given OPFS file handles. The pointers are, in @@ -270,11 +270,11 @@ /* Inconsistent exception.name from Chrome/ium with the same exception.message text: */ || (e.cause.name==='DOMException' && 0===e.cause.message.indexOf('Access Handles cannot'))) ) ? ( - /*console.warn("SQLITE_BUSY",e),*/ + /*sqlite3.config.warn("SQLITE_BUSY",e),*/ state.sq3Codes.SQLITE_BUSY ) : rc; }else{ return rc; } @@ -841,11 +841,11 @@ } }; navigator.storage.getDirectory().then(function(d){ state.rootDir = d; - globalThis.onmessage = function({data}){ + self.onmessage = function({data}){ switch(data.type){ case 'opfs-async-init':{ /* Receive shared state from synchronous partner */ const opt = data.args; for(const k in opt) state[k] = opt[k]; @@ -878,20 +878,20 @@ } }; wPost('opfs-async-loaded'); }).catch((e)=>error("error initializing OPFS asyncer:",e)); }/*installAsyncProxy()*/; -if(!globalThis.SharedArrayBuffer){ +if(!self.SharedArrayBuffer){ wPost('opfs-unavailable', "Missing SharedArrayBuffer API.", "The server must emit the COOP/COEP response headers to enable that."); -}else if(!globalThis.Atomics){ +}else if(!self.Atomics){ wPost('opfs-unavailable', "Missing Atomics API.", "The server must emit the COOP/COEP response headers to enable that."); -}else if(!globalThis.FileSystemHandle || - !globalThis.FileSystemDirectoryHandle || - !globalThis.FileSystemFileHandle || - !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || - !navigator?.storage?.getDirectory){ +}else if(!self.FileSystemHandle || + !self.FileSystemDirectoryHandle || + !self.FileSystemFileHandle || + !self.FileSystemFileHandle.prototype.createSyncAccessHandle || + !navigator.storage.getDirectory){ wPost('opfs-unavailable',"Missing required OPFS APIs."); }else{ installAsyncProxy(self); } Index: ext/wasm/api/sqlite3-v-helper.js ================================================================== --- ext/wasm/api/sqlite3-v-helper.js +++ ext/wasm/api/sqlite3-v-helper.js @@ -13,17 +13,14 @@ This file installs sqlite3.vfs, and object which exists to assist in the creation of JavaScript implementations of sqlite3_vfs, along with its virtual table counterpart, sqlite3.vtab. */ 'use strict'; -globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ +self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ const wasm = sqlite3.wasm, capi = sqlite3.capi, toss = sqlite3.util.toss3; const vfs = Object.create(null), vtab = Object.create(null); - const StructBinder = sqlite3.StructBinder - /* we require a local alias b/c StructBinder is removed from the sqlite3 - object during the final steps of the API cleanup. */; sqlite3.vfs = vfs; sqlite3.vtab = vtab; const sii = capi.sqlite3_index_info; /** @@ -113,11 +110,11 @@ environment in an undefined state. */ const installMethod = function callee( tgt, name, func, applyArgcCheck = callee.installMethodArgcCheck ){ - if(!(tgt instanceof StructBinder.StructType)){ + if(!(tgt instanceof sqlite3.StructBinder.StructType)){ toss("Usage error: target object is-not-a StructType."); }else if(!(func instanceof Function) && !wasm.isPtr(func)){ toss("Usage errror: expecting a Function or WASM pointer to one."); } if(1===arguments.length){ @@ -133,11 +130,11 @@ } return func.apply(this, args); } }; /* An ondispose() callback for use with - StructBinder-created types. */ + sqlite3.StructBinder-created types. */ callee.removeFuncList = function(){ if(this.ondispose.__removeFuncList){ this.ondispose.__removeFuncList.forEach( (v,ndx)=>{ if('number'===typeof v){ @@ -222,11 +219,11 @@ Equivalent to calling installMethod(this,...arguments) with a first argument of this object. If called with 1 or 2 arguments and the first is an object, it's instead equivalent to calling installMethods(this,...arguments). */ - StructBinder.StructType.prototype.installMethod = function callee( + sqlite3.StructBinder.StructType.prototype.installMethod = function callee( name, func, applyArgcCheck = installMethod.installMethodArgcCheck ){ return (arguments.length < 3 && name && 'object'===typeof name) ? installMethods(this, ...arguments) : installMethod(this, ...arguments); @@ -234,11 +231,11 @@ /** Equivalent to calling installMethods() with a first argument of this object. */ - StructBinder.StructType.prototype.installMethods = function( + sqlite3.StructBinder.StructType.prototype.installMethods = function( methods, applyArgcCheck = installMethod.installMethodArgcCheck ){ return installMethods(this, methods, applyArgcCheck); }; Index: ext/wasm/api/sqlite3-vfs-opfs.c-pp.js ================================================================== --- ext/wasm/api/sqlite3-vfs-opfs.c-pp.js +++ ext/wasm/api/sqlite3-vfs-opfs.c-pp.js @@ -16,11 +16,11 @@ Worker, implemented in sqlite3-opfs-async-proxy.js. This file is intended to be appended to the main sqlite3 JS deliverable somewhere after sqlite3-api-oo1.js and before sqlite3-api-cleanup.js. */ 'use strict'; -globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ +self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ /** installOpfsVfs() returns a Promise which, on success, installs an sqlite3_vfs named "opfs", suitable for use with all sqlite3 APIs which accept a VFS. It is intended to be called via sqlite3ApiBootstrap.initializersAsync or an equivalent mechanism. @@ -74,35 +74,35 @@ On success, the Promise resolves to the top-most sqlite3 namespace object and that object gets a new object installed in its `opfs` property, containing several OPFS-specific utilities. */ const installOpfsVfs = function callee(options){ - if(!globalThis.SharedArrayBuffer - || !globalThis.Atomics){ + if(!self.SharedArrayBuffer + || !self.Atomics){ return Promise.reject( new Error("Cannot install OPFS: Missing SharedArrayBuffer and/or Atomics. "+ "The server must emit the COOP/COEP response headers to enable those. "+ "See https://sqlite.org/wasm/doc/trunk/persistence.md#coop-coep") ); - }else if('undefined'===typeof WorkerGlobalScope){ + }else if(self.window===self && self.document){ return Promise.reject( new Error("The OPFS sqlite3_vfs cannot run in the main thread "+ "because it requires Atomics.wait().") ); - }else if(!globalThis.FileSystemHandle || - !globalThis.FileSystemDirectoryHandle || - !globalThis.FileSystemFileHandle || - !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || - !navigator?.storage?.getDirectory){ + }else if(!self.FileSystemHandle || + !self.FileSystemDirectoryHandle || + !self.FileSystemFileHandle || + !self.FileSystemFileHandle.prototype.createSyncAccessHandle || + !navigator.storage.getDirectory){ return Promise.reject( new Error("Missing required OPFS APIs.") ); } if(!options || 'object'!==typeof options){ options = Object.create(null); } - const urlParams = new URL(globalThis.location.href).searchParams; + const urlParams = new URL(self.location.href).searchParams; if(undefined===options.verbose){ options.verbose = urlParams.has('opfs-verbose') ? (+urlParams.get('opfs-verbose') || 2) : 1; } if(undefined===options.sanityChecks){ @@ -110,20 +110,20 @@ } if(undefined===options.proxyUri){ options.proxyUri = callee.defaultProxyUri; } - //sqlite3.config.warn("OPFS options =",options,globalThis.location); + //sqlite3.config.warn("OPFS options =",options,self.location); if('function' === typeof options.proxyUri){ options.proxyUri = options.proxyUri(); } - const thePromise = new Promise(function(promiseResolve_, promiseReject_){ + const thePromise = new Promise(function(promiseResolve, promiseReject_){ const loggers = { - 0:sqlite3.config.error, - 1:sqlite3.config.warn, - 2:sqlite3.config.log + 0:sqlite3.config.error.bind(console), + 1:sqlite3.config.warn.bind(console), + 2:sqlite3.config.log.bind(console) }; const logImpl = (level,...args)=>{ if(options.verbose>level) loggers[level]("OPFS syncer:",...args); }; const log = (...args)=>logImpl(2, ...args); @@ -147,15 +147,15 @@ /** Returns true if _this_ thread has access to the OPFS APIs. */ const thisThreadHasOPFS = ()=>{ - return globalThis.FileSystemHandle && - globalThis.FileSystemDirectoryHandle && - globalThis.FileSystemFileHandle && - globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle && - navigator?.storage?.getDirectory; + return self.FileSystemHandle && + self.FileSystemDirectoryHandle && + self.FileSystemFileHandle && + self.FileSystemFileHandle.prototype.createSyncAccessHandle && + navigator.storage.getDirectory; }; /** Not part of the public API. Solely for internal/development use. @@ -169,12 +169,12 @@ t += m.time; w += m.wait; m.avgTime = (m.count && m.time) ? (m.time / m.count) : 0; m.avgWait = (m.count && m.wait) ? (m.wait / m.count) : 0; } - sqlite3.config.log(globalThis.location.href, - "metrics for",globalThis.location.href,":",metrics, + sqlite3.config.log(self.location.href, + "metrics for",self.location.href,":",metrics, "\nTotal of",n,"op(s) for",t, "ms (incl. "+w+" ms of waiting on the async side)"); sqlite3.config.log("Serialization metrics:",metrics.s11n); W.postMessage({type:'opfs-async-metrics'}); }, @@ -191,40 +191,22 @@ s.count = s.time = 0; } }/*metrics*/; const opfsVfs = new sqlite3_vfs(); const opfsIoMethods = new sqlite3_io_methods(); - let promiseWasRejected = undefined; - const promiseReject = (err)=>{ - promiseWasRejected = true; + const promiseReject = function(err){ opfsVfs.dispose(); return promiseReject_(err); }; - const promiseResolve = (value)=>{ - promiseWasRejected = false; - return promiseResolve_(value); - }; const W = //#if target=es6-bundler-friendly new Worker(new URL("sqlite3-opfs-async-proxy.js", import.meta.url)); //#elif target=es6-module new Worker(new URL(options.proxyUri, import.meta.url)); //#else new Worker(options.proxyUri); //#endif - setTimeout(()=>{ - /* At attempt to work around a browser-specific quirk in which - the Worker load is failing in such a way that we neither - resolve nor reject it. This workaround gives that resolve/reject - a time limit and rejects if that timer expires. Discussion: - https://sqlite.org/forum/forumpost/a708c98dcb3ef */ - if(undefined===promiseWasRejected){ - promiseReject( - new Error("Timeout while waiting for OPFS async proxy worker.") - ); - } - }, 4000); W._originalOnError = W.onerror /* will be restored later */; W.onerror = function(err){ // The error object doesn't contain any useful info when the // failure is, e.g., that the remote script is 404. error("Error initializing OPFS asyncer:",err); @@ -351,10 +333,11 @@ next. */ state.opIds.xAccess = i++; state.opIds.xClose = i++; state.opIds.xDelete = i++; state.opIds.xDeleteNoWait = i++; + state.opIds.xFileControl = i++; state.opIds.xFileSize = i++; state.opIds.xLock = i++; state.opIds.xOpen = i++; state.opIds.xRead = i++; state.opIds.xSleep = i++; @@ -715,13 +698,16 @@ xDeviceCharacteristics: function(pFile){ //debug("xDeviceCharacteristics(",pFile,")"); return capi.SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN; }, xFileControl: function(pFile, opId, pArg){ - /*mTimeStart('xFileControl'); - mTimeEnd();*/ - return capi.SQLITE_NOTFOUND; + mTimeStart('xFileControl'); + const rc = (capi.SQLITE_FCNTL_SYNC===opId) + ? opRun('xSync', pFile, 0) + : capi.SQLITE_NOTFOUND; + mTimeEnd(); + return rc; }, xFileSize: function(pFile,pSz64){ mTimeStart('xFileSize'); let rc = opRun('xFileSize', pFile); if(0==rc){ @@ -773,15 +759,12 @@ } mTimeEnd(); return rc; }, xSync: function(pFile,flags){ - mTimeStart('xSync'); ++metrics.xSync.count; - const rc = opRun('xSync', pFile, flags); - mTimeEnd(); - return rc; + return 0; // impl'd in xFileControl() }, xTruncate: function(pFile,sz64){ mTimeStart('xTruncate'); const rc = opRun('xTruncate', pFile, Number(sz64)); mTimeEnd(); @@ -1186,19 +1169,11 @@ sqlite3.capi.sqlite3_busy_timeout(oo1Db, 10000); sqlite3.capi.sqlite3_exec(oo1Db, [ /* Truncate journal mode is faster than delete for this vfs, per speedtest1. That gap seems to have closed with Chrome version 108 or 109, but "persist" is very roughly 5-6% - faster than truncate in initial tests. - - For later analysis: Roy Hashimoto notes that TRUNCATE - and PERSIST modes may decrease OPFS concurrency because - multiple connections can open the journal file in those - modes: - - https://github.com/rhashimoto/wa-sqlite/issues/68 - */ + faster than truncate in initial tests. */ "pragma journal_mode=persist;", /* This vfs benefits hugely from cache on moderate/large speedtest1 --size 50 and --size 100 workloads. We currently rely on setting a non-default cache size when @@ -1284,22 +1259,18 @@ /* Async proxy has determined that OPFS is unavailable. There's nothing more for us to do here. */ promiseReject(new Error(data.payload.join(' '))); break; case 'opfs-async-loaded': - /* Arrives as soon as the asyc proxy finishes loading. - Pass our config and shared state on to the async - worker. */ + /*Arrives as soon as the asyc proxy finishes loading. + Pass our config and shared state on to the async worker.*/ W.postMessage({type: 'opfs-async-init',args: state}); break; - case 'opfs-async-inited': { - /* Indicates that the async partner has received the 'init' - and has finished initializing, so the real work can - begin... */ - if(true===promiseWasRejected){ - break /* promise was already rejected via timer */; - } + case 'opfs-async-inited':{ + /*Indicates that the async partner has received the 'init' + and has finished initializing, so the real work can + begin...*/ try { sqlite3.vfs.installVfs({ io: {struct: opfsIoMethods, methods: ioSyncWrappers}, vfs: {struct: opfsVfs, methods: vfsSyncWrappers} }); @@ -1327,27 +1298,22 @@ error(e); promiseReject(e); } break; } - default: { - const errMsg = ( - "Unexpected message from the OPFS async worker: " + - JSON.stringify(data) - ); - error(errMsg); - promiseReject(new Error(errMsg)); + default: + promiseReject(e); + error("Unexpected message from the async worker:",data); break; - } }/*switch(data.type)*/ }/*W.onmessage()*/; })/*thePromise*/; return thePromise; }/*installOpfsVfs()*/; installOpfsVfs.defaultProxyUri = "sqlite3-opfs-async-proxy.js"; -globalThis.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{ +self.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{ try{ let proxyJs = installOpfsVfs.defaultProxyUri; if(sqlite3.scriptInfo.sqlite3Dir){ installOpfsVfs.defaultProxyUri = sqlite3.scriptInfo.sqlite3Dir + proxyJs; Index: ext/wasm/api/sqlite3-wasm.c ================================================================== --- ext/wasm/api/sqlite3-wasm.c +++ ext/wasm/api/sqlite3-wasm.c @@ -161,18 +161,19 @@ /* SQLITE_USE_... */ #ifndef SQLITE_USE_URI # define SQLITE_USE_URI 1 #endif -#ifdef SQLITE_WASM_EXTRA_INIT -# define SQLITE_EXTRA_INIT sqlite3_wasm_extra_init +#include +#include "sqlite3.c" /* yes, .c instead of .h. */ + +#if defined(__EMSCRIPTEN__) +# include #endif -#include - /* -** SQLITE_WASM_EXPORT is functionally identical to EMSCRIPTEN_KEEPALIVE +** SQLITE_WASM_KEEP is functionally identical to EMSCRIPTEN_KEEPALIVE ** but is not Emscripten-specific. It explicitly marks functions for ** export into the target wasm file without requiring explicit listing ** of those functions in Emscripten's -sEXPORTED_FUNCTIONS=... list ** (or equivalent in other build platforms). Any function with neither ** this attribute nor which is listed as an explicit export will not @@ -190,38 +191,14 @@ ** non-Emscripten builds. If not, such builds will need to export ** those using the --export=... wasm-ld flag (or equivalent). As of ** this writing we are tied to Emscripten for various reasons ** and cannot test the library with other build environments. */ -#define SQLITE_WASM_EXPORT __attribute__((used,visibility("default"))) +#define SQLITE_WASM_KEEP __attribute__((used,visibility("default"))) // See also: //__attribute__((export_name("theExportedName"), used, visibility("default"))) -/* -** Which sqlite3.c we're using needs to be configurable to enable -** building against a custom copy, e.g. the SEE variant. Note that we -** #include the .c file, rather than the header, so that the WASM -** extensions have access to private API internals. -** -** The caveat here is that custom variants need to account for -** exporting any necessary symbols (e.g. sqlite3_activate_see()). We -** cannot export them from here using SQLITE_WASM_EXPORT because that -** attribute (apparently) has to be part of the function definition. -*/ -#ifndef SQLITE_C -# define SQLITE_C sqlite3.c /* yes, .c instead of .h. */ -#endif -#define INC__STRINGIFY_(f) #f -#define INC__STRINGIFY(f) INC__STRINGIFY_(f) -#include INC__STRINGIFY(SQLITE_C) -#undef INC__STRINGIFY_ -#undef INC__STRINGIFY -#undef SQLITE_C - -#if defined(__EMSCRIPTEN__) -# include -#endif #if 0 /* ** An EXPERIMENT in implementing a stack-based allocator analog to ** Emscripten's stackSave(), stackAlloc(), stackRestore(). @@ -231,28 +208,28 @@ ** to work just fine. ** ** Another option is to malloc() a chunk of our own and call that our ** "stack". */ -SQLITE_WASM_EXPORT void * sqlite3_wasm_stack_end(void){ +SQLITE_WASM_KEEP void * sqlite3_wasm_stack_end(void){ extern void __heap_base /* see https://stackoverflow.com/questions/10038964 */; return &__heap_base; } -SQLITE_WASM_EXPORT void * sqlite3_wasm_stack_begin(void){ +SQLITE_WASM_KEEP void * sqlite3_wasm_stack_begin(void){ extern void __data_end; return &__data_end; } static void * pWasmStackPtr = 0; -SQLITE_WASM_EXPORT void * sqlite3_wasm_stack_ptr(void){ +SQLITE_WASM_KEEP void * sqlite3_wasm_stack_ptr(void){ if(!pWasmStackPtr) pWasmStackPtr = sqlite3_wasm_stack_end(); return pWasmStackPtr; } -SQLITE_WASM_EXPORT void sqlite3_wasm_stack_restore(void * p){ +SQLITE_WASM_KEEP void sqlite3_wasm_stack_restore(void * p){ pWasmStackPtr = p; } -SQLITE_WASM_EXPORT void * sqlite3_wasm_stack_alloc(int n){ +SQLITE_WASM_KEEP void * sqlite3_wasm_stack_alloc(int n){ if(n<=0) return 0; n = (n + 7) & ~7 /* align to 8-byte boundary */; unsigned char * const p = (unsigned char *)sqlite3_wasm_stack_ptr(); unsigned const char * const b = (unsigned const char *)sqlite3_wasm_stack_begin(); if(b + n >= p || b + n < b/*overflow*/) return 0; @@ -284,18 +261,18 @@ &PStack_mem[0] + sizeof(PStack_mem) }; /* ** Returns the current pstack position. */ -SQLITE_WASM_EXPORT void * sqlite3_wasm_pstack_ptr(void){ +SQLITE_WASM_KEEP void * sqlite3_wasm_pstack_ptr(void){ return PStack.pPos; } /* ** Sets the pstack position poitner to p. Results are undefined if the ** given value did not come from sqlite3_wasm_pstack_ptr(). */ -SQLITE_WASM_EXPORT void sqlite3_wasm_pstack_restore(unsigned char * p){ +SQLITE_WASM_KEEP void sqlite3_wasm_pstack_restore(unsigned char * p){ assert(p>=PStack.pBegin && p<=PStack.pEnd && p>=PStack.pPos); assert(0==(p & 0x7)); if(p>=PStack.pBegin && p<=PStack.pEnd /*&& p>=PStack.pPos*/){ PStack.pPos = p; } @@ -306,11 +283,11 @@ ** is always adjusted to be a multiple of 8 and returned memory is ** always zeroed out before returning (because this keeps the client ** JS code from having to do so, and most uses of the pstack will ** call for doing so). */ -SQLITE_WASM_EXPORT void * sqlite3_wasm_pstack_alloc(int n){ +SQLITE_WASM_KEEP void * sqlite3_wasm_pstack_alloc(int n){ if( n<=0 ) return 0; //if( n & 0x7 ) n += 8 - (n & 0x7) /* align to 8-byte boundary */; n = (n + 7) & ~7 /* align to 8-byte boundary */; if( PStack.pBegin + n > PStack.pPos /*not enough space left*/ || PStack.pBegin + n <= PStack.pBegin /*overflow*/ ) return 0; @@ -319,11 +296,11 @@ } /* ** Return the number of bytes left which can be ** sqlite3_wasm_pstack_alloc()'d. */ -SQLITE_WASM_EXPORT int sqlite3_wasm_pstack_remaining(void){ +SQLITE_WASM_KEEP int sqlite3_wasm_pstack_remaining(void){ assert(PStack.pPos >= PStack.pBegin); assert(PStack.pPos <= PStack.pEnd); return (int)(PStack.pPos - PStack.pBegin); } @@ -330,11 +307,11 @@ /* ** Return the total number of bytes available in the pstack, including ** any space which is currently allocated. This value is a ** compile-time constant. */ -SQLITE_WASM_EXPORT int sqlite3_wasm_pstack_quota(void){ +SQLITE_WASM_KEEP int sqlite3_wasm_pstack_quota(void){ return (int)(PStack.pEnd - PStack.pBegin); } /* ** This function is NOT part of the sqlite3 public API. It is strictly @@ -348,11 +325,11 @@ ** Wasm bindings such as sqlite3_prepare_v2/v3(), and definitely not ** from client code. ** ** Returns err_code. */ -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP int sqlite3_wasm_db_error(sqlite3*db, int err_code, const char *zMsg){ if( db!=0 ){ if( 0!=zMsg ){ const int nMsg = sqlite3Strlen30(zMsg); sqlite3ErrorWithMsg(db, err_code, "%.*s", nMsg, zMsg); @@ -370,11 +347,11 @@ const char * cstr; int64_t v8; void (*xFunc)(void*); }; typedef struct WasmTestStruct WasmTestStruct; -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP void sqlite3_wasm_test_struct(WasmTestStruct * s){ if(s){ s->v4 *= 2; s->v8 = s->v4 * 2; s->ppV = s; @@ -398,11 +375,11 @@ ** ** If this function returns NULL then it means that the internal ** buffer is not large enough for the generated JSON and needs to be ** increased. In debug builds that will trigger an assert(). */ -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP const char * sqlite3_wasm_enum_json(void){ static char aBuffer[1024 * 20] = {0} /* where the JSON goes */; int n = 0, nChildren = 0, nStruct = 0 /* output counters for figuring out where commas go */; char * zPos = &aBuffer[1] /* skip first byte for now to help protect @@ -493,11 +470,10 @@ DefGroup(changeset){ DefInt(SQLITE_CHANGESETSTART_INVERT); DefInt(SQLITE_CHANGESETAPPLY_NOSAVEPOINT); DefInt(SQLITE_CHANGESETAPPLY_INVERT); - DefInt(SQLITE_CHANGESETAPPLY_IGNORENOOP); DefInt(SQLITE_CHANGESET_DATA); DefInt(SQLITE_CHANGESET_NOTFOUND); DefInt(SQLITE_CHANGESET_CONFLICT); DefInt(SQLITE_CHANGESET_CONSTRAINT); @@ -565,12 +541,10 @@ DefInt(SQLITE_DBCONFIG_DQS_DML); DefInt(SQLITE_DBCONFIG_DQS_DDL); DefInt(SQLITE_DBCONFIG_ENABLE_VIEW); DefInt(SQLITE_DBCONFIG_LEGACY_FILE_FORMAT); DefInt(SQLITE_DBCONFIG_TRUSTED_SCHEMA); - DefInt(SQLITE_DBCONFIG_STMT_SCANSTATUS); - DefInt(SQLITE_DBCONFIG_REVERSE_SCANORDER); DefInt(SQLITE_DBCONFIG_MAX); } _DefGroup; DefGroup(dbStatus){ DefInt(SQLITE_DBSTATUS_LOOKASIDE_USED); @@ -638,11 +612,10 @@ DefInt(SQLITE_FCNTL_CKPT_DONE); DefInt(SQLITE_FCNTL_RESERVE_BYTES); DefInt(SQLITE_FCNTL_CKPT_START); DefInt(SQLITE_FCNTL_EXTERNAL_READER); DefInt(SQLITE_FCNTL_CKSM_FILE); - DefInt(SQLITE_FCNTL_RESET_CACHE); } _DefGroup; DefGroup(flock) { DefInt(SQLITE_LOCK_NONE); DefInt(SQLITE_LOCK_SHARED); @@ -928,11 +901,10 @@ DefInt(SQLITE_INDEX_CONSTRAINT_OFFSET); DefInt(SQLITE_INDEX_CONSTRAINT_FUNCTION); DefInt(SQLITE_VTAB_CONSTRAINT_SUPPORT); DefInt(SQLITE_VTAB_INNOCUOUS); DefInt(SQLITE_VTAB_DIRECTONLY); - DefInt(SQLITE_VTAB_USES_ALL_SCHEMAS); DefInt(SQLITE_ROLLBACK); //DefInt(SQLITE_IGNORE); // Also used by sqlite3_authorizer() callback DefInt(SQLITE_FAIL); //DefInt(SQLITE_ABORT); // Also an error code DefInt(SQLITE_REPLACE); @@ -1208,11 +1180,11 @@ ** default VFS if pVfs is NULL), passing on the given filename. If ** zName is NULL, no default VFS is found, or it has no xDelete ** method, SQLITE_MISUSE is returned, else the result of the xDelete() ** call is returned. */ -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP int sqlite3_wasm_vfs_unlink(sqlite3_vfs *pVfs, const char *zName){ int rc = SQLITE_MISUSE /* ??? */; if( 0==pVfs && 0!=zName ) pVfs = sqlite3_vfs_find(0); if( zName && pVfs && pVfs->xDelete ){ rc = pVfs->xDelete(pVfs, zName, 1); @@ -1226,11 +1198,11 @@ ** ** Returns a pointer to the given DB's VFS for the given DB name, ** defaulting to "main" if zDbName is 0. Returns 0 if no db with the ** given name is open. */ -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP sqlite3_vfs * sqlite3_wasm_db_vfs(sqlite3 *pDb, const char *zDbName){ sqlite3_vfs * pVfs = 0; sqlite3_file_control(pDb, zDbName ? zDbName : "main", SQLITE_FCNTL_VFS_POINTER, &pVfs); return pVfs; @@ -1249,11 +1221,11 @@ ** proper cleanup. ** ** Returns 0 on success, an SQLITE_xxx code on error. Returns ** SQLITE_MISUSE if pDb is NULL. */ -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP int sqlite3_wasm_db_reset(sqlite3 *pDb){ int rc = SQLITE_MISUSE; if( pDb ){ sqlite3_table_column_metadata(pDb, "main", 0, 0, 0, 0, 0, 0, 0); rc = sqlite3_db_config(pDb, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0); @@ -1280,11 +1252,11 @@ ** ** This implementation appears to work fine, but ** sqlite3_wasm_db_serialize() is arguably the better way to achieve ** this. */ -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP int sqlite3_wasm_db_export_chunked( sqlite3* pDb, int (*xCallback)(unsigned const char *zOut, int n) ){ sqlite3_int64 nSize = 0; sqlite3_int64 nPos = 0; sqlite3_file * pFile = 0; @@ -1331,11 +1303,11 @@ ** NULL but 0 will be returned. ** ** If `*pOut` is not NULL, the caller is responsible for passing it to ** sqlite3_free() to free it. */ -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP int sqlite3_wasm_db_serialize( sqlite3 *pDb, const char *zSchema, unsigned char **pOut, sqlite3_int64 *nOut, unsigned int mFlags ){ unsigned char * z; if( !pDb || !pOut ) return SQLITE_MISUSE; @@ -1388,11 +1360,11 @@ ** ** Design note: nData is an integer, instead of int64, for WASM ** portability, so that the API can still work in builds where BigInt ** support is disabled or unavailable. */ -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP int sqlite3_wasm_vfs_create_file( sqlite3_vfs *pVfs, const char *zFilename, const unsigned char * pData, int nData ){ int rc; @@ -1472,11 +1444,11 @@ ** sqlite3_wasm_pstack_alloc() and returns 0 if that allocation fails, ** else it passes that string to kvstorageMakeKey() and returns a ** NUL-terminated pointer to that string. It is up to the caller to ** use sqlite3_wasm_pstack_restore() to free the returned pointer. */ -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP char * sqlite3_wasm_kvvfsMakeKeyOnPstack(const char *zClass, const char *zKeyIn){ assert(sqlite3KvvfsMethods.nKeySize>24); char *zKeyOut = (char *)sqlite3_wasm_pstack_alloc(sqlite3KvvfsMethods.nKeySize); @@ -1491,11 +1463,11 @@ ** for use by the sqlite project's own JS/WASM bindings. ** ** Returns the pointer to the singleton object which holds the kvvfs ** I/O methods and associated state. */ -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP sqlite3_kvvfs_methods * sqlite3_wasm_kvvfs_methods(void){ return &sqlite3KvvfsMethods; } /* @@ -1506,11 +1478,11 @@ ** its argument on, or not, to sqlite3_vtab_config(), depending on the ** value of its 2nd argument. Returns the result of ** sqlite3_vtab_config(), or SQLITE_MISUSE if the 2nd arg is not a ** valid value. */ -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP int sqlite3_wasm_vtab_config(sqlite3 *pDb, int op, int arg){ switch(op){ case SQLITE_VTAB_DIRECTONLY: case SQLITE_VTAB_INNOCUOUS: return sqlite3_vtab_config(pDb, op); @@ -1526,11 +1498,11 @@ ** for use by the sqlite project's own JS/WASM bindings. ** ** Wrapper for the variants of sqlite3_db_config() which take ** (int,int*) variadic args. */ -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP int sqlite3_wasm_db_config_ip(sqlite3 *pDb, int op, int arg1, int* pArg2){ switch(op){ case SQLITE_DBCONFIG_ENABLE_FKEY: case SQLITE_DBCONFIG_ENABLE_TRIGGER: case SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER: @@ -1545,12 +1517,10 @@ case SQLITE_DBCONFIG_DQS_DML: case SQLITE_DBCONFIG_DQS_DDL: case SQLITE_DBCONFIG_ENABLE_VIEW: case SQLITE_DBCONFIG_LEGACY_FILE_FORMAT: case SQLITE_DBCONFIG_TRUSTED_SCHEMA: - case SQLITE_DBCONFIG_STMT_SCANSTATUS: - case SQLITE_DBCONFIG_REVERSE_SCANORDER: return sqlite3_db_config(pDb, op, arg1, pArg2); default: return SQLITE_MISUSE; } } @@ -1559,11 +1529,11 @@ ** for use by the sqlite project's own JS/WASM bindings. ** ** Wrapper for the variants of sqlite3_db_config() which take ** (void*,int,int) variadic args. */ -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP int sqlite3_wasm_db_config_pii(sqlite3 *pDb, int op, void * pArg1, int arg2, int arg3){ switch(op){ case SQLITE_DBCONFIG_LOOKASIDE: return sqlite3_db_config(pDb, op, pArg1, arg2, arg3); default: return SQLITE_MISUSE; @@ -1575,11 +1545,11 @@ ** for use by the sqlite project's own JS/WASM bindings. ** ** Wrapper for the variants of sqlite3_db_config() which take ** (const char *) variadic args. */ -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP int sqlite3_wasm_db_config_s(sqlite3 *pDb, int op, const char *zArg){ switch(op){ case SQLITE_DBCONFIG_MAINDBNAME: return sqlite3_db_config(pDb, op, zArg); default: return SQLITE_MISUSE; @@ -1592,11 +1562,11 @@ ** for use by the sqlite project's own JS/WASM bindings. ** ** Binding for combinations of sqlite3_config() arguments which take ** a single integer argument. */ -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP int sqlite3_wasm_config_i(int op, int arg){ return sqlite3_config(op, arg); } /* @@ -1604,11 +1574,11 @@ ** for use by the sqlite project's own JS/WASM bindings. ** ** Binding for combinations of sqlite3_config() arguments which take ** two int arguments. */ -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP int sqlite3_wasm_config_ii(int op, int arg1, int arg2){ return sqlite3_config(op, arg1, arg2); } /* @@ -1616,11 +1586,11 @@ ** for use by the sqlite project's own JS/WASM bindings. ** ** Binding for combinations of sqlite3_config() arguments which take ** a single i64 argument. */ -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP int sqlite3_wasm_config_j(int op, sqlite3_int64 arg){ return sqlite3_config(op, arg); } #if 0 @@ -1645,11 +1615,11 @@ ** Using a function to return this pointer, as opposed to exporting it ** via sqlite3_wasm_enum_json(), is an attempt to work around a ** Safari-specific quirk covered at ** https://sqlite.org/forum/info/e5b20e1feb37a19a. **/ -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP void * sqlite3_wasm_ptr_to_sqlite3_free(void){ return (void*)sqlite3_free; } #endif @@ -1675,11 +1645,11 @@ ** Returns 0 on success, SQLITE_NOMEM if instantiation of the backend ** object fails, SQLITE_IOERR if mkdir() of the zMountPoint dir in ** the virtual FS fails. In builds compiled without SQLITE_ENABLE_WASMFS ** defined, SQLITE_NOTFOUND is returned without side effects. */ -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP int sqlite3_wasm_init_wasmfs(const char *zMountPoint){ static backend_t pOpfs = 0; if( !zMountPoint || !*zMountPoint ) zMountPoint = "/opfs"; if( !pOpfs ){ pOpfs = wasmfs_create_opfs_backend(); @@ -1695,65 +1665,65 @@ if(rc) return SQLITE_IOERR; } return pOpfs ? 0 : SQLITE_NOMEM; } #else -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP int sqlite3_wasm_init_wasmfs(const char *zUnused){ //emscripten_console_warn("WASMFS OPFS is not compiled in."); if(zUnused){/*unused*/} return SQLITE_NOTFOUND; } #endif /* __EMSCRIPTEN__ && SQLITE_ENABLE_WASMFS */ #if SQLITE_WASM_TESTS -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP int sqlite3_wasm_test_intptr(int * p){ return *p = *p * 2; } -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP void * sqlite3_wasm_test_voidptr(void * p){ return p; } -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP int64_t sqlite3_wasm_test_int64_max(void){ return (int64_t)0x7fffffffffffffff; } -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP int64_t sqlite3_wasm_test_int64_min(void){ return ~sqlite3_wasm_test_int64_max(); } -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP int64_t sqlite3_wasm_test_int64_times2(int64_t x){ return x * 2; } -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP void sqlite3_wasm_test_int64_minmax(int64_t * min, int64_t *max){ *max = sqlite3_wasm_test_int64_max(); *min = sqlite3_wasm_test_int64_min(); /*printf("minmax: min=%lld, max=%lld\n", *min, *max);*/ } -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP int64_t sqlite3_wasm_test_int64ptr(int64_t * p){ /*printf("sqlite3_wasm_test_int64ptr( @%lld = 0x%llx )\n", (int64_t)p, *p);*/ return *p = *p * 2; } -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP void sqlite3_wasm_test_stack_overflow(int recurse){ if(recurse) sqlite3_wasm_test_stack_overflow(recurse); } /* For testing the 'string:dealloc' whwasmutil.xWrap() conversion. */ -SQLITE_WASM_EXPORT +SQLITE_WASM_KEEP char * sqlite3_wasm_test_str_hello(int fail){ char * s = fail ? 0 : (char *)sqlite3_malloc(6); if(s){ memcpy(s, "hello", 5); s[5] = 0; @@ -1760,6 +1730,6 @@ } return s; } #endif /* SQLITE_WASM_TESTS */ -#undef SQLITE_WASM_EXPORT +#undef SQLITE_WASM_KEEP Index: ext/wasm/api/sqlite3-worker1.c-pp.js ================================================================== --- ext/wasm/api/sqlite3-worker1.c-pp.js +++ ext/wasm/api/sqlite3-worker1.c-pp.js @@ -29,22 +29,22 @@ This file accepts a URL arguments to adjust how it loads sqlite3.js: - `sqlite3.dir`, if set, treats the given directory name as the directory from which `sqlite3.js` will be loaded. */ +"use strict"; +(()=>{ //#if target=es6-bundler-friendly -import {default as sqlite3InitModule} from './sqlite3-bundler-friendly.mjs'; + importScripts('sqlite3.js'); //#else -"use strict"; -{ - const urlParams = globalThis.location - ? new URL(self.location.href).searchParams - : new URLSearchParams(); + const urlParams = new URL(self.location.href).searchParams; let theJs = 'sqlite3.js'; if(urlParams.has('sqlite3.dir')){ theJs = urlParams.get('sqlite3.dir') + '/' + theJs; } //console.warn("worker1 theJs =",theJs); importScripts(theJs); -} //#endif -sqlite3InitModule().then(sqlite3 => sqlite3.initWorker1API()); + sqlite3InitModule().then((sqlite3)=>{ + sqlite3.initWorker1API(); + }); +})(); Index: ext/wasm/common/whwasmutil.js ================================================================== --- ext/wasm/common/whwasmutil.js +++ ext/wasm/common/whwasmutil.js @@ -43,12 +43,12 @@ for their sub-optimally-documented Emscripten counterparts. Intended usage: ``` - globalThis.WhWasmUtilInstaller(appObject); - delete globalThis.WhWasmUtilInstaller; + self.WhWasmUtilInstaller(appObject); + delete self.WhWasmUtilInstaller; ``` Its global-scope symbol is intended only to provide an easy way to make it available to 3rd-party scripts and "should" be deleted after calling it. That symbols is _not_ used within the library. @@ -169,11 +169,11 @@ More specifically: https://fossil.wanderinghorse.net/r/jaccwabbyt/file/common/whwasmutil.js */ -globalThis.WhWasmUtilInstaller = function(target){ +self.WhWasmUtilInstaller = function(target){ 'use strict'; if(undefined===target.bigIntEnabled){ target.bigIntEnabled = !!self['BigInt64Array']; } @@ -2192,11 +2192,11 @@ that object, and not the `config` one.) Error handling is up to the caller, who may attach a `catch()` call to the promise. */ -globalThis.WhWasmUtilInstaller.yawl = function(config){ +self.WhWasmUtilInstaller.yawl = function(config){ const wfetch = ()=>fetch(config.uri, {credentials: 'same-origin'}); const wui = this; const finalThen = function(arg){ //log("finalThen()",arg); if(config.wasmUtilTarget){ @@ -2238,6 +2238,6 @@ .then(response => response.arrayBuffer()) .then(bytes => WebAssembly.instantiate(bytes, config.imports||{})) .then(finalThen); }; return loadWasm; -}.bind(globalThis.WhWasmUtilInstaller)/*yawl()*/; +}.bind(self.WhWasmUtilInstaller)/*yawl()*/; Index: ext/wasm/demo-worker1-promiser.js ================================================================== --- ext/wasm/demo-worker1-promiser.js +++ ext/wasm/demo-worker1-promiser.js @@ -7,11 +7,11 @@ * 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. *********************************************************************** - + Demonstration of the sqlite3 Worker API #1 Promiser: a Promise-based proxy for for the sqlite3 Worker #1 API. */ 'use strict'; (function(){ @@ -79,11 +79,11 @@ T.assert('boolean' === typeof r.bigIntEnabled); sqConfig = r; }); logHtml('', "Sending 'open' message and waiting for its response before continuing..."); - + await wtest('open', { filename: dbFilename, simulateError: 0 /* if true, fail the 'open' */, }, function(ev){ const r = ev.result; Index: ext/wasm/demo-worker1.js ================================================================== --- ext/wasm/demo-worker1.js +++ ext/wasm/demo-worker1.js @@ -60,11 +60,11 @@ }, shift: function(){ return this.queue.shift(); } }; - + const testCount = ()=>{ logHtml("","Total test count:",T.counter+". Total time =",(performance.now() - startTime),"ms"); }; const logEventResult = function(ev){ @@ -72,11 +72,11 @@ logHtml(evd.errorClass ? 'error' : '', "runOneTest",ev.messageId,"Worker time =", (ev.workerRespondTime - ev.workerReceivedTime),"ms.", "Round-trip event time =", (performance.now() - ev.departureTime),"ms.", - (evd.errorClass ? evd.message : "")//, JSON.stringify(evd) + (evd.errorClass ? ev.message : "")//, JSON.stringify(evd) ); }; const runOneTest = function(eventType, eventArgs, callback){ T.assert(eventArgs && 'object'===typeof eventArgs); Index: ext/wasm/dist.make ================================================================== --- ext/wasm/dist.make +++ ext/wasm/dist.make @@ -68,12 +68,11 @@ # $(bin.stripcomments) with a single -k flag. STRIP_K1.js := $(sqlite3-worker1.js) $(sqlite3-worker1-promiser.js) \ $(sqlite3-worker1-bundler-friendly.js) $(sqlite3-worker1-promiser-bundler-friendly.js) # STRIP_K2.js = list of JS files which need to be passed through # $(bin.stripcomments) with two -k flags. -STRIP_K2.js := $(sqlite3.js) $(sqlite3.mjs) \ - $(sqlite3-bundler-friendly.mjs) $(sqlite3-node.mjs) +STRIP_K2.js := $(sqlite3.js) $(sqlite3.mjs) $(sqlite3-bundler-friendly.mjs) ######################################################################## # dist: create the end-user deliverable archive. # # Maintenance reminder: because dist depends on $(dist.build), and # $(dist.build) will depend on clean, having any deps on DELETED ext/wasm/example_extra_init.c Index: ext/wasm/example_extra_init.c ================================================================== --- ext/wasm/example_extra_init.c +++ /dev/null @@ -1,23 +0,0 @@ -/* -** If the canonical build process finds the file -** sqlite3_wasm_extra_init.c in the main wasm build directory, it -** arranges to include that file in the build of sqlite3.wasm and -** defines SQLITE_EXTRA_INIT=sqlite3_wasm_extra_init. -** -** The C file must define the function sqlite3_wasm_extra_init() with -** this signature: -** -** int sqlite3_wasm_extra_init(const char *) -** -** and the sqlite3 library will call it with an argument of NULL one -** time during sqlite3_initialize(). If it returns non-0, -** initialization of the library will fail. -*/ - -#include "sqlite3.h" -#include - -int sqlite3_wasm_extra_init(const char *z){ - fprintf(stderr,"%s: %s()\n", __FILE__, __func__); - return 0; -} Index: ext/wasm/fiddle.make ================================================================== --- ext/wasm/fiddle.make +++ ext/wasm/fiddle.make @@ -27,17 +27,18 @@ fiddle.emcc-flags = \ $(emcc.cflags) $(emcc_opt_full) \ --minify 0 \ -sALLOW_TABLE_GROWTH \ -sABORTING_MALLOC \ - -sSTRICT_JS=0 \ + -sSTRICT_JS \ -sENVIRONMENT=web,worker \ -sMODULARIZE \ -sDYNAMIC_EXECUTION=0 \ -sWASM_BIGINT=$(emcc.WASM_BIGINT) \ -sEXPORT_NAME=$(sqlite3.js.init-func) \ -Wno-limited-postlink-optimizations \ + $(sqlite3.js.flags.--post-js) \ $(emcc.exportedRuntimeMethods) \ -sEXPORTED_FUNCTIONS=@$(abspath $(EXPORTED_FUNCTIONS.fiddle)) \ -sEXPORTED_RUNTIME_METHODS=FS,wasmMemory \ $(SQLITE_OPT) $(SHELL_OPT) \ -DSQLITE_SHELL_FIDDLE @@ -56,11 +57,11 @@ fiddle.SOAP.js := $(dir.fiddle)/$(notdir $(SOAP.js)) $(fiddle.SOAP.js): $(SOAP.js) cp $< $@ -$(eval $(call call-make-pre-post,fiddle-module,vanilla)) +$(eval $(call call-make-pre-js,fiddle-module,vanilla)) $(fiddle-module.js): $(MAKEFILE) $(MAKEFILE.fiddle) \ $(EXPORTED_FUNCTIONS.fiddle) \ $(fiddle.cses) $(pre-post-fiddle-module.deps.vanilla) $(fiddle.SOAP.js) $(emcc.bin) -o $@ $(fiddle.emcc-flags) \ $(pre-post-fiddle-module.flags.vanilla) \ Index: ext/wasm/fiddle/fiddle-worker.js ================================================================== --- ext/wasm/fiddle/fiddle-worker.js +++ ext/wasm/fiddle/fiddle-worker.js @@ -44,11 +44,11 @@ - module: Status text. This is intended to alert the main thread about module loading status so that, e.g., the main thread can update a progress widget and DTRT when the module is finished loading and available for work. Status messages come in the form - + {type:'module', data:{ type:'status', data: {text:string|null, step:1-based-integer} } @@ -368,15 +368,12 @@ emcc ... -sMODULARIZE=1 -sEXPORT_NAME=initFiddleModule */ sqlite3InitModule(fiddleModule).then((_sqlite3)=>{ sqlite3 = _sqlite3; - console.warn("Installing sqlite3 module globally (in Worker)", - "for use in the dev console."); - self.sqlite3 = sqlite3; const dbVfs = sqlite3.wasm.xWrap('fiddle_db_vfs', "*", ['string']); fiddleModule.fsUnlink = (fn)=>{ return sqlite3.wasm.sqlite3_wasm_vfs_unlink(dbVfs(0), fn); }; wMsg('fiddle-ready'); })/*then()*/; })(); Index: ext/wasm/index-dist.html ================================================================== --- ext/wasm/index-dist.html +++ ext/wasm/index-dist.html @@ -39,29 +39,17 @@ using the functional equivalent of:
althttpd -enable-sab -page index.html
and the individual pages be started in their own tab. Warnings and Caveats:
    -
  • All of these pages must be served via an HTTP - server. Browsers do not support loading WASM files via - file:// URLs.
  • -
  • Any OPFS-related pages or tests require: -
      -
    • That the web server emit the so-called - COOP - and - COEP - headers. althttpd requires the - -enable-sab flag for that. -
    • -
    • A very recent version of a Chromium-based browser - (v102 at least, possibly newer). OPFS support in the - other major browsers is pending. Development and testing - is currently done against a dev-channel release of - Chrome (v111 as of 2023-02-10). -
    • -
    +
  • Some of these pages require that the web server emit the + so-called + COOP + and + COEP + headers. althttpd requires the + -enable-sab flag for that.
The tests and demos...
    Index: ext/wasm/index.html ================================================================== --- ext/wasm/index.html +++ ext/wasm/index.html @@ -24,29 +24,23 @@ using:
althttpd -enable-sab -page index.html
and the individual tests be started in their own tab. Warnings and Caveats:
    -
  • All of these pages must be served via an HTTP - server. Browsers do not support loading WASM files via - file:// URLs.
  • -
  • Any OPFS-related pages or tests require: -
      -
    • That the web server emit the so-called - COOP - and - COEP - headers. althttpd requires the - -enable-sab flag for that. -
    • -
    • A very recent version of a - Chromium-based browser (v102 at least, possibly newer). OPFS - support in the other major browsers is pending. Development - and testing is currently done against a dev-channel release - of Chrome (v111 as of 2023-02-10). -
    • -
    +
  • Some of these pages require that + the web server emit the so-called + COOP + and + COEP + headers. althttpd requires the + -enable-sab flag for that. +
  • +
  • Any OPFS-related pages require very recent version of + Chrome or Chromium (v102 at least, possibly newer). OPFS + support in the other major browsers is pending. Development + and testing is currently done against a dev-channel release + of Chrome (v110 as of 2022-12-02).
The tests and demos...
    Index: ext/wasm/jaccwabyt/jaccwabyt.js ================================================================== --- ext/wasm/jaccwabyt/jaccwabyt.js +++ ext/wasm/jaccwabyt/jaccwabyt.js @@ -17,11 +17,11 @@ - https://fossil.wanderinghorse.net/r/jaccwabyt - https://sqlite.org/src/dir/ext/wasm/jaccwabyt */ 'use strict'; -globalThis.Jaccwabyt = function StructBinderFactory(config){ +self.Jaccwabyt = function StructBinderFactory(config){ /* ^^^^ it is recommended that clients move that object into wherever they'd like to have it and delete the self-held copy ("self" being the global window or worker object). This API does not require the global reference - it is simply installed as a convenience for connecting these bits to other co-developed code before it gets Index: ext/wasm/speedtest1-worker.html ================================================================== --- ext/wasm/speedtest1-worker.html +++ ext/wasm/speedtest1-worker.html @@ -21,11 +21,11 @@ failed and the JavaScript console may contain clues as to why.
Downloading...
- +
** ** [[SQLITE_DBCONFIG_DQS_DML]] -**
SQLITE_DBCONFIG_DQS_DML
+**
SQLITE_DBCONFIG_DQS_DML **
The SQLITE_DBCONFIG_DQS_DML option activates or deactivates ** the legacy [double-quoted string literal] misfeature for DML statements ** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The ** default value of this setting is determined by the [-DSQLITE_DQS] ** compile-time option. **
** ** [[SQLITE_DBCONFIG_DQS_DDL]] -**
SQLITE_DBCONFIG_DQS_DDL
+**
SQLITE_DBCONFIG_DQS_DDL **
The SQLITE_DBCONFIG_DQS option activates or deactivates ** the legacy [double-quoted string literal] misfeature for DDL statements, ** such as CREATE TABLE and CREATE INDEX. The ** default value of this setting is determined by the [-DSQLITE_DQS] ** compile-time option. **
** ** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]] -**
SQLITE_DBCONFIG_TRUSTED_SCHEMA
+**
SQLITE_DBCONFIG_TRUSTED_SCHEMA **
The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to ** assume that database schemas are untainted by malicious content. ** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite ** takes additional defensive steps to protect the application from harm ** including: @@ -2434,20 +2415,20 @@ ** all applications are advised to turn it off if possible. This setting ** can also be controlled using the [PRAGMA trusted_schema] statement. **
** ** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]] -**
SQLITE_DBCONFIG_LEGACY_FILE_FORMAT
+**
SQLITE_DBCONFIG_LEGACY_FILE_FORMAT **
The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates ** the legacy file format flag. When activated, this flag causes all newly ** created database file to have a schema format version number (the 4-byte ** integer found at offset 44 into the database header) of 1. This in turn ** means that the resulting database file will be readable and writable by ** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting, ** newly created databases are generally not understandable by SQLite versions ** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there -** is now scarcely any need to generate database files that are compatible +** is now scarcely any need to generated database files that are compatible ** all the way back to version 3.0.0, and so this setting is of little ** practical use, but is provided so that SQLite can continue to claim the ** ability to generate new database files that are compatible with version ** 3.0.0. **

Note that when the SQLITE_DBCONFIG_LEGACY_FILE_FORMAT setting is on, @@ -2454,42 +2435,10 @@ ** the [VACUUM] command will fail with an obscure error when attempting to ** process a table with generated columns and a descending index. This is ** not considered a bug since SQLite versions 3.3.0 and earlier do not support ** either generated columns or decending indexes. **

-** -** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]] -**
SQLITE_DBCONFIG_STMT_SCANSTATUS
-**
The SQLITE_DBCONFIG_STMT_SCANSTATUS option is only useful in -** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears -** a flag that enables collection of the sqlite3_stmt_scanstatus_v2() -** statistics. For statistics to be collected, the flag must be set on -** the database handle both when the SQL statement is prepared and when it -** is stepped. The flag is set (collection of statistics is enabled) -** by default. This option takes two arguments: an integer and a pointer to -** an integer.. The first argument is 1, 0, or -1 to enable, disable, or -** leave unchanged the statement scanstatus option. If the second argument -** is not NULL, then the value of the statement scanstatus setting after -** processing the first argument is written into the integer that the second -** argument points to. -**
-** -** [[SQLITE_DBCONFIG_REVERSE_SCANORDER]] -**
SQLITE_DBCONFIG_REVERSE_SCANORDER
-**
The SQLITE_DBCONFIG_REVERSE_SCANORDER option changes the default order -** in which tables and indexes are scanned so that the scans start at the end -** and work toward the beginning rather than starting at the beginning and -** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the -** same as setting [PRAGMA reverse_unordered_selects]. This option takes -** two arguments which are an integer and a pointer to an integer. The first -** argument is 1, 0, or -1 to enable, disable, or leave unchanged the -** reverse scan order flag, respectively. If the second argument is not NULL, -** then 0 or 1 is written into the integer that the second argument points to -** depending on if the reverse scan order flag is set after processing the -** first argument. -**
-** ** */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ #define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ #define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */ @@ -2506,13 +2455,11 @@ #define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */ #define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */ #define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */ #define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */ -#define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */ -#define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */ -#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */ +#define SQLITE_DBCONFIG_MAX 1017 /* Largest DBCONFIG */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes ** METHOD: sqlite3 ** @@ -6253,17 +6200,10 @@ ** ^SQLite implements this interface by calling the xSleep() ** method of the default [sqlite3_vfs] object. If the xSleep() method ** of the default VFS is not implemented correctly, or not implemented at ** all, then the behavior of sqlite3_sleep() may deviate from the description ** in the previous paragraphs. -** -** If a negative argument is passed to sqlite3_sleep() the results vary by -** VFS and operating system. Some system treat a negative argument as an -** instruction to sleep forever. Others understand it to mean do not sleep -** at all. ^In SQLite version 3.42.0 and later, a negative -** argument passed into sqlite3_sleep() is changed to zero before it is relayed -** down into the xSleep method of the VFS. */ int sqlite3_sleep(int); /* ** CAPI3REF: Name Of The Folder Holding Temporary Files @@ -9623,32 +9563,22 @@ ** ** ** [[SQLITE_VTAB_INNOCUOUS]]
SQLITE_VTAB_INNOCUOUS
**
Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the -** the [xConnect] or [xCreate] methods of a [virtual table] implementation +** the [xConnect] or [xCreate] methods of a [virtual table] implmentation ** identify that virtual table as being safe to use from within triggers ** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the ** virtual table can do no serious harm even if it is controlled by a ** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS ** flag unless absolutely necessary. **
-** -** [[SQLITE_VTAB_USES_ALL_SCHEMAS]]
SQLITE_VTAB_USES_ALL_SCHEMAS
-**
Calls of the form -** [sqlite3_vtab_config](db,SQLITE_VTAB_USES_ALL_SCHEMA) from within the -** the [xConnect] or [xCreate] methods of a [virtual table] implementation -** instruct the query planner to begin at least a read transaction on -** all schemas ("main", "temp", and any ATTACH-ed databases) whenever the -** virtual table is used. -**
** */ #define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 #define SQLITE_VTAB_INNOCUOUS 2 #define SQLITE_VTAB_DIRECTONLY 3 -#define SQLITE_VTAB_USES_ALL_SCHEMAS 4 /* ** CAPI3REF: Determine The Virtual Table Conflict Policy ** ** This function may only be called from within a call to the [xUpdate] method @@ -9887,11 +9817,11 @@ ** ^(Use these routines to access all values on the right-hand side ** of the IN constraint using code like the following: ** **
 **    for(rc=sqlite3_vtab_in_first(pList, &pVal);
-**        rc==SQLITE_OK && pVal;
+**        rc==SQLITE_OK && pVal
 **        rc=sqlite3_vtab_in_next(pList, &pVal)
 **    ){
 **      // do something with pVal
 **    }
 **    if( rc!=SQLITE_OK ){
@@ -10021,10 +9951,11 @@
 ** [[SQLITE_SCANSTAT_SELECTID]] 
SQLITE_SCANSTAT_SELECTID
**
^The "int" variable pointed to by the V parameter will be set to the ** id for the X-th query plan element. The id value is unique within the ** statement. The select-id is the same value as is output in the first ** column of an [EXPLAIN QUERY PLAN] query. +** ** ** [[SQLITE_SCANSTAT_PARENTID]]
SQLITE_SCANSTAT_PARENTID
**
The "int" variable pointed to by the V parameter will be set to the ** the id of the parent of the current query element, if applicable, or ** to zero if the query element has no parent. This is the same value as @@ -10034,11 +9965,10 @@ **
The sqlite3_int64 output value is set to the number of cycles, ** according to the processor time-stamp counter, that elapsed while the ** query element was being processed. This value is not available for ** all query elements - if it is unavailable the output variable is ** set to -1. -** */ #define SQLITE_SCANSTAT_NLOOP 0 #define SQLITE_SCANSTAT_NVISIT 1 #define SQLITE_SCANSTAT_EST 2 #define SQLITE_SCANSTAT_NAME 3 @@ -10191,11 +10121,11 @@ ** seventh parameter is the final rowid value of the row being inserted ** or updated. The value of the seventh parameter passed to the callback ** function is not defined for operations on WITHOUT ROWID tables, or for ** DELETE operations on rowid tables. ** -** ^The sqlite3_preupdate_hook(D,C,P) function returns the P argument from +** ^The sqlite3_update_hook(D,C,P) function returns the P argument from ** the previous call on the same [database connection] D, or NULL for ** the first call on D. ** ** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()], ** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces @@ -10600,22 +10530,9 @@ */ #ifdef SQLITE_OMIT_FLOATING_POINT # undef double #endif -#if defined(__wasi__) -# undef SQLITE_WASI -# define SQLITE_WASI 1 -# undef SQLITE_OMIT_WAL -# define SQLITE_OMIT_WAL 1/* because it requires shared memory APIs */ -# ifndef SQLITE_OMIT_LOAD_EXTENSION -# define SQLITE_OMIT_LOAD_EXTENSION -# endif -# ifndef SQLITE_THREADSAFE -# define SQLITE_THREADSAFE 0 -# endif -#endif - #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif #endif /* SQLITE3_H */ Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -222,12 +222,12 @@ #pragma warn -csu /* Comparing signed and unsigned */ #pragma warn -spa /* Suspicious pointer arithmetic */ #endif /* -** A few places in the code require atomic load/store of aligned -** integer values. +** WAL mode depends on atomic aligned 32-bit loads and stores in a few +** places. The following macros try to make this explicit. */ #ifndef __has_extension # define __has_extension(x) 0 /* compatibility with non-clang compilers */ #endif #if GCC_VERSION>=4007000 || __has_extension(c_atomic) @@ -279,26 +279,19 @@ # define SQLITE_INT_TO_PTR(X) ((void*)(X)) # define SQLITE_PTR_TO_INT(X) ((int)(X)) #endif /* -** Macros to hint to the compiler that a function should or should not be +** A macro to hint to the compiler that a function should not be ** inlined. */ #if defined(__GNUC__) # define SQLITE_NOINLINE __attribute__((noinline)) -# define SQLITE_INLINE __attribute__((always_inline)) inline #elif defined(_MSC_VER) && _MSC_VER>=1310 # define SQLITE_NOINLINE __declspec(noinline) -# define SQLITE_INLINE __forceinline #else # define SQLITE_NOINLINE -# define SQLITE_INLINE -#endif -#if defined(SQLITE_COVERAGE_TEST) || defined(__STRICT_ANSI__) -# undef SQLITE_INLINE -# define SQLITE_INLINE #endif /* ** Make sure that the compiler intrinsics we desire are enabled when ** compiling with an appropriate version of MSVC unless prevented by @@ -824,13 +817,19 @@ */ #define SQLITE_MAX_U32 ((((u64)1)<<32)-1) /* ** The datatype used to store estimates of the number of rows in a -** table or index. +** table or index. This is an unsigned integer type. For 99.9% of +** the world, a 32-bit integer is sufficient. But a 64-bit integer +** can be used at compile-time if desired. */ -typedef u64 tRowcnt; +#ifdef SQLITE_64BIT_STATS + typedef u64 tRowcnt; /* 64-bit only if requested at compile-time */ +#else + typedef u32 tRowcnt; /* 32-bit is the default */ +#endif /* ** Estimated quantities used for query planning are stored as 16-bit ** logarithms. For quantity X, the value stored is 10*log2(X). This ** gives a possible range of values of approximately 1.0e986 to 1e-986. @@ -1762,11 +1761,11 @@ #define SQLITE_TrustedSchema 0x00000080 /* Allow unsafe functions and ** vtabs in the schema definition */ #define SQLITE_NullCallback 0x00000100 /* Invoke the callback once if the */ /* result set is empty */ #define SQLITE_IgnoreChecks 0x00000200 /* Do not enforce check constraints */ -#define SQLITE_StmtScanStatus 0x00000400 /* Enable stmt_scanstats() counters */ +#define SQLITE_ReadUncommit 0x00000400 /* READ UNCOMMITTED in shared-cache */ #define SQLITE_NoCkptOnClose 0x00000800 /* No checkpoint on close()/DETACH */ #define SQLITE_ReverseOrder 0x00001000 /* Reverse unordered SELECTs */ #define SQLITE_RecTriggers 0x00002000 /* Enable recursive triggers */ #define SQLITE_ForeignKeys 0x00004000 /* Enforce foreign key constraints */ #define SQLITE_AutoIndex 0x00008000 /* Enable automatic indexes */ @@ -1788,11 +1787,10 @@ #define SQLITE_EnableView 0x80000000 /* Enable the use of views */ #define SQLITE_CountRows HI(0x00001) /* Count rows changed by INSERT, */ /* DELETE, or UPDATE and return */ /* the count using a callback. */ #define SQLITE_CorruptRdOnly HI(0x00002) /* Prohibit writes due to error */ -#define SQLITE_ReadUncommit HI(0x00004) /* READ UNCOMMITTED in shared-cache */ /* Flags used only if debugging */ #ifdef SQLITE_DEBUG #define SQLITE_SqlTrace HI(0x0100000) /* Debug print SQL as it executes */ #define SQLITE_VdbeListing HI(0x0200000) /* Debug listings of VDBE progs */ @@ -1845,11 +1843,10 @@ #define SQLITE_ReleaseReg 0x00400000 /* Use OP_ReleaseReg for testing */ #define SQLITE_FlttnUnionAll 0x00800000 /* Disable the UNION ALL flattener */ /* TH3 expects this value ^^^^^^^^^^ See flatten04.test */ #define SQLITE_IndexedExpr 0x01000000 /* Pull exprs from index when able */ #define SQLITE_Coroutines 0x02000000 /* Co-routines for subqueries */ -#define SQLITE_NullUnusedCols 0x04000000 /* NULL unused columns in subqueries */ #define SQLITE_AllOpts 0xffffffff /* All optimizations */ /* ** Macros for testing whether or not optimizations are enabled or disabled. */ @@ -2317,11 +2314,10 @@ sqlite3 *db; /* Database connection associated with this table */ Module *pMod; /* Pointer to module implementation */ sqlite3_vtab *pVtab; /* Pointer to vtab instance */ int nRef; /* Number of pointers to this structure */ u8 bConstraint; /* True if constraints are supported */ - u8 bAllSchemas; /* True if might use any attached schema */ u8 eVtabRisk; /* Riskiness of allowing hacker access */ int iSavepoint; /* Depth of the SAVEPOINT stack */ VTable *pNext; /* Next in linked list (see above) */ }; @@ -2698,11 +2694,10 @@ unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */ unsigned bHasExpr:1; /* Index contains an expression, either a literal ** expression, or a reference to a VIRTUAL column */ #ifdef SQLITE_ENABLE_STAT4 int nSample; /* Number of elements in aSample[] */ - int mxSample; /* Number of slots allocated to aSample[] */ int nSampleCol; /* Size of IndexSample.anEq[] and so on */ tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */ IndexSample *aSample; /* Samples of the left-most key */ tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this index */ tRowcnt nRowEst0; /* Non-logarithmic number of rows in the index */ @@ -3350,11 +3345,11 @@ #define NC_IsCheck 0x000004 /* True if resolving a CHECK constraint */ #define NC_GenCol 0x000008 /* True for a GENERATED ALWAYS AS clause */ #define NC_HasAgg 0x000010 /* One or more aggregate functions seen */ #define NC_IdxExpr 0x000020 /* True if resolving columns of CREATE INDEX */ #define NC_SelfRef 0x00002e /* Combo: PartIdx, isCheck, GenCol, and IdxExpr */ -#define NC_Subquery 0x000040 /* A subquery has been seen */ +#define NC_VarSelect 0x000040 /* A correlated subquery has been seen */ #define NC_UEList 0x000080 /* True if uNC.pEList is used */ #define NC_UAggInfo 0x000100 /* True if uNC.pAggInfo is used */ #define NC_UUpsert 0x000200 /* True if uNC.pUpsert is used */ #define NC_UBaseReg 0x000400 /* True if uNC.iBaseReg is used */ #define NC_MinMaxAgg 0x001000 /* min/max aggregates seen. See note above */ @@ -3669,11 +3664,10 @@ Expr *pExpr; /* The expression contained in the index */ int iDataCur; /* The data cursor associated with the index */ int iIdxCur; /* The index cursor */ int iIdxCol; /* The index column that contains value of pExpr */ u8 bMaybeNullRow; /* True if we need an OP_IfNullRow check */ - u8 aff; /* Affinity of the pExpr expression */ IndexedExpr *pIENext; /* Next in a list of all indexed expressions */ #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS const char *zIdxName; /* Name of index, used only for bytecode comments */ #endif }; @@ -3722,13 +3716,10 @@ u8 prepFlags; /* SQLITE_PREPARE_* flags */ u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */ #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */ #endif -#ifdef SQLITE_DEBUG - u8 ifNotExists; /* Might be true if IF NOT EXISTS. Assert()s only */ -#endif int nRangeReg; /* Size of the temporary register block */ int iRangeReg; /* First register in temporary register block */ int nErr; /* Number of errors seen */ int nTab; /* Number of previously allocated VDBE cursors */ int nMem; /* Number of memory cells used so far */ @@ -4185,11 +4176,10 @@ struct RenameCtx *pRename; /* RENAME COLUMN context */ struct Table *pTab; /* Table of generated column */ struct CoveringIndexCheck *pCovIdxCk; /* Check for covering index */ SrcItem *pSrcItem; /* A single FROM clause item */ DbFixer *pFix; /* See sqlite3FixSelect() */ - Mem *aMem; /* See sqlite3BtreeCursorHint() */ } u; }; /* ** The following structure contains information used by the sqliteFix... @@ -4455,23 +4445,19 @@ # define sqlite3Isalpha(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x02) # define sqlite3Isdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x04) # define sqlite3Isxdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x08) # define sqlite3Tolower(x) (sqlite3UpperToLower[(unsigned char)(x)]) # define sqlite3Isquote(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x80) -# define sqlite3JsonId1(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x42) -# define sqlite3JsonId2(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x46) #else # define sqlite3Toupper(x) toupper((unsigned char)(x)) # define sqlite3Isspace(x) isspace((unsigned char)(x)) # define sqlite3Isalnum(x) isalnum((unsigned char)(x)) # define sqlite3Isalpha(x) isalpha((unsigned char)(x)) # define sqlite3Isdigit(x) isdigit((unsigned char)(x)) # define sqlite3Isxdigit(x) isxdigit((unsigned char)(x)) # define sqlite3Tolower(x) tolower((unsigned char)(x)) # define sqlite3Isquote(x) ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`') -# define sqlite3JsonId1(x) (sqlite3IsIdChar(x)&&(x)<'0') -# define sqlite3JsonId2(x) sqlite3IsIdChar(x) #endif int sqlite3IsIdChar(u8); /* ** Internal function prototypes @@ -4661,14 +4647,10 @@ int sqlite3GetTempReg(Parse*); void sqlite3ReleaseTempReg(Parse*,int); int sqlite3GetTempRange(Parse*,int); void sqlite3ReleaseTempRange(Parse*,int,int); void sqlite3ClearTempRegCache(Parse*); -void sqlite3TouchRegister(Parse*,int); -#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_DEBUG) -int sqlite3FirstAvailableRegister(Parse*,int); -#endif #ifdef SQLITE_DEBUG int sqlite3NoTempsInRange(Parse*,int,int); #endif Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int); Expr *sqlite3Expr(sqlite3*,int,const char*); @@ -4815,11 +4797,11 @@ int sqlite3Select(Parse*, Select*, SelectDest*); Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, Expr*,ExprList*,u32,Expr*); void sqlite3SelectDelete(sqlite3*, Select*); Table *sqlite3SrcListLookup(Parse*, SrcList*); -int sqlite3IsReadOnly(Parse*, Table*, Trigger*); +int sqlite3IsReadOnly(Parse*, Table*, int); void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*); #endif void sqlite3CodeChangeCount(Vdbe*,int,const char*); @@ -5352,11 +5334,14 @@ int sqlite3VtabCallConnect(Parse*, Table*); int sqlite3VtabCallDestroy(sqlite3*, int, const char *); int sqlite3VtabBegin(sqlite3 *, VTable *); FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*); -void sqlite3VtabUsesAllSchemas(Parse*); +#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \ + && !defined(SQLITE_OMIT_VIRTUALTABLE) + void sqlite3VtabUsesAllSchemas(sqlite3_index_info*); +#endif sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*); int sqlite3VdbeParameterIndex(Vdbe*, const char*, int); int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *); void sqlite3ParseObjectInit(Parse*,sqlite3*); void sqlite3ParseObjectReset(Parse*); @@ -5599,12 +5584,6 @@ || defined(SQLITE_PERFORMANCE_TRACE) \ || defined(SQLITE_ENABLE_STMT_SCANSTATUS) sqlite3_uint64 sqlite3Hwtime(void); #endif -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS -# define IS_STMT_SCANSTATUS(db) (db->flags & SQLITE_StmtScanStatus) -#else -# define IS_STMT_SCANSTATUS(db) 0 -#endif - #endif /* SQLITEINT_H */ Index: src/test1.c ================================================================== --- src/test1.c +++ src/test1.c @@ -14,17 +14,10 @@ ** testing of the SQLite library. */ #include "sqliteInt.h" #if SQLITE_OS_WIN # include "os_win.h" -# include -#else -# include -# if defined(__APPLE__) -# include -# include -# endif #endif #include "vdbeInt.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" @@ -2389,35 +2382,10 @@ pVfs->xCurrentTimeInt64(pVfs, &t); Tcl_SetObjResult(interp, Tcl_NewWideIntObj(t)); return TCL_OK; } -#ifndef SQLITE_OMIT_VIRTUALTABLE -/* -** Usage: create_null_module DB NAME -*/ -static int SQLITE_TCLAPI test_create_null_module( - void * clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *CONST objv[] -){ - sqlite3 *db; - char *zName; - - if( objc!=3 ){ - Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME"); - return TCL_ERROR; - } - if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; - zName = Tcl_GetString(objv[2]); - - sqlite3_create_module(db, zName, 0, 0); - return TCL_OK; -} -#endif /* SQLITE_OMIT_VIRTUALTABLE */ - #ifdef SQLITE_ENABLE_SNAPSHOT /* ** Usage: sqlite3_snapshot_get DB DBNAME */ static int SQLITE_TCLAPI test_snapshot_get( @@ -8313,11 +8281,10 @@ { "WRITABLE_SCHEMA", SQLITE_DBCONFIG_WRITABLE_SCHEMA }, { "LEGACY_ALTER_TABLE", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE }, { "DQS_DML", SQLITE_DBCONFIG_DQS_DML }, { "DQS_DDL", SQLITE_DBCONFIG_DQS_DDL }, { "LEGACY_FILE_FORMAT", SQLITE_DBCONFIG_LEGACY_FILE_FORMAT }, - { "STMT_SCANSTATUS", SQLITE_DBCONFIG_STMT_SCANSTATUS }, }; int i; int v = 0; const char *zSetting; sqlite3 *db; @@ -8670,44 +8637,10 @@ return TCL_ERROR; } return TCL_OK; } -/* -** Usage: number_of_cores -** -** Return a guess at the number of available cores available on the -** processor on which this process is running. -*/ -static int SQLITE_TCLAPI guess_number_of_cores( - void * clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *CONST objv[] -){ - unsigned int nCore = 1; -#if SQLITE_OS_WIN - SYSTEM_INFO sysinfo; - GetSystemInfo(&sysinfo); - nCore = (unsigned int)sysinfo.dwNumberOfProcessors; -#elif defined(__APPLE__) - int nm[2]; - size_t len = 4; - nm[0] = CTL_HW; nm[1] = HW_AVAILCPU; - sysctl(nm, 2, &nCore, &len, NULL, 0); - if( nCore<1 ){ - nm[1] = HW_NCPU; - sysctl(nm, 2, &nCore, &len, NULL, 0); - } -#else - nCore = sysconf(_SC_NPROCESSORS_ONLN); -#endif - if( nCore<=0 ) nCore = 1; - Tcl_SetObjResult(interp, Tcl_NewIntObj((int)nCore)); - return SQLITE_OK; -} - /* ** Register commands with the TCL interpreter. */ int Sqlitetest1_Init(Tcl_Interp *interp){ @@ -9004,14 +8937,10 @@ { "sqlite3_autovacuum_pages", test_autovacuum_pages, 0 }, { "decode_hexdb", test_decode_hexdb, 0 }, { "test_write_db", test_write_db, 0 }, { "sqlite3_register_cksumvfs", test_register_cksumvfs, 0 }, { "sqlite3_unregister_cksumvfs", test_unregister_cksumvfs, 0 }, - { "number_of_cores", guess_number_of_cores, 0 }, -#ifndef SQLITE_OMIT_VIRTUALTABLE - { "create_null_module", test_create_null_module, 0 }, -#endif }; static int bitmask_size = sizeof(Bitmask)*8; static int longdouble_size = sizeof(LONGDOUBLE_TYPE); int i; extern int sqlite3_sync_count, sqlite3_fullsync_count; Index: src/test_syscall.c ================================================================== --- src/test_syscall.c +++ src/test_syscall.c @@ -108,19 +108,19 @@ static char *ts_getcwd(char *zPath, size_t nPath); static int ts_stat(const char *zPath, struct stat *p); static int ts_fstat(int fd, struct stat *p); static int ts_ftruncate(int fd, off_t n); static int ts_fcntl(int fd, int cmd, ... ); -static ssize_t ts_read(int fd, void *aBuf, size_t nBuf); -static ssize_t ts_pread(int fd, void *aBuf, size_t nBuf, off_t off); +static int ts_read(int fd, void *aBuf, size_t nBuf); +static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off); /* Note: pread64() and pwrite64() actually use off64_t as the type on their ** last parameter. But that datatype is not defined on many systems ** (ex: Mac, OpenBSD). So substitute a likely equivalent: sqlite3_uint64 */ -static ssize_t ts_pread64(int fd, void *aBuf, size_t nBuf, sqlite3_uint64 off); -static ssize_t ts_write(int fd, const void *aBuf, size_t nBuf); -static ssize_t ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off); -static ssize_t ts_pwrite64(int fd, const void *aBuf, size_t nBuf, sqlite3_uint64 off); +static int ts_pread64(int fd, void *aBuf, size_t nBuf, sqlite3_uint64 off); +static int ts_write(int fd, const void *aBuf, size_t nBuf); +static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off); +static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, sqlite3_uint64 off); static int ts_fchmod(int fd, mode_t mode); static int ts_fallocate(int fd, off_t off, off_t len); static void *ts_mmap(void *, size_t, int, int, int, off_t); static void *ts_mremap(void*, size_t, size_t, int, ...); @@ -209,11 +209,11 @@ } /* ** A wrapper around tsIsFail(). If tsIsFail() returns non-zero, set the ** value of errno before returning. -*/ +*/ static int tsIsFailErrno(const char *zFunc){ if( tsIsFail() ){ errno = tsErrno(zFunc); return 1; } @@ -311,41 +311,41 @@ } /* ** A wrapper around read(). */ -static ssize_t ts_read(int fd, void *aBuf, size_t nBuf){ +static int ts_read(int fd, void *aBuf, size_t nBuf){ if( tsIsFailErrno("read") ){ return -1; } return orig_read(fd, aBuf, nBuf); } /* ** A wrapper around pread(). */ -static ssize_t ts_pread(int fd, void *aBuf, size_t nBuf, off_t off){ +static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off){ if( tsIsFailErrno("pread") ){ return -1; } return orig_pread(fd, aBuf, nBuf, off); } /* ** A wrapper around pread64(). */ -static ssize_t ts_pread64(int fd, void *aBuf, size_t nBuf, sqlite3_uint64 off){ +static int ts_pread64(int fd, void *aBuf, size_t nBuf, sqlite3_uint64 off){ if( tsIsFailErrno("pread64") ){ return -1; } return orig_pread64(fd, aBuf, nBuf, off); } /* ** A wrapper around write(). */ -static ssize_t ts_write(int fd, const void *aBuf, size_t nBuf){ +static int ts_write(int fd, const void *aBuf, size_t nBuf){ if( tsIsFailErrno("write") ){ if( tsErrno("write")==EINTR ) orig_write(fd, aBuf, nBuf/2); return -1; } return orig_write(fd, aBuf, nBuf); @@ -352,21 +352,21 @@ } /* ** A wrapper around pwrite(). */ -static ssize_t ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off){ +static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off){ if( tsIsFailErrno("pwrite") ){ return -1; } return orig_pwrite(fd, aBuf, nBuf, off); } /* ** A wrapper around pwrite64(). */ -static ssize_t ts_pwrite64(int fd, const void *aBuf, size_t nBuf, sqlite3_uint64 off){ +static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, sqlite3_uint64 off){ if( tsIsFailErrno("pwrite64") ){ return -1; } return orig_pwrite64(fd, aBuf, nBuf, off); } Index: src/trigger.c ================================================================== --- src/trigger.c +++ src/trigger.c @@ -200,11 +200,10 @@ if( !noErr ){ sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); }else{ assert( !db->init.busy ); sqlite3CodeVerifySchema(pParse, iDb); - VVA_ONLY( pParse->ifNotExists = 1; ) } goto trigger_cleanup; } } @@ -982,11 +981,11 @@ assert( db->mallocFailed==0 ); sqlite3GenerateColumnNames(pParse, &sSelect); } sqlite3ExprListDelete(db, sSelect.pEList); pNew = sqlite3ExpandReturning(pParse, pReturning->pReturnEL, pTab); - if( pParse->nErr==0 ){ + if( !db->mallocFailed ){ NameContext sNC; memset(&sNC, 0, sizeof(sNC)); if( pReturning->nRetCol==0 ){ pReturning->nRetCol = pNew->nExpr; pReturning->iRetCur = pParse->nTab++; @@ -1451,13 +1450,10 @@ const int op = pChanges ? TK_UPDATE : TK_DELETE; u32 mask = 0; Trigger *p; assert( isNew==1 || isNew==0 ); - if( IsView(pTab) ){ - return 0xffffffff; - } for(p=pTrigger; p; p=p->pNext){ if( p->op==op && (tr_tm&p->tr_tm) && checkColumnOverlap(p->pColumns,pChanges) ){ Index: src/update.c ================================================================== --- src/update.c +++ src/update.c @@ -406,11 +406,11 @@ #endif if( sqlite3ViewGetColumnNames(pParse, pTab) ){ goto update_cleanup; } - if( sqlite3IsReadOnly(pParse, pTab, pTrigger) ){ + if( sqlite3IsReadOnly(pParse, pTab, tmask) ){ goto update_cleanup; } /* Allocate a cursors for the main database table and for all indices. ** The index cursors might not be used, but if they are used they @@ -725,26 +725,16 @@ bFinishSeek = 0; }else{ /* Begin the database scan. ** ** Do not consider a single-pass strategy for a multi-row update if - ** there is anything that might disrupt the cursor being used to do - ** the UPDATE: - ** (1) This is a nested UPDATE - ** (2) There are triggers - ** (3) There are FOREIGN KEY constraints - ** (4) There are REPLACE conflict handlers - ** (5) There are subqueries in the WHERE clause - */ + ** there are any triggers or foreign keys to process, or rows may + ** be deleted as a result of REPLACE conflict handling. Any of these + ** things might disturb a cursor being used to scan through the table + ** or index, causing a single-pass approach to malfunction. */ flags = WHERE_ONEPASS_DESIRED; - if( !pParse->nested - && !pTrigger - && !hasFK - && !chngKey - && !bReplace - && (sNC.ncFlags & NC_Subquery)==0 - ){ + if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){ flags |= WHERE_ONEPASS_MULTIROW; } pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0,0,0,flags,iIdxCur); if( pWInfo==0 ) goto update_cleanup; Index: src/util.c ================================================================== --- src/util.c +++ src/util.c @@ -668,19 +668,17 @@ }else{ x = v; } i = sizeof(zTemp)-2; zTemp[sizeof(zTemp)-1] = 0; - while( 1 /*exit-by-break*/ ){ - zTemp[i] = (x%10) + '0'; + do{ + zTemp[i--] = (x%10) + '0'; x = x/10; - if( x==0 ) break; - i--; - }; - if( v<0 ) zTemp[--i] = '-'; - memcpy(zOut, &zTemp[i], sizeof(zTemp)-i); - return sizeof(zTemp)-1-i; + }while( x ); + if( v<0 ) zTemp[i--] = '-'; + memcpy(zOut, &zTemp[i+1], sizeof(zTemp)-1-i); + return sizeof(zTemp)-2-i; } /* ** Compare the 19-character string zNum against the text representation ** value 2^63: 9223372036854775808. Return negative, zero, or positive @@ -841,13 +839,11 @@ for(i=2; z[i]=='0'; i++){} for(k=i; sqlite3Isxdigit(z[k]); k++){ u = u*16 + sqlite3HexToInt(z[k]); } memcpy(pOut, &u, 8); - if( k-i>16 ) return 2; - if( z[k]!=0 ) return 1; - return 0; + return (z[k]==0 && k-i<=16) ? 0 : 2; }else #endif /* SQLITE_OMIT_HEX_INTEGER */ { return sqlite3Atoi64(z, pOut, sqlite3Strlen30(z), SQLITE_UTF8); } @@ -879,11 +875,11 @@ && sqlite3Isxdigit(zNum[2]) ){ u32 u = 0; zNum += 2; while( zNum[0]=='0' ) zNum++; - for(i=0; i<8 && sqlite3Isxdigit(zNum[i]); i++){ + for(i=0; sqlite3Isxdigit(zNum[i]) && i<8; i++){ u = u*16 + sqlite3HexToInt(zNum[i]); } if( (u&0x80000000)==0 && sqlite3Isxdigit(zNum[i])==0 ){ memcpy(pValue, &u, 4); return 1; Index: src/vdbe.c ================================================================== --- src/vdbe.c +++ src/vdbe.c @@ -681,14 +681,12 @@ if( p->flags & (MEM_Int|MEM_IntReal) ){ h += p->u.i; }else if( p->flags & MEM_Real ){ h += sqlite3VdbeIntValue(p); }else if( p->flags & (MEM_Str|MEM_Blob) ){ - /* All strings have the same hash and all blobs have the same hash, - ** though, at least, those hashes are different from each other and - ** from NULL. */ - h += 4093 + (p->flags & (MEM_Str|MEM_Blob)); + h += p->n; + if( p->flags & MEM_Zero ) h += p->u.nZero; } } return h; } @@ -734,11 +732,10 @@ Mem *pIn2 = 0; /* 2nd input operand */ Mem *pIn3 = 0; /* 3rd input operand */ Mem *pOut = 0; /* Output operand */ #if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE) u64 *pnCycle = 0; - int bStmtScanStatus = IS_STMT_SCANSTATUS(db)!=0; #endif /*** INSERT STACK UNION HERE ***/ assert( p->eVdbeState==VDBE_RUN_STATE ); /* sqlite3_step() verifies this */ if( DbMaskNonZero(p->lockMask) ){ @@ -799,21 +796,17 @@ ** jumps to abort_due_to_error. */ assert( rc==SQLITE_OK ); assert( pOp>=aOp && pOp<&aOp[p->nOp]); nVmStep++; - -#if defined(VDBE_PROFILE) +#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE) pOp->nExec++; pnCycle = &pOp->nCycle; - if( sqlite3NProfileCnt==0 ) *pnCycle -= sqlite3Hwtime(); -#elif defined(SQLITE_ENABLE_STMT_SCANSTATUS) - if( bStmtScanStatus ){ - pOp->nExec++; - pnCycle = &pOp->nCycle; +# ifdef VDBE_PROFILE + if( sqlite3NProfileCnt==0 ) +# endif *pnCycle -= sqlite3Hwtime(); - } #endif /* Only allow tracing if SQLITE_DEBUG is defined. */ #ifdef SQLITE_DEBUG @@ -1157,11 +1150,11 @@ #ifdef SQLITE_DEBUG if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); } #endif /* A deliberately coded "OP_Halt SQLITE_INTERNAL * * * *" opcode indicates - ** something is wrong with the code generator. Raise an assertion in order + ** something is wrong with the code generator. Raise and assertion in order ** to bring this to the attention of fuzzers and other testing tools. */ assert( pOp->p1!=SQLITE_INTERNAL ); if( p->pFrame && pOp->p1==SQLITE_OK ){ /* Halt the sub-program. Return control to the parent frame. */ @@ -2624,16 +2617,10 @@ ** ** P5 is a bitmask of data types. SQLITE_INTEGER is the least significant ** (0x01) bit. SQLITE_FLOAT is the 0x02 bit. SQLITE_TEXT is 0x04. ** SQLITE_BLOB is 0x08. SQLITE_NULL is 0x10. ** -** WARNING: This opcode does not reliably distinguish between NULL and REAL -** when P1>=0. If the database contains a NaN value, this opcode will think -** that the datatype is REAL when it should be NULL. When P1<0 and the value -** is already stored in register P3, then this opcode does reliably -** distinguish between NULL and REAL. The problem only arises then P1>=0. -** ** Take the jump to address P2 if and only if the datatype of the ** value determined by P1 and P3 corresponds to one of the bits in the ** P5 bitmask. ** */ @@ -2743,11 +2730,11 @@ */ case OP_IfNullRow: { /* jump */ VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; - if( pC && pC->nullRow ){ + if( ALWAYS(pC) && pC->nullRow ){ sqlite3VdbeMemSetNull(aMem + pOp->p3); goto jump_to_p2; } break; } @@ -3238,11 +3225,11 @@ pIn1->flags |= MEM_IntReal; pIn1->flags &= ~MEM_Int; }else{ pIn1->u.r = (double)pIn1->u.i; pIn1->flags |= MEM_Real; - pIn1->flags &= ~(MEM_Int|MEM_Str); + pIn1->flags &= ~MEM_Int; } } REGISTER_TRACE((int)(pIn1-aMem), pIn1); zAffinity++; if( zAffinity[0]==0 ) break; @@ -4977,11 +4964,10 @@ #endif VdbeBranchTaken(0,3); break; } nStep--; - pC->cacheStatus = CACHE_STALE; rc = sqlite3BtreeNext(pC->uc.pCursor, 0); if( rc ){ if( rc==SQLITE_DONE ){ rc = SQLITE_OK; goto seekscan_search_fail; @@ -7630,11 +7616,10 @@ sqlite3VdbeError(p, "%s", sqlite3_value_text(pMem)); goto abort_due_to_error; } sqlite3VdbeChangeEncoding(pMem, encoding); UPDATE_MAX_BLOBSIZE(pMem); - REGISTER_TRACE((int)(pMem-aMem), pMem); break; } #ifndef SQLITE_OMIT_WAL /* Opcode: Checkpoint P1 P2 P3 * * @@ -8781,14 +8766,12 @@ #if defined(VDBE_PROFILE) *pnCycle += sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime(); pnCycle = 0; #elif defined(SQLITE_ENABLE_STMT_SCANSTATUS) - if( pnCycle ){ - *pnCycle += sqlite3Hwtime(); - pnCycle = 0; - } + *pnCycle += sqlite3Hwtime(); + pnCycle = 0; #endif /* The following code adds nothing to the actual functionality ** of the program. It is only here for testing and debugging. ** On the other hand, it does burn CPU cycles every time through Index: src/vdbe.h ================================================================== --- src/vdbe.h +++ src/vdbe.h @@ -401,10 +401,6 @@ #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) void sqlite3VdbePrintOp(FILE*, int, VdbeOp*); #endif -#if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG) -int sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr); -#endif - #endif /* SQLITE_VDBE_H */ Index: src/vdbeapi.c ================================================================== --- src/vdbeapi.c +++ src/vdbeapi.c @@ -269,11 +269,11 @@ SQLITE_NULL, /* 0x1d (not possible) */ SQLITE_INTEGER, /* 0x1e (not possible) */ SQLITE_NULL, /* 0x1f (not possible) */ SQLITE_FLOAT, /* 0x20 INTREAL */ SQLITE_NULL, /* 0x21 (not possible) */ - SQLITE_FLOAT, /* 0x22 INTREAL + TEXT */ + SQLITE_TEXT, /* 0x22 INTREAL + TEXT */ SQLITE_NULL, /* 0x23 (not possible) */ SQLITE_FLOAT, /* 0x24 (not possible) */ SQLITE_NULL, /* 0x25 (not possible) */ SQLITE_FLOAT, /* 0x26 (not possible) */ SQLITE_NULL, /* 0x27 (not possible) */ @@ -1335,13 +1335,13 @@ p = (Vdbe *)pStmt; db = p->db; assert( db!=0 ); n = sqlite3_column_count(pStmt); if( N=0 ){ - u8 prior_mallocFailed = db->mallocFailed; N += useType*n; sqlite3_mutex_enter(db->mutex); + assert( db->mallocFailed==0 ); #ifndef SQLITE_OMIT_UTF16 if( useUtf16 ){ ret = sqlite3_value_text16((sqlite3_value*)&p->aColName[N]); }else #endif @@ -1349,12 +1349,11 @@ ret = sqlite3_value_text((sqlite3_value*)&p->aColName[N]); } /* A malloc may have failed inside of the _text() call. If this ** is the case, clear the mallocFailed flag and return NULL. */ - assert( db->mallocFailed==0 || db->mallocFailed==1 ); - if( db->mallocFailed > prior_mallocFailed ){ + if( db->mallocFailed ){ sqlite3OomClear(db); ret = 0; } sqlite3_mutex_leave(db->mutex); } @@ -2137,28 +2136,19 @@ int iScanStatusOp, /* Which metric to return */ int flags, void *pOut /* OUT: Write the answer here */ ){ Vdbe *p = (Vdbe*)pStmt; - VdbeOp *aOp = p->aOp; - int nOp = p->nOp; - ScanStatus *pScan = 0; + ScanStatus *pScan; int idx; - if( p->pFrame ){ - VdbeFrame *pFrame; - for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); - aOp = pFrame->aOp; - nOp = pFrame->nOp; - } - if( iScan<0 ){ int ii; if( iScanStatusOp==SQLITE_SCANSTAT_NCYCLE ){ i64 res = 0; - for(ii=0; iinOp; ii++){ + res += p->aOp[ii].nCycle; } *(i64*)pOut = res; return 0; } return 1; @@ -2180,19 +2170,19 @@ if( idx>=p->nScan ) return 1; switch( iScanStatusOp ){ case SQLITE_SCANSTAT_NLOOP: { if( pScan->addrLoop>0 ){ - *(sqlite3_int64*)pOut = aOp[pScan->addrLoop].nExec; + *(sqlite3_int64*)pOut = p->aOp[pScan->addrLoop].nExec; }else{ *(sqlite3_int64*)pOut = -1; } break; } case SQLITE_SCANSTAT_NVISIT: { if( pScan->addrVisit>0 ){ - *(sqlite3_int64*)pOut = aOp[pScan->addrVisit].nExec; + *(sqlite3_int64*)pOut = p->aOp[pScan->addrVisit].nExec; }else{ *(sqlite3_int64*)pOut = -1; } break; } @@ -2210,27 +2200,27 @@ *(const char**)pOut = pScan->zName; break; } case SQLITE_SCANSTAT_EXPLAIN: { if( pScan->addrExplain ){ - *(const char**)pOut = aOp[ pScan->addrExplain ].p4.z; + *(const char**)pOut = p->aOp[ pScan->addrExplain ].p4.z; }else{ *(const char**)pOut = 0; } break; } case SQLITE_SCANSTAT_SELECTID: { if( pScan->addrExplain ){ - *(int*)pOut = aOp[ pScan->addrExplain ].p1; + *(int*)pOut = p->aOp[ pScan->addrExplain ].p1; }else{ *(int*)pOut = -1; } break; } case SQLITE_SCANSTAT_PARENTID: { if( pScan->addrExplain ){ - *(int*)pOut = aOp[ pScan->addrExplain ].p2; + *(int*)pOut = p->aOp[ pScan->addrExplain ].p2; }else{ *(int*)pOut = -1; } break; } @@ -2244,22 +2234,22 @@ int iIns = pScan->aAddrRange[ii]; int iEnd = pScan->aAddrRange[ii+1]; if( iIns==0 ) break; if( iIns>0 ){ while( iIns<=iEnd ){ - res += aOp[iIns].nCycle; + res += p->aOp[iIns].nCycle; iIns++; } }else{ int iOp; - for(iOp=0; iOpnOp; iOp++){ + Op *pOp = &p->aOp[iOp]; if( pOp->p1!=iEnd ) continue; if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_NCYCLE)==0 ){ continue; } - res += aOp[iOp].nCycle; + res += p->aOp[iOp].nCycle; } } } } *(i64*)pOut = res; Index: src/vdbeaux.c ================================================================== --- src/vdbeaux.c +++ src/vdbeaux.c @@ -441,14 +441,14 @@ ** If the bPush flag is true, then make this opcode the parent for ** subsequent Explains until sqlite3VdbeExplainPop() is called. */ int sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){ int addr = 0; -#if !defined(SQLITE_DEBUG) +#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS) /* Always include the OP_Explain opcodes if SQLITE_DEBUG is defined. ** But omit them (for performance) during production builds */ - if( pParse->explain==2 || IS_STMT_SCANSTATUS(pParse->db) ) + if( pParse->explain==2 ) #endif { char *zMsg; Vdbe *v; va_list ap; @@ -818,12 +818,10 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ int nMaxArgs = *pMaxFuncArgs; Op *pOp; Parse *pParse = p->pParse; int *aLabel = pParse->aLabel; - - assert( pParse->db->mallocFailed==0 ); /* tag-20230419-1 */ p->readOnly = 1; p->bIsReader = 0; pOp = &p->aOp[p->nOp-1]; assert( p->aOp[0].opcode==OP_Init ); while( 1 /* Loop termates when it reaches the OP_Init opcode */ ){ @@ -879,11 +877,10 @@ /* The mkopcodeh.tcl script has so arranged things that the only ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to ** have non-negative values for P2. */ assert( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 ); assert( ADDR(pOp->p2)<-pParse->nLabel ); - assert( aLabel!=0 ); /* True because of tag-20230419-1 */ pOp->p2 = aLabel[ADDR(pOp->p2)]; } break; } } @@ -1123,24 +1120,22 @@ int addrLoop, /* Address of loop counter */ int addrVisit, /* Address of rows visited counter */ LogEst nEst, /* Estimated number of output rows */ const char *zName /* Name of table or index being scanned */ ){ - if( IS_STMT_SCANSTATUS(p->db) ){ - sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus); - ScanStatus *aNew; - aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte); - if( aNew ){ - ScanStatus *pNew = &aNew[p->nScan++]; - memset(pNew, 0, sizeof(ScanStatus)); - pNew->addrExplain = addrExplain; - pNew->addrLoop = addrLoop; - pNew->addrVisit = addrVisit; - pNew->nEst = nEst; - pNew->zName = sqlite3DbStrDup(p->db, zName); - p->aScan = aNew; - } + sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus); + ScanStatus *aNew; + aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte); + if( aNew ){ + ScanStatus *pNew = &aNew[p->nScan++]; + memset(pNew, 0, sizeof(ScanStatus)); + pNew->addrExplain = addrExplain; + pNew->addrLoop = addrLoop; + pNew->addrVisit = addrVisit; + pNew->nEst = nEst; + pNew->zName = sqlite3DbStrDup(p->db, zName); + p->aScan = aNew; } } /* ** Add the range of instructions from addrStart to addrEnd (inclusive) to @@ -1153,26 +1148,24 @@ Vdbe *p, int addrExplain, int addrStart, int addrEnd ){ - if( IS_STMT_SCANSTATUS(p->db) ){ - ScanStatus *pScan = 0; - int ii; - for(ii=p->nScan-1; ii>=0; ii--){ - pScan = &p->aScan[ii]; - if( pScan->addrExplain==addrExplain ) break; - pScan = 0; - } - if( pScan ){ - if( addrEnd<0 ) addrEnd = sqlite3VdbeCurrentAddr(p)-1; - for(ii=0; iiaAddrRange); ii+=2){ - if( pScan->aAddrRange[ii]==0 ){ - pScan->aAddrRange[ii] = addrStart; - pScan->aAddrRange[ii+1] = addrEnd; - break; - } + ScanStatus *pScan = 0; + int ii; + for(ii=p->nScan-1; ii>=0; ii--){ + pScan = &p->aScan[ii]; + if( pScan->addrExplain==addrExplain ) break; + pScan = 0; + } + if( pScan ){ + if( addrEnd<0 ) addrEnd = sqlite3VdbeCurrentAddr(p)-1; + for(ii=0; iiaAddrRange); ii+=2){ + if( pScan->aAddrRange[ii]==0 ){ + pScan->aAddrRange[ii] = addrStart; + pScan->aAddrRange[ii+1] = addrEnd; + break; } } } } @@ -1185,25 +1178,23 @@ Vdbe *p, int addrExplain, int addrLoop, int addrVisit ){ - if( IS_STMT_SCANSTATUS(p->db) ){ - ScanStatus *pScan = 0; - int ii; - for(ii=p->nScan-1; ii>=0; ii--){ - pScan = &p->aScan[ii]; - if( pScan->addrExplain==addrExplain ) break; - pScan = 0; - } - if( pScan ){ - pScan->addrLoop = addrLoop; - pScan->addrVisit = addrVisit; - } - } -} -#endif /* defined(SQLITE_ENABLE_STMT_SCANSTATUS) */ + ScanStatus *pScan = 0; + int ii; + for(ii=p->nScan-1; ii>=0; ii--){ + pScan = &p->aScan[ii]; + if( pScan->addrExplain==addrExplain ) break; + pScan = 0; + } + if( pScan ){ + pScan->addrLoop = addrLoop; + pScan->addrVisit = addrVisit; + } +} +#endif /* ** Change the value of the opcode, or P1, P2, P3, or P5 operands ** for a specific instruction. @@ -1623,11 +1614,11 @@ } } /* Return the most recently added opcode */ -VdbeOp *sqlite3VdbeGetLastOp(Vdbe *p){ +VdbeOp * sqlite3VdbeGetLastOp(Vdbe *p){ return sqlite3VdbeGetOp(p, p->nOp - 1); } #if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS) /* @@ -3327,12 +3318,10 @@ db->nDeferredCons = 0; db->nDeferredImmCons = 0; db->flags &= ~(u64)SQLITE_DeferFKs; sqlite3CommitInternalChanges(db); } - }else if( p->rc==SQLITE_SCHEMA && db->nVdbeActive>1 ){ - p->nChange = 0; }else{ sqlite3RollbackAll(db, SQLITE_OK); p->nChange = 0; } db->nStatement = 0; @@ -3647,13 +3636,13 @@ vdbeFreeOpArray(db, p->aOp, p->nOp); if( p->zSql ) sqlite3DbNNFreeNN(db, p->zSql); #ifdef SQLITE_ENABLE_NORMALIZE sqlite3DbFree(db, p->zNormSql); { - DblquoteStr *pThis, *pNxt; - for(pThis=p->pDblStr; pThis; pThis=pNxt){ - pNxt = pThis->pNextStr; + DblquoteStr *pThis, *pNext; + for(pThis=p->pDblStr; pThis; pThis=pNext){ + pNext = pThis->pNextStr; sqlite3DbFree(db, pThis); } } #endif #ifdef SQLITE_ENABLE_STMT_SCANSTATUS @@ -5276,24 +5265,10 @@ return 0; } return 1; } -#if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG) -/* -** This Walker callback is used to help verify that calls to -** sqlite3BtreeCursorHint() with opcode BTREE_HINT_RANGE have -** byte-code register values correctly initialized. -*/ -int sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr){ - if( pExpr->op==TK_REGISTER ){ - assert( (pWalker->u.aMem[pExpr->iTable].flags & MEM_Undefined)==0 ); - } - return WRC_Continue; -} -#endif /* SQLITE_ENABLE_CURSOR_HINTS && SQLITE_DEBUG */ - #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored ** in memory obtained from sqlite3_malloc) into a Vdbe.zErrMsg (text stored ** in memory obtained from sqlite3DbMalloc). @@ -5352,20 +5327,10 @@ sqlite3 *db = v->db; i64 iKey2; PreUpdate preupdate; const char *zTbl = pTab->zName; static const u8 fakeSortOrder = 0; -#ifdef SQLITE_DEBUG - int nRealCol; - if( pTab->tabFlags & TF_WithoutRowid ){ - nRealCol = sqlite3PrimaryKeyIndex(pTab)->nColumn; - }else if( pTab->tabFlags & TF_HasVirtual ){ - nRealCol = pTab->nNVCol; - }else{ - nRealCol = pTab->nCol; - } -#endif assert( db->pPreUpdate==0 ); memset(&preupdate, 0, sizeof(PreUpdate)); if( HasRowid(pTab)==0 ){ iKey1 = iKey2 = 0; @@ -5378,12 +5343,12 @@ } } assert( pCsr!=0 ); assert( pCsr->eCurType==CURTYPE_BTREE ); - assert( pCsr->nField==nRealCol - || (pCsr->nField==nRealCol+1 && op==SQLITE_DELETE && iReg==-1) + assert( pCsr->nField==pTab->nCol + || (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1) ); preupdate.v = v; preupdate.pCsr = pCsr; preupdate.op = op; Index: src/vdbemem.c ================================================================== --- src/vdbemem.c +++ src/vdbemem.c @@ -155,11 +155,10 @@ Mem tmp; char zBuf[100]; char *z; int i, j, incr; if( (p->flags & MEM_Str)==0 ) return 1; - if( p->db && p->db->mallocFailed ) return 1; if( p->flags & MEM_Term ){ /* Insure that the string is properly zero-terminated. Pay particular ** attention to the case where p->n is odd */ if( p->szMalloc>0 && p->z==p->zMalloc ){ assert( p->enc==SQLITE_UTF8 || p->szMalloc >= ((p->n+1)&~1)+2 ); @@ -438,11 +437,11 @@ return SQLITE_NOMEM_BKPT; } vdbeMemRenderNum(nByte, pMem->z, pMem); assert( pMem->z!=0 ); - assert( pMem->n==(int)sqlite3Strlen30NN(pMem->z) ); + assert( pMem->n==sqlite3Strlen30NN(pMem->z) ); pMem->enc = SQLITE_UTF8; pMem->flags |= MEM_Str|MEM_Term; if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal); sqlite3VdbeChangeEncoding(pMem, enc); return SQLITE_OK; @@ -1482,15 +1481,12 @@ assert( ExprUseXList(p) ); pList = p->x.pList; if( pList ) nVal = pList->nExpr; assert( !ExprHasProperty(p, EP_IntValue) ); pFunc = sqlite3FindFunction(db, p->u.zToken, nVal, enc, 0); -#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION - if( pFunc==0 ) return SQLITE_OK; -#endif assert( pFunc ); - if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0 + if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0 || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL) ){ return SQLITE_OK; } @@ -1521,21 +1517,24 @@ rc = ctx.isError; sqlite3ErrorMsg(pCtx->pParse, "%s", sqlite3_value_text(pVal)); }else{ sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8); assert( rc==SQLITE_OK ); + assert( enc==pVal->enc || db->mallocFailed ); +#if 0 /* Not reachable except after a prior failure */ rc = sqlite3VdbeChangeEncoding(pVal, enc); - if( NEVER(rc==SQLITE_OK && sqlite3VdbeMemTooBig(pVal)) ){ + if( rc==SQLITE_OK && sqlite3VdbeMemTooBig(pVal) ){ rc = SQLITE_TOOBIG; pCtx->pParse->nErr++; } +#endif } + pCtx->pParse->rc = rc; value_from_function_out: if( rc!=SQLITE_OK ){ pVal = 0; - pCtx->pParse->rc = rc; } if( apVal ){ for(i=0; iu.zToken,0); rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx); testcase( rc!=SQLITE_OK ); if( *ppVal ){ -#ifdef SQLITE_ENABLE_STAT4 - rc = ExpandBlob(*ppVal); -#else - /* zero-blobs only come from functions, not literal values. And - ** functions are only processed under STAT4 */ - assert( (ppVal[0][0].flags & MEM_Zero)==0 ); -#endif sqlite3VdbeMemCast(*ppVal, aff, enc); sqlite3ValueApplyAffinity(*ppVal, affinity, enc); } return rc; } Index: src/vtab.c ================================================================== --- src/vtab.c +++ src/vtab.c @@ -608,13 +608,11 @@ sCtx.pTab = pTab; sCtx.pVTable = pVTable; sCtx.pPrior = db->pVtabCtx; sCtx.bDeclared = 0; db->pVtabCtx = &sCtx; - pTab->nTabRef++; rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr); - sqlite3DeleteTable(db, pTab); db->pVtabCtx = sCtx.pPrior; if( rc==SQLITE_NOMEM ) sqlite3OomFault(db); assert( sCtx.pTab==pTab ); if( SQLITE_OK!=rc ){ @@ -1329,14 +1327,10 @@ } case SQLITE_VTAB_DIRECTONLY: { p->pVTable->eVtabRisk = SQLITE_VTABRISK_High; break; } - case SQLITE_VTAB_USES_ALL_SCHEMAS: { - p->pVTable->bAllSchemas = 1; - break; - } default: { rc = SQLITE_MISUSE_BKPT; break; } } Index: src/wal.c ================================================================== --- src/wal.c +++ src/wal.c @@ -1006,44 +1006,23 @@ } assert( nByte>=8 ); assert( (nByte&0x00000007)==0 ); assert( nByte<=65536 ); - assert( nByte%4==0 ); - if( !nativeCksum ){ + if( nativeCksum ){ + do { + s1 += *aData++ + s2; + s2 += *aData++ + s1; + }while( aDatasyncHeader ){ rc = sqlite3OsSync(pWal->apWalFd[iApp], CKPT_SYNC_FLAGS(sync_flags)); if( rc ) return rc; } } - if( (int)pWal->szPage!=szPage ){ - return SQLITE_CORRUPT_BKPT; /* TH3 test case: cov1/corrupt155.test */ - } + assert( (int)pWal->szPage==szPage ); /* Setup information needed to write frames into the WAL */ w.pWal = pWal; w.pFd = pWal->apWalFd[iApp]; w.iSyncPoint = 0; Index: src/where.c ================================================================== --- src/where.c +++ src/where.c @@ -829,11 +829,11 @@ Parse *pParse, Index *pIdx, /* Automatic index to explain */ int bPartial, /* True if pIdx is a partial index */ int *pAddrExplain /* OUT: Address of OP_Explain */ ){ - if( IS_STMT_SCANSTATUS(pParse->db) && pParse->explain!=2 ){ + if( pParse->explain!=2 ){ Table *pTab = pIdx->pTable; const char *zSep = ""; char *zText = 0; int ii = 0; sqlite3_str *pStr = sqlite3_str_new(pParse->db); @@ -890,12 +890,11 @@ CollSeq *pColl; /* Collating sequence to on a column */ WhereLoop *pLoop; /* The Loop object */ char *zNotUsed; /* Extra space on the end of pIdx */ Bitmask idxCols; /* Bitmap of columns used for indexing */ Bitmask extraCols; /* Bitmap of additional columns */ - u8 sentWarning = 0; /* True if a warning has been issued */ - u8 useBloomFilter = 0; /* True to also add a Bloom filter */ + u8 sentWarning = 0; /* True if a warnning has been issued */ Expr *pPartial = 0; /* Partial Index Expression */ int iContinue = 0; /* Jump here to skip excluded rows */ SrcItem *pTabItem; /* FROM clause term being indexed */ int addrCounter = 0; /* Address where integer counter is initialized */ int regBase; /* Array of registers where record is assembled */ @@ -961,15 +960,11 @@ ** original table never needs to be accessed. Automatic indices must ** be a covering index because the index will not be updated if the ** original table changes and the index and table cannot both be used ** if they go out of sync. */ - if( IsView(pTable) ){ - extraCols = ALLBITS; - }else{ - extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1)); - } + extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1)); mxBitCol = MIN(BMS-1,pTable->nCol); testcase( pTable->nCol==BMS-1 ); testcase( pTable->nCol==BMS-2 ); for(i=0; iaiColumn[n] = pTerm->u.x.leftColumn; pColl = sqlite3ExprCompareCollSeq(pParse, pX); assert( pColl!=0 || pParse->nErr>0 ); /* TH3 collate01.800 */ pIdx->azColl[n] = pColl ? pColl->zName : sqlite3StrBINARY; n++; - if( ALWAYS(pX->pLeft!=0) - && sqlite3ExprAffinity(pX->pLeft)!=SQLITE_AFF_TEXT - ){ - /* TUNING: only use a Bloom filter on an automatic index - ** if one or more key columns has the ability to hold numeric - ** values, since strings all have the same hash in the Bloom - ** filter implementation and hence a Bloom filter on a text column - ** is not usually helpful. */ - useBloomFilter = 1; - } } } } assert( (u32)n==pLoop->u.btree.nEq ); @@ -1043,12 +1028,11 @@ assert( pLevel->iIdxCur>=0 ); pLevel->iIdxCur = pParse->nTab++; sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol+1); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "for %s", pTable->zName)); - if( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) && useBloomFilter ){ - sqlite3WhereExplainBloomFilter(pParse, pWC->pWInfo, pLevel); + if( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ){ pLevel->regFilter = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Blob, 10000, pLevel->regFilter); } /* Fill the automatic index with content */ @@ -1137,14 +1121,10 @@ const WhereTerm *pWCEnd; /* Last WHERE clause term */ Parse *pParse = pWInfo->pParse; /* Parsing context */ Vdbe *v = pParse->pVdbe; /* VDBE under construction */ WhereLoop *pLoop = pLevel->pWLoop; /* The loop being coded */ int iCur; /* Cursor for table getting the filter */ - IndexedExpr *saved_pIdxEpr; /* saved copy of Parse.pIdxEpr */ - - saved_pIdxEpr = pParse->pIdxEpr; - pParse->pIdxEpr = 0; assert( pLoop!=0 ); assert( v!=0 ); assert( pLoop->wsFlags & WHERE_BLOOMFILTER ); @@ -1197,12 +1177,13 @@ Index *pIdx = pLoop->u.btree.pIndex; int n = pLoop->u.btree.nEq; int r1 = sqlite3GetTempRange(pParse, n); int jj; for(jj=0; jjaiColumn[jj]; assert( pIdx->pTable==pItem->pTab ); - sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iCur, jj, r1+jj); + sqlite3ExprCodeGetColumnOfTable(v, pIdx->pTable, iCur, iCol,r1+jj); } sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, n); sqlite3ReleaseTempRange(pParse, r1, n); } sqlite3VdbeResolveLabel(v, addrCont); @@ -1229,11 +1210,10 @@ break; } } }while( iLevel < pWInfo->nLevel ); sqlite3VdbeJumpHere(v, addrOnce); - pParse->pIdxEpr = saved_pIdxEpr; } #ifndef SQLITE_OMIT_VIRTUALTABLE /* @@ -1485,13 +1465,10 @@ sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc)); }else{ sqlite3ErrorMsg(pParse, "%s", pVtab->zErrMsg); } } - if( pTab->u.vtab.p->bAllSchemas ){ - sqlite3VtabUsesAllSchemas(pParse); - } sqlite3_free(pVtab->zErrMsg); pVtab->zErrMsg = 0; return rc; } #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */ @@ -1531,11 +1508,10 @@ UNUSED_PARAMETER( pParse ); #endif assert( pRec!=0 ); assert( pIdx->nSample>0 ); assert( pRec->nField>0 ); - /* Do a binary search to find the first sample greater than or equal ** to pRec. If pRec contains a single field, the set of samples to search ** is simply the aSample[] array. If the samples in aSample[] contain more ** than one fields, all fields following the first are ignored. @@ -1577,16 +1553,11 @@ ** appears that it should be 1 field in size. However, that would make it ** smaller than sample 1, so the binary search would not work. As a result, ** it is extended to two fields. The duplicates that this creates do not ** cause any problems. */ - if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){ - nField = pIdx->nKeyCol; - }else{ - nField = pIdx->nColumn; - } - nField = MIN(pRec->nField, nField); + nField = MIN(pRec->nField, pIdx->nSample); iCol = 0; iSample = pIdx->nSample * nField; do{ int iSamp; /* Index in aSample[] of test sample */ int n; /* Number of fields in test sample */ @@ -1648,16 +1619,16 @@ ** be greater than or equal to the (iCol) field prefix of sample i. ** If (i>0), then pRec must also be greater than sample (i-1). */ if( iCol>0 ){ pRec->nField = iCol; assert( sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)<=0 - || pParse->db->mallocFailed || CORRUPT_DB ); + || pParse->db->mallocFailed ); } if( i>0 ){ pRec->nField = nField; assert( sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0 - || pParse->db->mallocFailed || CORRUPT_DB ); + || pParse->db->mallocFailed ); } } } #endif /* ifdef SQLITE_DEBUG */ @@ -2018,11 +1989,11 @@ #else UNUSED_PARAMETER(pParse); UNUSED_PARAMETER(pBuilder); assert( pLower || pUpper ); #endif - assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 || pParse->nErr>0 ); + assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 ); nNew = whereRangeAdjust(pLower, nOut); nNew = whereRangeAdjust(pUpper, nNew); /* TUNING: If there is both an upper and lower limit and neither limit ** has an application-defined likelihood(), assume the range is @@ -2150,11 +2121,11 @@ nRowEst += nEst; pBuilder->nRecValid = nRecValid; } if( rc==SQLITE_OK ){ - if( nRowEst > (tRowcnt)nRow0 ) nRowEst = nRow0; + if( nRowEst > nRow0 ) nRowEst = nRow0; *pnRow = nRowEst; WHERETRACE(0x20,("IN row estimate: est=%d\n", nRowEst)); } assert( pBuilder->nRecValid==nRecValid ); return rc; @@ -4119,20 +4090,24 @@ HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1]; assert( pHidden->eDistinct>=0 && pHidden->eDistinct<=3 ); return pHidden->eDistinct; } +#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \ + && !defined(SQLITE_OMIT_VIRTUALTABLE) /* ** Cause the prepared statement that is associated with a call to ** xBestIndex to potentially use all schemas. If the statement being ** prepared is read-only, then just start read transactions on all ** schemas. But if this is a write operation, start writes on all ** schemas. ** ** This is used by the (built-in) sqlite_dbpage virtual table. */ -void sqlite3VtabUsesAllSchemas(Parse *pParse){ +void sqlite3VtabUsesAllSchemas(sqlite3_index_info *pIdxInfo){ + HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1]; + Parse *pParse = pHidden->pParse; int nDb = pParse->db->nDb; int i; for(i=0; ipNew->iTab. That table is guaranteed to be a virtual table. ** @@ -5305,14 +5281,10 @@ pWInfo->nOBSat = pFrom->isOrdered; if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){ if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){ pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; } - if( pWInfo->pSelect->pOrderBy - && pWInfo->nOBSat > pWInfo->pSelect->pOrderBy->nExpr ){ - pWInfo->nOBSat = pWInfo->pSelect->pOrderBy->nExpr; - } }else{ pWInfo->revMask = pFrom->revLoop; if( pWInfo->nOBSat<=0 ){ pWInfo->nOBSat = 0; if( nLoop>0 ){ @@ -5720,13 +5692,10 @@ p->pExpr = sqlite3ExprDup(pParse->db, pExpr, 0); p->iDataCur = pTabItem->iCursor; p->iIdxCur = iIdxCur; p->iIdxCol = i; p->bMaybeNullRow = bMaybeNullRow; - if( sqlite3IndexAffinityStr(pParse->db, pIdx) ){ - p->aff = pIdx->zColAff[i]; - } #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS p->zIdxName = pIdx->zName; #endif pParse->pIdxEpr = p; if( p->pIENext==0 ){ @@ -5980,49 +5949,26 @@ if( pSelect && pSelect->pLimit ){ sqlite3WhereAddLimit(&pWInfo->sWC, pSelect); } if( pParse->nErr ) goto whereBeginError; - /* The False-WHERE-Term-Bypass optimization: - ** - ** If there are WHERE terms that are false, then no rows will be output, - ** so skip over all of the code generated here. - ** - ** Conditions: - ** - ** (1) The WHERE term must not refer to any tables in the join. - ** (2) The term must not come from an ON clause on the - ** right-hand side of a LEFT or FULL JOIN. - ** (3) The term must not come from an ON clause, or there must be - ** no RIGHT or FULL OUTER joins in pTabList. - ** (4) If the expression contains non-deterministic functions - ** that are not within a sub-select. This is not required - ** for correctness but rather to preserves SQLite's legacy - ** behaviour in the following two cases: - ** - ** WHERE random()>0; -- eval random() once per row - ** WHERE (SELECT random())>0; -- eval random() just once overall - ** - ** Note that the Where term need not be a constant in order for this - ** optimization to apply, though it does need to be constant relative to - ** the current subquery (condition 1). The term might include variables - ** from outer queries so that the value of the term changes from one - ** invocation of the current subquery to the next. + /* Special case: WHERE terms that do not refer to any tables in the join + ** (constant expressions). Evaluate each such term, and jump over all the + ** generated code if the result is not true. + ** + ** Do not do this if the expression contains non-deterministic functions + ** that are not within a sub-select. This is not strictly required, but + ** preserves SQLite's legacy behaviour in the following two cases: + ** + ** FROM ... WHERE random()>0; -- eval random() once per row + ** FROM ... WHERE (SELECT random())>0; -- eval random() once overall */ for(ii=0; iinBase; ii++){ - WhereTerm *pT = &sWLB.pWC->a[ii]; /* A term of the WHERE clause */ - Expr *pX; /* The expression of pT */ + WhereTerm *pT = &sWLB.pWC->a[ii]; if( pT->wtFlags & TERM_VIRTUAL ) continue; - pX = pT->pExpr; - assert( pX!=0 ); - assert( pT->prereqAll!=0 || !ExprHasProperty(pX, EP_OuterON) ); - if( pT->prereqAll==0 /* Conditions (1) and (2) */ - && (nTabList==0 || exprIsDeterministic(pX)) /* Condition (4) */ - && !(ExprHasProperty(pX, EP_InnerON) /* Condition (3) */ - && (pTabList->a[0].fg.jointype & JT_LTORJ)!=0 ) - ){ - sqlite3ExprIfFalse(pParse, pX, pWInfo->iBreak, SQLITE_JUMPIFNULL); + if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){ + sqlite3ExprIfFalse(pParse, pT->pExpr, pWInfo->iBreak, SQLITE_JUMPIFNULL); pT->wtFlags |= TERM_CODED; } } if( wctrlFlags & WHERE_WANT_DISTINCT ){ @@ -6261,11 +6207,11 @@ for(; b; b=b>>1, n++){} sqlite3VdbeChangeP4(v, -1, SQLITE_INT_TO_PTR(n), P4_INT32); assert( n<=pTab->nCol ); } #ifdef SQLITE_ENABLE_CURSOR_HINTS - if( pLoop->u.btree.pIndex!=0 && (pTab->tabFlags & TF_WithoutRowid)==0 ){ + if( pLoop->u.btree.pIndex!=0 ){ sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ|bFordelete); }else #endif { sqlite3VdbeChangeP5(v, bFordelete); @@ -6719,12 +6665,11 @@ } } k = pLevel->addrBody + 1; #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeAddopTrace ){ - printf("TRANSLATE cursor %d->%d in opcode range %d..%d\n", - pLevel->iTabCur, pLevel->iIdxCur, k, last-1); + printf("TRANSLATE opcodes in range %d..%d\n", k, last-1); } /* Proof that the "+1" on the k value above is safe */ pOp = sqlite3VdbeGetOp(v, k - 1); assert( pOp->opcode!=OP_Column || pOp->p1!=pLevel->iTabCur ); assert( pOp->opcode!=OP_Rowid || pOp->p1!=pLevel->iTabCur ); Index: src/wherecode.c ================================================================== --- src/wherecode.c +++ src/wherecode.c @@ -109,13 +109,13 @@ sqlite3_str_append(pStr, ")", 1); } /* ** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN -** command, or if stmt_scanstatus_v2() stats are enabled, or if SQLITE_DEBUG -** was defined at compile-time. If it is not a no-op, a single OP_Explain -** opcode is added to the output to describe the table scan strategy in pLevel. +** command, or if either SQLITE_DEBUG or SQLITE_ENABLE_STMT_SCANSTATUS was +** defined at compile-time. If it is not a no-op, a single OP_Explain opcode +** is added to the output to describe the table scan strategy in pLevel. ** ** If an OP_Explain opcode is added to the VM, its address is returned. ** Otherwise, if no OP_Explain is coded, zero is returned. */ int sqlite3WhereExplainOneScan( @@ -123,12 +123,12 @@ SrcList *pTabList, /* Table list this loop refers to */ WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ){ int ret = 0; -#if !defined(SQLITE_DEBUG) - if( sqlite3ParseToplevel(pParse)->explain==2 || IS_STMT_SCANSTATUS(pParse->db) ) +#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS) + if( sqlite3ParseToplevel(pParse)->explain==2 ) #endif { SrcItem *pItem = &pTabList->a[pLevel->iFrom]; Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ @@ -290,33 +290,31 @@ Vdbe *v, /* Vdbe to add scanstatus entry to */ SrcList *pSrclist, /* FROM clause pLvl reads data from */ WhereLevel *pLvl, /* Level to add scanstatus() entry for */ int addrExplain /* Address of OP_Explain (or 0) */ ){ - if( IS_STMT_SCANSTATUS( sqlite3VdbeDb(v) ) ){ - const char *zObj = 0; - WhereLoop *pLoop = pLvl->pWLoop; - int wsFlags = pLoop->wsFlags; - int viaCoroutine = 0; - - if( (wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){ - zObj = pLoop->u.btree.pIndex->zName; - }else{ - zObj = pSrclist->a[pLvl->iFrom].zName; - viaCoroutine = pSrclist->a[pLvl->iFrom].fg.viaCoroutine; - } - sqlite3VdbeScanStatus( - v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj - ); - - if( viaCoroutine==0 ){ - if( (wsFlags & (WHERE_MULTI_OR|WHERE_AUTO_INDEX))==0 ){ - sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iTabCur); - } - if( wsFlags & WHERE_INDEXED ){ - sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur); - } + const char *zObj = 0; + WhereLoop *pLoop = pLvl->pWLoop; + int wsFlags = pLoop->wsFlags; + int viaCoroutine = 0; + + if( (wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){ + zObj = pLoop->u.btree.pIndex->zName; + }else{ + zObj = pSrclist->a[pLvl->iFrom].zName; + viaCoroutine = pSrclist->a[pLvl->iFrom].fg.viaCoroutine; + } + sqlite3VdbeScanStatus( + v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj + ); + + if( viaCoroutine==0 ){ + if( (wsFlags & (WHERE_MULTI_OR|WHERE_AUTO_INDEX))==0 ){ + sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iTabCur); + } + if( wsFlags & WHERE_INDEXED ){ + sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur); } } } #endif @@ -489,79 +487,72 @@ int iEq, /* Look at loop terms starting here */ WhereLoop *pLoop, /* The current loop */ Expr *pX /* The IN expression to be reduced */ ){ sqlite3 *db = pParse->db; - Select *pSelect; /* Pointer to the SELECT on the RHS */ Expr *pNew; pNew = sqlite3ExprDup(db, pX, 0); if( db->mallocFailed==0 ){ - for(pSelect=pNew->x.pSelect; pSelect; pSelect=pSelect->pPrior){ - ExprList *pOrigRhs; /* Original unmodified RHS */ - ExprList *pOrigLhs = 0; /* Original unmodified LHS */ - ExprList *pRhs = 0; /* New RHS after modifications */ - ExprList *pLhs = 0; /* New LHS after mods */ - int i; /* Loop counter */ - - assert( ExprUseXSelect(pNew) ); - pOrigRhs = pSelect->pEList; - assert( pNew->pLeft!=0 ); - assert( ExprUseXList(pNew->pLeft) ); - if( pSelect==pNew->x.pSelect ){ - pOrigLhs = pNew->pLeft->x.pList; - } - for(i=iEq; inLTerm; i++){ - if( pLoop->aLTerm[i]->pExpr==pX ){ - int iField; - assert( (pLoop->aLTerm[i]->eOperator & (WO_OR|WO_AND))==0 ); - iField = pLoop->aLTerm[i]->u.x.iField - 1; - if( pOrigRhs->a[iField].pExpr==0 ) continue; /* Duplicate PK column */ - pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr); - pOrigRhs->a[iField].pExpr = 0; - if( pOrigLhs ){ - assert( pOrigLhs->a[iField].pExpr!=0 ); - pLhs = sqlite3ExprListAppend(pParse,pLhs,pOrigLhs->a[iField].pExpr); - pOrigLhs->a[iField].pExpr = 0; - } - } - } - sqlite3ExprListDelete(db, pOrigRhs); - if( pOrigLhs ){ - sqlite3ExprListDelete(db, pOrigLhs); - pNew->pLeft->x.pList = pLhs; - } - pSelect->pEList = pRhs; - if( pLhs && pLhs->nExpr==1 ){ - /* Take care here not to generate a TK_VECTOR containing only a - ** single value. Since the parser never creates such a vector, some - ** of the subroutines do not handle this case. */ - Expr *p = pLhs->a[0].pExpr; - pLhs->a[0].pExpr = 0; - sqlite3ExprDelete(db, pNew->pLeft); - pNew->pLeft = p; - } - if( pSelect->pOrderBy ){ - /* If the SELECT statement has an ORDER BY clause, zero the - ** iOrderByCol variables. These are set to non-zero when an - ** ORDER BY term exactly matches one of the terms of the - ** result-set. Since the result-set of the SELECT statement may - ** have been modified or reordered, these variables are no longer - ** set correctly. Since setting them is just an optimization, - ** it's easiest just to zero them here. */ - ExprList *pOrderBy = pSelect->pOrderBy; - for(i=0; inExpr; i++){ - pOrderBy->a[i].u.x.iOrderByCol = 0; - } - } + ExprList *pOrigRhs; /* Original unmodified RHS */ + ExprList *pOrigLhs; /* Original unmodified LHS */ + ExprList *pRhs = 0; /* New RHS after modifications */ + ExprList *pLhs = 0; /* New LHS after mods */ + int i; /* Loop counter */ + Select *pSelect; /* Pointer to the SELECT on the RHS */ + + assert( ExprUseXSelect(pNew) ); + pOrigRhs = pNew->x.pSelect->pEList; + assert( pNew->pLeft!=0 ); + assert( ExprUseXList(pNew->pLeft) ); + pOrigLhs = pNew->pLeft->x.pList; + for(i=iEq; inLTerm; i++){ + if( pLoop->aLTerm[i]->pExpr==pX ){ + int iField; + assert( (pLoop->aLTerm[i]->eOperator & (WO_OR|WO_AND))==0 ); + iField = pLoop->aLTerm[i]->u.x.iField - 1; + if( pOrigRhs->a[iField].pExpr==0 ) continue; /* Duplicate PK column */ + pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr); + pOrigRhs->a[iField].pExpr = 0; + assert( pOrigLhs->a[iField].pExpr!=0 ); + pLhs = sqlite3ExprListAppend(pParse, pLhs, pOrigLhs->a[iField].pExpr); + pOrigLhs->a[iField].pExpr = 0; + } + } + sqlite3ExprListDelete(db, pOrigRhs); + sqlite3ExprListDelete(db, pOrigLhs); + pNew->pLeft->x.pList = pLhs; + pNew->x.pSelect->pEList = pRhs; + if( pLhs && pLhs->nExpr==1 ){ + /* Take care here not to generate a TK_VECTOR containing only a + ** single value. Since the parser never creates such a vector, some + ** of the subroutines do not handle this case. */ + Expr *p = pLhs->a[0].pExpr; + pLhs->a[0].pExpr = 0; + sqlite3ExprDelete(db, pNew->pLeft); + pNew->pLeft = p; + } + pSelect = pNew->x.pSelect; + if( pSelect->pOrderBy ){ + /* If the SELECT statement has an ORDER BY clause, zero the + ** iOrderByCol variables. These are set to non-zero when an + ** ORDER BY term exactly matches one of the terms of the + ** result-set. Since the result-set of the SELECT statement may + ** have been modified or reordered, these variables are no longer + ** set correctly. Since setting them is just an optimization, + ** it's easiest just to zero them here. */ + ExprList *pOrderBy = pSelect->pOrderBy; + for(i=0; inExpr; i++){ + pOrderBy->a[i].u.x.iOrderByCol = 0; + } + } #if 0 - printf("For indexing, change the IN expr:\n"); - sqlite3TreeViewExpr(0, pX, 0); - printf("Into:\n"); - sqlite3TreeViewExpr(0, pNew, 0); + printf("For indexing, change the IN expr:\n"); + sqlite3TreeViewExpr(0, pX, 0); + printf("Into:\n"); + sqlite3TreeViewExpr(0, pNew, 0); #endif - } } return pNew; } @@ -1009,32 +1000,31 @@ ** know because CCurHint.pIdx!=0) then transform the TK_COLUMN into ** an access of the index rather than the original table. */ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){ int rc = WRC_Continue; - int reg; struct CCurHint *pHint = pWalker->u.pCCurHint; if( pExpr->op==TK_COLUMN ){ if( pExpr->iTable!=pHint->iTabCur ){ - reg = ++pWalker->pParse->nMem; /* Register for column value */ - reg = sqlite3ExprCodeTarget(pWalker->pParse, pExpr, reg); + int reg = ++pWalker->pParse->nMem; /* Register for column value */ + sqlite3ExprCode(pWalker->pParse, pExpr, reg); pExpr->op = TK_REGISTER; pExpr->iTable = reg; }else if( pHint->pIdx!=0 ){ pExpr->iTable = pHint->iIdxCur; pExpr->iColumn = sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn); assert( pExpr->iColumn>=0 ); } - }else if( pExpr->pAggInfo ){ + }else if( pExpr->op==TK_AGG_FUNCTION ){ + /* An aggregate function in the WHERE clause of a query means this must + ** be a correlated sub-query, and expression pExpr is an aggregate from + ** the parent context. Do not walk the function arguments in this case. + ** + ** todo: It should be possible to replace this node with a TK_REGISTER + ** expression, as the result of the expression must be stored in a + ** register at this point. The same holds for TK_AGG_COLUMN nodes. */ rc = WRC_Prune; - reg = ++pWalker->pParse->nMem; /* Register for column value */ - reg = sqlite3ExprCodeTarget(pWalker->pParse, pExpr, reg); - pExpr->op = TK_REGISTER; - pExpr->iTable = reg; - }else if( pExpr->op==TK_TRUEFALSE ){ - /* Do not walk disabled expressions. tag-20230504-1 */ - return WRC_Prune; } return rc; } /* @@ -1132,11 +1122,11 @@ /* If we survive all prior tests, that means this term is worth hinting */ pExpr = sqlite3ExprAnd(pParse, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0)); } if( pExpr!=0 ){ sWalker.xExprCallback = codeCursorHintFixExpr; - if( pParse->nErr==0 ) sqlite3WalkExpr(&sWalker, pExpr); + sqlite3WalkExpr(&sWalker, pExpr); sqlite3VdbeAddOp4(v, OP_CursorHint, (sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0, (const char*)pExpr, P4_EXPR); } } @@ -1926,11 +1916,11 @@ ** of entries in the tree, so basing the number of steps to try ** on the estimated number of rows in the btree seems like a good ** guess. */ addrSeekScan = sqlite3VdbeAddOp1(v, OP_SeekScan, (pIdx->aiRowLogEst[0]+9)/10); - if( pRangeStart || pRangeEnd ){ + if( pRangeStart ){ sqlite3VdbeChangeP5(v, 1); sqlite3VdbeChangeP2(v, addrSeekScan, sqlite3VdbeCurrentAddr(v)+1); addrSeekScan = 0; } VdbeCoverage(v); @@ -1967,11 +1957,20 @@ */ nConstraint = nEq; assert( pLevel->p2==0 ); if( pRangeEnd ){ Expr *pRight = pRangeEnd->pExpr->pRight; - assert( addrSeekScan==0 ); + if( addrSeekScan ){ + /* For a seek-scan that has a range on the lowest term of the index, + ** we have to make the top of the loop be code that sets the end + ** condition of the range. Otherwise, the OP_SeekScan might jump + ** over that initialization, leaving the range-end value set to the + ** range-start value, resulting in a wrong answer. + ** See ticket 5981a8c041a3c2f3 (2021-11-02). + */ + pLevel->p2 = sqlite3VdbeCurrentAddr(v); + } codeExprOrVector(pParse, pRight, regBase+nEq, nTop); whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd); if( (pRangeEnd->wtFlags & TERM_VNULL)==0 && sqlite3ExprCanBeNull(pRight) ){ @@ -2001,11 +2000,11 @@ } if( zStartAff ) sqlite3DbNNFreeNN(db, zStartAff); if( zEndAff ) sqlite3DbNNFreeNN(db, zEndAff); /* Top of the loop body */ - pLevel->p2 = sqlite3VdbeCurrentAddr(v); + if( pLevel->p2==0 ) pLevel->p2 = sqlite3VdbeCurrentAddr(v); /* Check if the index cursor is past the end of the range. */ if( nConstraint ){ if( regBignull ){ /* Except, skip the end-of-range check while doing the NULL-scan */ Index: src/whereexpr.c ================================================================== --- src/whereexpr.c +++ src/whereexpr.c @@ -972,70 +972,60 @@ ** true even if that particular column is not indexed, because the column ** might be added to an automatic index later. */ static SQLITE_NOINLINE int exprMightBeIndexed2( SrcList *pFrom, /* The FROM clause */ + Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */ int *aiCurCol, /* Write the referenced table cursor and column here */ - Expr *pExpr, /* An operand of a comparison operator */ - int j /* Start looking with the j-th pFrom entry */ + Expr *pExpr /* An operand of a comparison operator */ ){ Index *pIdx; int i; int iCur; - do{ - iCur = pFrom->a[j].iCursor; - for(pIdx=pFrom->a[j].pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->aColExpr==0 ) continue; - for(i=0; inKeyCol; i++){ - if( pIdx->aiColumn[i]!=XN_EXPR ) continue; - assert( pIdx->bHasExpr ); - if( sqlite3ExprCompareSkip(pExpr,pIdx->aColExpr->a[i].pExpr,iCur)==0 - && pExpr->op!=TK_STRING - ){ - aiCurCol[0] = iCur; - aiCurCol[1] = XN_EXPR; - return 1; - } - } - } - }while( ++j < pFrom->nSrc ); + for(i=0; mPrereq>1; i++, mPrereq>>=1){} + iCur = pFrom->a[i].iCursor; + for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( pIdx->aColExpr==0 ) continue; + for(i=0; inKeyCol; i++){ + if( pIdx->aiColumn[i]!=XN_EXPR ) continue; + assert( pIdx->bHasExpr ); + if( sqlite3ExprCompareSkip(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){ + aiCurCol[0] = iCur; + aiCurCol[1] = XN_EXPR; + return 1; + } + } + } return 0; } static int exprMightBeIndexed( SrcList *pFrom, /* The FROM clause */ + Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */ int *aiCurCol, /* Write the referenced table cursor & column here */ Expr *pExpr, /* An operand of a comparison operator */ int op /* The specific comparison operator */ ){ - int i; - /* If this expression is a vector to the left or right of a ** inequality constraint (>, <, >= or <=), perform the processing ** on the first element of the vector. */ assert( TK_GT+1==TK_LE && TK_GT+2==TK_LT && TK_GT+3==TK_GE ); assert( TK_ISop==TK_VECTOR && (op>=TK_GT && ALWAYS(op<=TK_GE)) ){ assert( ExprUseXList(pExpr) ); pExpr = pExpr->x.pList->a[0].pExpr; + } if( pExpr->op==TK_COLUMN ){ aiCurCol[0] = pExpr->iTable; aiCurCol[1] = pExpr->iColumn; return 1; } - - for(i=0; inSrc; i++){ - Index *pIdx; - for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->aColExpr ){ - return exprMightBeIndexed2(pFrom,aiCurCol,pExpr,i); - } - } - } - return 0; + if( mPrereq==0 ) return 0; /* No table references */ + if( (mPrereq&(mPrereq-1))!=0 ) return 0; /* Refs more than one table */ + return exprMightBeIndexed2(pFrom,mPrereq,aiCurCol,pExpr); } /* ** The input to this routine is an WhereTerm structure with only the @@ -1157,19 +1147,19 @@ assert( pLeft->op==TK_VECTOR ); assert( ExprUseXList(pLeft) ); pLeft = pLeft->x.pList->a[pTerm->u.x.iField-1].pExpr; } - if( exprMightBeIndexed(pSrc, aiCurCol, pLeft, op) ){ + if( exprMightBeIndexed(pSrc, prereqLeft, aiCurCol, pLeft, op) ){ pTerm->leftCursor = aiCurCol[0]; assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); pTerm->u.x.leftColumn = aiCurCol[1]; pTerm->eOperator = operatorMask(op) & opMask; } if( op==TK_IS ) pTerm->wtFlags |= TERM_IS; if( pRight - && exprMightBeIndexed(pSrc, aiCurCol, pRight, op) + && exprMightBeIndexed(pSrc, pTerm->prereqRight, aiCurCol, pRight, op) && !ExprHasProperty(pRight, EP_FixedCol) ){ WhereTerm *pNew; Expr *pDup; u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */ @@ -1209,11 +1199,11 @@ if( op==TK_ISNULL && !ExprHasProperty(pExpr,EP_OuterON) && 0==sqlite3ExprCanBeNull(pLeft) ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); - pExpr->op = TK_TRUEFALSE; /* See tag-20230504-1 */ + pExpr->op = TK_TRUEFALSE; pExpr->u.zToken = "false"; ExprSetProperty(pExpr, EP_IsFalse); pTerm->prereqAll = 0; pTerm->eOperator = 0; } @@ -1376,18 +1366,18 @@ sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName), pStr1); transferJoinMarkings(pNewExpr1, pExpr); idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags); testcase( idxNew1==0 ); + exprAnalyze(pSrc, pWC, idxNew1); pNewExpr2 = sqlite3ExprDup(db, pLeft, 0); pNewExpr2 = sqlite3PExpr(pParse, TK_LT, sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName), pStr2); transferJoinMarkings(pNewExpr2, pExpr); idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags); testcase( idxNew2==0 ); - exprAnalyze(pSrc, pWC, idxNew1); exprAnalyze(pSrc, pWC, idxNew2); pTerm = &pWC->a[idxTerm]; if( isComplete ){ markTermAsChild(pWC, idxNew1, idxTerm); markTermAsChild(pWC, idxNew2, idxTerm); @@ -1440,11 +1430,11 @@ */ else if( pExpr->op==TK_IN && pTerm->u.x.iField==0 && pExpr->pLeft->op==TK_VECTOR && ALWAYS( ExprUseXSelect(pExpr) ) - && (pExpr->x.pSelect->pPrior==0 || (pExpr->x.pSelect->selFlags & SF_Values)) + && pExpr->x.pSelect->pPrior==0 #ifndef SQLITE_OMIT_WINDOWFUNC && pExpr->x.pSelect->pWin==0 #endif && pWC->op==TK_AND ){ @@ -1854,17 +1844,14 @@ pColRef->y.pTab = pTab; pItem->colUsed |= sqlite3ExprColUsed(pColRef); pRhs = sqlite3PExpr(pParse, TK_UPLUS, sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0); pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs); - if( pItem->fg.jointype & (JT_LEFT|JT_RIGHT) ){ - testcase( pItem->fg.jointype & JT_LEFT ); /* testtag-20230227a */ - testcase( pItem->fg.jointype & JT_RIGHT ); /* testtag-20230227b */ + if( pItem->fg.jointype & (JT_LEFT|JT_LTORJ) ){ joinType = EP_OuterON; }else{ - testcase( pItem->fg.jointype & JT_LTORJ ); /* testtag-20230227c */ joinType = EP_InnerON; } sqlite3SetJoinExpr(pTerm, pItem->iCursor, joinType); whereClauseInsert(pWC, pTerm, TERM_DYNAMIC); } } Index: src/window.c ================================================================== --- src/window.c +++ src/window.c @@ -783,11 +783,10 @@ } } } /* no break */ deliberate_fall_through - case TK_IF_NULL_ROW: case TK_AGG_FUNCTION: case TK_COLUMN: { int iCol = -1; if( pParse->db->mallocFailed ) return WRC_Abort; if( p->pSub ){ DELETED test/aggfault.test Index: test/aggfault.test ================================================================== --- test/aggfault.test +++ /dev/null @@ -1,43 +0,0 @@ -# 2023 March 30 -# -# 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. -# -#*********************************************************************** -# - -set testdir [file dirname $argv0] -source $testdir/tester.tcl -set testprefix aggfault - - -do_execsql_test 1 { - CREATE TABLE t1(x); - CREATE INDEX t1x ON t1(x, x=0); -} -faultsim_save_and_close - -do_faultsim_test 2 -faults oom* -prep { - faultsim_restore_and_reopen - execsql { SELECT * FROM sqlite_schema } -} -body { - execsql { - SELECT * FROM t1 AS a1 WHERE ( - SELECT count(x AND 0=a1.x) FROM t1 GROUP BY abs(1) - ) AND x=( - SELECT * FROM t1 AS a1 - WHERE (SELECT count(x IS 1 AND a1.x=0) - FROM t1 - GROUP BY abs(1)) AND x=0 - ); - } -} -test { - faultsim_test_result {0 {}} -} - - -finish_test Index: test/altertab.test ================================================================== --- test/altertab.test +++ test/altertab.test @@ -979,24 +979,6 @@ UPDATE t1 SET x=x FROM (SELECT*); END; ALTER TABLE t1 RENAME TO x; } {1 {error in trigger r1: no tables specified}} -# 2023-04-13 https://sqlite.org/forum/forumpost/ff3840145a -# -reset_db -do_execsql_test 33.0 { - CREATE TABLE t1(a TEXT); - INSERT INTO t1(a) VALUES('abc'),('def'),(NULL); - CREATE TABLE t2(b TEXT); - CREATE TRIGGER r3 AFTER INSERT ON t1 BEGIN - UPDATE t2 SET (b,a)=(SELECT 1) FROM t1 JOIN t2 ON (SELECT * FROM (SELECT a)); - END; -} -do_catchsql_test 33.1 { - ALTER TABLE t1 RENAME COLUMN a TO b; -} {1 {error in trigger r3 after rename: no such column: a}} -do_execsql_test 33.2 { - SELECT quote(a) FROM t1 ORDER BY +a; -} {NULL 'abc' 'def'} - finish_test Index: test/analyze3.test ================================================================== --- test/analyze3.test +++ test/analyze3.test @@ -734,33 +734,6 @@ INSERT INTO sqlite_stat1(tbl,idx,stat) VALUES('t1','t1a','12000'); INSERT INTO sqlite_stat1(tbl,idx,stat) VALUES('t1','t1a','12000'); ANALYZE sqlite_master; } -# 2023-04-22 https://sqlite.org/forum/info/6c118daad0f1f5ef -# Case differences in the sqlite_stat4.idx field should not matter. -# -reset_db -do_execsql_test 8.0 { - CREATE TABLE t1(a PRIMARY KEY, v) WITHOUT ROWID; - ANALYZE sqlite_schema; - INSERT INTO sqlite_stat1 VALUES('t1','t1','1 1'); - INSERT INTO sqlite_stat4 VALUES('t1','t1','1','0','0',X'021b76657273696f6e'); - INSERT INTO sqlite_stat4 VALUES('T1','T1','1','0','0',X'021b76657273696f6e'); - ANALYZE sqlite_schema; -} {} - -# 2023-05-03 https://sqlite.org/forum/forumpost/537d8ab118 -# Same index appears by two different names in the sqlite_stat4 table. -# -reset_db -do_execsql_test 8.1 { - CREATE TABLE t1(a INT PRIMARY KEY, b INT) WITHOUT ROWID; - ANALYZE sqlite_schema; - INSERT INTO sqlite_stat4 VALUES - ('t1','t1','1','2','2',X'03000103'), - ('t1','sqlite_autoindex_t1_1','1','2','2',X'03000103'); - ANALYZE sqlite_schema; - PRAGMA integrity_check; -} {ok} - finish_test Index: test/analyzeE.test ================================================================== --- test/analyzeE.test +++ test/analyzeE.test @@ -237,58 +237,6 @@ do_execsql_test analyzeE-4.11 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1900 AND c=123 } {/SCAN t1/} -# 2023-03-23 https://sqlite.org/forum/forumpost/dc4854437b -# -reset_db -do_execsql_test analyzeE-5.0 { - PRAGMA encoding = 'UTF-16'; - CREATE TABLE t0 (c1 TEXT); - INSERT INTO t0 VALUES (''); - CREATE INDEX i0 ON t0(c1); - ANALYZE; - SELECT * FROM t0 WHERE t0.c1 BETWEEN '' AND (ABS('')); -} {{}} - -# 2023-03-24 https://sqlite.org/forum/forumpost/bc39e531e5 -# -reset_db -do_execsql_test analyzeE-6.0 { - CREATE TABLE t1(x); - CREATE INDEX i1 ON t1(x,x,x,x,x||2); - CREATE INDEX i2 ON t1(1<2); - WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1000) - INSERT INTO t1(x) SELECT x FROM c; - ANALYZE; -} {} -do_execsql_test analyzeE-6.1 { - SELECT count(*)>1 FROM sqlite_stat4 WHERE idx='i2' AND neq='1000 1'; -} 1 -do_execsql_test analyzeE-6.2 { - SELECT count(*) FROM sqlite_stat4 WHERE idx='i2' AND neq<>'1000 1'; -} 0 -do_execsql_test analyzeE-6.3 { - SELECT count(*)>1 FROM sqlite_stat4 WHERE idx='i1' AND neq='1 1 1 1 1 1'; -} 1 -do_execsql_test analyzeE-6.4 { - SELECT count(*) FROM sqlite_stat4 WHERE idx='i1' AND neq<>'1 1 1 1 1 1'; -} 0 - -# 2023-03-25 https://sqlite.org/forum/forumpost/5275207102 -# Correctly expand zeroblobs while processing STAT4 information -# during query planning. -# -reset_db -do_execsql_test analyzeE-7.0 { - CREATE TABLE t1(a TEXT COLLATE binary); - CREATE INDEX t1x ON t1(a); - INSERT INTO t1(a) VALUES(0),('apple'),(NULL),(''),('banana'); - ANALYZE; - SELECT format('(%s)',a) FROM t1 WHERE t1.a > CAST(zeroblob(5) AS TEXT); -} {(0) (apple) (banana)} -do_execsql_test analyzeE-7.1 { - SELECT format('(%s)',a) FROM t1 WHERE t1.a <= CAST(zeroblob(5) AS TEXT); -} {()} - finish_test Index: test/autoindex1.test ================================================================== --- test/autoindex1.test +++ test/autoindex1.test @@ -192,11 +192,10 @@ WHERE t501.a IN (SELECT x FROM t502 WHERE y=t501.b); } { QUERY PLAN |--SCAN t501 `--CORRELATED LIST SUBQUERY xxxxxx - |--BLOOM FILTER ON t502 (y=?) `--SEARCH t502 USING AUTOMATIC COVERING INDEX (y=?) } do_eqp_test autoindex1-502 { SELECT b FROM t501 WHERE t501.a=123 Index: test/autoindex3.test ================================================================== --- test/autoindex3.test +++ test/autoindex3.test @@ -84,11 +84,10 @@ do_eqp_test 220 { select count(*) from u, v where u.b = v.b and v.e > 34; } { QUERY PLAN |--SEARCH v USING INDEX ve (e>?) - |--BLOOM FILTER ON u (b=?) `--SEARCH u USING AUTOMATIC COVERING INDEX (b=?) } finish_test Index: test/backup.test ================================================================== --- test/backup.test +++ test/backup.test @@ -975,30 +975,7 @@ sqlite3 db1 :memory: sqlite3 db2 :memory: sqlite3_backup B db1 main db2 temp B finish } {SQLITE_OK} -db1 close -db2 close - -#------------------------------------------------------------------------- -do_test backup-12.1 { - sqlite3 db1 :memory: - sqlite3 db2 :memory: - db1 eval { - PRAGMA page_size = 8192; - CREATE TABLE t1(x); - } - db2 eval { - PRAGMA page_size = 1024; - CREATE TABLE t2(x); - } - - sqlite3_backup B db1 main db2 temp - B step 100 - B finish -} {SQLITE_READONLY} - - - finish_test Index: test/bloom1.test ================================================================== --- test/bloom1.test +++ test/bloom1.test @@ -97,92 +97,8 @@ | | `--SEARCH objs USING COVERING INDEX objs_cspo (o=? AND p=?) | `--RECURSIVE STEP | |--SCAN transit | `--SEARCH objs USING COVERING INDEX objs_cspo (o=? AND p=?) `--SCAN transit -} - -# 2023-02-28 -# https://sqlite.org/forum/forumpost/0846211821 -# -# Bloom filter gives an incorrect result if the collating sequence is -# anything other than binary. -# -reset_db -do_execsql_test 3.1 { - CREATE TABLE t0(x TEXT COLLATE rtrim); - INSERT INTO t0(x) VALUES ('a'), ('b'), ('c'); - CREATE VIEW v0(y) AS SELECT DISTINCT x FROM t0; - SELECT count(*) FROM t0, v0 WHERE x='b '; -} 3 -do_eqp_test 3.2 { - SELECT count(*) FROM t0, v0 WHERE x='b '; -} { - QUERY PLAN - |--CO-ROUTINE v0 - | |--SCAN t0 - | `--USE TEMP B-TREE FOR DISTINCT - |--SCAN v0 - `--SEARCH t0 USING AUTOMATIC PARTIAL COVERING INDEX (x=?) -} -# ^^^^^--- The key feature in the previous result is that no Bloom filter -# is used. In the following, a Bloom filter is used because the data type -# is INT instead of TEXT. -do_execsql_test 3.3 { - CREATE TABLE t1(x INT COLLATE rtrim); - INSERT INTO t1(x) VALUES ('a'), ('b'), ('c'); - CREATE VIEW v1(y) AS SELECT DISTINCT x FROM t1; - SELECT count(*) FROM t1, v1 WHERE x='b '; -} 3 -do_eqp_test 3.4 { - SELECT count(*) FROM t1, v1 WHERE x='b '; -} { - QUERY PLAN - |--CO-ROUTINE v1 - | |--SCAN t1 - | `--USE TEMP B-TREE FOR DISTINCT - |--SCAN v1 - |--BLOOM FILTER ON t1 (x=?) - `--SEARCH t1 USING AUTOMATIC PARTIAL COVERING INDEX (x=?) -} - -# 2023-03-14 -# https://sqlite.org/forum/forumpost/d47a0e8e3a -# https://sqlite.org/forum/forumpost/2e427099d5 -# -# Both reports are for the same problem - using a Bloom filter on an -# expression index can cause issues. -# -reset_db -do_execsql_test 4.1 { - CREATE TABLE t1(x TEXT, y INT, z TEXT); - INSERT INTO t1(rowid,x,y,z) VALUES(12,'aa','bb','aa'); - CREATE INDEX i1x ON t1(1 IS true,z); - CREATE TABLE t0(x TEXT); - INSERT INTO t0(rowid,x) VALUES(4,'aa'); - ANALYZE sqlite_schema; - INSERT INTO sqlite_stat1 VALUES('t0',NULL,'20'); - INSERT INTO sqlite_stat1 VALUES('t1','i1x','18 18 2'); - ANALYZE sqlite_schema; -} -do_execsql_test 4.2 { - SELECT * FROM t0 NATURAL JOIN t1 WHERE z=t1.x; -} {aa bb aa} -do_execsql_test 4.3 { - DROP TABLE t0; - CREATE TABLE t0(a TEXT); - INSERT INTO t0 VALUES ('xyz'); - CREATE INDEX t0x ON t0(a IS FALSE) WHERE false; - DROP TABLE t1; - CREATE TABLE t1(b INT); - INSERT INTO t1 VALUES('aaa'),('bbb'),('ccc'),('ddd'),(NULL); - CREATE TABLE t2(c REAL); - INSERT INTO t2 VALUES(7); - ANALYZE; - CREATE INDEX t2x ON t2(true IN ()); -} -do_execsql_test 4.4 { - SELECT * FROM t0 LEFT JOIN t1 LEFT JOIN t2 ON (b NOTNULL)==(c IN ()) WHERE c; -} {xyz {} 7.0} - +} finish_test Index: test/corrupt2.test ================================================================== --- test/corrupt2.test +++ test/corrupt2.test @@ -97,11 +97,11 @@ sqlite3 db2 corrupt.db # Note: This test is no longer meaningful due to the deferred computation # of MemPage.nFree catchsql {PRAGMA quick_check} db2 } {0 {{*** in database main *** -Tree 1 page 1: free space corruption}}} +Page 1: free space corruption}}} do_test corrupt2-1.5 { db2 close # Corrupt the free-block list on page 1. @@ -118,11 +118,11 @@ close $f sqlite3 db2 corrupt.db catchsql {PRAGMA quick_check} db2 } {0 {{*** in database main *** -Tree 1 page 1: free space corruption}}} +Page 1: free space corruption}}} db2 close # Corrupt a database by having 2 indices of the same name: do_test corrupt2-2.1 { @@ -246,12 +246,12 @@ set result [db2 eval {pragma integrity_check}] break } set result } {{*** in database main *** -Tree 11 page 2 cell 0: 2nd reference to page 10 -Page 4: never used}} +On tree page 2 cell 0: 2nd reference to page 10 +Page 4 is never used}} db2 close proc corruption_test {args} { set A(-corrupt) {} @@ -589,11 +589,11 @@ } {2} do_execsql_test 14.3 { PRAGMA integrity_check; } {{*** in database main *** -Freelist: size is 3 but should be 2}} +Main freelist: size is 3 but should be 2}} # Use 2 of the free pages on the free-list. # do_execsql_test 14.4 { INSERT INTO t1 VALUES(randomblob(2500)); @@ -601,11 +601,11 @@ } {0} do_execsql_test 14.5 { PRAGMA integrity_check; } {{*** in database main *** -Freelist: size is 1 but should be 0}} +Main freelist: size is 1 but should be 0}} finish_test finish_test Index: test/corrupt3.test ================================================================== --- test/corrupt3.test +++ test/corrupt3.test @@ -80,11 +80,11 @@ do_test corrupt3-1.8 { catchsql { PRAGMA integrity_check } } {0 {{*** in database main *** -Tree 2 page 2 cell 0: 2nd reference to page 3}}} +On tree page 2 cell 0: 2nd reference to page 3}}} # Change the pointer for the first page of the overflow # change to be a non-existant page. # do_test corrupt3-1.9 { @@ -98,12 +98,12 @@ do_test corrupt3-1.10 { catchsql { PRAGMA integrity_check } } {0 {{*** in database main *** -Tree 2 page 2 cell 0: invalid page number 4 -Page 3: never used}}} +On tree page 2 cell 0: invalid page number 4 +Page 3 is never used}}} do_test corrupt3-1.11 { db close hexio_write test.db 2044 [hexio_render_int32 0] sqlite3 db test.db catchsql { @@ -113,9 +113,9 @@ do_test corrupt3-1.12 { catchsql { PRAGMA integrity_check } } {0 {{*** in database main *** -Tree 2 page 2 cell 0: overflow list length is 0 but should be 1 -Page 3: never used}}} +On tree page 2 cell 0: overflow list length is 0 but should be 1 +Page 3 is never used}}} finish_test Index: test/corrupt7.test ================================================================== --- test/corrupt7.test +++ test/corrupt7.test @@ -68,18 +68,18 @@ db close hexio_write test.db 1062 FF sqlite3 db test.db db eval {PRAGMA integrity_check(1)} } {{*** in database main *** -Tree 2 page 2 cell 15: Offset 65457 out of range 945..1020}} +On tree page 2 cell 15: Offset 65457 out of range 945..1020}} do_test corrupt7-2.2 { db close hexio_write test.db 1062 04 sqlite3 db test.db db eval {PRAGMA integrity_check(1)} } {{*** in database main *** -Tree 2 page 2 cell 15: Offset 1201 out of range 945..1020}} +On tree page 2 cell 15: Offset 1201 out of range 945..1020}} # The code path that was causing the buffer overrun that this test # case was checking for was removed. # #do_test corrupt7-3.1 { Index: test/corruptC.test ================================================================== --- test/corruptC.test +++ test/corruptC.test @@ -96,11 +96,11 @@ hexio_write test.db 2053 [format %02x 0x04] sqlite3 db test.db catchsql {PRAGMA integrity_check} } {0 {{*** in database main *** -Tree 3 page 3: free space corruption}}} +Page 3: free space corruption}}} # test that a corrupt content offset size is handled (seed 5649) # # Update 2016-12-27: As of check-in [0b86fbca66] "In sqlite3BtreeInsert() when # replacing a re-existing row, try to overwrite the cell directly rather than @@ -163,11 +163,11 @@ sqlite3 db test.db catchsql {BEGIN; UPDATE t2 SET y='abcdef-uvwxyz'; ROLLBACK;} catchsql {PRAGMA integrity_check} } {0 {{*** in database main *** -Tree 4 page 4 cell 19: Extends off end of page} {database disk image is malformed}}} +On tree page 4 cell 19: Extends off end of page} {database disk image is malformed}}} # {0 {{*** in database main *** # Corruption detected in cell 710 on page 4 # Multiple uses for byte 661 of page 4 # Fragmented space is 249 byte reported as 21 on page 4}}} Index: test/corruptD.test ================================================================== --- test/corruptD.test +++ test/corruptD.test @@ -111,11 +111,11 @@ do_test corruptD-1.1.1 { incr_change_counter hexio_write test.db [expr 1024+1] FFFF catchsql { PRAGMA quick_check } } {0 {{*** in database main *** -Tree 2 page 2: free space corruption}}} +Page 2: free space corruption}}} do_test corruptD-1.1.2 { incr_change_counter hexio_write test.db [expr 1024+1] [hexio_render_int32 1021] catchsql { SELECT * FROM t1 ORDER BY rowid } } {1 {database disk image is malformed}} Index: test/corruptI.test ================================================================== --- test/corruptI.test +++ test/corruptI.test @@ -121,17 +121,22 @@ } set root [db one {SELECT rootpage FROM sqlite_master}] set offset [expr ($root-1) * 65536] +ifcapable oversize_cell_check { + set res {1 {database disk image is malformed}} +} else { + set res {0 {}} +} do_test 4.1 { db close hexio_write test.db [expr $offset + 8 + 2] 0000 hexio_write test.db [expr $offset + 5] 0000 sqlite3 db test.db catchsql { DELETE FROM t1 WHERE a=0 } -} {1 {database disk image is malformed}} +} $res #------------------------------------------------------------------------- # Database properties: # Index: test/corruptL.test ================================================================== --- test/corruptL.test +++ test/corruptL.test @@ -1267,18 +1267,15 @@ | 4080: 0e 01 04 11 13 17 63 31 63 31 63 37 20 31 00 00 ......c1c1c7 1.. | end crash-3afa1ca9e9c1bd.db }]} {} extra_schema_checks 0 -do_catchsql_test 15.1 { +do_execsql_test 15.1 { PRAGMA cell_size_check = 0; UPDATE c1 SET c= NOT EXISTS(SELECT 1 FROM c1 ORDER BY (SELECT 1 FROM c1 ORDER BY a)) +10 WHERE d BETWEEN 4 AND 7; -} {1 {database disk image is malformed}} +} {} extra_schema_checks 1 -do_execsql_test 15.2 { - PRAGMA integrity_check; -} {/in database main/} #------------------------------------------------------------------------- reset_db do_execsql_test 16.0 { CREATE TABLE t1(w, x, y, z, UNIQUE(w, x), UNIQUE(y, z)); Index: test/countofview.test ================================================================== --- test/countofview.test +++ test/countofview.test @@ -49,59 +49,8 @@ } {4} do_execsql_test 2.1 { SELECT count(*) FROM v1 GROUP BY y; } {3 3} -# 2023-03-01 dbsqlfuzz ef8623915d843b150c159166ee4548c78cc6895a -# count-of-view should not apply to CTEs. -# -ifcapable progress { - proc progress_stop args {return 1} - db progress 1000 progress_stop - do_catchsql_test 3.1 { - WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c) - SELECT count(*) FROM c; - } {1 interrupted} -} - -# 2023-03-07 dbsqlfuzz 23d782160b71c3f8f535ccb2da313dfc8eb8c631 -# -do_execsql_test 4.1 { - DROP TABLE t1; - DROP TABLE t2; - DROP TABLE t3; - CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT); - INSERT INTO t1 VALUES(4,'four'); - CREATE TABLE t2(c INTEGER PRIMARY KEY, d TEXT); - CREATE VIEW t3 AS SELECT a, b FROM t1 UNION ALL SELECT c, d FROM t2; - SELECT count(*) FROM t3 ORDER BY sum(a); -} 1 - -# 2023-03-31 dbsqlfuzz 6a107e3055bd22afab31cfddabc2d9d54fcbaf69 -# Having clauses should disqualify count-of-view -# -reset_db -do_execsql_test 5.1 { - CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT); - INSERT INTO t1 VALUES(1,'one'),(4,'four'); - CREATE TABLE t2(c INTEGER PRIMARY KEY, d TEXT); - INSERT INTO t2 VALUES(2,'two'),(5,'five'); - CREATE VIEW t3 AS SELECT a, b FROM t1 UNION ALL SELECT c, d FROM t2; - SELECT count(*) FROM t3 HAVING count(*)>0; -} 4 -do_execsql_test 5.2 { - SELECT count(*) FROM t3 HAVING count(*)>5; -} {} -do_execsql_test 5.3 { - SELECT count(*) FROM t3 HAVING max(b)>'mmm'; -} 4 -do_execsql_test 5.4 { - SELECT count(*) FROM t3 HAVING min(b)>'mmm'; -} {} -do_execsql_test 5.5 { - SELECT count(*) FROM ( - SELECT a, max(b) FROM t1 HAVING a<100 UNION ALL SELECT c, d FROM t2 - ) -} 3 finish_test Index: test/cursorhint.test ================================================================== --- test/cursorhint.test +++ test/cursorhint.test @@ -156,59 +156,7 @@ do_test 4.6desc { p4_of_opcode db CursorHint { SELECT rowid FROM t1 WHERE b=22 AND c>=10 AND c<=20 ORDER BY b,c DESC; } } {AND(AND(EQ(c0,22),GE(c1,10)),LE(c1,20))} - -# 2023-03-24 https://sqlite.org/forum/forumpost/591006b1cc -# -reset_db -do_execsql_test 5.0 { - CREATE TABLE t1(x TEXT PRIMARY KEY) WITHOUT ROWID; - CREATE VIEW t2 AS SELECT 0 FROM t1 WHERE x>='a' OR x='1'; - SELECT * FROM t2 RIGHT JOIN t1 ON true; -} -# Additional test case from https://sqlite.org/forum/forumpost/d34ad68c36?t=c -# which is a different way to acces the same problem. -# -do_execsql_test 5.1 { - CREATE TABLE v1 (c1, PRIMARY KEY( c1 )) WITHOUT ROWID; - CREATE VIEW v2 AS SELECT 0 FROM v1 WHERE c1 IS '' OR c1 > ''; - CREATE VIEW v3 AS SELECT 0 FROM v2 JOIN (v2 RIGHT JOIN v1); - CREATE VIEW v4 AS SELECT 0 FROM v3, v3; - SELECT * FROM v3 JOIN v3 AS a0, v4 AS a1, v4 AS a2, v3 AS a3, - v3 AS a4, v4 AS a5 - ORDER BY 1; -} - -# 2023-04-10 https://sqlite.org/forum/forumpost/0b53708c95 -# -do_execsql_test 6.0 { - CREATE TABLE t6(a TEXT UNIQUE, b TEXT); - INSERT INTO t6(a,b) VALUES('uvw','xyz'),('abc','def'); - WITH v1(a) AS (SELECT a COLLATE NOCASE FROM t6) - SELECT v1.a, count(*) FROM t6 LEFT JOIN v1 ON true - GROUP BY 1 - HAVING (SELECT true FROM t6 AS aa LEFT JOIN t6 AS bb ON length(v1.a)>5); -} {abc 2 uvw 2} - - -# 2023-05-04 https://sqlite.org/forum/forumpost/29a47cf6d1 -# -# codeCursorHint() should not walk expressions that have been optimized -# out and converted to TRUE or FALSE. This only comes up when compiling -# with SQLITE_ENABLE_CURSOR_HINTS -# -reset_db -do_execsql_test 7.1 { - CREATE TABLE t1(a INT PRIMARY KEY) WITHOUT ROWID; - CREATE TABLE t2(b INT PRIMARY KEY) WITHOUT ROWID; - CREATE TABLE t3(c INT PRIMARY KEY) WITHOUT ROWID; - INSERT INTO t1(a) VALUES(1),(2); - INSERT INTO t2(b) VALUES(4),(8); - INSERT INTO t3(c) VALUES(16),(32); - CREATE VIEW v4(d) AS SELECT c FROM t3; - SELECT * FROM t1 RIGHT JOIN t2 ON true JOIN v4 ON (d IS NULL); -} {} - finish_test Index: test/delete.test ================================================================== --- test/delete.test +++ test/delete.test @@ -414,30 +414,6 @@ WHERE EXISTS(SELECT 1 FROM t11 WHERE t11.a>xyz.a AND t11.b<=xyz.b); SELECT * FROM t11; } {6 2 12 4 18 6 19 23 20 40} -# 2023-03-15 -# https://sqlite.org/forum/forumpost/e61252062c9d286d -# -# When the WHERE clause of a DELETE statement contains a subquery -# which uses the table that is being deleted from and there is a -# short-circuit operator of some kind in the WHERE clause such that -# the subquery might not run right away, then the subquery might -# run after one or more rows have been deleted, which can change -# the result of the subquery, and result in the wrong answer. -# -# Similar problem for UPDATE tested by update-21.4 -# https://sqlite.org/forum/forumpost/0007d1fdb1 -# -reset_db -do_execsql_test delete-12.0 { - CREATE TABLE t0(vkey INTEGER, pkey INTEGER,c1 INTEGER); - INSERT INTO t0 VALUES(2,1,-20),(2,2,NULL),(2,3,0),(8,4,95); - DELETE FROM t0 WHERE NOT ( - (t0.vkey <= t0.c1) AND - (t0.vkey <> (SELECT vkey FROM t0 ORDER BY vkey LIMIT 1 OFFSET 2)) - ); - SELECT * FROM t0; -} {8 4 95} - finish_test Index: test/distinct.test ================================================================== --- test/distinct.test +++ test/distinct.test @@ -346,63 +346,7 @@ a a a b a c b a b b b c } } -# 2023-03-16 -# https://sqlite.org/forum/forumpost/16ce2bb7a639e29b -# ticket c36cdb4afd504dc1 -# ticket 4051a7f931d9ba24 -# ticket d6fd512f50513ab7 -# -do_execsql_test 10.1 { - SELECT DISTINCT - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1 - ORDER BY - 'x','x','x','x','x','x','x','x','x','x', - 'x','x','x','x','x','x','x','x','x','x', - 'x','x','x','x','x','x','x','x','x','x', - 'x','x','x','x','x','x','x','x','x','x', - 'x','x','x','x','x','x','x','x','x','x', - 'x','x','x','x','x','x','x','x','x','x', - 'x','x','x','x'; -} {1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1} -do_execsql_test 10.2 { - EXPLAIN - SELECT DISTINCT - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1 - ORDER BY - 'x','x','x','x','x','x','x','x','x','x', - 'x','x','x','x','x','x','x','x','x','x', - 'x','x','x','x','x','x','x','x','x','x', - 'x','x','x','x','x','x','x','x','x','x', - 'x','x','x','x','x','x','x','x','x','x', - 'x','x','x','x','x','x','x','x','x','x', - 'x','x','x','x'; -} {/0 Init 0 /} -do_execsql_test 10.3 { - EXPLAIN CREATE TABLE t2 AS SELECT DISTINCT ':memory:', 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 ORDER BY '%J%j%w%s', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', '%J%j%w%s', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 42e-300, 'unixepoch', 'unixepoch', 'unixepoch' LIMIT 0xda; -} {/0 Init 0/} -do_execsql_test 10.4 { - DROP TABLE IF EXISTS t0; - CREATE TABLE t0 AS SELECT DISTINCT 0xda, 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 0xda-0xda-42e-300, 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0', 'lit0' ORDER BY '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%Y-%m-%d', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', 'lit0', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', 'auto', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', ':memory:', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', '%%', ''; - SELECT count(*) FROM t0; -} {1} -do_execsql_test 10.5 { - DROP TABLE IF EXISTS t2; - CREATE TABLE t2 AS SELECT DISTINCT ':memory:', 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0.0*7/0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 ORDER BY '%J%j%w%s', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', '%J%j%w%s', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 'unixepoch', 42e-300, 'unixepoch', 'unixepoch', 'unixepoch' LIMIT 0xda; - SELECT count(*) FROM t2; -} {1} finish_test Index: test/distinct2.test ================================================================== --- test/distinct2.test +++ test/distinct2.test @@ -299,18 +299,6 @@ } { {} 1 {} {} 1 a } -#------------------------------------------------------------------------- -# -reset_db - -do_execsql_test 4010 { - CREATE TABLE t1(a, b COLLATE RTRIM); - INSERT INTO t1 VALUES(1, ''), (2, ' '), (3, ' '); -} -do_execsql_test 4020 { - SELECT b FROM t1 UNION SELECT 1; -} {1 { }} - finish_test Index: test/e_createtable.test ================================================================== --- test/e_createtable.test +++ test/e_createtable.test @@ -1512,14 +1512,13 @@ 3 "INSERT INTO t3 VALUES('c', 'd', NULL)" {t3.c} 4 "INSERT INTO t3 VALUES('e', NULL, 'f')" {t3.b} 5 "INSERT INTO t3 VALUES(NULL, 'g', 'h')" {t3.a} } -# EVIDENCE-OF: R-34093-09213 PRIMARY KEY, UNIQUE and NOT NULL -# constraints may be explicitly assigned another default conflict -# resolution algorithm by including a conflict-clause in their -# definitions. +# EVIDENCE-OF: R-42511-39459 PRIMARY KEY, UNIQUE and NOT NULL +# constraints may be explicitly assigned a default conflict resolution +# algorithm by including a conflict-clause in their definitions. # # Conflict clauses: ABORT, ROLLBACK, IGNORE, FAIL, REPLACE # # Test cases 4.15.*, 4.16.* and 4.17.* focus on PRIMARY KEY, NOT NULL # and UNIQUE constraints, respectively. @@ -1630,13 +1629,13 @@ do_test e_createtable-4.17.$tn.3 { sqlite3_get_autocommit db } $ac do_execsql_test 4.17.$tn.4 "SELECT * FROM $tbl ORDER BY rowid" $data } catchsql COMMIT -# EVIDENCE-OF: R-17539-59899 Or, if a constraint definition does not -# include a conflict-clause, the default conflict resolution algorithm -# is ABORT. +# EVIDENCE-OF: R-12645-39772 Or, if a constraint definition does not +# include a conflict-clause or it is a CHECK constraint, the default +# conflict resolution algorithm is ABORT. # # The first half of the above is tested along with explicit ON # CONFLICT clauses above (specifically, the tests involving t1_xx, t2_xx # and t3_xx). The following just tests that the default conflict # handling for CHECK constraints is ABORT. Index: test/e_expr.test ================================================================== --- test/e_expr.test +++ test/e_expr.test @@ -213,11 +213,11 @@ # Check that both = and == are both acceptable as the "equals" operator. # Similarly, either != or <> work as the not-equals operator. # # EVIDENCE-OF: R-03679-60639 Equals can be either = or ==. # -# EVIDENCE-OF: R-49372-18364 The not-equal operator can be either != or +# EVIDENCE-OF: R-30082-38996 The non-equals operator can be either != or # <>. # foreach {tn literal different} { 1 'helloworld' '12345' 2 22 23 @@ -1890,14 +1890,13 @@ } null {} do_expr_test e_expr-35.1.6 { (SELECT a FROM t2 UNION SELECT COALESCE(b, 55) FROM t2 ORDER BY 1) } integer 4 -# EVIDENCE-OF: R-43101-20178 A subquery that returns two or more columns -# is a row value subquery and can only be used as an operand of a -# comparison operator or as the value in an UPDATE SET clause whose -# column name list has the same size. +# EVIDENCE-OF: R-22239-33740 A subquery that returns two or more columns +# is a row value subquery and can only be used as the operand of a +# comparison operator. # # The following block tests that errors are returned in a bunch of cases # where a subquery returns more than one column. # set M {/1 {sub-select returns [23] columns - expected 1}/} Index: test/filter1.test ================================================================== --- test/filter1.test +++ test/filter1.test @@ -218,20 +218,8 @@ SELECT max(a), max(a) FILTER (WHERE b<12345), b FROM t1; } { 444 {} 120000 } -# 2023-02-17 dbsqlfuzz 4f8e0de6e272bbbb3e1b41cb5aea31e0b47297e3 -# count() with FILTER clause using the COUNTOFVIEW optimization. -# -reset_db -do_execsql_test 8.0 { - CREATE TABLE t0(c0 INT); - CREATE TABLE t1a(a INTEGER PRIMARY KEY, b TEXT); - INSERT INTO t1a VALUES(1,'one'),(2,NULL),(3,'three'); - CREATE TABLE t1b(c INTEGER PRIMARY KEY, d TEXT); - INSERT INTO t1b VALUES(4,'four'),(5,NULL),(6,'six'); - CREATE VIEW t1 AS SELECT a, b FROM t1a UNION ALL SELECT c, d FROM t1b; - SELECT count()FILTER(WHERE b IS NULL) FROM t1; -} 2 + finish_test Index: test/fkey1.test ================================================================== --- test/fkey1.test +++ test/fkey1.test @@ -270,17 +270,6 @@ } {} do_catchsql_test 8.3 { REINDEX; } {1 {database disk image is malformed}} -# 2023-04-13 https://bugs.chromium.org/p/chromium/issues/detail?id=1405220 -# Avoid double-de-quoting of table names when processing foreign keys. -# -reset_db -do_execsql_test 9.1 { - PRAGMA foreign_keys = ON; - CREATE TABLE """1"("""2", """3" PRIMARY KEY); - CREATE TABLE """4"("""5" REFERENCES """1" ON DELETE RESTRICT); - DELETE FROM """1"; -} - finish_test Index: test/fts3join.test ================================================================== --- test/fts3join.test +++ test/fts3join.test @@ -98,10 +98,9 @@ } { QUERY PLAN |--MATERIALIZE rr | `--SCAN ft4 VIRTUAL TABLE INDEX 3: |--SCAN t4 - |--BLOOM FILTER ON rr (docid=?) `--SEARCH rr USING AUTOMATIC COVERING INDEX (docid=?) LEFT-JOIN } finish_test DELETED test/func8.test Index: test/func8.test ================================================================== --- test/func8.test +++ /dev/null @@ -1,64 +0,0 @@ -# 2023-03-17 -# -# 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. -# -#************************************************************************* -# -# Test cases for SQL functions with names that are the same as join -# keywords: CROSS FULL INNER LEFT NATURAL OUTER RIGHT -# -set testdir [file dirname $argv0] -source $testdir/tester.tcl - -proc joinx {args} {return [join $args -]} -db func cross {joinx cross} -db func full {joinx full} -db func inner {joinx inner} -db func left {joinx left} -db func natural {joinx natural} -db func outer {joinx outer} -db func right {joinx right} -do_execsql_test func8-100 { - CREATE TABLE cross(cross,full,inner,left,natural,outer,right); - CREATE TABLE full(cross,full,inner,left,natural,outer,right); - CREATE TABLE inner(cross,full,inner,left,natural,outer,right); - CREATE TABLE left(cross,full,inner,left,natural,outer,right); - CREATE TABLE natural(cross,full,inner,left,natural,outer,right); - CREATE TABLE outer(cross,full,inner,left,natural,outer,right); - CREATE TABLE right(cross,full,inner,left,natural,outer,right); - INSERT INTO cross VALUES(1,2,3,4,5,6,7); - INSERT INTO full VALUES(1,2,3,4,5,6,7); - INSERT INTO inner VALUES(1,2,3,4,5,6,7); - INSERT INTO left VALUES(1,2,3,4,5,6,7); - INSERT INTO natural VALUES(1,2,3,4,5,6,7); - INSERT INTO outer VALUES(1,2,3,4,5,6,7); - INSERT INTO right VALUES(1,2,3,4,5,6,7); -} -do_execsql_test func8-110 { - SELECT cross(cross,full,inner,left,natural,outer,right) FROM cross; -} cross-1-2-3-4-5-6-7 -do_execsql_test func8-120 { - SELECT full(cross,full,inner,left,natural,outer,right) FROM full; -} full-1-2-3-4-5-6-7 -do_execsql_test func8-130 { - SELECT inner(cross,full,inner,left,natural,outer,right) FROM inner; -} inner-1-2-3-4-5-6-7 -do_execsql_test func8-140 { - SELECT left(cross,full,inner,left,natural,outer,right) FROM left; -} left-1-2-3-4-5-6-7 -do_execsql_test func8-150 { - SELECT natural(cross,full,inner,left,natural,outer,right) FROM natural; -} natural-1-2-3-4-5-6-7 -do_execsql_test func8-160 { - SELECT outer(cross,full,inner,left,natural,outer,right) FROM outer; -} outer-1-2-3-4-5-6-7 -do_execsql_test func8-170 { - SELECT right(cross,full,inner,left,natural,outer,right) FROM right; -} right-1-2-3-4-5-6-7 - -finish_test Index: test/fuzzcheck.c ================================================================== --- test/fuzzcheck.c +++ test/fuzzcheck.c @@ -999,18 +999,16 @@ /* ** This function is called to recover data from the database. */ static int recoverDatabase(sqlite3 *db){ int rc; /* Return code from this routine */ - const char *zRecoveryDb = ""; /* Name of "recovery" database */ const char *zLAF = "lost_and_found"; /* Name of "lost_and_found" table */ int bFreelist = 1; /* True to scan the freelist */ int bRowids = 1; /* True to restore ROWID values */ - sqlite3_recover *p = 0; /* The recovery object */ + sqlite3_recover *p; /* The recovery object */ p = sqlite3_recover_init_sql(db, "main", recoverSqlCb, 0); - sqlite3_recover_config(p, 789, (void*)zRecoveryDb); sqlite3_recover_config(p, SQLITE_RECOVER_LOST_AND_FOUND, (void*)zLAF); sqlite3_recover_config(p, SQLITE_RECOVER_ROWIDS, (void*)&bRowids); sqlite3_recover_config(p, SQLITE_RECOVER_FREELIST_CORRUPT,(void*)&bFreelist); sqlite3_recover_run(p); if( sqlite3_recover_errcode(p)!=SQLITE_OK ){ @@ -1038,11 +1036,11 @@ if( zSql[0]==0 ) return SQLITE_OK; if( eVerbosity>=4 ){ printf("RUNNING-SQL: [%s]\n", zSql); fflush(stdout); } - (*pBtsFlags) &= BTS_BADPRAGMA; + (*pBtsFlags) &= ~BTS_BADPRAGMA; rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( rc==SQLITE_OK ){ int nRow = 0; while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){ nRow++; @@ -1181,11 +1179,10 @@ rc = sqlite3_open(0, &cx.db); if( rc ){ sqlite3_free(aDb); return 1; } - sqlite3_db_config(cx.db, SQLITE_DBCONFIG_STMT_SCANSTATUS, 1, 0); if( bVdbeDebug ){ sqlite3_exec(cx.db, "PRAGMA vdbe_debug=ON", 0, 0, 0); } /* Invoke the progress handler frequently to check to see if we Index: test/fuzzdata8.db ================================================================== --- test/fuzzdata8.db +++ test/fuzzdata8.db cannot compute difference between binary files Index: test/fuzzinvariants.c ================================================================== --- test/fuzzinvariants.c +++ test/fuzzinvariants.c @@ -101,11 +101,11 @@ return rc; } } if( eVerbosity>=2 ){ char *zSql = sqlite3_expanded_sql(pTestStmt); - printf("invariant-sql row=%d #%d:\n%s\n", iRow, iCnt, zSql); + printf("invariant-sql #%d:\n%s\n", iCnt, zSql); sqlite3_free(zSql); } while( (rc = sqlite3_step(pTestStmt))==SQLITE_ROW ){ for(i=0; i=nCol ) break; } if( rc==SQLITE_DONE ){ /* No matching output row found */ sqlite3_stmt *pCk = 0; - int iOrigRSO; - /* This is not a fault if the database file is corrupt, because anything ** can happen with a corrupt database file */ rc = sqlite3_prepare_v2(db, "PRAGMA integrity_check", -1, &pCk, 0); if( rc ){ sqlite3_finalize(pCk); sqlite3_finalize(pTestStmt); return rc; } - if( eVerbosity>=2 ){ - char *zSql = sqlite3_expanded_sql(pCk); - printf("invariant-validity-check #1:\n%s\n", zSql); - sqlite3_free(zSql); - } - rc = sqlite3_step(pCk); if( rc!=SQLITE_ROW || sqlite3_column_text(pCk, 0)==0 || strcmp((const char*)sqlite3_column_text(pCk,0),"ok")!=0 ){ @@ -142,33 +134,32 @@ sqlite3_finalize(pTestStmt); return SQLITE_CORRUPT; } sqlite3_finalize(pCk); - /* - ** If inverting the scan order also results in a miss, assume that the - ** query is ambiguous and do not report a fault. - */ - sqlite3_db_config(db, SQLITE_DBCONFIG_REVERSE_SCANORDER, -1, &iOrigRSO); - sqlite3_db_config(db, SQLITE_DBCONFIG_REVERSE_SCANORDER, !iOrigRSO, 0); - sqlite3_prepare_v2(db, sqlite3_sql(pStmt), -1, &pCk, 0); - sqlite3_db_config(db, SQLITE_DBCONFIG_REVERSE_SCANORDER, iOrigRSO, 0); - if( eVerbosity>=2 ){ - char *zSql = sqlite3_expanded_sql(pCk); - printf("invariant-validity-check #2:\n%s\n", zSql); - sqlite3_free(zSql); - } - while( (rc = sqlite3_step(pCk))==SQLITE_ROW ){ - for(i=0; i=nCol ) break; - } - sqlite3_finalize(pCk); - if( rc==SQLITE_DONE ){ - sqlite3_finalize(pTestStmt); - return SQLITE_DONE; + if( sqlite3_strlike("%group%by%",sqlite3_sql(pStmt),0)==0 ){ + /* + ** If there is a GROUP BY clause, it might not cover every term in the + ** output. And then non-covered terms can take on a value from any + ** row in the result set. This can cause differing answers. + */ + goto not_a_fault; + } + + if( sqlite3_strlike("%limit%)%order%by%", sqlite3_sql(pTestStmt),0)==0 ){ + /* crash-89bd6a6f8c6166e9a4c5f47b3e70b225f69b76c6 + ** Original statement is: + ** + ** SELECT a,b,c* FROM t1 LIMIT 1%5<4 + ** + ** When running: + ** + ** SELECT * FROM (...) ORDER BY 1 + ** + ** A different subset of the rows come out + */ + goto not_a_fault; } /* The original sameValue() comparison assumed a collating sequence ** of "binary". It can sometimes get an incorrect result for different ** collating sequences. So rerun the test with no assumptions about @@ -176,16 +167,10 @@ */ rc = sqlite3_prepare_v2(db, "SELECT ?1=?2 OR ?1=?2 COLLATE nocase OR ?1=?2 COLLATE rtrim", -1, &pCk, 0); if( rc==SQLITE_OK ){ - if( eVerbosity>=2 ){ - char *zSql = sqlite3_expanded_sql(pCk); - printf("invariant-validity-check #3:\n%s\n", zSql); - sqlite3_free(zSql); - } - sqlite3_reset(pTestStmt); while( (rc = sqlite3_step(pTestStmt))==SQLITE_ROW ){ for(i=0; i=2 ){ - char *zSql = sqlite3_expanded_sql(pCk); - printf("invariant-validity-check #4:\n%s\n", zSql); - sqlite3_free(zSql); - } sqlite3_bind_pointer(pCk, 1, pStmt, "stmt-pointer", 0); rc = sqlite3_step(pCk); } sqlite3_finalize(pCk); if( rc==SQLITE_DONE ){ Index: test/gencol1.test ================================================================== --- test/gencol1.test +++ test/gencol1.test @@ -613,60 +613,6 @@ SELECT * FROM t0 AS x JOIN t0 AS y WHERE x.b='2' AND (y.a=2 OR (x.b LIKE '2*' AND y.a=x.b)); } {2 2 2 2} - -# 2023-03-02 dbsqlfuzz 65f5eb57f8859344d5f1f33e08c77ee12960ed83 -# -set typelist {ANY INT REAL BLOB TEXT {}} -set cnt 0 -foreach t1 $typelist { - foreach t2 $typelist { - incr cnt - db eval " - DROP TABLE IF EXISTS t1; - CREATE TABLE t1( - x $t1, - a $t2 AS (x) VIRTUAL, - b BLOB AS (x) VIRTUAL - ); - CREATE INDEX x2 ON t1(a); - INSERT INTO t1(x) VALUES(NULL),('1'),(2),(3.5),('xyz'); - " - set x1 [lsort [db eval {SELECT typeof(b) FROM t1}]] - do_test gencol1-23.1.$cnt { - lsort [db eval {SELECT typeof(b) FROM t1 INDEXED BY x2}] - } $x1 - } -} -do_execsql_test gencol1-23.2 { - DROP TABLE t1; - CREATE TABLE t1( - x, - a INT AS (x) VIRTUAL, - b BLOB AS (x) VIRTUAL - ); - CREATE INDEX x2 ON t1(a); - INSERT INTO t1(x) VALUES(NULL),('1'),('xyz'),(2),(3.5); - SELECT quote(a) FROM t1 INDEXED BY x2; -} {NULL 1 2 3.5 'xyz'} -do_execsql_test gencol1-23.3 { - EXPLAIN SELECT a FROM t1 INDEXED BY x2; -} {~/Column 0/} -# ^^^^^^^^---- verfies that x2 acts like a covering index -do_execsql_test gencol1-23.4 { - EXPLAIN SELECT b FROM t1 INDEXED BY x2; -} {/Column 0/} -# ^^^^^^^^^^--- Must reference the original table in this case because -# of the different datatype on column b. - -# 2023-03-07 https://sqlite.org/forum/forumpost/b312e075b5 -# -do_execsql_test gencol1-23.5 { - CREATE TABLE v0(c1 INT, c2 AS (RAISE(IGNORE))); -} -do_catchsql_test gencol1-23.6 { - SELECT * FROM v0; -} {1 {RAISE() may only be used within a trigger-program}} - finish_test Index: test/in.test ================================================================== --- test/in.test +++ test/in.test @@ -804,60 +804,7 @@ do_execsql_test in-21.1 { CREATE TABLE t0(c0); SELECT COUNT(*) FROM t0 ORDER BY (t0.c0 IN ()); } {0} -# Ignore extra parentheses around a subquery on the RHS of an IN operator, -# because that is what PostgreSQL does. -# -do_execsql_test in-22.1 { - DROP TABLE IF EXISTS t1; - CREATE TABLE t1(x INT PRIMARY KEY, y INT); - WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<8) - INSERT INTO t1(x,y) SELECT x, x*100 FROM c; - DROP TABLE IF EXISTS t2; - CREATE TABLE t2(a INT); - INSERT INTO t2 VALUES(2),(4),(6); - SELECT * FROM t1 WHERE x IN (SELECT a FROM t2); -} {2 200 4 400 6 600} -do_execsql_test in-22.2 { - SELECT * FROM t1 WHERE x IN ((SELECT a FROM t2)); -} {2 200 4 400 6 600} -do_execsql_test in-22.3 { - SELECT * FROM t1 WHERE x IN (((SELECT a FROM t2))); -} {2 200 4 400 6 600} -do_execsql_test in-22.4 { - SELECT * FROM t1 WHERE x IN ((((((SELECT a FROM t2)))))); -} {2 200 4 400 6 600} - -# 2023-04-04 https://sqlite.org/forum/forumpost/dc16ec63d3 -# Faulty assert() statement in the IN optimization. -# -do_execsql_test in-23.0 { - DROP TABLE IF EXISTS t4; - CREATE TABLE t4(a TEXT, b INT); - INSERT INTO t4(a,b) VALUES('abc',0),('ABC',1),('def',2); - CREATE INDEX t4x ON t4(a, +a COLLATE NOCASE); - SELECT a0.a, group_concat(a1.a) AS b - FROM t4 AS a0 JOIN t4 AS a1 - GROUP BY a0.a - HAVING (SELECT sum( (a1.a == +a0.a COLLATE NOCASE) IN (SELECT b FROM t4))); -} {ABC abc,ABC,def abc abc,ABC,def def abc,ABC,def} -do_execsql_test in-23.0-b { - SELECT a0.a, group_concat(a1.a) AS b - FROM t4 AS a0 JOIN t4 AS a1 - GROUP BY a0.a - HAVING (SELECT sum( (a1.a GLOB +a0.a COLLATE NOCASE) IN (SELECT b FROM t4))); -} {ABC abc,ABC,def abc abc,ABC,def def abc,ABC,def} -# -# Follow-up forum/forumpost/0713a16a44 -# -do_execsql_test in-23.1 { - CREATE VIEW t5 AS - SELECT 1 AS b - WHERE (SELECT count(0=NOT+a COLLATE NOCASE IN (SELECT 0)) - FROM t4 - GROUP BY a); - SELECT * FROM t5; -} 1 finish_test Index: test/indexexpr1.test ================================================================== --- test/indexexpr1.test +++ test/indexexpr1.test @@ -563,57 +563,8 @@ SUM(c) AS t3, SUM(CASE WHEN b->>'x'=1 THEN c END) AS t4 FROM t1; } {/.*SCAN t1 USING INDEX t1x.*/} -reset_db -do_execsql_test indexexpr1-2100 { - CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT); - INSERT INTO t1(a,b) VALUES(1,0); - CREATE INDEX x1 ON t1( "y" ); - CREATE INDEX x2 ON t1( +"y" ); - CREATE INDEX x3 ON t1( +'y' ); - CREATE INDEX x4 ON t1( "y*" ); -} -do_execsql_test indexexpr1-2110 { - UPDATE t1 SET b=100 WHERE (SELECT 'y') GLOB "y"; - SELECT b FROM t1; -} 100 -do_execsql_test indexexpr1-2120 { - UPDATE t1 SET b=200 WHERE (SELECT 'y') GLOB +"y"; - SELECT b FROM t1; -} 200 -do_execsql_test indexexpr1-2130 { - UPDATE t1 SET b=300 WHERE (SELECT 'y') GLOB +'y'; - SELECT b FROM t1; -} 300 -do_execsql_test indexexpr1-2140 { - UPDATE t1 SET b=400 WHERE (SELECT 'y') GLOB "y*"; - SELECT b FROM t1; -} 400 - -# 2023-04-18 Forum post https://sqlite.org/forum/forumpost/f34e32d120 from -# Alexis King. -# -# This problem originates at check-in b9190d3da70c4171 (2022-11-25). -# A similar problem arose on 2023-03-04 at -# https://sqlite.org/forum/forumpost/a68313d054 and was fixed at -# check-in e06973876993926f. See the test case tkt-99378-400. -# -reset_db -do_execsql_test indexexpr1-2200 { - CREATE TABLE t1(id INTEGER PRIMARY KEY, tag INT); - INSERT INTO t1 VALUES (0, 7), (1, 8); - CREATE TABLE t2(type INT, t1_id INT, value INT); - INSERT INTO t2 VALUES (0, 0, 100), (0, 1, 101); - CREATE INDEX t1x ON t1(-tag); - SELECT u.tag, v.max_value - FROM (SELECT tag FROM t1 GROUP BY -tag) u - JOIN (SELECT t1.tag AS "tag", t2.type AS "type", - MAX(t2.value) AS "max_value" - FROM t1 - JOIN t2 ON t2.t1_id = t1.id - GROUP BY t2.type, t1.tag - ) v ON v.type = 0 AND v.tag = u.tag; -} {7 100 8 101} + finish_test Index: test/indexexpr2.test ================================================================== --- test/indexexpr2.test +++ test/indexexpr2.test @@ -370,59 +370,6 @@ do_execsql_test 8.5.$tn.2 " SELECT ($expr) IS TRUE FROM t1 LEFT JOIN t2 " {1 1} } -# 2023-03-24 https://sqlite.org/forum/forumpost/79cf371080 -# -reset_db -do_execsql_test 9.0 { - CREATE TABLE t1(a INT, b INT); - CREATE INDEX t1x ON t1(a, abs(b)); - CREATE TABLE t2(c INT, d INT); - INSERT INTO t1(a,b) VALUES(4,4),(5,-5),(5,20),(6,6); - INSERT INTO t2(c,d) VALUES(100,1),(200,1),(300,2); - SELECT *, - (SELECT max(c+abs(b)) FROM t2 GROUP BY d ORDER BY d LIMIT 1) AS subq - FROM t1 WHERE a=5; -} {5 -5 205 5 20 220} - -# 2023-04-03 https://sqlite.org/forum/forumpost/44270909bb -# and https://sqlite.org/forum/forumpost/e45108732c which are the -# same problem, namely the failure to omit the EP_Collate property -# from an expression node when changing it from TK_COLLATE into -# TK_AGG_COLUMN because it resolves to an indexed expression. -# -reset_db -do_execsql_test 10.0 { - CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT); - CREATE INDEX t1x ON t1 (b, +b COLLATE NOCASE); - INSERT INTO t1(a,b) VALUES(1,'abcde'); - SELECT * FROM t1 AS a0 - WHERE (SELECT count(a0.b=+a0.b COLLATE NOCASE IN (b)) FROM t1 GROUP BY 2.5) - ORDER BY a0.b; -} {1 abcde} -do_execsql_test 10.1 { - CREATE TABLE t2(a TEXT); - INSERT INTO t2 VALUES('alice'),('bob'),('cindy'),('david'); - CREATE INDEX t2x ON t2 (+a COLLATE NOCASE); - SELECT count(+a COLLATE NOCASE IN (SELECT 1)) AS x - FROM t2 - GROUP BY SUBSTR(0,0); -} 4 - -# 2023-04-03 https://sqlite.org/forum/forumpost/409ebc7368 -# When a generated column appears in both an outer and an inner loop -# (that is to say, the same table is used in both loops) and the -# generated column is indexed and it is used inside an aggregate function, -# make sure that the terms resolve to the correct aggregate. -# -do_execsql_test 11.0 { - CREATE TABLE t3 (a INT, b AS (-a)); - CREATE INDEX t3x ON t3(b, a); - INSERT INTO t3(a) VALUES(44); - SELECT * FROM t3 AS a0 - WHERE (SELECT sum(-a0.a=b) FROM t3 GROUP BY b) - GROUP BY b; -} {44 -44} - finish_test Index: test/join.test ================================================================== --- test/join.test +++ test/join.test @@ -1036,60 +1036,22 @@ INSERT INTO t0 VALUES(10,10),(10,11),(10,12); SELECT DISTINCT c FROM t0 LEFT JOIN (SELECT a+1 AS c FROM t0) ORDER BY c ; } {11} # 2019-12-22 ticket 7929c1efb2d67e98 -# Verification of testtag-20230227a -# -# 2023-02-27 https://sqlite.org/forum/forumpost/422e635f3beafbf6 -# Verification of testtag-20230227a, testtag-20230227b, and testtag-20230227c # reset_db ifcapable vtab { - do_execsql_test join-23.10 { - CREATE TABLE t0(c0); - INSERT INTO t0(c0) VALUES(123); - CREATE VIEW v0(c0) AS SELECT 0 GROUP BY 1; - SELECT t0.c0, v0.c0, vt0.name - FROM v0, t0 LEFT JOIN pragma_table_info('t0') AS vt0 - ON vt0.name LIKE 'c0' - WHERE v0.c0 == 0; - } {123 0 c0} - do_execsql_test join-23.20 { - CREATE TABLE a(value TEXT); - INSERT INTO a(value) SELECT value FROM json_each('["a", "b", null]'); - CREATE TABLE b(value TEXT); - INSERT INTO b(value) SELECT value FROM json_each('["a", "c", null]'); - SELECT a.value, b.value FROM a RIGHT JOIN b ON a.value = b.value; - } {a a {} c {} {}} - do_execsql_test join-23.21 { - SELECT a.value, b.value FROM b LEFT JOIN a ON a.value = b.value; - } {a a {} c {} {}} - do_execsql_test join-23.22 { - SELECT a.value, b.value - FROM json_each('["a", "c", null]') AS b - LEFT JOIN - json_each('["a", "b", null]') AS a ON a.value = b.value; - } {a a {} c {} {}} - do_execsql_test join-23.23 { - SELECT a.value, b.value - FROM json_each('["a", "b", null]') AS a - RIGHT JOIN - json_each('["a", "c", null]') AS b ON a.value = b.value; - } {a a {} c {} {}} - do_execsql_test join-23.24 { - SELECT a.value, b.value - FROM json_each('["a", "b", null]') AS a - RIGHT JOIN - b ON a.value = b.value; - } {a a {} c {} {}} - do_execsql_test join-23.25 { - SELECT a.value, b.value - FROM a - RIGHT JOIN - json_each('["a", "c", null]') AS b ON a.value = b.value; - } {a a {} c {} {}} +do_execsql_test join-23.10 { + CREATE TABLE t0(c0); + INSERT INTO t0(c0) VALUES(123); + CREATE VIEW v0(c0) AS SELECT 0 GROUP BY 1; + SELECT t0.c0, v0.c0, vt0.name + FROM v0, t0 LEFT JOIN pragma_table_info('t0') AS vt0 + ON vt0.name LIKE 'c0' + WHERE v0.c0 == 0; +} {123 0 c0} } #------------------------------------------------------------------------- reset_db do_execsql_test join-24.1 { @@ -1243,24 +1205,6 @@ # | |--SCAN t1 # | `--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN # |--SCAN t4 # `--SEARCH t3 USING AUTOMATIC COVERING INDEX (a=?) - -# 2023-05-01 https://sqlite.org/forum/forumpost/96cd4a7e9e -# -reset_db -db null NULL -do_execsql_test join-29.1 { - CREATE TABLE t0(a INT); INSERT INTO t0(a) VALUES (1); - CREATE TABLE t1(b INT); INSERT INTO t1(b) VALUES (2); - CREATE VIEW v2(c) AS SELECT 3 FROM t1; - SELECT * FROM t1 JOIN v2 ON 0 FULL OUTER JOIN t0 ON true; -} {NULL NULL 1} -do_execsql_test join-29.2 { - SELECT * FROM t1 JOIN v2 ON 1=0 FULL OUTER JOIN t0 ON true; -} {NULL NULL 1} -do_execsql_test join-29.3 { - SELECT * FROM t1 JOIN v2 ON false FULL OUTER JOIN t0 ON true; -} {NULL NULL 1} - finish_test Index: test/join2.test ================================================================== --- test/join2.test +++ test/join2.test @@ -352,80 +352,7 @@ optimization_control db query-flattener 0 do_execsql_test 9.11 { SELECT ccc, ccc IS NULL AS ddd FROM t1 LEFT JOIN v2; } {{} 1} -# 2023-03-01 https://sqlite.org/forum/forumpost/26387ea7ef -# When flattening a VIEW which is the RHS of a LEFT JOIN, always put -# an TK_IF_NULL_ROW operator on all accesses, even TK_COLUMN nodes, since -# the TK_COLUMN might reference an outer subquery. -# -reset_db -db null NULL -do_execsql_test 10.1 { - CREATE TABLE t1 (x INTEGER); - INSERT INTO t1 VALUES(1); -- Some true value - CREATE TABLE t2 (z TEXT); - INSERT INTO t2 VALUES('some value'); - CREATE TABLE t3(w TEXT); - INSERT INTO t3 VALUES('some other value'); -} -do_execsql_test 10.2 { - SELECT ( - SELECT 1 FROM t2 LEFT JOIN (SELECT x AS v FROM t3) ON 500=v WHERE (v OR FALSE) - ) FROM t1; -} NULL -do_execsql_test 10.3 { - SELECT ( - SELECT 1 FROM t2 LEFT JOIN (SELECT x AS v FROM t3) ON 500=v WHERE (v) - ) FROM t1; -} NULL -optimization_control db all 0 -do_execsql_test 10.4 { - SELECT ( - SELECT 1 FROM t2 LEFT JOIN (SELECT x AS v FROM t3) ON 500=v WHERE (v OR FALSE) - ) FROM t1; -} NULL - -# 2023-03-02 https://sqlite.org/forum/forumpost/402f05296d -# -# The TK_IF_NULL_ROW expression node must ensure that it does not overwrite -# the result register of an OP_Once subroutine. -# -optimization_control db all 1 -do_execsql_test 11.1 { - DROP TABLE t1; - DROP TABLE t2; - DROP TABLE t3; - CREATE TABLE t1(x TEXT, y INTEGER); - INSERT INTO t1(x,y) VALUES(NULL,-2),(NULL,1),('0',2); - CREATE TABLE t2(z INTEGER); - INSERT INTO t2(z) VALUES(2),(-2); - CREATE VIEW t3 AS SELECT z, (SELECT count(*) FROM t1) AS w FROM t2; - SELECT * FROM t1 LEFT JOIN t3 ON y=z; -} {NULL -2 -2 3 NULL 1 NULL NULL 0 2 2 3} - -# 2023-03-11 https://sqlite.org/forum/forumpost/b405033490fa56d9 -# The fix that test 11.1 above checks also caused a performance regression. -# This test case verifies that the performance regression has been resolved. -# -do_execsql_test 12.1 { - DROP TABLE t1; - DROP TABLE t2; - DROP VIEW t3; - CREATE TABLE t1(a INTEGER PRIMARY KEY); - WITH RECURSIVE c(n) AS (VALUES(1) UNION ALL SELECT n+1 FROM c WHERE n<100) - INSERT INTO t1(a) SELECT n FROM c; - CREATE VIEW t2(b) AS SELECT a FROM t1; -} -do_vmstep_test 12.2 { - SELECT * FROM t1 LEFT JOIN t2 ON a=b LIMIT 10 OFFSET 98; -} 2000 {99 99 100 100} -do_eqp_test 12.3 { - SELECT * FROM t1 LEFT JOIN t2 ON a=b LIMIT 10 OFFSET 98; -} { - QUERY PLAN - |--SCAN t1 - `--SEARCH t1 USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN -} finish_test Index: test/join8.test ================================================================== --- test/join8.test +++ test/join8.test @@ -157,11 +157,10 @@ CREATE INDEX t2dc ON t2(d, c); SELECT (SELECT c FROM sqlite_temp_schema FULL JOIN t2 ON d IN (1,2,3) ORDER BY d) AS x FROM t1; } {0 {- -}} # 2022-04-29 dbsqlfuzz 19f1102a70cf966ab249de56d944fc20dbebcfcf -# Verification of testtag-20230227b and testtag-20230227c # reset_db do_execsql_test join8-6000 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT, c TEXT, d REAL); INSERT INTO t1 VALUES(1,'A','aa',2.5); @@ -180,20 +179,10 @@ CREATE TABLE t1(a INTEGER PRIMARY KEY,b); INSERT INTO t1 VALUES(0,NULL),(1,2); SELECT value, t1.* FROM json_each('17') NATURAL RIGHT JOIN t1 WHERE (a,b) IN (SELECT rowid, b FROM t1); } {17 1 2} -do_execsql_test join8-6021 { - SELECT value, t1.* FROM json_each('null') NATURAL RIGHT JOIN t1 - WHERE (a,b) IN (SELECT rowid, b FROM t1); -} {{} 1 2} -do_execsql_test join8-6022 { - CREATE TABLE a(key TEXT); - INSERT INTO a(key) VALUES('a'),('b'); - SELECT quote(a.key), b.value - FROM a RIGHT JOIN json_each('["a","c"]') AS b ON a.key=b.value; -} {'a' a NULL c} # Bloom filter usage by RIGHT and FULL JOIN # reset_db do_execsql_test join8-7000 { Index: test/joinH.test ================================================================== --- test/joinH.test +++ test/joinH.test @@ -87,37 +87,7 @@ do_execsql_test 4.4 { SELECT (d IS NULL) FROM t1 RIGHT JOIN t2 ON (j=33); } {1} -#------------------------------------------------------------------------- -# -reset_db -do_execsql_test 5.0 { - CREATE TABLE t0(w); - CREATE TABLE t1(x); - CREATE TABLE t2(y); - CREATE TABLE t3(z); - INSERT INTO t3 VALUES('t3val'); -} - -do_execsql_test 5.1 { - SELECT * FROM t1 INNER JOIN t2 ON (0) RIGHT OUTER JOIN t3; -} {{} {} t3val} - -do_execsql_test 5.2 { - SELECT * FROM t1 INNER JOIN t2 ON (0) FULL OUTER JOIN t3; -} {{} {} t3val} - -do_execsql_test 5.3 { - SELECT * FROM t3 LEFT JOIN t2 ON (0); -} {t3val {}} - -do_execsql_test 5.4 { - SELECT * FROM t0 RIGHT JOIN t1 INNER JOIN t2 ON (0) RIGHT JOIN t3 -} {{} {} {} t3val} - -do_execsql_test 5.5 { - SELECT * FROM t0 RIGHT JOIN t1 INNER JOIN t2 ON (0) -} {} finish_test DELETED test/json/README.md Index: test/json/README.md ================================================================== --- test/json/README.md +++ /dev/null @@ -1,27 +0,0 @@ -The files in this subdirectory are used to help measure the performance -of the SQLite JSON parser. - -# 1.0 Prerequisites - - 1. Valgrind - - 2. Fossil - -# 2.0 Setup - - 1. Run: "`tclsh json-generator.tcl | sqlite3 json100mb.db`" to create - the 100 megabyte test database. Do this so that the "json100mb.db" - file lands in the directory from which you will run tests, not in - the test/json subdirectory of the source tree. - - 2. Build the baseline sqlite3.c file. ("`make sqlite3.c`") - - 3. Run "`sh json-speed-check-1.sh trunk`". This creates the baseline - profile in "jout-trunk.txt". - -# 3.0 Testing - - 1. Build the sqlite3.c to be tested. - - 2. Run "`sh json-speed-check-1.sh x1`". The profile output will appear - in jout-x1.txt. Substitute any label you want in place of "x1". DELETED test/json/json-generator.tcl Index: test/json/json-generator.tcl ================================================================== --- test/json/json-generator.tcl +++ /dev/null @@ -1,401 +0,0 @@ -#!/usr/bin/tclsh -# -# Generate SQL that will populate an SQLite database with about 100 megabytes -# of pseudo-random JSON text. -# -# tclsh json-generator.tcl | sqlite3 json110mb.db -# -# srand() is used to initialize the random seed so that the same JSON -# is generated for every run. -# -expr srand(12345678) -set wordlist { - ability able abroad access account act - action active actor add address adept - adroit advance advice affect age ageless - agency agent agile agree air airfare - airline airport alert almond alpha always - amend amount amplify analyst anchor angel - angelic angle ankle annual answer antique - anybody anyhow appeal apple apricot apt - area argon arm army arrival arsenic - art artful article arugula aside ask - aspect assist assume atom atone attempt - author autumn average avocado award awl - azure back bacon bag bagel bake - baker balance ball balloon bamboo banana - band banjo bank barium base basil - basin basis basket bass bat bath - battery beach beak bean bear bearcub - beauty beef beet beige being bell - belly belt bench bend benefit best - beta better beyond bicycle bid big - bike bill bird biscuit bismuth bisque - bit black blank blest blind bliss - block bloom blue board boat body - bokchoy bone bonus book bookish boot - border boron boss bossy bottle bottom - bow bowl bowtie box brain brainy - branch brave bravely bread break breath - breezy brick bridge brie brief briefly - bright broad broil bromine bronze brother - brow brown brush buddy budget buffalo - bug bugle bull bunch burger burly - burrito bus busy butter button buy - buyer byte cab cabbage cabinet cable - cadet cadmium caesium cake calcium caliper - call caller calm calmly camera camp - can canary cancel candle candy cap - capable caper capital captain car carbon - card care career careful carp carpet - carrot carry case cash cassava casual - cat catch catfish catsear catsup cause - cave celery cell century chain chair - chalk chance change channel chapter chard - charge charity chart check cheddar cheery - cheese chicken chicory chiffon child chin - chip chives choice chowder chum church - circle city claim clam class classic - classy clay clean cleaner clear clearly - clerk click client climate clock clorine - closet clothes cloud clown club clue - cluster coach coast coat cobbler cobolt - cod code coffee colby cold collar - college comb combine comet comfort command - comment common company complex concept concern - concert conduit consist contact contest context - control convert cook cookie copilot copper - copy coral cordial corn corner corny - correct cost count counter country county - couple courage course court cover cow - cowbird crab crack craft crash crazy - cream credit creek cress crevice crew - crimson croaker crop cross crowd cube - cuckoo cuisine culture cup current curve - cut cyan cycle dagger daily dance - dare darter data date day daylily - deal dear dearly debate debit decade - decimal deep deft deftly degree delay - deluxe deposit depth design desk detail - device dew diamond diet dig dill - dinner dip direct dirt dish disk - display diver divide divine doctor dodger - donut door dot double dough draft - drag dragon drama draw drawer drawing - dream drill drink drive driver drop - drum dry dryer drywall duck due - dump dusk dust duty dye eagle - ear earring earth ease east easy - eat economy edge editor eel effect - effort egg eight elbow elegant element - elf elk email emerald employ end - endive endless energy engine enjoy enter - entry equal equip error escape essay - eternal evening event exam example excuse - exit expert extent extreme eye face - fact factor factual fail failure fair - fajita fall family fan fang farm - farmer fat fault feature feed feel - feeling fench fennel festive few fiber - field fig figure file fill film - filter final finance finding finger finish - fire fish fishing fit fitting five - fix flier flight floor floral florine - flour flow flower fly flying focus - fold folding food foot force forest - forever forgive form formal format fortune - forum frame free freedom freely fresh - friend frog front fruit fuchsia fuel - fun funny future gain galaxy gallium - game gamma gap garage garden garlic - gas gate gather gauge gear gem - gene general gentle gently gherkin ghost - gift give glad glass gleeful glossy - glove glue goal goat goby gold - goldeye golf good gouda goulash gourd - grab grace grade gram grand grape - grapes grass gravy gray great green - grits grocery ground group grouper grout - growth guard guave guess guest guide - guitar gumbo guppy habit hacksaw haddock - hafnium hagfish hair half halibut hall - hammer hand handle handy hanger happy - hat havarti hay haybale head health - healthy hearing heart hearty heat heavy - heel height helium hello help helpful - herald herring hide high highly highway - hill hip hipster hire history hit - hoki hold hole holiday holly home - honest honey hook hope hopeful horizon - horn horse host hotel hour house - housing human humane humor hunt hurry - ice icecube icefish icy idea ideal - image impact impress inch income indigo - initial inkpen insect inside intense invite - iodine iridium iron island issue item - ivory jacket jargon javelin jello jelly - jewel job jocund join joint joke - jovial joy joyful joyous judge juice - jump junior jury just justice kale - keel keep kelp ketchup key keyhole - keyway khaki kick kid kidney kiloohm - kind kindly king kitchen kite kiwi - knee knife krill krypton kumquat lab - lace lack ladder lake lamp lamprey - land laser laugh law lawn lawyer - layer lead leader leading leaf leafy - league leather leave lecture leek leg - lemon length lentil lesson let letter - lettuce level library life lift light - lily lime limit line linen link - lip list listen lithium lively living - lizard load loan lobster local lock - log long longfin look lotus love - lovely loving low lucid luck luffa - lunch lung machine magenta magnet mail - main major make mall manager mango - manner many map march market maroon - martian master match math matter maximum - maybe meal meaning meat media medium - meet meeting melody melon member memory - mention menu mercury merry mess message - messy metal meter method micron middle - might mile milk mind mine minimum - minnow minor mint minute mirror miss - mission misty mix mixer mixture mobile - mode model moment monitor monk month - moon moray morning most motor mouse - mouth move mover movie much mud - mudfish muffin mullet munster muon muscle - music mustard nail name nation native - natural nature navy neat neatly nebula - neck needle neon nerve net network - neutron news nibble nice nickel night - niobium nobody noise noodle normal north - nose note nothing notice nova novel - number nurse nursery oar object offer - office officer oil okay okra old - olive one onion open opening opinion - option orange orbit orchid order oregano - other ounce outcome outside oven owner - oxygen oyster pace pack package page - pager paint pair pale pan pancake - papaya paper pardon parent park parking - parsley parsnip part partner party pass - passage past pasta path patient pattern - pause pay pea peace peach peacock - peahen peak peanut pear pearl pen - penalty pencil pension people pepper perch - perfect period permit person phase phone - photo phrase physics piano pick picture - pie piece pigeon pike pilot pin - pink pinkie pious pipe pitch pizza - place plan plane planet plant planter - plastic plate play player playful plenty - pliers plum pod poem poet poetry - point police policy pollock pony pool - pop popover poptart pork port portal - post pot potato pound powder power - present press price pride primary print - prior private prize problem process produce - product profile profit program project promise - prompt proof proper protein proton public - puff puffer pull pumpkin pup pupfish - pure purple purpose push put quality - quark quarter quiet quill quit quote - rabbit raccoon race radiant radio radish - radium radon rain rainbow raise ramp - ranch range rasp rate ratio ray - razor reach read reading real reality - reason recipe record recover red redeem - reed reef refuse region regret regular - relaxed release relief relish remote remove - rent repair repeat reply report request - reserve resist resolve resort rest result - return reveal review reward ribbon rice - rich ride ridge right ring rise - risk river rivet road roast rock - rocket role roll roof room rope - rose rough roughy round row royal - rub ruby rudder ruin rule run - runner rush rust sacred saddle safe - safety sail salad salami sale salmon - salt sample sand sander sandy sauce - save saving saw scale scampi scene - scheme school score screen script sea - search season seat second secret sector - seemly self sell senate senior sense - series serve set shake shape share - shark shell shift shine shiny ship - shock shoe shoot shop shovel show - side sign signal silk silly silver - simple sing singer single sink site - size skill skin sky slate sleep - sleepy slice slide slip smart smell - smelt smile smoke smooth snap snipe - snow snowy sock socket sodium soft - softly soil sole solid song sorrel - sort soul sound soup source south - space spare speech speed spell spend - sphere spice spider spirit spite split - spoon sport spot spray spread spring - squab square squash stable staff stage - stand staple star start state status - stay steak steel step stern stew - stick still stock stone stop store - storm story strain street stress strike - string stroke strong studio study stuff - style sugar suit sulfur summer sun - sunny sunset super superb surf survey - sweet swim swing switch symbol system - table tackle tail tale talk tan - tank tap tape target task taste - tau tea teach teal team tear - tell ten tender tennis tent term - test tetra text thanks theme theory - thing think thread throat thumb ticket - tidy tie tiger till time timely - tin tip title toast today toe - tomato tone tongue tool tooth top - topic total touch tough tour towel - tower town track trade train trash - travel tray treat tree trick trip - trout trowel truck trupet trust truth - try tube tuna tune turf turkey - turn turnip tutor tux tweet twist - two type union unique unit upbeat - upper use useful user usual valley - value van vase vast veil vein - velvet verse very vessel vest video - view violet visit visual vivid voice - volume vowel voyage waffle wait wake - walk wall warm warmth wasabi wash - watch water wave wax way wealth - wear web wedge week weekly weight - west whale what wheat wheel when - where while who whole why will - win wind window wing winner winter - wire wish witty wolf wonder wood - wool woolly word work worker world - worry worth worthy wrap wrench wrist - writer xenon yak yam yard yarrow - year yearly yellow yew yogurt young - youth zebra zephyr zinc zone zoo -} -set nwordlist [llength $wordlist] - -proc random_char {} { - return [string index \ - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" \ - [expr {int(rand()*52)}]] -} -proc random_label {} { - set label [random_char] - while {rand()>0.8} { - append label [random_char] - } - if {rand()>0.9} {append label -} - append label [format %d [expr {int(rand()*100)}]] - return $label -} -proc random_numeric {} { - set n [expr {(rand()*2-1.0)*1e6}] - switch [expr {int(rand()*6)}] { - 0 {set format %.3f} - 1 {set format %.6E} - 2 {set format %.4e} - default {set format %g} - } - return [format $format $n] -} - - -proc random_json {limit indent} { - global nwordlist wordlist - set res {} - if {$indent==0 || ($limit>0 && rand()>0.5)} { - incr limit -1 - incr indent 2 - set n [expr {int(rand()*5)+1}] - if {$n==5} {incr n [expr {int(rand()*10)}]} - if {rand()>0.5} { - set res \173\n - for {set i 0} {$i<$n} {incr i} { - append res [string repeat { } $indent] - if {rand()>0.8} { - if {rand()>0.5} { - set sep ":\n [string repeat { } $indent]" - } else { - set sep " : " - } - } else { - set sep : - } - append res \"[random_label]\"$sep[random_json $limit $indent] - if {$i<$n-1} {append res ,} - append res \n - } - incr indent -2 - append res [string repeat { } $indent] - append res \175 - return $res - } else { - set res \[\n - for {set i 0} {$i<$n} {incr i} { - append res [string repeat { } $indent] - append res [random_json $limit $indent] - if {$i<$n-1} {append res ,} - append res \n - } - incr indent -2 - append res [string repeat { } $indent] - append res \] - return $res - } - } elseif {rand()>0.9} { - if {rand()>0.7} {return "true"} - if {rand()>0.5} {return "false"} - return "null" - } elseif {rand()>0.5} { - return [random_numeric] - } else { - set res \" - set n [expr {int(rand()*4)+1}] - if {$n>=4} {set n [expr {$n+int(rand()*6)}]} - for {set i 0} {$i<$n} {incr i} { - if {rand()<0.05} { - set w [random_numeric] - } else { - set k [expr {int(rand()*$nwordlist)}] - set w [lindex $wordlist $k] - } - if {rand()<0.07} { - set w \\\"$w\\\" - } - if {$i<$n-1} { - switch [expr {int(rand()*9)}] { - 0 {set sp {, }} - 1 {set sp "\\n "} - 2 {set sp "-"} - default {set sp { }} - } - append res $w$sp - } else { - append res $w - if {rand()<0.2} {append res .} - } - } - return $res\" - } -} - -puts "CREATE TABLE IF NOT EXISTS data1(x JSON);" -puts "BEGIN;" -set sz 0 -for {set i 0} {$sz<100000000} {incr i} { - set j [random_json 7 0] - incr sz [string length $j] - puts "INSERT INTO data1(x) VALUES('$j');" -} -puts "COMMIT;" -puts "SELECT sum(length(x)) FROM data1;" DELETED test/json/json-q1.txt Index: test/json/json-q1.txt ================================================================== --- test/json/json-q1.txt +++ /dev/null @@ -1,4 +0,0 @@ -.mode qbox -.timer on -.param set $label 'q87' -SELECT rowid, x->>$label FROM data1 WHERE x->>$label IS NOT NULL; DELETED test/json/json-speed-check.sh Index: test/json/json-speed-check.sh ================================================================== --- test/json/json-speed-check.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash -# -# This is a template for a script used for day-to-day size and -# performance monitoring of SQLite. Typical usage: -# -# sh speed-check.sh trunk # Baseline measurement of trunk -# sh speed-check.sh x1 # Measure some experimental change -# fossil xdiff --tk jout-trunk.txt jout-x1.txt # View chanages -# -# There are multiple output files, all with a base name given by -# the first argument: -# -# summary-$BASE.txt # Copy of standard output -# jout-$BASE.txt # cachegrind output -# explain-$BASE.txt # EXPLAIN listings (only with --explain) -# -if test "$1" = "" -then - echo "Usage: $0 OUTPUTFILE [OPTIONS]" - exit -fi -NAME=$1 -shift -#CC_OPTS="-DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_MEMSYS5" -CC_OPTS="-DSQLITE_ENABLE_MEMSYS5" -CC=gcc -LEAN_OPTS="-DSQLITE_THREADSAFE=0" -LEAN_OPTS="$LEAN_OPTS -DSQLITE_DEFAULT_MEMSTATUS=0" -LEAN_OPTS="$LEAN_OPTS -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1" -LEAN_OPTS="$LEAN_OPTS -DSQLITE_LIKE_DOESNT_MATCH_BLOBS" -LEAN_OPTS="$LEAN_OPTS -DSQLITE_MAX_EXPR_DEPTH=0" -LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_DECLTYPE" -LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_DEPRECATED" -LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_PROGRESS_CALLBACK" -LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_SHARED_CACHE" -LEAN_OPTS="$LEAN_OPTS -DSQLITE_USE_ALLOCA" -BASELINE="trunk" -doExplain=0 -doCachegrind=1 -doVdbeProfile=0 -doWal=1 -doDiff=1 -while test "$1" != ""; do - case $1 in - --nodiff) - doDiff=0 - ;; - --lean) - CC_OPTS="$CC_OPTS $LEAN_OPTS" - ;; - --clang) - CC=clang - ;; - --gcc7) - CC=gcc-7 - ;; - -*) - CC_OPTS="$CC_OPTS $1" - ;; - *) - BASELINE=$1 - ;; - esac - shift -done -echo "NAME = $NAME" | tee summary-$NAME.txt -echo "CC_OPTS = $CC_OPTS" | tee -a summary-$NAME.txt -rm -f cachegrind.out.* jsonshell -$CC -g -Os -Wall -I. $CC_OPTS ./shell.c ./sqlite3.c -o jsonshell -ldl -lpthread -ls -l jsonshell | tee -a summary-$NAME.txt -home=`echo $0 | sed -e 's,/[^/]*$,,'` -echo ./jsonshell json100mb.db "<$home/json-q1.txt" -valgrind --tool=cachegrind ./jsonshell json100mb.db <$home/json-q1.txt \ - 2>&1 | tee -a summary-$NAME.txt -cg_anno.tcl cachegrind.out.* >jout-$NAME.txt -echo '*****************************************************' >>jout-$NAME.txt -sed 's/^[0-9=-]\{9\}/==00000==/' summary-$NAME.txt >>jout-$NAME.txt -if test "$NAME" != "$BASELINE"; then - fossil xdiff --tk -c 20 jout-$BASELINE.txt jout-$NAME.txt -fi Index: test/json101.test ================================================================== --- test/json101.test +++ test/json101.test @@ -308,37 +308,16 @@ do_execsql_test json-6.1 { SELECT json_valid('{"a":55,"b":72,}'); } {0} do_execsql_test json-6.2 { - SELECT json_error_position('{"a":55,"b":72,}'); -} {0} -do_execsql_test json-6.3 { - SELECT json_valid(json('{"a":55,"b":72,}')); -} {1} -do_execsql_test json-6.4 { - SELECT json_valid('{"a":55,"b":72 , }'); -} {0} -do_execsql_test json-6.5 { - SELECT json_error_position('{"a":55,"b":72 , }'); -} {0} -do_execsql_test json-6.6 { - SELECT json_error_position('{"a":55,"b":72,,}'); -} {16} -do_execsql_test json-6.7 { SELECT json_valid('{"a":55,"b":72}'); } {1} -do_execsql_test json-6.8 { - SELECT json_error_position('["a",55,"b",72,]'); -} {0} -do_execsql_test json-6.9 { - SELECT json_error_position('["a",55,"b",72 , ]'); -} {0} -do_execsql_test json-6.10 { - SELECT json_error_position('["a",55,"b",72,,]'); -} {16} -do_execsql_test json-6.11 { +do_execsql_test json-6.3 { + SELECT json_valid('["a",55,"b",72,]'); +} {0} +do_execsql_test json-6.4 { SELECT json_valid('["a",55,"b",72]'); } {1} # White-space tests. Note that form-feed is not white-space in JSON. # ticket [57eec374ae1d0a1d4a23077a95f4e173fe269113] @@ -903,112 +882,7 @@ } {1 {malformed JSON}} do_execsql_test json-19.3 { COMMIT; SELECT * FROM t1; } {} - -# 2023-03-17 positive and negative infinities -# -do_execsql_test json-20.1 { - SELECT json_object('a',2e370,'b',-3e380); -} {{{"a":9.0e+999,"b":-9.0e+999}}} -do_execsql_test json-20.2 { - SELECT json_object('a',2e370,'b',-3e380)->>'a'; -} Inf -do_execsql_test json-20.3 { - SELECT json_object('a',2e370,'b',-3e380)->>'b'; -} {-Inf} - -# 2023-05-02 https://sqlite.org/forum/forumpost/06c6334412 -# JSON functions should normally return NULL when given -# a NULL value as the JSON input. -# -db null NULL -do_execsql_test json-21.1 { - SELECT json_valid(NULL); -} NULL -do_execsql_test json-21.2 { - SELECT json_error_position(NULL); -} NULL -do_execsql_test json-21.3 { - SELECT json(NULL); -} NULL -do_execsql_test json-21.4 { - SELECT json_array(NULL); -} {[null]} -do_execsql_test json-21.5 { - SELECT json_extract(NULL); -} NULL -do_execsql_test json-21.6 { - SELECT json_insert(NULL,'$',123); -} NULL -do_execsql_test json-21.7 { - SELECT NULL->0; -} NULL -do_execsql_test json-21.8 { - SELECT NULL->>0; -} NULL -do_execsql_test json-21.9 { - SELECT '{a:5}'->NULL; -} NULL -do_execsql_test json-21.10 { - SELECT '{a:5}'->>NULL; -} NULL -do_catchsql_test json-21.11 { - SELECT json_object(NULL,5); -} {1 {json_object() labels must be TEXT}} -do_execsql_test json-21.12 { - SELECT json_patch(NULL,'{a:5}'); -} NULL -do_execsql_test json-21.13 { - SELECT json_patch('{a:5}',NULL); -} NULL -do_execsql_test json-21.14 { - SELECT json_patch(NULL,NULL); -} NULL -do_execsql_test json-21.15 { - SELECT json_remove(NULL,'$'); -} NULL -do_execsql_test json-21.16 { - SELECT json_remove('{a:5,b:7}',NULL); -} NULL -do_execsql_test json-21.17 { - SELECT json_replace(NULL,'$.a',123); -} NULL -do_execsql_test json-21.18 { - SELECT json_replace('{a:5,b:7}',NULL,NULL); -} {{{"a":5,"b":7}}} -do_execsql_test json-21.19 { - SELECT json_set(NULL,'$.a',123); -} NULL -do_execsql_test json-21.20 { - SELECT json_set('{a:5,b:7}',NULL,NULL); -} {{{"a":5,"b":7}}} -do_execsql_test json-21.21 { - SELECT json_type(NULL); -} NULL -do_execsql_test json-21.22 { - SELECT json_type('{a:5,b:7}',NULL); -} NULL -do_execsql_test json-21.23 { - SELECT json_quote(NULL); -} null -do_execsql_test json-21.24 { - SELECT count(*) FROM json_each(NULL); -} 0 -do_execsql_test json-21.25 { - SELECT count(*) FROM json_tree(NULL); -} 0 -do_execsql_test json-21.26 { - WITH c(x) AS (VALUES(1),(2.0),(NULL),('three')) - SELECT json_group_array(x) FROM c; -} {[1,2.0,null,"three"]} -do_execsql_test json-21.27 { - WITH c(x,y) AS (VALUES('a',1),('b',2.0),('c',NULL),(NULL,'three'),('e','four')) - SELECT json_group_object(x,y) FROM c; -} {{{"a":1,"b":2.0,"c":null,:"three","e":"four"}}} - - - - finish_test Index: test/json102.test ================================================================== --- test/json102.test +++ test/json102.test @@ -299,31 +299,22 @@ # # JSON does not allow leading zeros. But the JSON extension was # allowing them. The following tests verify that the problem is now # fixed. # -foreach {id j x0 x5} { - 1401 {'{"x":01}'} 0 0 - 1402 {'{"x":-01}'} 0 0 - 1403 {'{"x":0}'} 1 1 - 1404 {'{"x":-0}'} 1 1 - 1405 {'{"x":0.1}'} 1 1 - 1406 {'{"x":-0.1}'} 1 1 - 1407 {'{"x":0.0000}'} 1 1 - 1408 {'{"x":-0.0000}'} 1 1 - 1409 {'{"x":01.5}'} 0 0 - 1410 {'{"x":-01.5}'} 0 0 - 1411 {'{"x":00}'} 0 0 - 1412 {'{"x":-00}'} 0 0 - 1413 {'{"x":+0}'} 0 1 - 1414 {'{"x":+5}'} 0 1 - 1415 {'{"x":+5.5}'} 0 1 -} { - do_execsql_test json102-$id " - SELECT json_valid($j), NOT json_error_position($j); - " [list $x0 $x5] -} +do_execsql_test json102-1401 { SELECT json_valid('{"x":01}') } 0 +do_execsql_test json102-1402 { SELECT json_valid('{"x":-01}') } 0 +do_execsql_test json102-1403 { SELECT json_valid('{"x":0}') } 1 +do_execsql_test json102-1404 { SELECT json_valid('{"x":-0}') } 1 +do_execsql_test json102-1405 { SELECT json_valid('{"x":0.1}') } 1 +do_execsql_test json102-1406 { SELECT json_valid('{"x":-0.1}') } 1 +do_execsql_test json102-1407 { SELECT json_valid('{"x":0.0000}') } 1 +do_execsql_test json102-1408 { SELECT json_valid('{"x":-0.0000}') } 1 +do_execsql_test json102-1409 { SELECT json_valid('{"x":01.5}') } 0 +do_execsql_test json102-1410 { SELECT json_valid('{"x":-01.5}') } 0 +do_execsql_test json102-1411 { SELECT json_valid('{"x":00}') } 0 +do_execsql_test json102-1412 { SELECT json_valid('{"x":-00}') } 0 #------------------------------------------------------------------------ # 2017-04-10 ticket 6c9b5514077fed34551f98e64c09a10dc2fc8e16 # JSON extension accepts strings containing control characters. # Index: test/json104.test ================================================================== --- test/json104.test +++ test/json104.test @@ -26,52 +26,10 @@ }','{ "a":"z", "c": { "f": null } - }'); -} {{{"a":"z","c":{"d":"e"}}}} -do_execsql_test json104-101 { - SELECT json_patch('{ - "a": "b", - "c": { - "d": "e", - "f": "g" - } - }','{ - a:"z", - c: { - f: null - } - }'); -} {{{"a":"z","c":{"d":"e"}}}} -do_execsql_test json104-102 { - SELECT json_patch('{ - a: "b", - c: { - d: "e", - f: "g" - } - }','{ - "a":"z", - "c": { - "f": null - } - }'); -} {{{"a":"z","c":{"d":"e"}}}} -do_execsql_test json104-103 { - SELECT json_patch('{ - a: "b", - c: { - d: "e", - f: "g" - } - }','{ - a:"z", - c: { - f: null - } }'); } {{{"a":"z","c":{"d":"e"}}}} # This is the example from pages 4 and 5 of RFC-7396 DELETED test/json501.test Index: test/json501.test ================================================================== --- test/json501.test +++ /dev/null @@ -1,304 +0,0 @@ -# 2023-04-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 implements tests for the JSON5 enhancements to the -# JSON SQL functions extension to the SQLite library. -# - -set testdir [file dirname $argv0] -source $testdir/tester.tcl -set testprefix json501 - -# From https://spec.json5.org/#introduction -# -#----------------------------------------------------------------------------- -# Summary of Features -# -# The following ECMAScript 5.1 features, which are not supported in JSON, have -# been extended to JSON5. -# -# Objects -# -# 1) Object keys may be an ECMAScript 5.1 IdentifierName. -# 2) Objects may have a single trailing comma. -# -# Arrays -# -# 3) Arrays may have a single trailing comma. -# -# Strings -# -# 4) Strings may be single quoted. -# 5) Strings may span multiple lines by escaping new line characters. -# 6) Strings may include character escapes. -# -# Numbers -# -# 7) Numbers may be hexadecimal. -# 8) Numbers may have a leading or trailing decimal point. -# 9) Numbers may be IEEE 754 positive infinity, negative infinity, and NaN. -# 10) Numbers may begin with an explicit plus sign. -# -# Comments -# -# 11) Single and multi-line comments are allowed. -# -# White Space -# -# 12) Additional white space characters are allowed. -#----------------------------------------------------------------------------- -# -# Test number in this file are of the form X.Y where X is one of the item -# numbers in the feature list above and Y is the test sequence number. -# - -############################################################################### -# 1) Object keys may be an ECMAScript 5.1 IdentifierName. -do_execsql_test 1.1 { - WITH c(x) AS (VALUES('{a:5,b:6}')) - SELECT x->>'a', json(x), json_valid(x), NOT json_error_position(x) FROM c; -} {5 {{"a":5,"b":6}} 0 1} -do_execsql_test 1.2 { - SELECT '[7,null,{a:5,b:6},[8,9]]'->>'$[2].b'; -} {6} -do_execsql_test 1.3 { - SELECT '{ $123 : 789 }'->>'$."$123"'; -} 789 -do_execsql_test 1.4 { - SELECT '{ _123$xyz : 789 }'->>'$."_123$xyz"'; -} 789 -do_execsql_test 1.5 { - SELECT '{ MNO_123$xyz : 789 }'->>'$."MNO_123$xyz"'; -} 789 - -do_execsql_test 1.6 { - SELECT json('{ MNO_123$xyz : 789 }'); -} [list {{"MNO_123$xyz":789}}] - -do_catchsql_test 1.10 { - SELECT json('{ MNO_123/xyz : 789 }'); -} {1 {malformed JSON}} - -do_execsql_test 1.11 { - SELECT '{ MNO_123æxyz : 789 }'->>'MNO_123æxyz'; -} {789} - -############################################################################### -# 2) Objects may have a single trailing comma. - -do_execsql_test 2.1 { - WITH c(x) AS (VALUES('{"a":5, "b":6, }')) - SELECT x->>'b', json(x), json_valid(x), NOT json_error_position(x) FROM c; -} {6 {{"a":5,"b":6}} 0 1} -do_execsql_test 2.2 { - SELECT '{a:5, b:6 , }'->>'b'; -} 6 -do_catchsql_test 2.3 { - SELECT '{a:5, b:6 ,, }'->>'b'; -} {1 {malformed JSON}} -do_catchsql_test 2.4 { - SELECT '{a:5, b:6, ,}'->>'b'; -} {1 {malformed JSON}} - -############################################################################### -# 3) Arrays may have a single trailing comma. - -do_execsql_test 3.1 { - WITH c(x) AS (VALUES('[5, 6,]')) - SELECT x->>1, json(x), json_valid(x), NOT json_error_position(x) FROM c; -} {6 {[5,6]} 0 1} -do_execsql_test 3.2 { - SELECT '[5, 6 , ]'->>1; -} 6 -do_catchsql_test 3.3 { - SELECT '[5, 6,,]'->>1; -} {1 {malformed JSON}} -do_catchsql_test 3.4 { - SELECT '[5, 6 , , ]'->>1; -} {1 {malformed JSON}} - -############################################################################### -# 4) Strings may be single quoted. - -do_execsql_test 4.1 { - WITH c(x) AS (VALUES('{"a": ''abcd''}')) - SELECT x->>'a', json(x), json_valid(x), NOT json_error_position(x) FROM c; -} {abcd {{"a":"abcd"}} 0 1} -do_execsql_test 4.2 { - SELECT '{b: 123, ''a'': ''ab\''cd''}'->>'a'; -} {ab'cd} - -############################################################################### -# 5) Strings may span multiple lines by escaping new line characters. - -do_execsql_test 5.1 { - WITH c(x) AS (VALUES('{a: "abc'||char(0x5c,0x0a)||'xyz"}')) - SELECT x->>'a', json(x), json_valid(x), NOT json_error_position(x) FROM c; -} {abcxyz {{"a":"abcxyz"}} 0 1} -do_execsql_test 5.2 { - SELECT ('{a: "abc'||char(0x5c,0x0d)||'xyz"}')->>'a'; -} {abcxyz} -do_execsql_test 5.3 { - SELECT ('{a: "abc'||char(0x5c,0x0d,0x0a)||'xyz"}')->>'a'; -} {abcxyz} -do_execsql_test 5.4 { - SELECT ('{a: "abc'||char(0x5c,0x2028)||'xyz"}')->>'a'; -} {abcxyz} -do_execsql_test 5.5 { - SELECT ('{a: "abc'||char(0x5c,0x2029)||'xyz"}')->>'a'; -} {abcxyz} - - -############################################################################### -# 6) Strings may include character escapes. - -do_execsql_test 6.1 { - SELECT ('{a: "abc'||char(0x5c,0x27)||'xyz"}')->>'a'; -} {abc'xyz} -do_execsql_test 6.2 { - SELECT ('{a: "abc'||char(0x5c,0x22)||'xyz"}')->>'a'; -} {abc"xyz} -do_execsql_test 6.3 { - SELECT ('{a: "abc'||char(0x5c,0x5c)||'xyz"}')->>'a'; -} {{abc\xyz}} -do_execsql_test 6.4 { - SELECT hex(('{a: "abc\bxyz"}')->>'a'); -} {6162630878797A} -do_execsql_test 6.5 { - SELECT hex(('{a: "abc\f\n\r\t\vxyz"}')->>'a'); -} {6162630C0A0D090B78797A} -do_execsql_test 6.6 { - SELECT hex(('{a: "abc\0xyz"}')->>'a'); -} {6162630078797A} -do_execsql_test 6.7 { - SELECT '{a: "abc\x35\x4f\x6Exyz"}'->>'a'; -} {abc5Onxyz} -do_execsql_test 6.8 { - SELECT '{a: "\x6a\x6A\x6b\x6B\x6c\x6C\x6d\x6D\x6e\x6E\x6f\x6F"}'->>'a'; -} {jjkkllmmnnoo} - -############################################################################### -# 7) Numbers may be hexadecimal. - -do_execsql_test 7.1 { - SELECT '{a: 0x0}'->>'a'; -} 0 -do_execsql_test 7.2 { - SELECT '{a: -0x0}'->>'a'; -} 0 -do_execsql_test 7.3 { - SELECT '{a: +0x0}'->>'a'; -} 0 -do_execsql_test 7.4 { - SELECT '{a: 0xabcdef}'->>'a'; -} 11259375 -do_execsql_test 7.5 { - SELECT '{a: -0xaBcDeF}'->>'a'; -} -11259375 -do_execsql_test 7.6 { - SELECT '{a: +0xABCDEF}'->>'a'; -} 11259375 - -############################################################################### -# 8) Numbers may have a leading or trailing decimal point. - -do_execsql_test 8.1 { - WITH c(x) AS (VALUES('{x: 4.}')) SELECT x->>'x', json(x) FROM c; -} {4.0 {{"x":4.0}}} -do_execsql_test 8.2 { - WITH c(x) AS (VALUES('{x: +4.}')) SELECT x->>'x', json(x) FROM c; -} {4.0 {{"x":4.0}}} -do_execsql_test 8.3 { - WITH c(x) AS (VALUES('{x: -4.}')) SELECT x->>'x', json(x) FROM c; -} {-4.0 {{"x":-4.0}}} -do_execsql_test 8.3 { - WITH c(x) AS (VALUES('{x: .5}')) SELECT x->>'x', json(x) FROM c; -} {0.5 {{"x":0.5}}} -do_execsql_test 8.4 { - WITH c(x) AS (VALUES('{x: -.5}')) SELECT x->>'x', json(x) FROM c; -} {-0.5 {{"x":-0.5}}} -do_execsql_test 8.5 { - WITH c(x) AS (VALUES('{x: +.5}')) SELECT x->>'x', json(x) FROM c; -} {0.5 {{"x":0.5}}} -do_execsql_test 8.6 { - WITH c(x) AS (VALUES('{x: 4.e0}')) SELECT x->>'x', json(x) FROM c; -} {4.0 {{"x":4.0e0}}} -do_execsql_test 8.7 { - WITH c(x) AS (VALUES('{x: +4.e1}')) SELECT x->>'x', json(x) FROM c; -} {40.0 {{"x":4.0e1}}} -do_execsql_test 8.8 { - WITH c(x) AS (VALUES('{x: -4.e2}')) SELECT x->>'x', json(x) FROM c; -} {-400.0 {{"x":-4.0e2}}} -do_execsql_test 8.9 { - WITH c(x) AS (VALUES('{x: .5e3}')) SELECT x->>'x', json(x) FROM c; -} {500.0 {{"x":0.5e3}}} -do_execsql_test 8.10 { - WITH c(x) AS (VALUES('{x: -.5e-1}')) SELECT x->>'x', json(x) FROM c; -} {-0.05 {{"x":-0.5e-1}}} -do_execsql_test 8.11 { - WITH c(x) AS (VALUES('{x: +.5e-2}')) SELECT x->>'x', json(x) FROM c; -} {0.005 {{"x":0.5e-2}}} - - -############################################################################### -# 9) Numbers may be IEEE 754 positive infinity, negative infinity, and NaN. - -do_execsql_test 9.1 { - WITH c(x) AS (VALUES('{x: +Infinity}')) SELECT x->>'x', json(x) FROM c; -} {Inf {{"x":9.0e999}}} -do_execsql_test 9.2 { - WITH c(x) AS (VALUES('{x: -Infinity}')) SELECT x->>'x', json(x) FROM c; -} {-Inf {{"x":-9.0e999}}} -do_execsql_test 9.3 { - WITH c(x) AS (VALUES('{x: Infinity}')) SELECT x->>'x', json(x) FROM c; -} {Inf {{"x":9.0e999}}} -do_execsql_test 9.4 { - WITH c(x) AS (VALUES('{x: NaN}')) SELECT x->>'x', json(x) FROM c; -} {{} {{"x":null}}} - -############################################################################### -# 10) Numbers may begin with an explicit plus sign. - -do_execsql_test 10.1 { - SELECT '{a: +123}'->'a'; -} 123 - -############################################################################### -# 11) Single and multi-line comments are allowed. - -do_execsql_test 11.1 { - SELECT ' /* abc */ { /*def*/ aaa /* xyz */ : // to the end of line - 123 /* xyz */ , /* 123 */ }'->>'aaa'; -} 123 - -############################################################################### -# 12) Additional white space characters are allowed. - -do_execsql_test 12.1 { - SELECT (char(0x09,0x0a,0x0b,0x0c,0x0d,0x20,0xa0,0x2028,0x2029) - || '{a: "xyz"}')->>'a'; -} xyz -do_execsql_test 12.2 { - SELECT ('{a:' || char(0x09,0x0a,0x0b,0x0c,0x0d,0x20,0xa0,0x2028,0x2029) - || '"xyz"}')->>'a'; -} xyz -do_execsql_test 12.3 { - SELECT (char(0x1680,0x2000,0x2001,0x2002,0x2003,0x2004,0x2005, - 0x2006,0x2007,0x2008,0x2009,0x200a,0x3000,0xfeff) - || '{a: "xyz"}')->>'a'; -} xyz -do_execsql_test 12.4 { - SELECT ('{a: ' ||char(0x1680,0x2000,0x2001,0x2002,0x2003,0x2004,0x2005, - 0x2006,0x2007,0x2008,0x2009,0x200a,0x3000,0xfeff) - || ' "xyz"}')->>'a'; -} xyz - - -finish_test DELETED test/json502.test Index: test/json502.test ================================================================== --- test/json502.test +++ /dev/null @@ -1,25 +0,0 @@ -# 2023-04-28 -# -# 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 tests for the JSON5 enhancements to the -# JSON SQL functions extension to the SQLite library. -# - -set testdir [file dirname $argv0] -source $testdir/tester.tcl -set testprefix json502 - -do_execsql_test 1.1 { - CREATE TABLE t1(x JSON); - INSERT INTO t1(x) VALUES('{a:{b:{c:"hello",},},}'); - SELECT fullkey FROM t1, json_tree(x); -} {{$} {$.a} {$.a.b} {$.a.b.c}} - -finish_test Index: test/misc1.test ================================================================== --- test/misc1.test +++ test/misc1.test @@ -590,13 +590,10 @@ do_test misc1-18.1 { set n [sqlite3_sleep 100] expr {$n>=100} } {1} -do_test misc1-18.2 { - sqlite3_sleep -100 -} {0} # 2014-01-10: In a CREATE TABLE AS, if one or more of the column names # are an empty string, that is still OK. # do_execsql_test misc1-19.1 { Index: test/notnull2.test ================================================================== --- test/notnull2.test +++ test/notnull2.test @@ -26,10 +26,28 @@ ) INSERT INTO t1 SELECT i, i FROM x; INSERT INTO t2 SELECT * FROM t1; } +proc do_vmstep_test {tn sql nstep {res {}}} { + uplevel [list do_execsql_test $tn.0 $sql $res] + + set vmstep [db status vmstep] + if {[string range $nstep 0 0]=="+"} { + set body "if {$vmstep<$nstep} { + error \"got $vmstep, expected more than [string range $nstep 1 end]\" + }" + } else { + set body "if {$vmstep>$nstep} { + error \"got $vmstep, expected less than $nstep\" + }" + } + + # set name "$tn.vmstep=$vmstep,expect=$nstep" + set name "$tn.1" + uplevel [list do_test $name $body {}] +} do_vmstep_test 1.1.1 { SELECT * FROM t1 LEFT JOIN t2 WHERE a=c AND d IS NULL; } 100 {} do_vmstep_test 1.1.2 { Index: test/pragma.test ================================================================== --- test/pragma.test +++ test/pragma.test @@ -431,13 +431,13 @@ execsql { ATTACH 'testerr.db' AS t2; PRAGMA integrity_check } } {{*** in database t2 *** -Page 4: never used -Page 5: never used -Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}} +Page 4 is never used +Page 5 is never used +Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}} do_execsql_test pragma-3.9b { PRAGMA t2.integrity_check=t2; } {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}} do_execsql_test pragma-3.9c { PRAGMA t2.integrity_check=sqlite_schema; @@ -445,83 +445,83 @@ do_test pragma-3.10 { execsql { PRAGMA integrity_check=1 } } {{*** in database t2 *** -Page 4: never used}} +Page 4 is never used}} do_test pragma-3.11 { execsql { PRAGMA integrity_check=5 } } {{*** in database t2 *** -Page 4: never used -Page 5: never used -Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2}} +Page 4 is never used +Page 5 is never used +Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2}} do_test pragma-3.12 { execsql { PRAGMA integrity_check=4 } } {{*** in database t2 *** -Page 4: never used -Page 5: never used -Page 6: never used} {row 1 missing from index i2}} +Page 4 is never used +Page 5 is never used +Page 6 is never used} {row 1 missing from index i2}} do_test pragma-3.13 { execsql { PRAGMA integrity_check=3 } } {{*** in database t2 *** -Page 4: never used -Page 5: never used -Page 6: never used}} +Page 4 is never used +Page 5 is never used +Page 6 is never used}} do_test pragma-3.14 { execsql { PRAGMA integrity_check(2) } } {{*** in database t2 *** -Page 4: never used -Page 5: never used}} +Page 4 is never used +Page 5 is never used}} do_test pragma-3.15 { execsql { ATTACH 'testerr.db' AS t3; PRAGMA integrity_check } } {{*** in database t2 *** -Page 4: never used -Page 5: never used -Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 *** -Page 4: never used -Page 5: never used -Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}} +Page 4 is never used +Page 5 is never used +Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 *** +Page 4 is never used +Page 5 is never used +Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}} do_test pragma-3.16 { execsql { PRAGMA integrity_check(10) } } {{*** in database t2 *** -Page 4: never used -Page 5: never used -Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 *** -Page 4: never used -Page 5: never used -Page 6: never used} {row 1 missing from index i2}} +Page 4 is never used +Page 5 is never used +Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 *** +Page 4 is never used +Page 5 is never used +Page 6 is never used} {row 1 missing from index i2}} do_test pragma-3.17 { execsql { PRAGMA integrity_check=8 } } {{*** in database t2 *** -Page 4: never used -Page 5: never used -Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 *** -Page 4: never used -Page 5: never used}} +Page 4 is never used +Page 5 is never used +Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 *** +Page 4 is never used +Page 5 is never used}} do_test pragma-3.18 { execsql { PRAGMA integrity_check=4 } } {{*** in database t2 *** -Page 4: never used -Page 5: never used -Page 6: never used} {row 1 missing from index i2}} +Page 4 is never used +Page 5 is never used +Page 6 is never used} {row 1 missing from index i2}} } do_test pragma-3.19 { catch {db close} forcedelete test.db test.db-journal sqlite3 db test.db @@ -2058,19 +2058,6 @@ do_catchsql_test 24.2 { PRAGMA integrity_check; } {0 {{database disk image is malformed}}} } database_never_corrupt - -# 2023-03-27. Register allocation issue in integrity_check discovered -# by new assert() statements added in [6f8b97f31a4c8552]. -# dbsqlfuzz dc9ab26037cf5ef797d28cd1ae0855ade584216d -# tag-20230327-1 -# -reset_db -do_execsql_test 25.0 { - CREATE TABLE t1(a INT, b AS (a*2) NOT NULL); - CREATE TEMP TABLE t2(a PRIMARY KEY, b, c UNIQUE) WITHOUT ROWID; - CREATE UNIQUE INDEX t2x ON t2(c,b); - PRAGMA integrity_check; -} ok finish_test Index: test/printf.test ================================================================== --- test/printf.test +++ test/printf.test @@ -3784,44 +3784,6 @@ # do_execsql_test printf-16.1 { SELECT printf('%.*g',2147483647,0.01); } {0.01} -# 2023-02-23 https://sqlite.org/forum/forumpost/d1387c3979c7f557 -# Loss of precision when doing floating-point to decimal -# conversions on values that have no factional part. -# -do_execsql_test printf-17.1 { - SELECT format('%!.20g', 13.0); -} 13.0 -do_execsql_test printf-17.2 { - SELECT format('%.3e', 199990000.0); -} 2.000e+08 -do_execsql_test printf-17.3 { - SELECT format('%.3f', 199990000.0); -} 199990000.000 -do_execsql_test printf-17.4 { - SELECT format('%.3g', 199990000.0); -} 2e+08 -do_execsql_test printf-17.5 { - SELECT format('%.4e', 199990000.0); -} 1.9999e+08 -do_execsql_test printf-17.6 { - SELECT format('%.4f', 199990000.0); -} 199990000.0000 -do_execsql_test printf-17.7 { - SELECT format('%.4g', 199990000.0); -} 2e+08 -do_execsql_test printf-17.8 { - SELECT format('%.5e', 199990000.0); -} 1.99990e+08 -do_execsql_test printf-17.9 { - SELECT format('%.5f', 199990000.0); -} 199990000.00000 -do_execsql_test printf-17.10 { - SELECT format('%.5g', 199990000.0); -} 1.9999e+08 -do_execsql_test printf-17.11 { - SELECT format('%.30f',1.0000000000000000076e-50); -} 0.000000000000000000000000000000 - finish_test Index: test/pushdown.test ================================================================== --- test/pushdown.test +++ test/pushdown.test @@ -120,68 +120,7 @@ SELECT v1.a, v1.b, t0.c0 AS cd FROM t0 LEFT JOIN v0 ON v0.c0!=0, v1 ) WHERE a=2 AND b=0 AND cd=0; } { 2 0 0 } - -# 2023-02-22 https://sqlite.org/forum/forumpost/bcc4375032 -# Performance regression caused by check-in [1ad41840c5e0fa70] from 2022-11-25. -# That check-in added a new restriction on push-down. The new restriction is -# no longer necessary after check-in [27655c9353620aa5] from 2022-12-14. -# -do_execsql_test 3.5 { - DROP TABLE IF EXISTS t1; - CREATE TABLE t1(a INT, b INT, c TEXT, PRIMARY KEY(a,b)) WITHOUT ROWID; - INSERT INTO t1(a,b,c) VALUES - (1,100,'abc'), - (2,200,'def'), - (3,300,'abc'); - DROP TABLE IF EXISTS t2; - CREATE TABLE t2(a INT, b INT, c TEXT, PRIMARY KEY(a,b)) WITHOUT ROWID; - INSERT INTO t2(a,b,c) VALUES - (1,110,'efg'), - (2,200,'hij'), - (3,330,'klm'); - CREATE VIEW v3 AS - SELECT a, b, c FROM t1 - UNION ALL - SELECT a, b, 'xyz' FROM t2; - SELECT * FROM v3 WHERE a=2 AND b=200; -} {2 200 def 2 200 xyz} -do_eqp_test 3.6 { - SELECT * FROM v3 WHERE a=2 AND b=200; -} { - QUERY PLAN - |--CO-ROUTINE v3 - | `--COMPOUND QUERY - | |--LEFT-MOST SUBQUERY - | | `--SEARCH t1 USING PRIMARY KEY (a=? AND b=?) - | `--UNION ALL - | `--SEARCH t2 USING PRIMARY KEY (a=? AND b=?) - `--SCAN v3 -} -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -# We want both arms of the compound subquery to use the -# primary key. - -# The following is a test of the count-of-view optimization. This does -# not have anything to do with push-down. It is here because this is a -# convenient place to put the test. -# -do_execsql_test 3.7 { - SELECT count(*) FROM v3; -} 6 -do_eqp_test 3.8 { - SELECT count(*) FROM v3; -} { - QUERY PLAN - |--SCAN CONSTANT ROW - |--SCALAR SUBQUERY xxxxxx - | `--SCAN t1 - `--SCALAR SUBQUERY xxxxxx - `--SCAN t2 -} -# ^^^^^^^^^^^^^^^^^^^^ -# The query should be converted into: -# SELECT (SELECT count(*) FROM t1)+(SELECT count(*) FROM t2) - + finish_test Index: test/returning1.test ================================================================== --- test/returning1.test +++ test/returning1.test @@ -210,17 +210,17 @@ CREATE TRIGGER tr2 INSTEAD OF UPDATE ON t1 BEGIN INSERT INTO log VALUES('update', new.rowid, new.a, new.b); END; } -do_catchsql_test 10.3a { +do_catchsql_test 10.3 { INSERT INTO t1(a, b) VALUES(1234, 5678) RETURNING rowid; -} {1 {no such column: new.rowid}} +} {1 {no such column: rowid}} -do_catchsql_test 10.3b { +do_catchsql_test 10.3 { UPDATE t1 SET a='z' WHERE b='y' RETURNING rowid; -} {1 {no such column: new.rowid}} +} {1 {no such column: rowid}} do_execsql_test 10.4 { SELECT * FROM log; } {} @@ -406,37 +406,6 @@ CREATE TABLE bug(id INTEGER PRIMARY KEY NOT NULL, x); INSERT INTO bug(id,x) VALUES(20, NULL); UPDATE bug SET x=NULL WHERE id = 20 RETURNING quote(x), x IS NULL; } {NULL 1} -# 2023-03-08 https://sqlite.org/forum/forumpost/f5a2b1db87 -# NULL pointer dereference following an error. -# -do_execsql_test 18.0 { - CREATE TABLE v0(c1 INT); - CREATE VIEW view_2(c1) AS SELECT CASE WHEN c1 COLLATE TRUE THEN TRUE ELSE TRUE END FROM v0; - CREATE TRIGGER x1 INSTEAD OF INSERT ON view_2 BEGIN SELECT true; END; -} -do_catchsql_test 18.1 { - INSERT INTO view_2 DEFAULT VALUES RETURNING *; -} {1 {no such collation sequence: TRUE}} - -# 2023-03-16 -# https://sqlite.org/forum/forumpost/c99d6e0329 -# ticket d15b3a4ea901ef0d -# ticket 89d259d45b855a0d -# -# A RETURNING clause on an IF NOT EXISTS trigger does not generate -# an error if the trigger already exists. -# -do_execsql_test 19.0 { - DROP TABLE IF EXISTS t1;CREATE TABLE t1(a); - CREATE TRIGGER r1 AFTER UPDATE ON t1 BEGIN VALUES(0); END; -} {} -do_catchsql_test 19.1 { - CREATE TRIGGER IF NOT EXISTS r1 AFTER DELETE ON t1 BEGIN - INSERT INTO t1(a) VALUES (1) RETURNING FALSE; - INSERT INTO t1(a) VALUES (2) RETURNING TRUE; - END; -} {0 {}} - finish_test Index: test/rowvalue9.test ================================================================== --- test/rowvalue9.test +++ test/rowvalue9.test @@ -306,49 +306,9 @@ do_catchsql_test 8.2 { SELECT a FROM t1 NATURAL JOIN t1 WHERE (a,b)> (SELECT 2 IN (SELECT 2,2), 2); } {1 {sub-select returns 2 columns - expected 1}} -#------------------------------------------------------------------------- -# -reset_db -do_execsql_test 9.0 { - CREATE TABLE t1(a, b); - INSERT INTO t1 VALUES(1, 1), (1, 2), (2, 2), (2, 3), (3, 3), (3, 4), (4, 4); -} - -do_execsql_test 9.1 { - SELECT * FROM t1 WHERE (a, b) IN ( (3, 3), (2, 2) ); -} { - 2 2 3 3 -} -do_execsql_test 9.2 { - CREATE INDEX i1 ON t1(a); -} - -do_execsql_test 9.4 { - SELECT * FROM t1 WHERE (a, b) IN ( (3, 3), (2, 2) ); -} { - 2 2 3 3 -} -do_eqp_test 9.4e { - SELECT * FROM t1 WHERE (a, b) IN ( (3, 3), (2, 2) ); -} { - *SEARCH t1 USING INDEX i1* -} - -do_execsql_test 9.5 { - CREATE INDEX i2 ON t1(b, a); - SELECT * FROM t1 WHERE (a, b) IN ( (3, 3), (2, 2) ); -} { - 2 2 3 3 -} -do_eqp_test 9.5e { - SELECT * FROM t1 WHERE (a, b) IN ( (3, 3), (2, 2) ); -} { - *SEARCH t1 USING COVERING INDEX i2* -} - finish_test Index: test/scanstatus.test ================================================================== --- test/scanstatus.test +++ test/scanstatus.test @@ -43,24 +43,16 @@ } uplevel [list do_test $tn [list set {} $ret] [list {*}$res]] } -do_execsql_test 1.1a { SELECT count(*) FROM t1, t2; } 6 -do_scanstatus_test 1.1b { +do_execsql_test 1.1 { SELECT count(*) FROM t1, t2; } 6 +do_scanstatus_test 1.2 { nLoop 1 nVisit 2 nEst 1048576.0 zName t1 zExplain {SCAN t1} nLoop 2 nVisit 6 nEst 1048576.0 zName t2 zExplain {SCAN t2} } -sqlite3_db_config db STMT_SCANSTATUS 0 - -do_execsql_test 1.2a { SELECT count(*) FROM t1, t2; } 6 -do_scanstatus_test 1.2b { -} - -sqlite3_db_config db STMT_SCANSTATUS 1 - do_execsql_test 1.3 { ANALYZE; SELECT count(*) FROM t1, t2; } 6 do_scanstatus_test 1.4 { @@ -100,11 +92,10 @@ #------------------------------------------------------------------------- # Try a few different types of scans. # reset_db -sqlite3_db_config db STMT_SCANSTATUS 1 do_execsql_test 2.1 { CREATE TABLE x1(i INTEGER PRIMARY KEY, j); INSERT INTO x1 VALUES(1, 'one'); INSERT INTO x1 VALUES(2, 'two'); INSERT INTO x1 VALUES(3, 'three'); @@ -284,11 +275,10 @@ #------------------------------------------------------------------------- # Further tests of different scan types. # reset_db -sqlite3_db_config db STMT_SCANSTATUS 1 proc tochar {i} { set alphabet {a b c d e f g h i j k l m n o p q r s t u v w x y z} return [lindex $alphabet [expr $i % [llength $alphabet]]] } db func tochar tochar @@ -373,11 +363,10 @@ do_eqp_test 5.5.1 { SELECT count(*) FROM t1, t3 WHERE y = c; } { QUERY PLAN |--SCAN t3 - |--BLOOM FILTER ON t1 (c=?) `--SEARCH t1 USING AUTOMATIC COVERING INDEX (c=?) } do_execsql_test 5.5.2 { SELECT count(*) FROM t1, t3 WHERE y = c; } {200} Index: test/scanstatus2.test ================================================================== --- test/scanstatus2.test +++ test/scanstatus2.test @@ -17,12 +17,10 @@ ifcapable !scanstatus { finish_test return } -sqlite3_db_config db STMT_SCANSTATUS 1 - do_execsql_test 1.0 { CREATE TABLE t1(a, b); CREATE TABLE t2(x, y); INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(3, 4); @@ -141,11 +139,10 @@ } #------------------------------------------------------------------------- ifcapable fts5 { reset_db - sqlite3_db_config db STMT_SCANSTATUS 1 do_execsql_test 2.0 { CREATE VIRTUAL TABLE ft USING fts5(a); INSERT INTO ft VALUES('abc'); INSERT INTO ft VALUES('def'); INSERT INTO ft VALUES('ghi'); @@ -159,11 +156,10 @@ } } #------------------------------------------------------------------------- reset_db -sqlite3_db_config db STMT_SCANSTATUS 1 do_execsql_test 3.0 { CREATE TABLE x1(a, b); CREATE TABLE x2(c, d); WITH s(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1000) @@ -175,17 +171,15 @@ SELECT * FROM x1, x2 WHERE c=+a; } { QUERY (nCycle=nnn) --SCAN x1 (nCycle=nnn) --CREATE AUTOMATIC INDEX ON x2(c, d) (nCycle=nnn) ---BLOOM FILTER ON x2 (c=?) --SEARCH x2 USING AUTOMATIC COVERING INDEX (c=?) (nCycle=nnn) } #------------------------------------------------------------------------- reset_db -sqlite3_db_config db STMT_SCANSTATUS 1 do_execsql_test 4.0 { CREATE TABLE rt1 (id INTEGER PRIMARY KEY, x1, x2); CREATE TABLE rt2 (id, x1, x2); } @@ -193,21 +187,19 @@ SELECT * FROM rt1, rt2 WHERE rt1.id%2 AND rt2.x1=rt1.x1; } { QUERY (nCycle=nnn) --SCAN rt1 (nCycle=nnn) --CREATE AUTOMATIC INDEX ON rt2(x1, id, x2) (nCycle=nnn) ---BLOOM FILTER ON rt2 (x1=?) --SEARCH rt2 USING AUTOMATIC COVERING INDEX (x1=?) (nCycle=nnn) } do_graph_test 4.2 { SELECT rt2.id FROM rt1, rt2 WHERE rt1.id%2 AND rt2.x1=rt1.x1; } { QUERY (nCycle=nnn) --SCAN rt1 (nCycle=nnn) --CREATE AUTOMATIC INDEX ON rt2(x1, id) (nCycle=nnn) ---BLOOM FILTER ON rt2 (x1=?) --SEARCH rt2 USING AUTOMATIC COVERING INDEX (x1=?) (nCycle=nnn) } do_graph_test 4.3 { SELECT rt2.id FROM rt1, rt2 WHERE rt1.id%2 AND (rt2.x1+1)=(rt1.x1+1); @@ -221,11 +213,10 @@ SELECT rt2.id FROM rt1, rt2 WHERE rt1.id%2 AND rt2.x1=(rt1.x1+1) AND rt2.id>5; } { QUERY (nCycle=nnn) --SCAN rt1 (nCycle=nnn) --CREATE AUTOMATIC INDEX ON rt2(x1, id) WHERE (nCycle=nnn) ---BLOOM FILTER ON rt2 (x1=?) --SEARCH rt2 USING AUTOMATIC PARTIAL COVERING INDEX (x1=?) (nCycle=nnn) } do_graph_test 4.5 { SELECT v1.cnt FROM rt1, ( @@ -236,40 +227,11 @@ --CO-ROUTINE v1 ----SCAN rt2 (nCycle=nnn) ----USE TEMP B-TREE FOR GROUP BY --SCAN rt1 (nCycle=nnn) --CREATE AUTOMATIC INDEX ON v1(x1, cnt) (nCycle=nnn) ---BLOOM FILTER ON v1 (x1=?) --SEARCH v1 USING AUTOMATIC COVERING INDEX (x1=?) (nCycle=nnn) } -#------------------------------------------------------------------------- -reset_db - -ifcapable trace { - do_execsql_test 5.0 { - CREATE TABLE t1(x, y); - CREATE TRIGGER tr1 AFTER DELETE ON t1 BEGIN - SELECT 1; - END; - INSERT INTO t1 VALUES(1, 2); - } - - proc trace {stmt sql} { - array set A [sqlite3_stmt_scanstatus -flags complex [format %x $stmt] 0] - lappend ::trace_explain $A(zExplain) - } - db trace_v2 trace - - set ::trace_explain [list] - do_execsql_test 5.1 { - DELETE FROM t1 WHERE x=1; - } - - do_test 5.2 { - set ::trace_explain - } {{SCAN t1} {SCAN t1} {SCAN t1}} -} - finish_test Index: test/seekscan1.test ================================================================== --- test/seekscan1.test +++ test/seekscan1.test @@ -22,11 +22,10 @@ INSERT INTO t1 VALUES('abc',234,6); INSERT INTO t1 VALUES('abc',345,7); ANALYZE; } - do_execsql_test 1.1 { SELECT a,b,c FROM t1 WHERE b IN (234, 345) AND c BETWEEN 6 AND 6.5 AND a='abc' ORDER BY a, b; } { @@ -58,11 +57,7 @@ } { abc 234 6 abc 345 7 } -do_execsql_test 1.5 { - SELECT a,b,c FROM t1 WHERE b IN (235, 345) AND c<=3 AND a='abc' ORDER BY a, b; -} - finish_test Index: test/selectC.test ================================================================== --- test/selectC.test +++ test/selectC.test @@ -228,15 +228,10 @@ do_execsql_test selectC-4.2 { select a from (select distinct a, b from t_distinct_bug) } {1 1 1} -do_execsql_test selectC-4.2b { - CREATE VIEW v42b AS SELECT DISTINCT a, b FROM t_distinct_bug; - SELECT a FROM v42b; -} {1 1 1} - do_execsql_test selectC-4.3 { select a, udf() from (select distinct a, b from t_distinct_bug) } {1 1 1 2 1 3} #------------------------------------------------------------------------- DELETED test/selectH.test Index: test/selectH.test ================================================================== --- test/selectH.test +++ /dev/null @@ -1,118 +0,0 @@ -# 2023-02-16 -# -# 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. -# -#*********************************************************************** -# -# Test cases for the omit-unused-subquery-column optimization. -# - -set testdir [file dirname $argv0] -source $testdir/tester.tcl -set testprefix selectH - -do_execsql_test 1.1 { - CREATE TABLE t1( - c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, - c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, - c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, - c30, c31, c32, c33, c34, c35, c36, c37, c38, c39, - c40, c41, c42, c43, c44, c45, c46, c47, c48, c49, - c50, c51, c52, c53, c54, c55, c56, c57, c58, c59, - c60, c61, c62, c63, c64, c65 - ); - INSERT INTO t1 VALUES( - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65 - ); - CREATE INDEX t1c60 ON t1(c60); -} - -# The SQL counter(N) function adjusts the value of the global -# TCL variable ::selectH_cnt by the value N and returns the new -# value. By putting calls to counter(N) as unused columns in a -# view or subquery, we can check to see if the counter gets incremented, -# and if not that means that the unused column was omitted. -# -unset -nocomplain selectH_cnt -set selectH_cnt 0 -proc selectH_counter {amt} { - global selectH_cnt - incr selectH_cnt $amt - return $selectH_cnt -} -db func counter selectH_counter - -do_execsql_test 1.2 { - SELECT DISTINCT c44 FROM ( - SELECT c0 AS a, *, counter(1) FROM t1 - UNION ALL - SELECT c1 AS a, *, counter(1) FROM t1 - ) WHERE c60=60; -} {44} -do_test 1.3 { - set ::selectH_cnt -} {0} - -do_execsql_test 2.1 { - SELECT a FROM ( - SELECT counter(1) AS cnt, c15 AS a, *, c62 AS b FROM t1 - UNION ALL - SELECT counter(1) AS cnt, c16 AS a, *, c61 AS b FROM t1 - ORDER BY b - ); -} {16 15} -do_test 2.2 { - set ::selectH_cnt -} {0} - -do_execsql_test 3.1 { - CREATE VIEW v1 AS - SELECT c16 AS a, *, counter(1) AS x FROM t1 - UNION ALL - SELECT c17 AS a, *, counter(1) AS x FROM t1 - UNION ALL - SELECT c18 AS a, *, counter(1) AS x FROM t1 - UNION ALL - SELECT c19 AS a, *, counter(1) AS x FROM t1; - SELECT count(*) FROM v1 WHERE c60=60; -} {4} -do_test 3.2 { - set ::selectH_cnt -} {0} -do_execsql_test 3.3 { - SELECT count(a) FROM v1 WHERE c60=60; -} {4} -do_execsql_test 3.4 { - SELECT a FROM v1 WHERE c60=60; -} {16 17 18 19} -do_test 3.5 { - set ::selectH_cnt -} {0} -do_execsql_test 3.6 { - SELECT x FROM v1 WHERE c60=60; -} {1 2 3 4} -do_test 3.7 { - set ::selectH_cnt -} {4} - -# 2023-02-25 dbsqlfuzz bf1d3ed6e0e0dd8766027797d43db40c776d2b15 -# -do_execsql_test 4.1 { - DROP TABLE IF EXISTS t1; - CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT); - SELECT 1 FROM (SELECT DISTINCT name COLLATE rtrim FROM sqlite_schema - UNION ALL SELECT a FROM t1); -} 1 - -finish_test Index: test/shell1.test ================================================================== --- test/shell1.test +++ test/shell1.test @@ -173,20 +173,10 @@ # -version show SQLite version do_test shell1-1.16.1 { set x [catchcmd "-version test.db" ""] } {/3.[0-9.]+ 20\d\d-[01]\d-\d\d \d\d:\d\d:\d\d [0-9a-f]+/} -# Handle no-more-options option -forcedelete ./--db -do_test shell1-1.17.1 { - catchcmd {-- --db "CREATE TABLE T(c1);"} -} {0 {}} -do_test shell1-1.17.2 { - catchcmd {-- --db "SELECT name from sqlite_schema;"} -} {0 T} -forcedelete ./--db - #---------------------------------------------------------------------------- # Test cases shell1-2.*: Basic "dot" command token parsing. # # check first token handling @@ -252,15 +242,10 @@ } {0 {}} do_test shell1-2.4.2 { catchcmd "test.db" ".mode \"csv\"" } {0 {}} -# check that certain quoted arg escapes work -do_test shell1-2.5.1 { - catchcmd ":memory:" ".print \"\\060\\077 \\x3f\\x30 \\a\\t\"" -} [list 0 "0? ?0 \a\t"] - #---------------------------------------------------------------------------- # Test cases shell1-3.*: Basic test that "dot" command can be called. # Index: test/shell2.test ================================================================== --- test/shell2.test +++ test/shell2.test @@ -214,53 +214,7 @@ SELECT max(seq) FROM sqlite_sequence;}]] } {0 {t... done done 2}} -# Verify that generate_series stays sane near 64-bit range boundaries. -# See overflow report at https://sqlite.org/forum/forumpost/5d34ce5280 -do_test shell2-1.4.10 { - set res [catchcmd :memory: [string trim { - SELECT * FROM generate_series(9223372036854775807,9223372036854775807,1); - SELECT * FROM generate_series(9223372036854775807,9223372036854775807,-1); - SELECT avg(rowid),min(value),max(value) FROM generate_series( - -9223372036854775808,9223372036854775807,1085102592571150095); - SELECT * FROM generate_series(-9223372036854775808,9223372036854775807, - 9223372036854775807); - SELECT value,rowid FROM generate_series(-4611686018427387904, - 4611686018427387904, 4611686018427387904) ORDER BY value DESC; - SELECT * FROM generate_series(0,-2,-1); - SELECT * FROM generate_series(0,-2); - SELECT * FROM generate_series(0,2) LIMIT 3;}]] -} {0 {9223372036854775807 -9223372036854775807 -9.5|-9223372036854775808|9223372036854775807 --9223372036854775808 --1 -9223372036854775806 -4611686018427387904|3 -0|2 --4611686018427387904|1 -0 --1 --2 -0 -1 -2}} - -# Bug discovered while messing around, .import hangs with -# bit 7 set in column separator. -do_test shell2-1.4.11 { - forcedelete dummy.csv - set df [open dummy.csv w] - puts $df dog,cat - close $df - set res [catchcmd :memory: [string trim { - CREATE TABLE t(line text); -.mode ascii -.separator "\377" "\n" -.import dummy.csv t - SELECT count(*) FROM t;}]] -} {0 1} - finish_test Index: test/skipscan1.test ================================================================== --- test/skipscan1.test +++ test/skipscan1.test @@ -417,16 +417,6 @@ AND b IN (1,3,2,4) AND b >= 0 AND a <= 10; } {3} -# 2023-03-24 https://sqlite.org/forum/forumpost/8cc1dc0fe9 -# -reset_db -do_execsql_test skipscan1-5.0 { - CREATE TABLE t1(a TEXT, UNIQUE(a,a,a)); - INSERT INTO t1 VALUES (hex(zeroblob(241))),(1),(2),(3); - ANALYZE; - SELECT max(a) FROM t1 WHERE a IN t1; -} {3} - finish_test Index: test/speedtest1.c ================================================================== --- test/speedtest1.c +++ test/speedtest1.c @@ -10,11 +10,10 @@ " --big-transactions Add BEGIN/END around all large tests\n" " --cachesize N Set PRAGMA cache_size=N. Note: N is pages, not bytes\n" " --checkpoint Run PRAGMA wal_checkpoint after each test case\n" " --exclusive Enable locking_mode=EXCLUSIVE\n" " --explain Like --sqlonly but with added EXPLAIN keywords\n" - " --fullfsync Enable fullfsync=TRUE\n" " --heap SZ MIN Memory allocator uses SZ bytes & min allocation MIN\n" " --incrvacuum Enable incremenatal vacuum mode\n" " --journal M Set the journal_mode to M\n" " --key KEY Set the encryption key to KEY\n" " --lookaside N SZ Configure lookaside for N slots of SZ bytes each\n" @@ -38,11 +37,10 @@ " --sqlonly No-op. Only show the SQL that would have been run.\n" " --shrink-memory Invoke sqlite3_db_release_memory() frequently.\n" " --size N Relative test size. Default=100\n" " --strict Use STRICT table where appropriate\n" " --stats Show statistics at the end\n" - " --stmtscanstatus Activate SQLITE_DBCONFIG_STMT_SCANSTATUS\n" " --temp N N from 0 to 9. 0: no temp table. 9: all temp tables\n" " --testset T Run test-set T (main, cte, rtree, orm, fp, debug)\n" " --trace Turn on SQL tracing\n" " --threads N Use up to N threads for sorting\n" " --utf16be Set text encoding to UTF-16BE\n" @@ -100,11 +98,10 @@ int eTemp; /* 0: no TEMP. 9: always TEMP. */ int szTest; /* Scale factor for test iterations */ int nRepeat; /* Repeat selects this many times */ int doCheckpoint; /* Run PRAGMA wal_checkpoint after each trans */ int nReserve; /* Reserve bytes */ - int stmtScanStatus; /* True to activate Stmt ScanStatus reporting */ int doBigTransactions; /* Enable transactions on tests 410 and 510 */ const char *zWR; /* Might be WITHOUT ROWID */ const char *zNN; /* Might be NOT NULL */ const char *zPK; /* Might be UNIQUE or PRIMARY KEY */ unsigned int x, y; /* Pseudo-random number generator state */ @@ -2202,11 +2199,10 @@ } int main(int argc, char **argv){ int doAutovac = 0; /* True for --autovacuum */ int cacheSize = 0; /* Desired cache size. 0 means default */ int doExclusive = 0; /* True for --exclusive */ - int doFullFSync = 0; /* True for --fullfsync */ int nHeap = 0, mnHeap = 0; /* Heap size from --heap */ int doIncrvac = 0; /* True for --incrvacuum */ const char *zJMode = 0; /* Journal mode */ const char *zKey = 0; /* Encryption key */ int nLook = -1, szLook = 0; /* --lookaside configuration */ @@ -2267,12 +2263,10 @@ }else if( strcmp(z,"cachesize")==0 ){ ARGC_VALUE_CHECK(1); cacheSize = integerValue(argv[++i]); }else if( strcmp(z,"exclusive")==0 ){ doExclusive = 1; - }else if( strcmp(z,"fullfsync")==0 ){ - doFullFSync = 1; }else if( strcmp(z,"checkpoint")==0 ){ g.doCheckpoint = 1; }else if( strcmp(z,"explain")==0 ){ g.bSqlOnly = 1; g.bExplain = 1; @@ -2395,12 +2389,10 @@ ARGC_VALUE_CHECK(1); zVfs = argv[++i]; }else if( strcmp(z,"reserve")==0 ){ ARGC_VALUE_CHECK(1); g.nReserve = atoi(argv[++i]); - }else if( strcmp(z,"stmtscanstatus")==0 ){ - g.stmtScanStatus = 1; }else if( strcmp(z,"without-rowid")==0 ){ if( strstr(g.zWR,"WITHOUT")!=0 ){ /* no-op */ }else if( strstr(g.zWR,"STRICT")!=0 ){ g.zWR = "WITHOUT ROWID,STRICT"; @@ -2480,13 +2472,10 @@ } #endif if( g.nReserve>0 ){ sqlite3_file_control(g.db, 0, SQLITE_FCNTL_RESERVE_BYTES, &g.nReserve); } - if( g.stmtScanStatus ){ - sqlite3_db_config(g.db, SQLITE_DBCONFIG_STMT_SCANSTATUS, 1, 0); - } /* Set database connection options */ sqlite3_create_function(g.db, "random", 0, SQLITE_UTF8, 0, randomFunc, 0, 0); #ifndef SQLITE_OMIT_DEPRECATED if( doTrace ) sqlite3_trace(g.db, traceCallback, 0); @@ -2513,15 +2502,11 @@ speedtest1_exec("PRAGMA page_size=%d", pageSize); } if( cacheSize ){ speedtest1_exec("PRAGMA cache_size=%d", cacheSize); } - if( noSync ){ - speedtest1_exec("PRAGMA synchronous=OFF"); - }else if( doFullFSync ){ - speedtest1_exec("PRAGMA fullfsync=ON"); - } + if( noSync ) speedtest1_exec("PRAGMA synchronous=OFF"); if( doExclusive ){ speedtest1_exec("PRAGMA locking_mode=EXCLUSIVE"); } if( zJMode ){ speedtest1_exec("PRAGMA journal_mode=%s", zJMode); Index: test/subtype1.test ================================================================== --- test/subtype1.test +++ test/subtype1.test @@ -51,27 +51,9 @@ } {0} do_execsql_test subtype1-231 { WITH t4(a) AS NOT MATERIALIZED (SELECT json(1)) SELECT subtype(a) FROM t4; } {0} -# 2023-03-01 -# https://sqlite.org/forum/forumpost/37dd14a538 -# -# Additional tests to show that subtypes do not traverse subquery boundaries. -# -do_execsql_test subtype1-300 { - CREATE TABLE t0(c0); - INSERT INTO t0 VALUES ('1'); - CREATE VIEW v0(c0) AS SELECT CASE WHEN 1 THEN json_patch('1', '1') END - FROM t0 GROUP BY t0.c0; - SELECT * FROM v0 WHERE json_quote(v0.c0) != '1'; -} {1} -do_execsql_test subtype1-310 { - SELECT *, json_quote(y) FROM (SELECT +json('1') AS y); -} {1 {"1"}} -do_execsql_test subtype1-320 { - SELECT *, json_quote(y) FROM (SELECT +json('1') AS y) - WHERE json_quote(y)='"1"'; -} {1 {"1"}} + finish_test Index: test/tabfunc01.test ================================================================== --- test/tabfunc01.test +++ test/tabfunc01.test @@ -59,11 +59,11 @@ do_execsql_test tabfunc01-1.8 { SELECT * FROM generate_series(0,32,5) ORDER BY rowid DESC; } {30 25 20 15 10 5 0} do_execsql_test tabfunc01-1.9 { SELECT rowid, * FROM generate_series(0,32,5) ORDER BY value DESC; -} {7 30 6 25 5 20 4 15 3 10 2 5 1 0} +} {1 30 2 25 3 20 4 15 5 10 6 5 7 0} do_execsql_test tabfunc01-1.10 { SELECT rowid, * FROM generate_series(0,32,5) ORDER BY +value DESC; } {7 30 6 25 5 20 4 15 3 10 2 5 1 0} do_execsql_test tabfunc01-1.20 { @@ -268,11 +268,10 @@ JOIN carray(inttoptr($PTR5),5,'char*') AS bb ON aa.rowid=bb.rowid; } } {5.0 x5 | 7.0 x7 | 13.0 x13 | 17.0 x17 | 23.0 x23 |} # ticket https://www.sqlite.org/src/info/2ae0c599b735d59e -# Verification of testtag-20230227a do_test tabfunc01-751 { db eval { SELECT aa.value, bb.value, '|' FROM carray(inttoptr($PTR4),5,'double') AS aa LEFT JOIN carray(inttoptr($PTR5),5,'char*') AS bb ON aa.rowid=bb.rowid; Index: test/tester.tcl ================================================================== --- test/tester.tcl +++ test/tester.tcl @@ -947,33 +947,10 @@ proc normalize_list {L} { set L2 [list] foreach l $L {lappend L2 $l} set L2 } - -# Run SQL and verify that the number of "vmsteps" required is greater -# than or less than some constant. -# -proc do_vmstep_test {tn sql nstep {res {}}} { - uplevel [list do_execsql_test $tn.0 $sql $res] - - set vmstep [db status vmstep] - if {[string range $nstep 0 0]=="+"} { - set body "if {$vmstep<$nstep} { - error \"got $vmstep, expected more than [string range $nstep 1 end]\" - }" - } else { - set body "if {$vmstep>$nstep} { - error \"got $vmstep, expected less than $nstep\" - }" - } - - # set name "$tn.vmstep=$vmstep,expect=$nstep" - set name "$tn.1" - uplevel [list do_test $name $body {}] -} - # Either: # # do_execsql_test TESTNAME SQL ?RES? # do_execsql_test -db DB TESTNAME SQL ?RES? Index: test/testrunner.tcl ================================================================== --- test/testrunner.tcl +++ test/testrunner.tcl @@ -22,11 +22,10 @@ $a0 status where SWITCHES are: --jobs NUMBER-OF-JOBS --fuzztest - --zipvfs ZIPVFS-SOURCE-DIR Interesting values for PERMUTATION are: veryquick - a fast subset of the tcl test scripts. This is the default. full - all tcl test scripts. @@ -69,36 +68,30 @@ # Command [guess_number_of_cores] attempts to glean the number of logical # cores. Command [default_njob] returns the default value for the --jobs # switch. # proc guess_number_of_cores {} { - if {[catch {number_of_cores} ret]} { - set ret 4 - - if {$::tcl_platform(os)=="Darwin"} { - set cmd "sysctl -n hw.logicalcpu" - } else { - set cmd "nproc" - } - catch { - set fd [open "|$cmd" r] - set ret [gets $fd] - close $fd - set ret [expr $ret] - } + set ret 4 + + if {$::tcl_platform(os)=="Darwin"} { + set cmd "sysctl -n hw.logicalcpu" + } else { + set cmd "nproc" + } + catch { + set fd [open "|$cmd" r] + set ret [gets $fd] + close $fd + set ret [expr $ret] } return $ret } proc default_njob {} { set nCore [guess_number_of_cores] - if {$nCore<=2} { - set nHelper 1 - } else { - set nHelper [expr int($nCore*0.5)] - } - return $nHelper + set nHelper [expr int($nCore*0.75)] + expr $nHelper>0 ? $nHelper : 1 } #------------------------------------------------------------------------- #------------------------------------------------------------------------- # Setup various default values in the global TRG() array. @@ -111,11 +104,10 @@ set TRG(nJob) [default_njob] ;# Default number of helper processes set TRG(patternlist) [list] set TRG(cmdline) $argv set TRG(reporttime) 2000 set TRG(fuzztest) 0 ;# is the fuzztest option present. -set TRG(zipvfs) "" ;# -zipvfs option, if any switch -nocase -glob -- $tcl_platform(os) { *darwin* { set TRG(platform) osx set TRG(make) make.sh @@ -350,14 +342,10 @@ incr ii set TRG(nJob) [lindex $argv $ii] if {$isLast} { usage } } elseif {($n>2 && [string match "$a*" --fuzztest]) || $a=="-f"} { set TRG(fuzztest) 1 - } elseif {($n>2 && [string match "$a*" --zipvfs]) || $a=="-z"} { - incr ii - set TRG(zipvfs) [lindex $argv $ii] - if {$isLast} { usage } } else { usage } } else { lappend TRG(patternlist) [string map {% *} $a] @@ -583,16 +571,10 @@ proc make_new_testset {} { global TRG set tests [testset_patternlist $TRG(patternlist)] - - if {$TRG(zipvfs)!=""} { - source [file join $TRG(zipvfs) test zipvfs_testrunner.tcl] - set tests [concat $tests [zipvfs_testrunner_testset]] - } - r_write_db { trdb eval $TRG(schema) set nJob $TRG(nJob) set cmdline $TRG(cmdline) @@ -716,21 +698,17 @@ set testdir [file dirname $TRG(info_script)] set srcdir [file dirname $testdir] set builddir [build_to_dirname $b] create_or_clear_dir $builddir - if {$b=="Zipvfs"} { - set script [zipvfs_testrunner_script] - } else { - set cmd [info nameofexec] - lappend cmd [file join $testdir releasetest_data.tcl] - lappend cmd trscript - if {$TRG(platform)=="win"} { lappend cmd -msvc } - lappend cmd $b $srcdir - set script [exec {*}$cmd] - } - + set cmd [info nameofexec] + lappend cmd [file join $testdir releasetest_data.tcl] + lappend cmd trscript + if {$TRG(platform)=="win"} { lappend cmd -msvc } + lappend cmd $b $srcdir + + set script [exec {*}$cmd] set fd [open [file join $builddir $TRG(make)] w] puts $fd $script close $fd puts "Launching build \"$b\" in directory $builddir..." @@ -882,12 +860,9 @@ sqlite3 trdb $TRG(dbname) trdb timeout $TRG(timeout) set tm [lindex [time { make_new_testset }] 0] -if {$TRG(nJob)>1} { - puts "splitting work across $TRG(nJob) cores" -} puts "built testset in [expr $tm/1000]ms.." run_testset trdb close #puts [pwd] Index: test/tkt-99378177930f87bd.test ================================================================== --- test/tkt-99378177930f87bd.test +++ test/tkt-99378177930f87bd.test @@ -174,23 +174,6 @@ ) AND a==2 ); } {1 2} -# 2023-03-04 https://sqlite.org/forum/forumpost/a68313d054 -# -# See also indexexpr1-2200 added on 2023-03-18. -# -do_execsql_test tkt-99378-400 { - DROP TABLE t1; - CREATE TABLE t0(w); - INSERT INTO t0(w) VALUES(1); - CREATE TABLE t1(x); - INSERT INTO t1(x) VALUES(1); - CREATE INDEX t1x ON t1(x > 0); - CREATE VIEW t2(y) AS SELECT avg(w) FROM t0 GROUP BY w>1; - CREATE VIEW t3(z) AS SELECT count(*) FROM t2 WHERE y BETWEEN 0 and 0; - SELECT count(*) FROM t1 NOT INDEXED WHERE (SELECT z FROM t3); - SELECT count(*) FROM t1 INDEXED BY t1x WHERE (SELECT z FROM t3); -} {0 0} - finish_test Index: test/update.test ================================================================== --- test/update.test +++ test/update.test @@ -730,39 +730,6 @@ } {1 {constraint failed}} do_execsql_test update-20.30 { PRAGMA integrity_check; } {ok} -# 2023-03-16 https://sqlite.org/forum/forumpost/0007d1fdb1 -# A subquery in the WHERE clause of an UPDATE and behind a -# short-circuit evaluation caused problems because multi-row -# single-pass was selected. -# -# Similar problem for DELETE tested by delete-12.0. -# https://sqlite.org/src/info/73f0036f045bf371 -# -reset_db -do_execsql_test update-21.1 { - CREATE TABLE t1 (vkey INTEGER, c5 INTEGER); - INSERT INTO t1 VALUES(3,NULL),(6,-54); -} -db null NULL -do_execsql_test update-21.2 { - BEGIN; - UPDATE t1 SET vkey = 100 WHERE c5 is null; - SELECT * FROM t1 ORDER BY vkey, c5; - ROLLBACK; -} {6 -54 100 NULL} -do_execsql_test update-21.3 { - BEGIN; - UPDATE t1 SET vkey = 100 WHERE NOT (-10*(select min(vkey) from t1) >= c5); - SELECT * FROM t1 ORDER BY vkey, c5; - ROLLBACK; -} {3 NULL 6 -54} -do_execsql_test update-21.4 { - BEGIN; - UPDATE t1 SET vkey = 100 WHERE c5 is null OR NOT (-10*(select min(vkey) from t1) >= c5); - SELECT * FROM t1 ORDER BY vkey, c5; - ROLLBACK; -} {6 -54 100 NULL} - finish_test Index: test/vt02.c ================================================================== --- test/vt02.c +++ test/vt02.c @@ -175,10 +175,12 @@ #include #include #include #endif +#ifndef SQLITE_OMIT_VIRTUALTABLE + /* Forward declarations */ typedef struct vt02_vtab vt02_vtab; typedef struct vt02_cur vt02_cur; /* @@ -377,11 +379,11 @@ pCur->i = 0; for(m=1000, i=0; i<=e; i++, m /= 10){ sqlite3_int64 v; pVal = 0; if( sqlite3_vtab_in_first(0, &pVal)!=SQLITE_MISUSE - || sqlite3_vtab_in_first(argv[iArg], &pVal)!=SQLITE_ERROR + || sqlite3_vtab_in_first(argv[iArg], &pVal)!=SQLITE_MISUSE ){ vt02ErrMsg(pCursor->pVtab, "unexpected success from sqlite3_vtab_in_first()"); return SQLITE_ERROR; } @@ -416,11 +418,11 @@ }else{ goto vt02_bad_idxnum; } if( bUseOffset ){ int nSkip = sqlite3_value_int(argv[iArg]); - while( nSkip-- > 0 && pCur->iiEof ) vt02Next(pCursor); + while( nSkip-- > 0 ) vt02Next(pCursor); } return SQLITE_OK; vt02_bad_idxnum: vt02ErrMsg(pCursor->pVtab, "invalid idxNum for vt02: %d", iOrigIdxNum); @@ -997,10 +999,14 @@ sqlite3_create_module(db, "vt02", &vt02Module, 0); sqlite3_create_module(db, "vt02pkx", &vt02Module, (void*)zPkXSchema); sqlite3_create_module(db, "vt02pkabcd", &vt02Module, (void*)zPkABCDSchema); } +#else +# define vt02CoreInit(db) +#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ + #ifdef TH3_VERSION static void vt02_init(th3state *p, int iDb, char *zArg){ vt02CoreInit(th3dbPointer(p, iDb)); } #else Index: test/whereL.test ================================================================== --- test/whereL.test +++ test/whereL.test @@ -187,26 +187,7 @@ ) AS B ON A.ID = B.ID AND A.RunYearMonth = B.RunYearMonth; } {4 202004 4 202004 5 202004 5 202004} -# 2023-02-10 https://sqlite.org/forum/forumpost/0a539c76db3b9e29 -# The original constant propagation implementation caused a performance -# regression. Because "abs(v)" was rewritten into "abs(1)" it no longer -# matches the indexed column and the index is not used. -# -reset_db -do_execsql_test 700 { - CREATE TABLE t1(v INTEGER); - WITH RECURSIVE c(x) AS (VALUES(-10) UNION ALL SELECT x+1 FROM c WHERE x<10) - INSERT INTO t1(v) SELECT x FROM c; - CREATE INDEX idx ON t1( abs(v) ); - SELECT v FROM t1 WHERE abs(v)=1 and v=1; -} 1 -do_eqp_test 710 { - SELECT v FROM t1 WHERE abs(v)=1 and v=1; -} { - QUERY PLAN - `--SEARCH t1 USING INDEX idx (=?) -} finish_test Index: test/window1.test ================================================================== --- test/window1.test +++ test/window1.test @@ -2208,159 +2208,6 @@ CREATE TABLE dual(dummy); INSERT INTO dual VALUES('X'); CREATE VIEW v1(x,y) AS SELECT RANK() OVER (PARTITION BY 0), SUM(0) FROM dual; SELECT * FROM v1 WHERE true; } {1 0} -#------------------------------------------------------------------------- -reset_db - -do_execsql_test 72.0 { - CREATE TABLE t0(c0); - INSERT INTO t0(c0) VALUES (0); - CREATE VIEW v0(c0) AS SELECT TOTAL(0) OVER (PARTITION BY t0.c0) FROM t0; -} -do_execsql_test 72.1 { - SELECT COUNT(*) FROM ( - SELECT TOTAL(0) OVER (PARTITION BY t0.c0) FROM t0 - ) - WHERE ('1' IS NOT ('abcde' NOTNULL)); -} {1} - -# 2023-03-28 https://sqlite.org/forum/forumpost/dc3b92cfa0 (Song Liu) -# -reset_db -do_execsql_test 73.0 { - CREATE TABLE t1(a INT); - INSERT INTO t1(a) VALUES(1),(2),(4); - CREATE VIEW t2(b,c) AS SELECT * FROM t1 JOIN t1 A ORDER BY sum(0) OVER(PARTITION BY 0); - CREATE TRIGGER x1 INSTEAD OF UPDATE ON t2 BEGIN SELECT true; END; -} -do_execsql_test 73.1 { - SELECT * FROM t2; -} {1 1 1 2 1 4 2 1 2 2 2 4 4 1 4 2 4 4} -do_execsql_test 73.2 { - UPDATE t2 SET c=99 WHERE b=4 RETURNING *; -} {4 99 4 99 4 99} -do_execsql_test 73.3 { - SELECT *, nth_value(15,2) OVER() FROM t2, t1 WHERE b=4; -} { - 4 1 1 15 - 4 2 1 15 - 4 4 1 15 - 4 1 2 15 - 4 2 2 15 - 4 4 2 15 - 4 1 4 15 - 4 2 4 15 - 4 4 4 15 -} -do_execsql_test 73.4 { - UPDATE t2 SET c=nth_value(15,2) OVER() FROM (SELECT * FROM t1) WHERE b=4 RETURNING *; -} { - 4 15 - 4 15 - 4 15 - 4 15 - 4 15 - 4 15 - 4 15 - 4 15 - 4 15 -} -do_execsql_test 73.5 { - DROP TRIGGER x1; -} -do_catchsql_test 73.6 { - UPDATE t2 SET c=99 WHERE b=4 RETURNING *; -} {1 {cannot modify t2 because it is a view}} -do_catchsql_test 73.7 { - UPDATE t2 SET c=nth_value(15,2) OVER() FROM (SELECT * FROM t1) WHERE b=4 RETURNING *; -} {1 {cannot modify t2 because it is a view}} - -# 2023-03-28 https://sqlite.org/forum/forumpost/bad532820c -# -reset_db -do_execsql_test 74.0 { - CREATE TABLE t1 (a INT, b INT); - CREATE TABLE t2 (c INT, d INT); - CREATE INDEX idx ON t1(abs(a)); - INSERT INTO t1 VALUES(1,2),(3,4); - INSERT INTO t2 VALUES(5,6),(7,8); -} -do_execsql_test 74.1 { - SELECT ( - SELECT count( a ) FROM t2 LIMIT 1 - ) - FROM t1; -} {2} ;# Verified using PG 14.2 -do_execsql_test 74.2 { - SELECT ( - SELECT count( a+c ) FROM t2 LIMIT 1 - ) - FROM t1; -} {2 2} ;# verified on PG 14.2. Crashes PG 9.6! -do_execsql_test 74.3 { - SELECT ( - SELECT count( ( SELECT(sum(0) OVER(ORDER BY c, abs(a))) ) ) - FROM t2 GROUP BY c LIMIT 1 - ) - FROM t1; -} {1 1} ;# verified on PG 14.2 -do_execsql_test 74.4 { - /* Original test case reported in https://sqlite.org/forum/forumpost/bad532820c - CREATE TABLE v0 (c1); - CREATE INDEX i ON v0 (c1, c1=1); - SELECT 0 FROM v0 AS a1 - WHERE (SELECT count((SELECT(sum(0) OVER(PARTITION BY(c1), (a1.c1=1) )))) - FROM v0 - GROUP BY hex(0)) - AND a1.c1=0; -} {} - -# 2023-04-11 https://sqlite.org/forum/forumpost/6c5678e3da -# An ALWAYS() turns out to be sometimes false. -# -do_execsql_test 75.0 { - DROP TABLE t1; - CREATE TABLE t1(a INT, b INT); - CREATE INDEX t1x ON t1(a+b); -} -do_catchsql_test 75.1 { - SELECT count((SELECT count(a0.a+a0.b) ORDER BY sum(0) OVER (PARTITION BY 0))) - FROM t1 AS a0 JOIN t1 AS a1 - GROUP BY a1.a; -} {1 {misuse of aggregate: count()}} - -# 2023-04-13 https://sqlite.org/forum/forumpost/0d48347967 -reset_db -do_execsql_test 76.0 { - CREATE TABLE t1(a INT, b INT); - INSERT INTO t1(a,b) VALUES (111,222),(111,223),(118,229); - CREATE INDEX t1a ON t1(a); - CREATE TABLE t2(x INT); - INSERT INTO t2 VALUES (333),(444),(555); -} -do_execsql_test 76.1 { - SELECT c, (SELECT c + sum(1) OVER ()) AS "res" - FROM t2 LEFT JOIN (SELECT +a AS c FROM t1) AS v1 ON true - GROUP BY c - ORDER by c; -} {111 112 118 119} -# ^^^^^^^^^^^^^^^^^-- results verified against PG 14.2 - -do_execsql_test 76.2 { - CREATE TABLE t3(x); - CREATE TABLE t4(y); - INSERT INTO t3 VALUES(100), (200), (400); - INSERT INTO t4 VALUES(100), (300), (400); -} -do_execsql_test 76.3 { - SELECT (SELECT y+sum(0) OVER ()) FROM t3 LEFT JOIN t4 ON x=y; -} {100 {} 400} -do_execsql_test 76.4 { - SELECT (SELECT y+sum(0) OVER ()) FROM t3 LEFT JOIN t4 ON x=y GROUP BY x; -} {100 {} 400} -do_execsql_test 76.5 { - SELECT (SELECT max(y)+sum(0) OVER ()) FROM t3 LEFT JOIN t4 ON x=y GROUP BY x; -} {100 {} 400} - finish_test Index: test/with1.test ================================================================== --- test/with1.test +++ test/with1.test @@ -1122,11 +1122,11 @@ do_execsql_test 24.1 { CREATE TABLE t1(a, b, c); CREATE VIEW v1 AS SELECT max(a), min(b) FROM t1 GROUP BY c; } do_test 24.1 { - set program [db eval {EXPLAIN SELECT * FROM v1 AS aa, v1 AS bb, v1 AS cc}] + set program [db eval {EXPLAIN SELECT 1 FROM v1,v1,v1}] expr [lsearch $program OpenDup]>0 } {1} do_execsql_test 24.2 { ATTACH "" AS aux; CREATE VIEW aux.v3 AS VALUES(1); Index: test/with3.test ================================================================== --- test/with3.test +++ test/with3.test @@ -107,11 +107,10 @@ | |--SETUP | | `--SCAN CONSTANT ROW | `--RECURSIVE STEP | `--SCAN cnt |--SCAN y1 - |--BLOOM FILTER ON cnt (i=?) `--SEARCH cnt USING AUTOMATIC COVERING INDEX (i=?) }] } do_execsql_test 3.2.1 { Index: test/with6.test ================================================================== --- test/with6.test +++ test/with6.test @@ -361,17 +361,13 @@ | | `--USE TEMP B-TREE FOR ORDER BY | |--SCAN src | |--SEARCH raw USING INDEX sqlite_autoindex_raw_1 (country=? AND date>? AND date12 ){ @@ -607,11 +607,11 @@ } } printf("%s};\n", j==0 ? "" : "\n"); printf("/* aKWLen[i] is the length (in bytes) of the i-th keyword */\n"); - printf("static const unsigned char aKWLen[%d] = {0,\n", nKeyword+1); + printf("static const unsigned char aKWLen[%d] = {\n", nKeyword); for(i=j=0; i12 ){ @@ -621,11 +621,11 @@ } printf("%s};\n", j==0 ? "" : "\n"); printf("/* aKWOffset[i] is the index into zKWText[] of the start of\n"); printf("** the text for the i-th keyword. */\n"); - printf("static const unsigned short int aKWOffset[%d] = {0,\n", nKeyword+1); + printf("static const unsigned short int aKWOffset[%d] = {\n", nKeyword); for(i=j=0; i12 ){ @@ -634,11 +634,11 @@ } } printf("%s};\n", j==0 ? "" : "\n"); printf("/* aKWCode[i] is the parser symbol code for the i-th keyword */\n"); - printf("static const unsigned char aKWCode[%d] = {0,\n", nKeyword+1); + printf("static const unsigned char aKWCode[%d] = {\n", nKeyword); for(i=j=0; i=2 ){\n"); printf(" i = ((charMap(z[0])*%d) %c", HASH_C0, HASH_CC); printf(" (charMap(z[n-1])*%d) %c", HASH_C1, HASH_CC); printf(" n*%d) %% %d;\n", HASH_C2, bestSize); - printf(" for(i=(int)aKWHash[i]; i>0; i=aKWNext[i]){\n"); + printf(" for(i=((int)aKWHash[i])-1; i>=0; i=((int)aKWNext[i])-1){\n"); printf(" if( aKWLen[i]!=n ) continue;\n"); printf(" zKW = &zKWText[aKWOffset[i]];\n"); printf("#ifdef SQLITE_ASCII\n"); printf(" if( (z[0]&~0x20)!=zKW[0] ) continue;\n"); printf(" if( (z[1]&~0x20)!=zKW[1] ) continue;\n"); @@ -685,11 +685,11 @@ printf(" while( j=SQLITE_N_KEYWORD ) return SQLITE_ERROR;\n"); - printf(" i++;\n"); printf(" *pzName = zKWText + aKWOffset[i];\n"); printf(" *pnName = aKWLen[i];\n"); printf(" return SQLITE_OK;\n"); printf("}\n"); printf("int sqlite3_keyword_count(void){ return SQLITE_N_KEYWORD; }\n"); Index: tool/showwal.c ================================================================== --- tool/showwal.c +++ tool/showwal.c @@ -231,25 +231,20 @@ aData = getContent(iStart, 24); extendCksum(pCksum, aData, 8, 0); extendCksum(pCksum, getContent(iStart+24, pagesize), pagesize, 0); s0 = getInt32(aData+16); s1 = getInt32(aData+20); - fprintf(stdout, "Frame %4d: %6d %6d 0x%08x,%08x 0x%08x,%08x", + fprintf(stdout, "Frame %4d: %6d %6d 0x%08x,%08x 0x%08x,%08x %s\n", iFrame, getInt32(aData), getInt32(aData+4), getInt32(aData+8), getInt32(aData+12), s0, - s1 + s1, + (s0==pCksum->s0 && s1==pCksum->s1) ? "" : "cksum-fail" ); - if( s0==pCksum->s0 && s1==pCksum->s1 ){ - fprintf(stdout, "\n"); - }else{ - fprintf(stdout, " should be 0x%08x,%08x\n", - pCksum->s0, pCksum->s1); - } /* Reset the checksum so that a single frame checksum failure will not ** cause all subsequent frames to also show a failure. */ pCksum->s0 = s0; pCksum->s1 = s1; Index: tool/speed-check.sh ================================================================== --- tool/speed-check.sh +++ tool/speed-check.sh @@ -156,13 +156,10 @@ SPEEDTEST_OPTS="$SPEEDTEST_OPTS --testset cte" ;; --fp) SPEEDTEST_OPTS="$SPEEDTEST_OPTS --testset fp" ;; - --stmtscanstatus) - SPEEDTEST_OPTS="$SPEEDTEST_OPTS --stmtscanstatus" - ;; -*) CC_OPTS="$CC_OPTS $1" ;; *) BASELINE=$1