From 90401f041e4d351e3e9cae0ddcb1cfffcd71ae7e Mon Sep 17 00:00:00 2001 From: Stephen Lombardo Date: Fri, 7 Jan 2022 12:16:23 -0500 Subject: [PATCH] Snapshot of upstream SQLite 3.37.2 --- Makefile.in | 13 +- Makefile.msc | 42 +- VERSION | 2 +- autoconf/tea/win/nmakehlp.c | 44 +- configure | 58 +- configure.ac | 11 + ext/expert/expert1.test | 4 +- ext/expert/sqlite3expert.c | 99 +- ext/fts3/fts3.c | 16 +- ext/fts3/fts3Int.h | 22 +- ext/fts3/fts3_aux.c | 6 +- ext/fts3/fts3_expr.c | 10 +- ext/fts3/fts3_snippet.c | 23 +- ext/fts3/fts3_write.c | 28 +- ext/fts5/fts5Int.h | 21 +- ext/fts5/fts5_buffer.c | 7 +- ext/fts5/fts5_config.c | 7 +- ext/fts5/fts5_expr.c | 27 +- ext/fts5/fts5_hash.c | 2 +- ext/fts5/fts5_index.c | 151 ++- ext/fts5/fts5_main.c | 3 +- ext/fts5/fts5_storage.c | 11 +- ext/fts5/fts5_vocab.c | 12 +- ext/fts5/test/fts5af.test | 8 +- ext/fts5/test/fts5corrupt3.test | 231 ++++ ext/fts5/test/fts5corrupt5.test | 798 ++++++++++++++ ext/fts5/test/fts5corrupt6.test | 54 + ext/fts5/test/fts5detail.test | 4 + ext/fts5/test/fts5misc.test | 29 + ext/fts5/test/fts5vocab2.test | 49 + ext/fts5/tool/mkfts5c.tcl | 3 +- ext/misc/carray.c | 32 +- ext/misc/carray.h | 29 +- ext/misc/fileio.c | 29 + ext/misc/ieee754.c | 6 +- ext/misc/json1.c | 111 +- ext/misc/regexp.c | 4 +- ext/misc/series.c | 20 +- ext/misc/zipfile.c | 8 +- ext/rbu/rbu10.test | 2 +- ext/rbu/rbuexlock.test | 207 ++++ ext/rbu/rbuvacuum2.test | 6 +- ext/rbu/sqlite3rbu.c | 106 +- ext/repair/checkfreelist.c | 15 +- ext/rtree/geopoly.c | 9 +- ext/rtree/rtree.c | 148 ++- ext/rtree/rtree1.test | 5 +- ext/rtree/rtree9.test | 2 +- ext/rtree/rtreeA.test | 12 +- ext/rtree/rtreedoc.test | 1583 +++++++++++++++++++++++++++ ext/rtree/rtreedoc2.test | 346 ++++++ ext/rtree/rtreedoc3.test | 292 +++++ ext/rtree/test_rtreedoc.c | 348 ++++++ ext/session/session1.test | 20 + ext/session/session6.test | 1 + ext/session/sessionat.test | 7 +- ext/session/sqlite3session.c | 58 +- main.mk | 7 +- manifest | 513 ++++----- manifest.uuid | 2 +- src/alter.c | 206 ++-- src/analyze.c | 59 +- src/attach.c | 7 +- src/auth.c | 4 +- src/bitvec.c | 2 +- src/btree.c | 550 ++++++---- src/btree.h | 10 +- src/btreeInt.h | 1 - src/build.c | 498 ++++++--- src/callback.c | 2 + src/ctime.c | 356 +++--- src/date.c | 191 ++-- src/dbstat.c | 71 +- src/delete.c | 13 +- src/expr.c | 595 ++++++---- src/fkey.c | 69 +- src/func.c | 194 +++- src/global.c | 54 + src/hash.h | 2 +- src/insert.c | 201 ++-- src/loadext.c | 5 + src/main.c | 157 ++- src/malloc.c | 12 +- src/mem2.c | 6 +- src/memdb.c | 26 +- src/memjournal.c | 2 +- src/os.c | 4 + src/os_unix.c | 51 +- src/pager.c | 25 +- src/parse.y | 63 +- src/pcache.c | 5 +- src/pcache1.c | 12 +- src/pragma.c | 170 ++- src/pragma.h | 132 ++- src/prepare.c | 15 +- src/printf.c | 30 +- src/resolve.c | 96 +- src/select.c | 287 +++-- src/shell.c.in | 802 ++++++++++---- src/sqlite.h.in | 161 ++- src/sqlite3ext.h | 12 + src/sqliteInt.h | 498 +++++---- src/tclsqlite.c | 142 ++- src/test1.c | 124 ++- src/test_config.c | 2 +- src/test_multiplex.c | 87 +- src/test_tclsh.c | 2 + src/tokenize.c | 6 +- src/treeview.c | 47 +- src/trigger.c | 26 +- src/update.c | 29 +- src/upsert.c | 2 +- src/util.c | 71 +- src/vacuum.c | 8 +- src/vdbe.c | 213 +++- src/vdbeInt.h | 11 +- src/vdbeapi.c | 25 +- src/vdbeaux.c | 40 +- src/vdbeblob.c | 14 +- src/vdbemem.c | 45 +- src/vdbesort.c | 3 +- src/vdbetrace.c | 4 +- src/vtab.c | 131 ++- src/wal.c | 164 ++- src/walker.c | 2 +- src/where.c | 110 +- src/whereInt.h | 2 +- src/wherecode.c | 69 +- src/whereexpr.c | 65 +- src/window.c | 50 +- test/aggnested.test | 42 + test/alter.test | 20 + test/alter3.test | 49 +- test/altercorrupt.test | 6 + test/{altermalloc3.test => alterfault.test} | 26 +- test/altermalloc3.test | 31 + test/alterqf.test | 7 + test/altertab.test | 13 + test/altertab3.test | 38 + test/analyze4.test | 6 + test/atof1.test | 5 + test/auth3.test | 24 +- test/autoindex5.test | 6 +- test/autovacuum.test | 3 +- test/autovacuum2.test | 87 ++ test/bestindex1.test | 3 + test/capi2.test | 12 +- test/carray01.test | 32 + test/changes.test | 90 ++ test/columncount.test | 6 + test/corruptL.test | 9 +- test/corruptN.test | 50 +- test/count.test | 11 + test/delete.test | 2 +- test/e_blobbytes.test | 5 + test/e_blobclose.test | 5 + test/e_blobopen.test | 5 + test/e_blobwrite.test | 5 + test/e_changes.test | 14 +- test/e_createtable.test | 15 +- test/e_expr.test | 10 +- test/e_fkey.test | 12 +- test/e_totalchanges.test | 45 +- test/e_uri.test | 1 + test/fkey1.test | 49 + test/fts3corrupt4.test | 421 +++++++ test/fts3f.test | 57 + test/fts3offsets.test | 12 + test/func.test | 3 + test/func3.test | 8 + test/fuzzcheck.c | 234 +++- test/fuzzdata8.db | Bin 2398208 -> 3019776 bytes test/gencol1.test | 29 + test/hook.test | 129 +-- test/in4.test | 47 + test/incrblob3.test | 5 + test/incrblobfault.test | 5 + test/indexexpr1.test | 52 +- test/io.test | 2 + test/ioerr.test | 1 + test/istrue.test | 30 +- test/json104.test | 3 + test/memdb1.test | 54 + test/memjournal2.test | 62 ++ test/minmax.test | 12 +- test/misc1.test | 9 +- test/mmap1.test | 2 +- test/multiplex.test | 17 + test/notnull2.test | 20 + test/pager1.test | 34 +- test/permutations.test | 13 +- test/pragma.test | 70 +- test/quote.test | 78 +- test/releasetest.tcl | 1100 ------------------- test/releasetest_data.tcl | 181 +-- test/returning1.test | 15 + test/returningfault.test | 36 + test/rowid.test | 30 + test/rowvalueA.test | 77 ++ test/rowvaluefault.test | 18 + test/schema3.test | 6 + test/shell1.test | 24 +- test/shell2.test | 12 +- test/shell3.test | 41 +- test/shell5.test | 15 + test/shell8.test | 25 +- test/shrink.test | 2 +- test/skipscan2.test | 1 - test/sorterref.test | 6 + test/speedtest1.c | 19 +- test/sqldiff1.test | 9 + test/sqllimits1.test | 37 +- test/stat.test | 12 +- test/statfault.test | 10 + test/strict1.test | 138 +++ test/strict2.test | 158 +++ test/tabfunc01.test | 10 +- test/tclsqlite.test | 38 +- test/tester.tcl | 66 +- test/threadtest3.c | 97 +- test/tkt-2d1a5c67d.test | 2 +- test/tkt-8454a207b9.test | 6 + test/tkt-f67b41381a.test | 5 + test/transitive1.test | 46 + test/tt3_checkpoint.c | 4 +- test/tt3_vacuum.c | 2 +- test/update.test | 22 +- test/upfrom2.test | 16 + test/upsert1.test | 14 + test/vacuum-into.test | 33 + test/vacuum3.test | 12 +- test/view.test | 5 + test/vtab1.test | 32 + test/vtabA.test | 2 +- test/vtabK.test | 83 ++ test/where.test | 23 + test/whereE.test | 6 + test/window1.test | 42 +- test/windowB.test | 8 + test/windowC.test | 85 ++ test/windowfault.test | 39 + test/with2.test | 122 ++- test/without_rowid1.test | 42 +- test/without_rowid5.test | 85 ++ test/zeroblob.test | 50 +- test/zeroblobfault.test | 28 + tool/lemon.c | 61 +- tool/lempar.c | 15 +- tool/logest.c | 3 + tool/mkctimec.tcl | 4 +- tool/mkkeywordhash.c | 3 +- tool/mkopcodec.tcl | 3 +- tool/mkpragmatab.tcl | 10 +- tool/mkshellc.tcl | 6 +- tool/mksqlite3c.tcl | 82 +- tool/replace.tcl | 2 +- tool/showdb.c | 6 +- tool/showwal.c | 19 +- tool/spaceanal.tcl | 4 +- tool/speed-check.sh | 3 + tool/sqldiff.c | 104 +- tool/sqlite3_analyzer.c.in | 2 +- 262 files changed, 13713 insertions(+), 4637 deletions(-) create mode 100644 ext/fts5/test/fts5corrupt5.test create mode 100644 ext/fts5/test/fts5corrupt6.test create mode 100644 ext/rbu/rbuexlock.test create mode 100644 ext/rtree/rtreedoc.test create mode 100644 ext/rtree/rtreedoc2.test create mode 100644 ext/rtree/rtreedoc3.test create mode 100644 ext/rtree/test_rtreedoc.c copy test/{altermalloc3.test => alterfault.test} (53%) create mode 100644 test/autovacuum2.test create mode 100644 test/changes.test create mode 100644 test/fts3f.test create mode 100644 test/memjournal2.test delete mode 100755 test/releasetest.tcl create mode 100644 test/returningfault.test create mode 100644 test/rowvalueA.test create mode 100644 test/strict1.test create mode 100644 test/strict2.test create mode 100644 test/vtabK.test create mode 100644 test/windowC.test create mode 100644 test/zeroblobfault.test diff --git a/Makefile.in b/Makefile.in index 2795ffa9..b3ea4628 100644 --- a/Makefile.in +++ b/Makefile.in @@ -165,6 +165,7 @@ LTINSTALL = $(LIBTOOL) --mode=install $(INSTALL) ############################################################################### USE_AMALGAMATION = @USE_AMALGAMATION@ +AMALGAMATION_LINE_MACROS = @AMALGAMATION_LINE_MACROS@ # Object files for the SQLite library (non-amalgamation). # @@ -467,7 +468,8 @@ TESTSRC += \ $(TOP)/ext/misc/unionvtab.c \ $(TOP)/ext/misc/wholenumber.c \ $(TOP)/ext/misc/zipfile.c \ - $(TOP)/ext/userauth/userauth.c + $(TOP)/ext/userauth/userauth.c \ + $(TOP)/ext/rtree/test_rtreedoc.c # Source code to the library files needed by the test fixture # @@ -622,7 +624,7 @@ 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_FTS5 FUZZCHECK_OPT += -DSQLITE_ENABLE_RTREE FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB @@ -756,7 +758,7 @@ mptest: mptester$(TEXE) touch .target_source sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl - $(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl + $(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl $(AMALGAMATION_LINE_MACROS) cp tsrc/sqlite3ext.h . cp $(TOP)/ext/session/sqlite3session.h . @@ -1249,7 +1251,10 @@ coretestprogs: $(TESTPROGS) testprogs: coretestprogs srcck1$(BEXE) fuzzcheck$(TEXE) sessionfuzz$(TEXE) # A very detailed test running most or all test cases -fulltest: $(TESTPROGS) fuzztest +fulltest: alltest fuzztest + +# Run most or all tcl test cases +alltest: $(TESTPROGS) ./testfixture$(TEXE) $(TOP)/test/all.test $(TESTOPTS) # Really really long testing diff --git a/Makefile.msc b/Makefile.msc index 4f20c0c0..3cbf560d 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -235,8 +235,9 @@ DEBUG = 0 !ENDIF # <> -# Disable use of the --linemacros argument to the mksqlite3c.tcl tool, which -# is used to build the amalgamation. +# By default, use --linemacros=1 argument to the mksqlite3c.tcl tool, which +# is used to build the amalgamation. This can be turned off to ease debug +# of the amalgamation away from the source tree. # !IFNDEF NO_LINEMACROS NO_LINEMACROS = 0 @@ -788,9 +789,9 @@ MKSQLITE3C_TOOL = $(TOP)\tool\mksqlite3c.tcl !IFNDEF MKSQLITE3C_ARGS !IF $(DEBUG)>1 && $(NO_LINEMACROS)==0 -MKSQLITE3C_ARGS = --linemacros +MKSQLITE3C_ARGS = --linemacros=1 !ELSE -MKSQLITE3C_ARGS = +MKSQLITE3C_ARGS = --linemacros=0 !ENDIF !IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0 MKSQLITE3C_ARGS = $(MKSQLITE3C_ARGS) --useapicall @@ -1585,6 +1586,7 @@ TESTEXT = \ $(TOP)\ext\misc\totype.c \ $(TOP)\ext\misc\unionvtab.c \ $(TOP)\ext\misc\wholenumber.c \ + $(TOP)\ext\rtree\test_rtreedoc.c \ fts5.c # If use of zlib is enabled, add the "zipfile.c" source file. @@ -1697,6 +1699,7 @@ MPTESTER_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 FUZZERSHELL_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 FUZZCHECK_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ -DSQLITE_MAX_MEMORY=50000000 -DSQLITE_PRINTF_PRECISION_LIMIT=1000 FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_FTS4 +FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_FTS5 FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_RTREE FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_GEOPOLY FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_DBSTAT_VTAB @@ -2208,11 +2211,11 @@ SHELL_SRC = \ $(TOP)\src\shell.c.in \ $(TOP)\ext\misc\appendvfs.c \ $(TOP)\ext\misc\completion.c \ - $(TOP)\ext\misc\decimal.c \ + $(TOP)\ext\misc\decimal.c \ $(TOP)\ext\misc\fileio.c \ - $(TOP)\ext\misc\ieee754.c \ - $(TOP)\ext\misc\regexp.c \ - $(TOP)\ext\misc\series.c \ + $(TOP)\ext\misc\ieee754.c \ + $(TOP)\ext\misc\regexp.c \ + $(TOP)\ext\misc\series.c \ $(TOP)\ext\misc\shathree.c \ $(TOP)\ext\misc\uint.c \ $(TOP)\ext\expert\sqlite3expert.c \ @@ -2435,7 +2438,9 @@ coretestprogs: $(TESTPROGS) testprogs: coretestprogs srcck1.exe fuzzcheck.exe sessionfuzz.exe -fulltest: $(TESTPROGS) fuzztest +fulltest: alltest fuzztest + +alltest: $(TESTPROGS) @set PATH=$(LIBTCLPATH);$(PATH) .\testfixture.exe $(TOP)\test\all.test $(TESTOPTS) @@ -2463,7 +2468,11 @@ quicktest: testfixture.exe sourcetest # This is the common case. Run many tests that do not take too long, # including fuzzcheck, sqlite3_analyzer, and sqldiff tests. # -test: $(TESTPROGS) sourcetest fuzztest +test: $(TESTPROGS) sourcetest fuzztest tcltest + +# The veryquick.test TCL tests. +# +tcltest: testfixture.exe @set PATH=$(LIBTCLPATH);$(PATH) .\testfixture.exe $(TOP)\test\veryquick.test $(TESTOPTS) @@ -2585,6 +2594,17 @@ rbu.exe: $(TOP)\ext\rbu\rbu.c $(TOP)\ext\rbu\sqlite3rbu.c $(SQLITE3C) $(SQLITE3H $(LTLINK) $(NO_WARN) -DSQLITE_ENABLE_RBU \ $(TOP)\ext\rbu\rbu.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) +THREADTEST3_SRC = \ + $(TOP)\test\threadtest3.c \ + $(TOP)\test\tt3_checkpoint.c \ + $(TOP)\test\tt3_index.c \ + $(TOP)\test\tt3_vacuum.c \ + $(TOP)\test\tt3_stress.c \ + $(TOP)\test\tt3_lookaside1.c + +threadtest3.exe: $(THREADTEST3_SRC) $(TOP)\src\test_multiplex.c $(SQLITE3C) $(SQLITE3H) + $(LTLINK) $(NO_WARN) $(TOP)\test\threadtest3.c $(TOP)\src\test_multiplex.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) + LSMDIR=$(TOP)\ext\lsm1 !INCLUDE $(LSMDIR)\Makefile.msc @@ -2622,7 +2642,7 @@ clean: del /Q sqlite-*-output.vsix 2>NUL del /Q fuzzershell.exe fuzzcheck.exe sqldiff.exe dbhash.exe 2>NUL del /Q sqltclsh.* 2>NUL - del /Q dbfuzz.exe sessionfuzz.exe 2>NUL + del /Q dbfuzz.exe sessionfuzz.exe threadtest3.exe 2>NUL del /Q kvtest.exe ossshell.exe scrub.exe 2>NUL del /Q showshm.exe sqlite3_checker.* sqlite3_expert.exe 2>NUL del /Q fts5.* fts5parse.* 2>NUL diff --git a/VERSION b/VERSION index 0b477b45..8587f052 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.36.0 +3.37.2 diff --git a/autoconf/tea/win/nmakehlp.c b/autoconf/tea/win/nmakehlp.c index 7536edee..2dc33cc6 100644 --- a/autoconf/tea/win/nmakehlp.c +++ b/autoconf/tea/win/nmakehlp.c @@ -14,8 +14,10 @@ #define _CRT_SECURE_NO_DEPRECATE #include +#ifdef _MSC_VER #pragma comment (lib, "user32.lib") #pragma comment (lib, "kernel32.lib") +#endif #include #include @@ -37,7 +39,7 @@ /* protos */ static int CheckForCompilerFeature(const char *option); -static int CheckForLinkerFeature(const char **options, int count); +static int CheckForLinkerFeature(char **options, int count); static int IsIn(const char *string, const char *substring); static int SubstituteFile(const char *substs, const char *filename); static int QualifyPath(const char *path); @@ -54,8 +56,8 @@ typedef struct { char buffer[STATICBUFFERSIZE]; } pipeinfo; -pipeinfo Out = {INVALID_HANDLE_VALUE, '\0'}; -pipeinfo Err = {INVALID_HANDLE_VALUE, '\0'}; +pipeinfo Out = {INVALID_HANDLE_VALUE, ""}; +pipeinfo Err = {INVALID_HANDLE_VALUE, ""}; /* * exitcodes: 0 == no, 1 == yes, 2 == error @@ -273,7 +275,7 @@ CheckForCompilerFeature( "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| - FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars], + FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPSTR)&msg[chars], (300-chars), 0); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL); return 2; @@ -326,7 +328,7 @@ CheckForCompilerFeature( static int CheckForLinkerFeature( - const char **options, + char **options, int count) { STARTUPINFO si; @@ -407,7 +409,7 @@ CheckForLinkerFeature( "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| - FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars], + FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPSTR)&msg[chars], (300-chars), 0); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL); return 2; @@ -503,7 +505,6 @@ GetVersionFromFile( const char *match, int numdots) { - size_t cbBuffer = 100; static char szBuffer[100]; char *szResult = NULL; FILE *fp = fopen(filename, "rt"); @@ -513,7 +514,7 @@ GetVersionFromFile( * Read data until we see our match string. */ - while (fgets(szBuffer, cbBuffer, fp) != NULL) { + while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) { LPSTR p, q; p = strstr(szBuffer, match); @@ -523,7 +524,7 @@ GetVersionFromFile( */ p += strlen(match); - while (*p && !isdigit(*p)) { + while (*p && !isdigit((unsigned char)*p)) { ++p; } @@ -532,14 +533,13 @@ GetVersionFromFile( */ q = p; - while (*q && (strchr("0123456789.ab", *q)) && ((!strchr(".ab", *q) - && (!strchr("ab", q[-1])) || --numdots))) { + while (*q && (strchr("0123456789.ab", *q)) && (((!strchr(".ab", *q) + && !strchr("ab", q[-1])) || --numdots))) { ++q; } - memcpy(szBuffer, p, q - p); - szBuffer[q-p] = 0; - szResult = szBuffer; + *q = 0; + szResult = p; break; } } @@ -562,7 +562,7 @@ typedef struct list_item_t { static list_item_t * list_insert(list_item_t **listPtrPtr, const char *key, const char *value) { - list_item_t *itemPtr = malloc(sizeof(list_item_t)); + list_item_t *itemPtr = (list_item_t *)malloc(sizeof(list_item_t)); if (itemPtr) { itemPtr->key = strdup(key); itemPtr->value = strdup(value); @@ -611,9 +611,7 @@ SubstituteFile( const char *substitutions, const char *filename) { - size_t cbBuffer = 1024; static char szBuffer[1024], szCopy[1024]; - char *szResult = NULL; list_item_t *substPtr = NULL; FILE *fp, *sp; @@ -626,7 +624,7 @@ SubstituteFile( sp = fopen(substitutions, "rt"); if (sp != NULL) { - while (fgets(szBuffer, cbBuffer, sp) != NULL) { + while (fgets(szBuffer, sizeof(szBuffer), sp) != NULL) { unsigned char *ks, *ke, *vs, *ve; ks = (unsigned char*)szBuffer; while (ks && *ks && isspace(*ks)) ++ks; @@ -657,7 +655,7 @@ SubstituteFile( * Run the substitutions over each line of the input */ - while (fgets(szBuffer, cbBuffer, fp) != NULL) { + while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) { list_item_t *p = NULL; for (p = substPtr; p != NULL; p = p->nextPtr) { char *m = strstr(szBuffer, p->key); @@ -674,7 +672,7 @@ SubstituteFile( memcpy(szBuffer, szCopy, sizeof(szCopy)); } } - printf(szBuffer); + printf("%s", szBuffer); } list_free(&substPtr); @@ -725,7 +723,8 @@ static int LocateDependencyHelper(const char *dir, const char *keypath) { HANDLE hSearch; char path[MAX_PATH+1]; - int dirlen, keylen, ret; + size_t dirlen; + int keylen, ret; WIN32_FIND_DATA finfo; if (dir == NULL || keypath == NULL) @@ -792,7 +791,8 @@ static int LocateDependencyHelper(const char *dir, const char *keypath) */ static int LocateDependency(const char *keypath) { - int i, ret; + size_t i; + int ret; static const char *paths[] = {"..", "..\\..", "..\\..\\.."}; for (i = 0; i < (sizeof(paths)/sizeof(paths[0])); ++i) { diff --git a/configure b/configure index 5df13863..55852f3e 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for sqlite 3.36.0. +# Generated by GNU Autoconf 2.69 for sqlite 3.37.2. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -726,8 +726,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' -PACKAGE_VERSION='3.36.0' -PACKAGE_STRING='sqlite 3.36.0' +PACKAGE_VERSION='3.37.2' +PACKAGE_STRING='sqlite 3.37.2' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -770,6 +770,7 @@ ac_includes_default="\ ac_subst_vars='LTLIBOBJS LIBOBJS BUILD_CFLAGS +AMALGAMATION_LINE_MACROS USE_GCOV OPT_FEATURE_FLAGS HAVE_ZLIB @@ -1467,7 +1468,7 @@ 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.36.0 to adapt to many kinds of systems. +\`configure' configures sqlite 3.37.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1532,7 +1533,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of sqlite 3.36.0:";; + short | recursive ) echo "Configuration of sqlite 3.37.2:";; esac cat <<\_ACEOF @@ -1660,7 +1661,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -sqlite configure 3.36.0 +sqlite configure 3.37.2 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2079,7 +2080,7 @@ 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.36.0, which was +It was created by sqlite $as_me 3.37.2, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3937,13 +3938,13 @@ if ${lt_cv_nm_interface+:} false; then : else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:3940: $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:3943: $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:3946: 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" @@ -5149,7 +5150,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 5152 "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=$? @@ -6674,11 +6675,11 @@ else -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:6677: $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:6681: \$? = $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. @@ -7013,11 +7014,11 @@ else -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:7016: $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:7020: \$? = $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. @@ -7118,11 +7119,11 @@ else -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:7121: $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:7125: \$? = $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 @@ -7173,11 +7174,11 @@ else -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:7176: $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:7180: \$? = $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 @@ -9553,7 +9554,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 9556 "configure" +#line 9557 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -9649,7 +9650,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 9652 "configure" +#line 9653 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11860,6 +11861,17 @@ else fi +######### +# Enable/disabled amalagamation line macros +######## +AMALGAMATION_LINE_MACROS=--linemacros=0 +if test "${amalgamation_line_macros}" = "yes" ; then + AMALGAMATION_LINE_MACROS=--linemacros=1 +fi +if test "${amalgamation_line_macros}" = "no" ; then + AMALGAMATION_LINE_MACROS=--linemacros=0 +fi + ######### # Output the config header @@ -12378,7 +12390,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # 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.36.0, which was +This file was extended by sqlite $as_me 3.37.2, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -12444,7 +12456,7 @@ _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.36.0 +sqlite config.status 3.37.2 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 70664dd4..32fe0d22 100644 --- a/configure.ac +++ b/configure.ac @@ -791,6 +791,17 @@ else fi AC_SUBST(USE_GCOV) +######### +# Enable/disabled amalagamation line macros +######## +AMALGAMATION_LINE_MACROS=--linemacros=0 +if test "${amalgamation_line_macros}" = "yes" ; then + AMALGAMATION_LINE_MACROS=--linemacros=1 +fi +if test "${amalgamation_line_macros}" = "no" ; then + AMALGAMATION_LINE_MACROS=--linemacros=0 +fi +AC_SUBST(AMALGAMATION_LINE_MACROS) ######### # Output the config header diff --git a/ext/expert/expert1.test b/ext/expert/expert1.test index 3987d0c9..73541122 100644 --- a/ext/expert/expert1.test +++ b/ext/expert/expert1.test @@ -196,7 +196,7 @@ do_setup_rec_test $tn.9.1 { } { SELECT * FROM "t t" WHERE a=? } { - CREATE INDEX 't t_idx_00000061' ON 't t'(a); + CREATE INDEX "t t_idx_00000061" ON "t t"(a); SEARCH t t USING INDEX t t_idx_00000061 (a=?) } @@ -205,7 +205,7 @@ do_setup_rec_test $tn.9.2 { } { SELECT * FROM "t t" WHERE b BETWEEN ? AND ? } { - CREATE INDEX 't t_idx_00000062' ON 't t'(b); + CREATE INDEX "t t_idx_00000062" ON "t t"(b); SEARCH t t USING INDEX t t_idx_00000062 (b>? AND b #include +#if !defined(SQLITE_AMALGAMATION) +#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) +# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 +#endif +#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) +# define ALWAYS(X) (1) +# define NEVER(X) (0) +#elif !defined(NDEBUG) +# define ALWAYS(X) ((X)?1:(assert(0),0)) +# define NEVER(X) ((X)?(assert(0),1):0) +#else +# define ALWAYS(X) (X) +# define NEVER(X) (X) +#endif +#endif /* !defined(SQLITE_AMALGAMATION) */ + + #ifndef SQLITE_OMIT_VIRTUALTABLE typedef sqlite3_int64 i64; @@ -690,11 +707,13 @@ static int idxGetTableInfo( rc = idxPrintfPrepareStmt(db, &p1, pzErrmsg, "PRAGMA table_xinfo=%Q", zTab); while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){ const char *zCol = (const char*)sqlite3_column_text(p1, 1); + const char *zColSeq = 0; nByte += 1 + STRLEN(zCol); rc = sqlite3_table_column_metadata( - db, "main", zTab, zCol, 0, &zCol, 0, 0, 0 + db, "main", zTab, zCol, 0, &zColSeq, 0, 0, 0 ); - nByte += 1 + STRLEN(zCol); + if( zColSeq==0 ) zColSeq = "binary"; + nByte += 1 + STRLEN(zColSeq); nCol++; nPk += (sqlite3_column_int(p1, 5)>0); } @@ -714,6 +733,7 @@ static int idxGetTableInfo( nCol = 0; while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){ const char *zCol = (const char*)sqlite3_column_text(p1, 1); + const char *zColSeq = 0; int nCopy = STRLEN(zCol) + 1; pNew->aCol[nCol].zName = pCsr; pNew->aCol[nCol].iPk = (sqlite3_column_int(p1, 5)==1 && nPk==1); @@ -721,12 +741,13 @@ static int idxGetTableInfo( pCsr += nCopy; rc = sqlite3_table_column_metadata( - db, "main", zTab, zCol, 0, &zCol, 0, 0, 0 + db, "main", zTab, zCol, 0, &zColSeq, 0, 0, 0 ); if( rc==SQLITE_OK ){ - nCopy = STRLEN(zCol) + 1; + if( zColSeq==0 ) zColSeq = "binary"; + nCopy = STRLEN(zColSeq) + 1; pNew->aCol[nCol].zColl = pCsr; - memcpy(pCsr, zCol, nCopy); + memcpy(pCsr, zColSeq, nCopy); pCsr += nCopy; } @@ -737,9 +758,9 @@ static int idxGetTableInfo( if( rc!=SQLITE_OK ){ sqlite3_free(pNew); pNew = 0; - }else{ + }else if( ALWAYS(pNew!=0) ){ pNew->zName = pCsr; - memcpy(pNew->zName, zTab, nTab+1); + if( ALWAYS(pNew->zName!=0) ) memcpy(pNew->zName, zTab, nTab+1); } *ppOut = pNew; @@ -910,6 +931,19 @@ static int idxFindCompatible( return 0; } +/* Callback for sqlite3_exec() with query with leading count(*) column. + * The first argument is expected to be an int*, referent to be incremented + * if that leading column is not exactly '0'. + */ +static int countNonzeros(void* pCount, int nc, + char* azResults[], char* azColumns[]){ + (void)azColumns; /* Suppress unused parameter warning */ + if( nc>0 && (azResults[0][0]!='0' || azResults[0][1]!=0) ){ + *((int *)pCount) += 1; + } + return 0; +} + static int idxCreateFromCons( sqlite3expert *p, IdxScan *pScan, @@ -936,17 +970,40 @@ static int idxCreateFromCons( if( rc==SQLITE_OK ){ /* Hash the list of columns to come up with a name for the index */ const char *zTable = pScan->pTab->zName; - char *zName; /* Index name */ - int i; - for(i=0; zCols[i]; i++){ - h += ((h<<3) + zCols[i]); - } - zName = sqlite3_mprintf("%s_idx_%08x", zTable, h); - if( zName==0 ){ + int quoteTable = idxIdentifierRequiresQuotes(zTable); + char *zName = 0; /* Index name */ + int collisions = 0; + do{ + int i; + char *zFind; + for(i=0; zCols[i]; i++){ + h += ((h<<3) + zCols[i]); + } + sqlite3_free(zName); + zName = sqlite3_mprintf("%s_idx_%08x", zTable, h); + if( zName==0 ) break; + /* Is is unique among table, view and index names? */ + zFmt = "SELECT count(*) FROM sqlite_schema WHERE name=%Q" + " AND type in ('index','table','view')"; + zFind = sqlite3_mprintf(zFmt, zName); + i = 0; + rc = sqlite3_exec(dbm, zFind, countNonzeros, &i, 0); + assert(rc==SQLITE_OK); + sqlite3_free(zFind); + if( i==0 ){ + collisions = 0; + break; + } + ++collisions; + }while( collisions<50 && zName!=0 ); + if( collisions ){ + /* This return means "Gave up trying to find a unique index name." */ + rc = SQLITE_BUSY_TIMEOUT; + }else if( zName==0 ){ rc = SQLITE_NOMEM; }else{ - if( idxIdentifierRequiresQuotes(zTable) ){ - zFmt = "CREATE INDEX '%q' ON %Q(%s)"; + if( quoteTable ){ + zFmt = "CREATE INDEX \"%w\" ON \"%w\"(%s)"; }else{ zFmt = "CREATE INDEX %s ON %s(%s)"; } @@ -955,7 +1012,11 @@ static int idxCreateFromCons( rc = SQLITE_NOMEM; }else{ rc = sqlite3_exec(dbm, zIdx, 0, 0, p->pzErrmsg); - idxHashAdd(&rc, &p->hIdx, zName, zIdx); + if( rc!=SQLITE_OK ){ + rc = SQLITE_BUSY_TIMEOUT; + }else{ + idxHashAdd(&rc, &p->hIdx, zName, zIdx); + } } sqlite3_free(zName); sqlite3_free(zIdx); @@ -1879,6 +1940,10 @@ int sqlite3_expert_analyze(sqlite3expert *p, char **pzErr){ /* Create candidate indexes within the in-memory database file */ if( rc==SQLITE_OK ){ rc = idxCreateCandidates(p); + }else if ( rc==SQLITE_BUSY_TIMEOUT ){ + if( pzErr ) + *pzErr = sqlite3_mprintf("Cannot find a unique index name to propose."); + return rc; } /* Generate the stat1 data */ diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index 9c5703d3..074123d6 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -313,13 +313,6 @@ static int fts3EvalStart(Fts3Cursor *pCsr); static int fts3TermSegReaderCursor( Fts3Cursor *, const char *, int, int, Fts3MultiSegReader **); -#ifndef SQLITE_AMALGAMATION -# if defined(SQLITE_DEBUG) -int sqlite3Fts3Always(int b) { assert( b ); return b; } -int sqlite3Fts3Never(int b) { assert( !b ); return b; } -# endif -#endif - /* ** This variable is set to false when running tests for which the on disk ** structures should not be corrupt. Otherwise, true. If it is false, extra @@ -4480,7 +4473,7 @@ void sqlite3Fts3DoclistPrev( assert( nDoclist>0 ); assert( *pbEof==0 ); - assert( p || *piDocid==0 ); + assert_fts3_nc( p || *piDocid==0 ); assert( !p || (p>aDoclist && p<&aDoclist[nDoclist]) ); if( p==0 ){ @@ -5344,8 +5337,8 @@ static void fts3EvalNextRow( Fts3Expr *pRight = pExpr->pRight; sqlite3_int64 iCmp = DOCID_CMP(pLeft->iDocid, pRight->iDocid); - assert( pLeft->bStart || pLeft->iDocid==pRight->iDocid ); - assert( pRight->bStart || pLeft->iDocid==pRight->iDocid ); + assert_fts3_nc( pLeft->bStart || pLeft->iDocid==pRight->iDocid ); + assert_fts3_nc( pRight->bStart || pLeft->iDocid==pRight->iDocid ); if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){ fts3EvalNextRow(pCsr, pLeft, pRc); @@ -5983,6 +5976,9 @@ int sqlite3Fts3EvalPhrasePoslist( if( bEofSave==0 && pNear->iDocid==iDocid ) break; } assert( rc!=SQLITE_OK || pPhrase->bIncr==0 ); + if( rc==SQLITE_OK && pNear->bEof!=bEofSave ){ + rc = FTS_CORRUPT_VTAB; + } } if( bTreeEof ){ while( rc==SQLITE_OK && !pNear->bEof ){ diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h index 8c257916..3a62ccc7 100644 --- a/ext/fts3/fts3Int.h +++ b/ext/fts3/fts3Int.h @@ -151,17 +151,18 @@ extern int sqlite3_fts3_may_be_corrupt; ** Macros indicating that conditional expressions are always true or ** false. */ -#ifdef SQLITE_COVERAGE_TEST -# define ALWAYS(x) (1) -# define NEVER(X) (0) -#elif defined(SQLITE_DEBUG) -# define ALWAYS(x) sqlite3Fts3Always((x)!=0) -# define NEVER(x) sqlite3Fts3Never((x)!=0) -int sqlite3Fts3Always(int b); -int sqlite3Fts3Never(int b); +#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) +# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 +#endif +#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) +# define ALWAYS(X) (1) +# define NEVER(X) (0) +#elif !defined(NDEBUG) +# define ALWAYS(X) ((X)?1:(assert(0),0)) +# define NEVER(X) ((X)?(assert(0),1):0) #else -# define ALWAYS(x) (x) -# define NEVER(x) (x) +# define ALWAYS(X) (X) +# define NEVER(X) (X) #endif /* @@ -620,6 +621,7 @@ void sqlite3Fts3ExprFree(Fts3Expr *); int sqlite3Fts3ExprInitTestInterface(sqlite3 *db, Fts3Hash*); int sqlite3Fts3InitTerm(sqlite3 *db); #endif +void *sqlite3Fts3MallocZero(i64 nByte); int sqlite3Fts3OpenTokenizer(sqlite3_tokenizer *, int, const char *, int, sqlite3_tokenizer_cursor ** diff --git a/ext/fts3/fts3_aux.c b/ext/fts3/fts3_aux.c index b6e65185..d3b194c9 100644 --- a/ext/fts3/fts3_aux.c +++ b/ext/fts3/fts3_aux.c @@ -297,6 +297,7 @@ static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){ if( fts3auxGrowStatArray(pCsr, 2) ) return SQLITE_NOMEM; memset(pCsr->aStat, 0, sizeof(struct Fts3auxColstats) * pCsr->nStat); iCol = 0; + rc = SQLITE_OK; while( iaStat[iCol+1].nDoc++; eState = 2; @@ -348,7 +353,6 @@ static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){ } pCsr->iCol = 0; - rc = SQLITE_OK; }else{ pCsr->isEof = 1; } diff --git a/ext/fts3/fts3_expr.c b/ext/fts3/fts3_expr.c index 7a69a935..ea8167c5 100644 --- a/ext/fts3/fts3_expr.c +++ b/ext/fts3/fts3_expr.c @@ -122,7 +122,7 @@ static int fts3isspace(char c){ ** zero the memory before returning a pointer to it. If unsuccessful, ** return NULL. */ -static void *fts3MallocZero(sqlite3_int64 nByte){ +void *sqlite3Fts3MallocZero(sqlite3_int64 nByte){ void *pRet = sqlite3_malloc64(nByte); if( pRet ) memset(pRet, 0, nByte); return pRet; @@ -203,7 +203,7 @@ static int getNextToken( rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition); if( rc==SQLITE_OK ){ nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken; - pRet = (Fts3Expr *)fts3MallocZero(nByte); + pRet = (Fts3Expr *)sqlite3Fts3MallocZero(nByte); if( !pRet ){ rc = SQLITE_NOMEM; }else{ @@ -458,7 +458,7 @@ static int getNextNode( if( fts3isspace(cNext) || cNext=='"' || cNext=='(' || cNext==')' || cNext==0 ){ - pRet = (Fts3Expr *)fts3MallocZero(sizeof(Fts3Expr)); + pRet = (Fts3Expr *)sqlite3Fts3MallocZero(sizeof(Fts3Expr)); if( !pRet ){ return SQLITE_NOMEM; } @@ -637,7 +637,7 @@ static int fts3ExprParse( && p->eType==FTSQUERY_PHRASE && pParse->isNot ){ /* Create an implicit NOT operator. */ - Fts3Expr *pNot = fts3MallocZero(sizeof(Fts3Expr)); + Fts3Expr *pNot = sqlite3Fts3MallocZero(sizeof(Fts3Expr)); if( !pNot ){ sqlite3Fts3ExprFree(p); rc = SQLITE_NOMEM; @@ -671,7 +671,7 @@ static int fts3ExprParse( /* Insert an implicit AND operator. */ Fts3Expr *pAnd; assert( pRet && pPrev ); - pAnd = fts3MallocZero(sizeof(Fts3Expr)); + pAnd = sqlite3Fts3MallocZero(sizeof(Fts3Expr)); if( !pAnd ){ sqlite3Fts3ExprFree(p); rc = SQLITE_NOMEM; diff --git a/ext/fts3/fts3_snippet.c b/ext/fts3/fts3_snippet.c index 613d3e5f..c5192c4e 100644 --- a/ext/fts3/fts3_snippet.c +++ b/ext/fts3/fts3_snippet.c @@ -138,9 +138,8 @@ static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){ + sizeof(MatchinfoBuffer); sqlite3_int64 nStr = strlen(zMatchinfo); - pRet = sqlite3_malloc64(nByte + nStr+1); + pRet = sqlite3Fts3MallocZero(nByte + nStr+1); if( pRet ){ - memset(pRet, 0, nByte); pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet; pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0] + sizeof(u32)*((int)nElem+1); @@ -544,11 +543,10 @@ static int fts3BestSnippet( ** the required space using malloc(). */ nByte = sizeof(SnippetPhrase) * nList; - sIter.aPhrase = (SnippetPhrase *)sqlite3_malloc64(nByte); + sIter.aPhrase = (SnippetPhrase *)sqlite3Fts3MallocZero(nByte); if( !sIter.aPhrase ){ return SQLITE_NOMEM; } - memset(sIter.aPhrase, 0, nByte); /* Initialize the contents of the SnippetIter object. Then iterate through ** the set of phrases in the expression to populate the aPhrase[] array. @@ -1112,10 +1110,12 @@ static int fts3MatchinfoLcsCb( ** position list for the next column. */ static int fts3LcsIteratorAdvance(LcsIterator *pIter){ - char *pRead = pIter->pRead; + char *pRead; sqlite3_int64 iRead; int rc = 0; + if( NEVER(pIter==0) ) return 1; + pRead = pIter->pRead; pRead += sqlite3Fts3GetVarint(pRead, &iRead); if( iRead==0 || iRead==1 ){ pRead = 0; @@ -1149,9 +1149,8 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){ /* Allocate and populate the array of LcsIterator objects. The array ** contains one element for each matchable phrase in the query. **/ - aIter = sqlite3_malloc64(sizeof(LcsIterator) * pCsr->nPhrase); + aIter = sqlite3Fts3MallocZero(sizeof(LcsIterator) * pCsr->nPhrase); if( !aIter ) return SQLITE_NOMEM; - memset(aIter, 0, sizeof(LcsIterator) * pCsr->nPhrase); (void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter); for(i=0; inPhrase; i++){ @@ -1612,7 +1611,7 @@ void sqlite3Fts3Offsets( if( rc!=SQLITE_OK ) goto offsets_out; /* Allocate the array of TermOffset iterators. */ - sCtx.aTerm = (TermOffset *)sqlite3_malloc64(sizeof(TermOffset)*nToken); + sCtx.aTerm = (TermOffset *)sqlite3Fts3MallocZero(sizeof(TermOffset)*nToken); if( 0==sCtx.aTerm ){ rc = SQLITE_NOMEM; goto offsets_out; @@ -1633,13 +1632,13 @@ void sqlite3Fts3Offsets( const char *zDoc; int nDoc; - /* Initialize the contents of sCtx.aTerm[] for column iCol. There is - ** no way that this operation can fail, so the return code from - ** fts3ExprIterate() can be discarded. + /* Initialize the contents of sCtx.aTerm[] for column iCol. This + ** operation may fail if the database contains corrupt records. */ sCtx.iCol = iCol; sCtx.iTerm = 0; - (void)fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx); + rc = fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx); + if( rc!=SQLITE_OK ) goto offsets_out; /* Retreive the text stored in column iCol. If an SQL NULL is stored ** in column iCol, jump immediately to the next iteration of the loop. diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c index 56c59ce3..201e5813 100644 --- a/ext/fts3/fts3_write.c +++ b/ext/fts3/fts3_write.c @@ -1335,8 +1335,18 @@ static int fts3SegReaderNext( char *aCopy; PendingList *pList = (PendingList *)fts3HashData(pElem); int nCopy = pList->nData+1; - pReader->zTerm = (char *)fts3HashKey(pElem); - pReader->nTerm = fts3HashKeysize(pElem); + + int nTerm = fts3HashKeysize(pElem); + if( (nTerm+1)>pReader->nTermAlloc ){ + sqlite3_free(pReader->zTerm); + pReader->zTerm = (char*)sqlite3_malloc((nTerm+1)*2); + if( !pReader->zTerm ) return SQLITE_NOMEM; + pReader->nTermAlloc = (nTerm+1)*2; + } + memcpy(pReader->zTerm, fts3HashKey(pElem), nTerm); + pReader->zTerm[nTerm] = '\0'; + pReader->nTerm = nTerm; + aCopy = (char*)sqlite3_malloc(nCopy); if( !aCopy ) return SQLITE_NOMEM; memcpy(aCopy, pList->aData, nCopy); @@ -1589,9 +1599,7 @@ int sqlite3Fts3MsrOvfl( */ void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){ if( pReader ){ - if( !fts3SegReaderIsPending(pReader) ){ - sqlite3_free(pReader->zTerm); - } + sqlite3_free(pReader->zTerm); if( !fts3SegReaderIsRootOnly(pReader) ){ sqlite3_free(pReader->aNode); } @@ -3783,7 +3791,7 @@ static int nodeReaderNext(NodeReader *p){ return FTS_CORRUPT_VTAB; } blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc); - if( rc==SQLITE_OK ){ + if( rc==SQLITE_OK && ALWAYS(p->term.a!=0) ){ memcpy(&p->term.a[nPrefix], &p->aNode[p->iOff], nSuffix); p->term.n = nPrefix+nSuffix; p->iOff += nSuffix; @@ -4177,7 +4185,11 @@ static int fts3TermCmp( int nCmp = MIN(nLhs, nRhs); int res; - res = (nCmp ? memcmp(zLhs, zRhs, nCmp) : 0); + if( nCmp && ALWAYS(zLhs) && ALWAYS(zRhs) ){ + res = memcmp(zLhs, zRhs, nCmp); + }else{ + res = 0; + } if( res==0 ) res = nLhs - nRhs; return res; @@ -4821,7 +4833,7 @@ static int fts3IncrmergeHintLoad(Fts3Table *p, Blob *pHint){ if( aHint ){ blobGrowBuffer(pHint, nHint, &rc); if( rc==SQLITE_OK ){ - memcpy(pHint->a, aHint, nHint); + if( ALWAYS(pHint->a!=0) ) memcpy(pHint->a, aHint, nHint); pHint->n = nHint; } } diff --git a/ext/fts5/fts5Int.h b/ext/fts5/fts5Int.h index c639f9b5..754f28c6 100644 --- a/ext/fts5/fts5Int.h +++ b/ext/fts5/fts5Int.h @@ -35,8 +35,20 @@ typedef sqlite3_uint64 u64; #endif #define testcase(x) -#define ALWAYS(x) 1 -#define NEVER(x) 0 + +#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) +# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 +#endif +#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) +# define ALWAYS(X) (1) +# define NEVER(X) (0) +#elif !defined(NDEBUG) +# define ALWAYS(X) ((X)?1:(assert(0),0)) +# define NEVER(X) ((X)?(assert(0),1):0) +#else +# define ALWAYS(X) (X) +# define NEVER(X) (X) +#endif #define MIN(x,y) (((x) < (y)) ? (x) : (y)) #define MAX(x,y) (((x) > (y)) ? (x) : (y)) @@ -96,7 +108,7 @@ extern int sqlite3_fts5_may_be_corrupt; ** A version of memcmp() that does not cause asan errors if one of the pointer ** parameters is NULL and the number of bytes to compare is zero. */ -#define fts5Memcmp(s1, s2, n) ((n)==0 ? 0 : memcmp((s1), (s2), (n))) +#define fts5Memcmp(s1, s2, n) ((n)<=0 ? 0 : memcmp((s1), (s2), (n))) /* Mark a function parameter as unused, to suppress nuisance compiler ** warnings. */ @@ -435,6 +447,9 @@ void sqlite3Fts5IndexCloseReader(Fts5Index*); */ const char *sqlite3Fts5IterTerm(Fts5IndexIter*, int*); int sqlite3Fts5IterNextScan(Fts5IndexIter*); +void *sqlite3Fts5StructureRef(Fts5Index*); +void sqlite3Fts5StructureRelease(void*); +int sqlite3Fts5StructureTest(Fts5Index*, void*); /* diff --git a/ext/fts5/fts5_buffer.c b/ext/fts5/fts5_buffer.c index a8f3bee3..b9614e12 100644 --- a/ext/fts5/fts5_buffer.c +++ b/ext/fts5/fts5_buffer.c @@ -66,7 +66,6 @@ void sqlite3Fts5BufferAppendBlob( u32 nData, const u8 *pData ){ - assert_nc( *pRc || nData>=0 ); if( nData ){ if( fts5BufferGrow(pRc, pBuf, nData) ) return; memcpy(&pBuf->p[pBuf->n], pData, nData); @@ -176,9 +175,8 @@ int sqlite3Fts5PoslistNext64( return 1; }else{ i64 iOff = *piOff; - int iVal; + u32 iVal; fts5FastGetVarint32(a, i, iVal); - assert( iVal>=0 ); if( iVal<=1 ){ if( iVal==0 ){ *pi = i; @@ -186,6 +184,7 @@ int sqlite3Fts5PoslistNext64( } fts5FastGetVarint32(a, i, iVal); iOff = ((i64)iVal) << 32; + assert( iOff>=0 ); fts5FastGetVarint32(a, i, iVal); if( iVal<2 ){ /* This is a corrupt record. So stop parsing it here. */ @@ -197,7 +196,7 @@ int sqlite3Fts5PoslistNext64( *piOff = (iOff & (i64)0x7FFFFFFF<<32)+((iOff + (iVal-2)) & 0x7FFFFFFF); } *pi = i; - assert( *piOff>=iOff ); + assert_nc( *piOff>=iOff ); return 0; } } diff --git a/ext/fts5/fts5_config.c b/ext/fts5/fts5_config.c index 32335c93..ab1a846b 100644 --- a/ext/fts5/fts5_config.c +++ b/ext/fts5/fts5_config.c @@ -562,6 +562,7 @@ int sqlite3Fts5ConfigParse( z = fts5ConfigSkipWhitespace(z); if( z && *z=='=' ){ bOption = 1; + assert( zOne!=0 ); z++; if( bMustBeCol ) z = 0; } @@ -578,7 +579,11 @@ int sqlite3Fts5ConfigParse( rc = SQLITE_ERROR; }else{ if( bOption ){ - rc = fts5ConfigParseSpecial(pGlobal, pRet, zOne, zTwo?zTwo:"", pzErr); + rc = fts5ConfigParseSpecial(pGlobal, pRet, + ALWAYS(zOne)?zOne:"", + zTwo?zTwo:"", + pzErr + ); }else{ rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr); zOne = 0; diff --git a/ext/fts5/fts5_expr.c b/ext/fts5/fts5_expr.c index f3cec00b..d9c1dd0f 100644 --- a/ext/fts5/fts5_expr.c +++ b/ext/fts5/fts5_expr.c @@ -135,6 +135,7 @@ void sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...){ va_list ap; va_start(ap, zFmt); if( pParse->rc==SQLITE_OK ){ + assert( pParse->zErr==0 ); pParse->zErr = sqlite3_vmprintf(zFmt, ap); pParse->rc = SQLITE_ERROR; } @@ -433,6 +434,7 @@ static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){ int bRetValid = 0; Fts5ExprTerm *p; + assert( pTerm ); assert( pTerm->pSynonym ); assert( bDesc==0 || bDesc==1 ); for(p=pTerm; p; p=p->pSynonym){ @@ -1873,7 +1875,7 @@ int sqlite3Fts5ExprClonePhrase( sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase)); } - if( rc==SQLITE_OK ){ + if( rc==SQLITE_OK && ALWAYS(sCtx.pPhrase) ){ /* All the allocations succeeded. Put the expression object together. */ pNew->pIndex = pExpr->pIndex; pNew->pConfig = pExpr->pConfig; @@ -2144,9 +2146,8 @@ void sqlite3Fts5ParseSetColset( ){ Fts5Colset *pFree = pColset; if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){ - pParse->rc = SQLITE_ERROR; - pParse->zErr = sqlite3_mprintf( - "fts5: column queries are not supported (detail=none)" + sqlite3Fts5ParseError(pParse, + "fts5: column queries are not supported (detail=none)" ); }else{ fts5ParseSetColset(pParse, pExpr, pColset, &pFree); @@ -2320,13 +2321,10 @@ Fts5ExprNode *sqlite3Fts5ParseNode( || pPhrase->nTerm>1 || (pPhrase->nTerm>0 && pPhrase->aTerm[0].bFirst) ){ - assert( pParse->rc==SQLITE_OK ); - pParse->rc = SQLITE_ERROR; - assert( pParse->zErr==0 ); - pParse->zErr = sqlite3_mprintf( + sqlite3Fts5ParseError(pParse, "fts5: %s queries are not supported (detail!=full)", pNear->nPhrase==1 ? "phrase": "NEAR" - ); + ); sqlite3_free(pRet); pRet = 0; } @@ -2858,6 +2856,15 @@ struct Fts5PoslistPopulator { int bMiss; }; +/* +** Clear the position lists associated with all phrases in the expression +** passed as the first argument. Argument bLive is true if the expression +** might be pointing to a real entry, otherwise it has just been reset. +** +** At present this function is only used for detail=col and detail=none +** fts5 tables. This implies that all phrases must be at most 1 token +** in size, as phrase matches are not supported without detail=full. +*/ Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){ Fts5PoslistPopulator *pRet; pRet = sqlite3_malloc64(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase); @@ -2867,7 +2874,7 @@ Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){ for(i=0; inPhrase; i++){ Fts5Buffer *pBuf = &pExpr->apExprPhrase[i]->poslist; Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode; - assert( pExpr->apExprPhrase[i]->nTerm==1 ); + assert( pExpr->apExprPhrase[i]->nTerm<=1 ); if( bLive && (pBuf->n==0 || pNode->iRowid!=pExpr->pRoot->iRowid || pNode->bEof) ){ diff --git a/ext/fts5/fts5_hash.c b/ext/fts5/fts5_hash.c index 0f4651a8..bc9244fc 100644 --- a/ext/fts5/fts5_hash.c +++ b/ext/fts5/fts5_hash.c @@ -356,7 +356,7 @@ int sqlite3Fts5HashWrite( p->bContent = 1; }else{ /* Append a new column value, if necessary */ - assert( iCol>=p->iCol ); + assert_nc( iCol>=p->iCol ); if( iCol!=p->iCol ){ if( pHash->eDetail==FTS5_DETAIL_FULL ){ pPtr[p->nData++] = 0x01; diff --git a/ext/fts5/fts5_index.c b/ext/fts5/fts5_index.c index 7cc0d46a..fe253984 100644 --- a/ext/fts5/fts5_index.c +++ b/ext/fts5/fts5_index.c @@ -600,8 +600,11 @@ static int fts5BufferCompareBlob( ** res = *pLeft - *pRight */ static int fts5BufferCompare(Fts5Buffer *pLeft, Fts5Buffer *pRight){ - int nCmp = MIN(pLeft->n, pRight->n); - int res = fts5Memcmp(pLeft->p, pRight->p, nCmp); + int nCmp, res; + nCmp = MIN(pLeft->n, pRight->n); + assert( nCmp<=0 || pLeft->p!=0 ); + assert( nCmp<=0 || pRight->p!=0 ); + res = fts5Memcmp(pLeft->p, pRight->p, nCmp); return (res==0 ? (pLeft->n - pRight->n) : res); } @@ -697,6 +700,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){ return pRet; } + /* ** Release a reference to data record returned by an earlier call to ** fts5DataRead(). @@ -821,6 +825,58 @@ static void fts5StructureRef(Fts5Structure *pStruct){ pStruct->nRef++; } +void *sqlite3Fts5StructureRef(Fts5Index *p){ + fts5StructureRef(p->pStruct); + return (void*)p->pStruct; +} +void sqlite3Fts5StructureRelease(void *p){ + if( p ){ + fts5StructureRelease((Fts5Structure*)p); + } +} +int sqlite3Fts5StructureTest(Fts5Index *p, void *pStruct){ + if( p->pStruct!=(Fts5Structure*)pStruct ){ + return SQLITE_ABORT; + } + return SQLITE_OK; +} + +/* +** Ensure that structure object (*pp) is writable. +** +** This function is a no-op if (*pRc) is not SQLITE_OK when it is called. If +** an error occurs, (*pRc) is set to an SQLite error code before returning. +*/ +static void fts5StructureMakeWritable(int *pRc, Fts5Structure **pp){ + Fts5Structure *p = *pp; + if( *pRc==SQLITE_OK && p->nRef>1 ){ + i64 nByte = sizeof(Fts5Structure)+(p->nLevel-1)*sizeof(Fts5StructureLevel); + Fts5Structure *pNew; + pNew = (Fts5Structure*)sqlite3Fts5MallocZero(pRc, nByte); + if( pNew ){ + int i; + memcpy(pNew, p, nByte); + for(i=0; inLevel; i++) pNew->aLevel[i].aSeg = 0; + for(i=0; inLevel; i++){ + Fts5StructureLevel *pLvl = &pNew->aLevel[i]; + nByte = sizeof(Fts5StructureSegment) * pNew->aLevel[i].nSeg; + pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(pRc, nByte); + if( pLvl->aSeg==0 ){ + for(i=0; inLevel; i++){ + sqlite3_free(pNew->aLevel[i].aSeg); + } + sqlite3_free(pNew); + return; + } + memcpy(pLvl->aSeg, p->aLevel[i].aSeg, nByte); + } + p->nRef--; + pNew->nRef = 1; + } + *pp = pNew; + } +} + /* ** Deserialize and return the structure record currently stored in serialized ** form within buffer pData/nData. @@ -922,9 +978,11 @@ static int fts5StructureDecode( } /* -** +** Add a level to the Fts5Structure.aLevel[] array of structure object +** (*ppStruct). */ static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){ + fts5StructureMakeWritable(pRc, ppStruct); if( *pRc==SQLITE_OK ){ Fts5Structure *pStruct = *ppStruct; int nLevel = pStruct->nLevel; @@ -1718,6 +1776,7 @@ static void fts5SegIterInit( 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; @@ -1820,8 +1879,12 @@ static void fts5SegIterReverseNewPage(Fts5Index *p, Fts5SegIter *pIter){ int iRowidOff; iRowidOff = fts5LeafFirstRowidOff(pNew); if( iRowidOff ){ - pIter->pLeaf = pNew; - pIter->iLeafOffset = iRowidOff; + if( iRowidOff>=pNew->szLeaf ){ + p->rc = FTS5_CORRUPT; + }else{ + pIter->pLeaf = pNew; + pIter->iLeafOffset = iRowidOff; + } } } @@ -2101,7 +2164,7 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){ if( pDlidx ){ int iSegid = pIter->pSeg->iSegid; pgnoLast = fts5DlidxIterPgno(pDlidx); - pLast = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, pgnoLast)); + pLast = fts5LeafRead(p, FTS5_SEGMENT_ROWID(iSegid, pgnoLast)); }else{ Fts5Data *pLeaf = pIter->pLeaf; /* Current leaf data */ @@ -2128,7 +2191,7 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){ ** forward to find the page containing the last rowid. */ for(pgno=pIter->iLeafPgno+1; !p->rc && pgno<=pSeg->pgnoLast; pgno++){ i64 iAbs = FTS5_SEGMENT_ROWID(pSeg->iSegid, pgno); - Fts5Data *pNew = fts5DataRead(p, iAbs); + Fts5Data *pNew = fts5LeafRead(p, iAbs); if( pNew ){ int iRowid, bTermless; iRowid = fts5LeafFirstRowidOff(pNew); @@ -2159,6 +2222,10 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){ pIter->pLeaf = pLast; pIter->iLeafPgno = pgnoLast; iOff = fts5LeafFirstRowidOff(pLast); + if( iOff>pLast->szLeaf ){ + p->rc = FTS5_CORRUPT; + return; + } iOff += fts5GetVarint(&pLast->p[iOff], (u64*)&pIter->iRowid); pIter->iLeafOffset = iOff; @@ -2167,7 +2234,6 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){ }else{ pIter->iEndofDoclist = fts5LeafFirstTermOff(pLast); } - } fts5SegIterReverseInitPage(p, pIter); @@ -2219,21 +2285,20 @@ static void fts5LeafSeek( Fts5SegIter *pIter, /* Iterator to seek */ const u8 *pTerm, int nTerm /* Term to search for */ ){ - int iOff; + u32 iOff; const u8 *a = pIter->pLeaf->p; - int szLeaf = pIter->pLeaf->szLeaf; - int n = pIter->pLeaf->nn; + u32 n = (u32)pIter->pLeaf->nn; u32 nMatch = 0; u32 nKeep = 0; u32 nNew = 0; u32 iTermOff; - int iPgidx; /* Current offset in pgidx */ + u32 iPgidx; /* Current offset in pgidx */ int bEndOfPage = 0; assert( p->rc==SQLITE_OK ); - iPgidx = szLeaf; + iPgidx = (u32)pIter->pLeaf->szLeaf; iPgidx += fts5GetVarint32(&a[iPgidx], iTermOff); iOff = iTermOff; if( iOff>n ){ @@ -2299,15 +2364,15 @@ static void fts5LeafSeek( if( pIter->pLeaf==0 ) return; a = pIter->pLeaf->p; if( fts5LeafIsTermless(pIter->pLeaf)==0 ){ - iPgidx = pIter->pLeaf->szLeaf; + iPgidx = (u32)pIter->pLeaf->szLeaf; iPgidx += fts5GetVarint32(&pIter->pLeaf->p[iPgidx], iOff); - if( iOff<4 || iOff>=pIter->pLeaf->szLeaf ){ + if( iOff<4 || (i64)iOff>=pIter->pLeaf->szLeaf ){ p->rc = FTS5_CORRUPT; return; }else{ nKeep = 0; iTermOff = iOff; - n = pIter->pLeaf->nn; + n = (u32)pIter->pLeaf->nn; iOff += fts5GetVarint32(&a[iOff], nNew); break; } @@ -2675,7 +2740,7 @@ static void fts5SegIterGotoPage( fts5SegIterNextPage(p, pIter); assert( p->rc!=SQLITE_OK || pIter->iLeafPgno==iLeafPgno ); - if( p->rc==SQLITE_OK ){ + if( p->rc==SQLITE_OK && ALWAYS(pIter->pLeaf!=0) ){ int iOff; u8 *a = pIter->pLeaf->p; int n = pIter->pLeaf->szLeaf; @@ -3107,7 +3172,11 @@ static void fts5SegiterPoslist( Fts5Colset *pColset, Fts5Buffer *pBuf ){ + assert( pBuf!=0 ); + assert( pSeg!=0 ); if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos+FTS5_DATA_ZERO_PADDING) ){ + assert( pBuf->p!=0 ); + assert( pBuf->nSpace >= pBuf->n+pSeg->nPos+FTS5_DATA_ZERO_PADDING ); memset(&pBuf->p[pBuf->n+pSeg->nPos], 0, FTS5_DATA_ZERO_PADDING); if( pColset==0 ){ fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback); @@ -3331,6 +3400,7 @@ static void fts5IterSetOutputs_Full(Fts5Iter *pIter, Fts5SegIter *pSeg){ } static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){ + assert( pIter!=0 || (*pRc)!=SQLITE_OK ); if( *pRc==SQLITE_OK ){ Fts5Config *pConfig = pIter->pIndex->pConfig; if( pConfig->eDetail==FTS5_DETAIL_NONE ){ @@ -3402,7 +3472,10 @@ static void fts5MultiIterNew( } } *ppOut = pNew = fts5MultiIterAlloc(p, nSeg); - if( pNew==0 ) return; + if( pNew==0 ){ + assert( p->rc!=SQLITE_OK ); + goto fts5MultiIterNew_post_check; + } pNew->bRev = (0!=(flags & FTS5INDEX_QUERY_DESC)); pNew->bSkipEmpty = (0!=(flags & FTS5INDEX_QUERY_SKIPEMPTY)); pNew->pColset = pColset; @@ -3466,6 +3539,10 @@ static void fts5MultiIterNew( fts5MultiIterFree(pNew); *ppOut = 0; } + +fts5MultiIterNew_post_check: + assert( (*ppOut)!=0 || p->rc!=SQLITE_OK ); + return; } /* @@ -3513,7 +3590,8 @@ static void fts5MultiIterNew2( ** False otherwise. */ static int fts5MultiIterEof(Fts5Index *p, Fts5Iter *pIter){ - assert( p->rc + assert( pIter!=0 || p->rc!=SQLITE_OK ); + assert( p->rc!=SQLITE_OK || (pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf==0)==pIter->base.bEof ); return (p->rc || pIter->base.bEof); @@ -4317,6 +4395,7 @@ static void fts5IndexMergeLevel( ** and last leaf page number at the same time. */ fts5WriteFinish(p, &writer, &pSeg->pgnoLast); + assert( pIter!=0 || p->rc!=SQLITE_OK ); if( fts5MultiIterEof(p, pIter) ){ int i; @@ -4417,7 +4496,7 @@ static void fts5IndexAutomerge( Fts5Structure **ppStruct, /* IN/OUT: Current structure of index */ int nLeaf /* Number of output leaves just written */ ){ - if( p->rc==SQLITE_OK && p->pConfig->nAutomerge>0 ){ + if( p->rc==SQLITE_OK && p->pConfig->nAutomerge>0 && ALWAYS((*ppStruct)!=0) ){ Fts5Structure *pStruct = *ppStruct; u64 nWrite; /* Initial value of write-counter */ int nWork; /* Number of work-quanta to perform */ @@ -5527,11 +5606,15 @@ int sqlite3Fts5IndexQuery( /* Scan multiple terms in the main index */ int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0; fts5SetupPrefixIter(p, bDesc, iPrefixIdx, buf.p, nToken+1, pColset,&pRet); - assert( p->rc!=SQLITE_OK || pRet->pColset==0 ); - fts5IterSetOutputCb(&p->rc, pRet); - if( p->rc==SQLITE_OK ){ - Fts5SegIter *pSeg = &pRet->aSeg[pRet->aFirst[1].iFirst]; - if( pSeg->pLeaf ) pRet->xSetOutputs(pRet, pSeg); + if( pRet==0 ){ + assert( p->rc!=SQLITE_OK ); + }else{ + assert( pRet->pColset==0 ); + fts5IterSetOutputCb(&p->rc, pRet); + if( p->rc==SQLITE_OK ){ + Fts5SegIter *pSeg = &pRet->aSeg[pRet->aFirst[1].iFirst]; + if( pSeg->pLeaf ) pRet->xSetOutputs(pRet, pSeg); + } } } @@ -5779,7 +5862,7 @@ static int fts5QueryCksum( Fts5IndexIter *pIter = 0; int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIter); - while( rc==SQLITE_OK && 0==sqlite3Fts5IterEof(pIter) ){ + while( rc==SQLITE_OK && ALWAYS(pIter!=0) && 0==sqlite3Fts5IterEof(pIter) ){ i64 rowid = pIter->iRowid; if( eDetail==FTS5_DETAIL_NONE ){ @@ -6144,6 +6227,7 @@ int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum){ Fts5Buffer poslist = {0,0,0}; /* Buffer used to hold a poslist */ Fts5Iter *pIter; /* Used to iterate through entire index */ Fts5Structure *pStruct; /* Index structure */ + int iLvl, iSeg; #ifdef SQLITE_DEBUG /* Used by extra internal tests only run if NDEBUG is not defined */ @@ -6154,15 +6238,16 @@ int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum){ /* Load the FTS index structure */ pStruct = fts5StructureRead(p); + if( pStruct==0 ){ + assert( p->rc!=SQLITE_OK ); + return fts5IndexReturn(p); + } /* Check that the internal nodes of each segment match the leaves */ - if( pStruct ){ - int iLvl, iSeg; - for(iLvl=0; iLvlnLevel; iLvl++){ - for(iSeg=0; iSegaLevel[iLvl].nSeg; iSeg++){ - Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg]; - fts5IndexIntegrityCheckSegment(p, pSeg); - } + for(iLvl=0; iLvlnLevel; iLvl++){ + for(iSeg=0; iSegaLevel[iLvl].nSeg; iSeg++){ + Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg]; + fts5IndexIntegrityCheckSegment(p, pSeg); } } diff --git a/ext/fts5/fts5_main.c b/ext/fts5/fts5_main.c index 3dea6caf..fd3a9066 100644 --- a/ext/fts5/fts5_main.c +++ b/ext/fts5/fts5_main.c @@ -1374,7 +1374,8 @@ static int fts5FilterMethod( pTab->pStorage, fts5StmtType(pCsr), &pCsr->pStmt, &pTab->p.base.zErrMsg ); if( rc==SQLITE_OK ){ - if( pCsr->ePlan==FTS5_PLAN_ROWID ){ + if( pRowidEq!=0 ){ + assert( pCsr->ePlan==FTS5_PLAN_ROWID ); sqlite3_bind_value(pCsr->pStmt, 1, pRowidEq); }else{ sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iFirstRowid); diff --git a/ext/fts5/fts5_storage.c b/ext/fts5/fts5_storage.c index c5052b04..02b98d9e 100644 --- a/ext/fts5/fts5_storage.c +++ b/ext/fts5/fts5_storage.c @@ -417,12 +417,16 @@ static int fts5StorageDeleteFromIndex( if( pConfig->abUnindexed[iCol-1]==0 ){ const char *zText; int nText; + assert( pSeek==0 || apVal==0 ); + assert( pSeek!=0 || apVal!=0 ); if( pSeek ){ zText = (const char*)sqlite3_column_text(pSeek, iCol); nText = sqlite3_column_bytes(pSeek, iCol); - }else{ + }else if( ALWAYS(apVal) ){ zText = (const char*)sqlite3_value_text(apVal[iCol-1]); nText = sqlite3_value_bytes(apVal[iCol-1]); + }else{ + continue; } ctx.szCol = 0; rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, @@ -1058,8 +1062,9 @@ int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol){ assert( p->pConfig->bColumnsize ); rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP_DOCSIZE, &pLookup, 0); - if( rc==SQLITE_OK ){ + if( pLookup ){ int bCorrupt = 1; + assert( rc==SQLITE_OK ); sqlite3_bind_int64(pLookup, 1, iRowid); if( SQLITE_ROW==sqlite3_step(pLookup) ){ const u8 *aBlob = sqlite3_column_blob(pLookup, 0); @@ -1072,6 +1077,8 @@ int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol){ if( bCorrupt && rc==SQLITE_OK ){ rc = FTS5_CORRUPT; } + }else{ + assert( rc!=SQLITE_OK ); } return rc; diff --git a/ext/fts5/fts5_vocab.c b/ext/fts5/fts5_vocab.c index 48aa6939..18774c4e 100644 --- a/ext/fts5/fts5_vocab.c +++ b/ext/fts5/fts5_vocab.c @@ -60,6 +60,7 @@ struct Fts5VocabCursor { int bEof; /* True if this cursor is at EOF */ Fts5IndexIter *pIter; /* Term/rowid iterator object */ + void *pStruct; /* From sqlite3Fts5StructureRef() */ int nLeTerm; /* Size of zLeTerm in bytes */ char *zLeTerm; /* (term <= $zLeTerm) paramater, or NULL */ @@ -373,7 +374,7 @@ static int fts5VocabOpenMethod( } if( rc==SQLITE_OK ){ - int nByte = pFts5->pConfig->nCol * sizeof(i64)*2 + sizeof(Fts5VocabCursor); + i64 nByte = pFts5->pConfig->nCol * sizeof(i64)*2 + sizeof(Fts5VocabCursor); pCsr = (Fts5VocabCursor*)sqlite3Fts5MallocZero(&rc, nByte); } @@ -393,6 +394,8 @@ static int fts5VocabOpenMethod( static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){ pCsr->rowid = 0; sqlite3Fts5IterClose(pCsr->pIter); + sqlite3Fts5StructureRelease(pCsr->pStruct); + pCsr->pStruct = 0; pCsr->pIter = 0; sqlite3_free(pCsr->zLeTerm); pCsr->nLeTerm = -1; @@ -470,9 +473,11 @@ static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab; - int rc = SQLITE_OK; int nCol = pCsr->pFts5->pConfig->nCol; + int rc; + rc = sqlite3Fts5StructureTest(pCsr->pFts5->pIndex, pCsr->pStruct); + if( rc!=SQLITE_OK ) return rc; pCsr->rowid++; if( pTab->eType==FTS5_VOCAB_INSTANCE ){ @@ -646,6 +651,9 @@ static int fts5VocabFilterMethod( if( rc==SQLITE_OK ){ Fts5Index *pIndex = pCsr->pFts5->pIndex; rc = sqlite3Fts5IndexQuery(pIndex, zTerm, nTerm, f, 0, &pCsr->pIter); + if( rc==SQLITE_OK ){ + pCsr->pStruct = sqlite3Fts5StructureRef(pIndex); + } } if( rc==SQLITE_OK && eType==FTS5_VOCAB_INSTANCE ){ rc = fts5VocabInstanceNewTerm(pCsr); diff --git a/ext/fts5/test/fts5af.test b/ext/fts5/test/fts5af.test index 86c8f753..a3ff330e 100644 --- a/ext/fts5/test/fts5af.test +++ b/ext/fts5/test/fts5af.test @@ -165,7 +165,7 @@ do_execsql_test 4.0 { } do_execsql_test 5.0 { - CREATE VIRTUAL TABLE p1 USING fts5(a, b); + CREATE VIRTUAL TABLE p1 USING fts5(a, b, detail=%DETAIL%); INSERT INTO p1 VALUES( 'x a a a a a a a a a a', 'a a a a a a a a a a a a a a a a a a a x' @@ -184,6 +184,12 @@ do_execsql_test 5.3 { do_execsql_test 5.4 { SELECT snippet(p1, 0, '[', NULL, '...', 6) FROM p1('x'); } {{[x a a a a a...}} +do_execsql_test 5.5 { + SELECT snippet(p1, 0, '[', NULL, '...', 6) FROM p1('x OR ""'); +} {{[x a a a a a...}} +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 diff --git a/ext/fts5/test/fts5corrupt3.test b/ext/fts5/test/fts5corrupt3.test index 5604bca7..adfaa6d8 100644 --- a/ext/fts5/test/fts5corrupt3.test +++ b/ext/fts5/test/fts5corrupt3.test @@ -15135,6 +15135,237 @@ do_catchsql_test 77.1 { UPDATE t1 SET B =quote(zeroblob(200)) WHERE b MATCH 'threa*thrad*tlrad*the�d'; } {1 {database disk image is malformed}} +#------------------------------------------------------------------------- +reset_db +do_execsql_test 78.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a,b,c); + DELETE FROM t1_data; + INSERT INTO t1_data VALUES(1,X'245a2424'); + INSERT INTO t1_data VALUES(10,X'000000000101010001010101'); + INSERT INTO t1_data VALUES(137438953473,X'0000032b0230300102060102060102061f0203010203010203010832303136303630390102070102070102070101340102050102050102050101350102040102040102040207303030303030301c0204010204010204010662696e6172790306010202030601020203060102020306010202030601020203060102020306010202030601020203060102020306010202030601020203060102020108636f6d70696c657201200102020201020201066462737ccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccccca2cccccccccc461740702030102030102030204656275670402020102020102020106656e61626c6507020201020201020201020201020201020201020201020201020201020201020201020201020201020201020201020201020201020523d6763632d352e342e30203230313630363039584e4f4341534526010500430f17434f4d50494c45523d6763632d352e342e3020323031363036303958525452494d0d000000240ee00004a810000fe80fe00fd80fd00fc80fc00fb80fb00fa80fa00f980f900f880f800f780f700f680f60945736502060102020306010202030601020203060102020306010202030601020203060102020306010202030601020203060102020306010202030601020201046f6d59741f0202010202010202010572747265651945030102030102030402696d010601020203060102020306010202030601120203060102020306010202030601020203060102020306010202030601020203060102020306010202010a7468726561647361666522020201020201020201047674616207020401020401020401407801060cb102010601010201060101020106010102010601010201060101020106010102010601010201060e0102010601010201060101020106010102010601010201060101020106010102010601010201060101020106010102010601010201060101021106010102010601010201060101020106010102010601010201060101020106010102010601010201060101020106010102010601011201060101020106010102010601010201060101020106010102041513020c124413110f47130f0c0e11100f0e100f440f1040150f'); +} + +do_execsql_test 78.1 { + CREATE VIRTUAL TABLE t3 USING fts5vocab('t1','col'); +} + +do_execsql_test 78.2 { + SELECT count(rowid) FROM t3 WHERE term>='nsocse'; +} 2 + +#------------------------------------------------------------------------- +reset_db +do_test 79.0 { + sqlite3 db {} + db deserialize [decode_hexdb { +.open --hexdb +| size 28672 pagesize 4096 filename sql053282.txt.db +| page 1 offset 0 +| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. +| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........ +| 32: 00 00 00 02 00 00 00 01 00 00 00 00 00 00 00 00 ................ +| 96: 00 00 00 00 0d 0f c7 00 06 0d b6 00 0f 8d 0f 36 ...............6 +| 112: 0e cb 0e 6b 0e 0e 0d b6 0d b5 00 00 00 00 00 00 ...k............ +| 3504: 00 00 00 00 00 00 56 07 06 17 1f 1f 01 7d 74 61 ......V.......ta +| 3520: 62 6c 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 blet1_configt1_c +| 3536: 6f 6e 66 69 67 07 43 52 45 41 54 45 20 54 41 42 onfig.CREATE TAB +| 3552: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b LE 't1_config'(k +| 3568: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 PRIMARY KEY, v) +| 3584: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 06 WITHOUT ROWID[. +| 3600: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64 ..!!...tablet1_d +| 3616: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 ocsizet1_docsize +| 3632: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 .CREATE TABLE 't +| 3648: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 1_docsize'(id IN +| 3664: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 TEGER PRIMARY KE +| 3680: 59 2c 20 73 7a 20 42 4c 4f 42 29 5e 05 07 17 21 Y, sz BLOB)^...! +| 3696: 21 01 81 07 74 61 62 6c 65 74 31 5f 63 6f 6e 74 !...tablet1_cont +| 3712: 65 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 05 43 52 entt1_content.CR +| 3728: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 EATE TABLE 't1_c +| 3744: 6f 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47 ontent'(id INTEG +| 3760: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY, +| 3776: 63 30 2c 20 63 31 2c 20 63 32 29 69 04 07 17 19 c0, c1, c2)i.... +| 3792: 19 01 81 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 ...-tablet1_idxt +| 3808: 31 5f 69 64 78 04 43 52 45 41 54 45 20 54 41 42 1_idx.CREATE TAB +| 3824: 4c 45 20 27 74 31 5f 69 64 78 27 28 73 65 67 69 LE 't1_idx'(segi +| 3840: 64 2c 20 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 d, term, pgno, P +| 3856: 52 49 4d 41 52 59 20 4b 45 59 28 73 65 67 69 64 RIMARY KEY(segid +| 3872: 2c 20 74 65 72 6d 29 29 20 57 49 54 48 4f 55 54 , term)) WITHOUT +| 3888: 20 52 4f 57 49 44 55 03 07 17 1b 1b 01 81 01 74 ROWIDU........t +| 3904: 61 62 6c 65 74 31 5f 64 61 74 61 74 31 5f 64 61 ablet1_datat1_da +| 3920: 74 61 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 ta.CREATE TABLE +| 3936: 27 74 31 5f 64 61 74 61 27 28 69 64 20 49 4e 54 't1_data'(id INT +| 3952: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY +| 3968: 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 38 02 06 , block BLOB)8.. +| 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR +| 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB +| 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 LE t1 USING fts5 +| 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c)......... +| page 3 offset 8192 +| 0: 0d 00 00 00 03 0c 94 00 0f e6 0f ef 0c 94 00 01 ................ +| 3216: 00 00 00 00 86 4a 84 80 80 80 80 01 04 00 8d 18 .....J.......... +| 3232: 00 00 03 2b 02 30 30 01 02 06 01 02 06 01 02 06 ...+.00......... +| 3248: 1f 02 03 01 02 03 01 02 03 01 08 32 30 31 36 30 ...........20160 +| 3264: 36 30 39 01 02 07 01 02 07 01 02 07 01 01 34 01 609...........4. +| 3280: 02 05 01 02 05 01 02 05 01 01 35 01 02 04 01 02 ..........5..... +| 3296: 04 01 02 04 02 07 30 30 30 30 30 30 30 1c 02 04 ......0000000... +| 3312: 01 02 04 01 02 04 01 06 62 69 6e 61 72 79 03 06 ........binary.. +| 3328: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................ +| 3344: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................ +| 3360: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................ +| 3376: 03 06 01 02 02 03 06 01 02 02 01 08 63 6f 6d 70 ............comp +| 3392: 69 6c 65 72 01 02 02 01 02 02 01 02 02 01 06 64 iler...........d +| 3408: 62 73 74 61 74 07 02 03 01 02 03 01 02 03 02 04 bstat........... +| 3424: 65 62 75 67 04 02 02 01 02 02 01 02 02 01 06 65 ebug...........e +| 3440: 6e 61 62 6c 65 07 02 02 01 02 02 01 02 02 01 02 nable........... +| 3456: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................ +| 3472: 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................ +| 3488: 02 02 01 02 02 01 02 02 01 02 12 01 02 02 01 02 ................ +| 3504: 02 01 02 02 02 08 78 74 65 6e 73 69 6f 6e 1f 02 ......xtension.. +| 3520: 04 01 02 04 01 02 04 01 04 66 74 73 34 0a 02 03 .........fts4... +| 3536: 01 02 03 01 02 03 04 01 35 0d 02 03 01 02 03 01 ........5....... +| 3552: 02 03 01 03 67 63 63 01 02 03 01 02 03 01 02 03 ....gcc......... +| 3568: 02 06 65 6f 70 6f 6c 79 10 02 03 01 02 03 01 02 ..eopoly........ +| 3584: 03 01 05 6a 73 6f 6e 31 13 02 03 01 02 03 01 02 ...json1........ +| 3600: 03 01 04 6c 6f 61 64 1f 02 03 01 02 03 01 02 03 ...load......... +| 3616: 01 03 6d 61 78 1c 02 02 01 02 02 01 02 02 02 05 ..max........... +| 3632: 65 6d 6f 72 79 1c 02 03 01 02 03 01 02 03 04 04 emory........... +| 3648: 73 79 73 35 16 02 03 01 02 03 01 02 03 01 06 6e sys5...........n +| 3664: 6f 63 61 73 65 02 06 01 02 02 03 06 01 02 02 03 ocase........... +| 3680: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................ +| 3696: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................ +| 3712: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................ +| 3728: 02 01 04 6f 6d 69 74 1f 02 02 01 02 02 01 02 02 ...omit......... +| 3744: 01 05 72 74 72 65 65 19 02 03 01 02 03 01 02 03 ..rtree......... +| 3760: 04 02 69 6d 01 06 01 02 02 03 06 01 02 02 03 06 ..im............ +| 3776: 01 02 02 03 06 01 01 02 03 06 01 02 02 03 06 01 ................ +| 3792: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................ +| 3808: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................ +| 3824: 01 0a 74 68 72 65 61 64 73 61 66 65 22 02 02 01 ..threadsafe.... +| 3840: 02 02 01 02 02 01 04 76 74 61 62 07 02 04 01 02 .......vtab..... +| 3856: 04 01 02 04 01 01 78 01 05 f1 01 02 01 06 01 01 ......x......... +| 3872: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................ +| 3888: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................ +| 3904: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................ +| 3920: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................ +| 3936: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................ +| 3952: 01 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................ +| 3968: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................ +| 3984: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................ +| 4000: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................ +| 4016: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................ +| 4032: 02 01 06 01 01 02 01 06 01 01 02 04 15 13 0c 0c ................ +| 4048: 12 44 13 11 0f 47 13 0f 0c 0e 11 10 0f 0e 10 0f .D...G.......... +| 4064: 44 0f 10 40 15 0f 07 01 03 00 14 24 5a 24 24 0f D..@.......$Z$$. +| 4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............ +| page 4 offset 12288 +| 0: 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................ +| page 5 offset 16384 +| 0: 0d 00 00 00 24 0c 0a 00 0f d8 0f af 0f 86 0f 74 ....$..........t +| 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... +| 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$...... +| 48: 0d bb 0d a0 0d 84 0d 68 0d 4f 0d 00 00 00 00 00 .......h.O...... +| 3072: 00 00 00 00 00 00 00 00 00 00 18 24 05 00 25 0f ...........$..%. +| 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI +| 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA +| 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE.. +| 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE= +| 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM +| 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO +| 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O +| 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI +| 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3.. +| 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS +| 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3.. +| 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000 +| 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. +| 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 +| 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3 +| 3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500 +| 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 2c 00000XRTRIM...., +| 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB +| 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB +| 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE. +| 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR +| 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E +| 3440: 4e 41 42 4c 45 20 4d 45 4d 5a 69 53 35 58 42 49 NABLE MEMZiS5XBI +| 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL +| 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE +| 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME +| 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....% +| 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB +| 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB +| 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE. +| 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO +| 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E +| 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49 NABLE GEOPOLYXBI +| 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL +| 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 45 E GEOPOLYXNOCASE +| 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE +| 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....# +| 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI +| 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL +| 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE... +| 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 3f d8 .#..ENABLE FTS?. +| 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB +| 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY.. +| 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4 +| 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN +| 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM. +| 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS +| 3840: 55 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e UAT VTABXBINARY. +| 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS +| 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE. +| 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS +| 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM.. +| 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR +| 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO +| 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 46 CASE.......DEBUF +| 3968: e8 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d .RTRIM'...C..COM +| 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 +| 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY' +| 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g +| 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060 +| 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 0f 17 43 9XNOCASE&...C..C +| 4064: 4f 4d 50 49 4c 45 52 3d 67 62 63 2d 35 2e 34 2e OMPILER=gbc-5.4. +| 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM +| page 6 offset 20480 +| 0: 0d 00 00 00 24 0e e0 00 0f f8 0f f0 0f e8 0f e0 ....$........... +| 16: 0f d8 0f d0 0f c8 0f c0 0f b8 0f bb 1f a8 0f a0 ................ +| 32: 0f 98 0f 90 0f 88 0f 80 0f 78 0f 70 0f 68 0f 60 .........x.p.h.` +| 48: 0f 58 0f 50 0f 48 0f 40 0f 38 0f 30 00 00 00 00 .X.P.H.@.8.0.... +| 3808: 06 24 03 00 12 02 01 01 06 23 03 00 12 02 01 01 .$.......#...... +| 3824: 06 22 03 00 12 02 01 01 06 21 03 00 12 03 01 01 .........!...... +| 3840: 06 20 03 00 12 03 01 01 06 1f 03 00 12 03 01 01 . .............. +| 3856: 06 1e 03 00 12 03 01 01 06 1d 03 00 12 03 01 01 ................ +| 3872: 06 1c 03 00 12 03 01 01 06 1b 03 00 12 02 01 01 ................ +| 3888: 06 1a 03 00 12 02 01 01 06 19 03 00 12 02 01 01 ................ +| 3904: 06 18 03 00 12 02 01 01 06 17 03 00 12 02 01 01 ................ +| 3920: 06 16 03 00 12 02 01 01 06 15 03 00 12 02 01 01 ................ +| 3936: 06 14 03 00 12 02 01 01 06 13 03 00 12 02 01 01 ................ +| 3952: 06 12 03 00 12 02 01 01 06 11 03 00 12 02 01 01 ................ +| 3968: 06 10 03 00 12 02 01 01 06 0f 03 00 12 02 01 01 ................ +| 3984: 06 0e 03 00 12 02 01 01 06 0d 03 00 12 02 01 01 ................ +| 4000: 06 0c 03 00 12 02 01 01 06 0b 03 00 12 02 01 01 ................ +| 4016: 06 0a 03 00 12 02 01 01 06 09 03 00 12 03 01 01 ................ +| 4032: 06 08 03 00 12 03 01 01 06 07 03 00 12 03 01 01 ................ +| 4048: 06 06 03 00 12 01 01 01 06 05 03 00 12 01 01 01 ................ +| 4064: 06 04 03 00 12 01 01 01 06 03 03 00 12 06 01 01 ................ +| 4080: 06 0a 83 00 12 06 01 01 06 01 03 00 12 06 01 01 ................ +| page 7 offset 24576 +| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................ +| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version. +| end sql053282.txt.db +}]} {} + +do_execsql_test 79.1 { + CREATE VIRTUAL TABLE t2 USING fts5vocab('t1','row'); +} + +do_catchsql_test 79.2 { + INSERT INTO t1(t1) SELECT 'merge' FROM t2; +} {1 {query aborted}} + sqlite3_fts5_may_be_corrupt 0 finish_test diff --git a/ext/fts5/test/fts5corrupt5.test b/ext/fts5/test/fts5corrupt5.test new file mode 100644 index 00000000..16682b13 --- /dev/null +++ b/ext/fts5/test/fts5corrupt5.test @@ -0,0 +1,798 @@ +# 2015 Apr 24 +# +# 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 tests that FTS5 handles corrupt databases (i.e. internal +# inconsistencies in the backing tables) correctly. In this case +# "correctly" means without crashing. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5corrupt3 + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} +sqlite3_fts5_may_be_corrupt 1 +database_may_be_corrupt + +#------------------------------------------------------------------------- +# dbsqlfuzz crash-0f47112aa7520cf08c6a835a88fdff8c2a32a188 +# +reset_db +do_test 1.0 { + sqlite3 db {} + db deserialize [decode_hexdb { +.open --hexdb +| size 24576 pagesize 4096 filename crash-0f47112aa7520c.db +| page 1 offset 0 +| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. +| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00 .....@ ........ +| 96: 00 00 00 00 0d 00 00 00 06 0e 0f 00 0f aa 0f 53 ...............S +| 112: 0e e8 0e 8b 0e 33 0e 0f 00 00 00 00 00 00 00 00 .....3.......... +| 3584: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 22 ................ +| 3600: 06 06 17 11 11 01 31 74 61 62 6c 65 62 62 62 62 ......1tablebbbb +| 3616: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 62 62 .CREATE TABLE bb +| 3632: 28 61 29 56 05 06 17 1f 1f 01 7d 74 61 62 6c 65 (a)V.......table +| 3648: 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 6f 6e 66 t1_configt1_conf +| 3664: 69 67 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 ig.CREATE TABLE +| 3680: 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b 20 50 52 't1_config'(k PR +| 3696: 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 20 57 49 IMARY KEY, v) WI +| 3712: 54 48 4f 55 54 20 52 4f 57 49 44 5b 04 07 17 21 THOUT ROWID[...! +| 3728: 21 01 81 01 74 61 62 6c 65 74 31 5f 64 6f 63 73 !...tablet1_docs +| 3744: 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 04 43 52 izet1_docsize.CR +| 3760: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 64 EATE TABLE 't1_d +| 3776: 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 54 45 47 ocsize'(id INTEG +| 3792: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY, +| 3808: 73 7a 20 42 4c 4f 42 29 69 03 07 17 19 19 01 81 sz BLOB)i....... +| 3824: 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 31 5f 69 -tablet1_idxt1_i +| 3840: 64 78 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 dx.CREATE TABLE +| 3856: 27 74 31 5f 69 64 78 27 28 73 65 67 69 64 2c 20 't1_idx'(segid, +| 3872: 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 52 49 4d term, pgno, PRIM +| 3888: 41 52 59 20 4b 45 59 28 73 65 67 69 64 2c 20 74 ARY KEY(segid, t +| 3904: 65 72 6d 29 29 20 57 49 54 48 4f 55 54 20 52 4f erm)) WITHOUT RO +| 3920: 57 49 44 55 02 07 17 1b 1b 01 81 01 74 61 62 6c WIDU........tabl +| 3936: 65 74 31 5f 64 61 74 61 74 31 5f 64 61 74 61 02 et1_datat1_data. +| 3952: 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 CREATE TABLE 't1 +| 3968: 5f 64 61 74 61 27 28 69 64 20 49 4e 54 45 47 45 _data'(id INTEGE +| 3984: 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 R PRIMARY KEY, b +| 4000: 6c 6f 63 6b 20 42 4c 4f 42 29 54 01 07 17 11 11 lock BLOB)T..... +| 4016: 08 81 15 74 61 62 6c 65 74 31 74 31 43 52 45 41 ...tablet1t1CREA +| 4032: 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 4c 45 TE VIRTUAL TABLE +| 4048: 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 28 61 t1 USING fts5(a +| 4064: 2c 62 2c 70 72 65 66 69 78 3d 22 31 2c 32 2c 33 ,b,prefix=.1,2,3 +| 4080: 2c 34 22 2c 20 63 6f 6e 74 65 6e 74 3d 22 22 29 ,4., content=..) +| page 2 offset 4096 +| 0: 0d 0b 6a 00 37 09 4c 02 0f e7 09 4c 0f c6 0f a4 ..j.7.L....L.... +| 16: 0f 88 0f 6d 0f 4b 0f 2c 0f 0e 0e ec 0e cd 0e ad ...m.K.,........ +| 32: 0e 8e 0e 6c 0e 4b 0e 29 0e 08 0d e6 0d c4 0d b5 ...l.K.)........ +| 48: 0d 97 0d 76 0d 54 0d 31 0d 15 0c f3 0c d3 0c b5 ...v.T.1........ +| 64: 0c 95 0c 73 0c 54 0c 32 0c 10 0b ee 0b cc 0b b0 ...s.T.2........ +| 80: 0b 8d 0b 7e 0b 48 0b 2e 0b 0b 0a ef 00 00 00 00 ...~.H.......... +| 2368: 00 00 00 00 00 00 00 00 00 00 00 00 15 0a 03 00 ................ +| 2384: 30 00 00 00 01 01 03 35 00 03 01 11 12 02 01 12 0......5........ +| 2400: 03 01 11 1c 8c 80 80 80 80 10 03 00 3e 00 00 00 ............>... +| 2416: 17 01 05 05 34 74 61 62 6c 03 02 03 01 04 77 68 ....4tabl.....wh +| 2432: 65 72 03 02 06 09 1b 8c 80 80 80 80 0f 03 00 3c er.............< +| 2448: 00 00 00 16 05 34 66 74 73 34 03 02 02 01 04 6e .....4fts4.....n +| 2464: 75 6d 62 03 06 01 04 09 1b 8c 80 80 80 80 0e 03 umb............. +| 2480: 00 3c 00 00 00 16 04 33 74 68 65 03 06 01 01 04 .<.....3the..... +| 2496: 01 03 77 68 65 03 02 04 04 0a 1b 8c 80 80 80 80 ..whe........... +| 2512: 0d 03 00 3c 00 00 00 16 04 33 6e 75 6d 03 06 01 ...<.....3num... +| 2528: 01 05 01 03 74 61 62 03 02 03 04 0a 19 8c 80 80 ....tab......... +| 2544: 80 80 0c 03 00 38 00 00 00 14 03 32 77 68 03 02 .....8.....2wh.. +| 2560: 04 00 04 33 66 74 73 03 02 02 04 07 18 8c 80 80 ...3fts......... +| 2576: 80 80 0b 03 00 36 00 00 00 13 03 32 74 61 03 02 .....6.....2ta.. +| 2592: 03 02 01 68 03 06 01 01 04 04 07 1b 8c 80 80 80 ...h............ +| 2608: 80 0a 03 00 3c 00 00 00 16 03 32 6e 75 03 06 01 ....<.....2nu... +| 2624: 01 05 01 02 6f 66 03 06 01 01 06 04 09 19 8c 80 ....of.......... +| 2640: 80 80 80 09 03 00 38 00 00 00 14 03 32 66 74 03 ......8.....2ft. +| 2656: 02 02 01 02 69 73 03 06 01 01 03 04 07 18 8c 80 ....is.......... +| 2672: 80 80 80 08 03 00 36 00 00 00 13 02 31 74 03 08 ......6.....1t.. +| 2688: 03 01 01 04 01 01 77 03 02 04 04 09 1a 8c 80 80 ......w......... +| 2704: 80 80 07 03 00 3a 00 00 00 15 02 31 6e 03 08 01 .....:.....1n... +| 2720: 01 02 05 01 00 6f 03 06 01 01 06 04 09 18 8c 80 .....o.......... +| 2736: 80 80 80 06 03 00 36 00 00 00 03 04 02 31 66 03 ......6......1f. +| 2752: 02 02 01 01 69 03 06 01 01 03 04 f6 1c 8c 80 80 ....i........... +| 2768: 80 80 05 03 00 3e 00 00 00 17 04 30 74 68 65 03 .....>.....0the. +| 2784: f6 01 01 04 01 05 77 68 65 72 65 03 02 04 0a 15 ......where..... +| 2800: 8c 80 80 80 80 04 03 00 30 00 00 00 11 01 01 06 ........0....... +| 2816: 06 30 74 61 62 6c 65 0f 42 03 07 1c 8c 81 80 80 .0table.B....... +| 2832: 80 03 03 00 3e 00 00 00 17 07 30 6e 75 6d 62 65 ....>.....0numbe +| 2848: 72 03 06 01 01 05 01 02 6f 66 03 06 04 0d 13 8c r.......of...... +| 2864: 80 80 80 80 02 03 00 2c 00 00 00 0f 01 01 03 02 .......,........ +| 2880: 30 6e 03 06 01 01 02 07 1b 8c 80 80 80 80 01 03 0n.............. +| 2896: 00 3c 00 00 00 16 08 30 66 74 73 34 61 75 78 03 .<.....0fts4aux. +| 2912: 02 02 01 02 69 73 03 06 04 0c 00 00 00 14 2a 00 ....is........*. +| 2928: 00 00 01 01 02 24 00 02 01 01 12 02 01 12 08 88 .....$.......... +| 2944: 80 80 80 80 12 03 00 16 00 00 00 05 02 1c 88 80 ................ +| 2960: 80 80 80 11 03 00 3e 00 00 00 17 05 34 72 6f 77 ......>.....4row +| 2976: 73 02 06 01 01 05 01 04 74 68 65 72 02 02 04 0b s.......ther.... +| 2992: 15 88 80 80 80 80 10 03 00 30 00 00 00 11 02 01 .........0...... +| 3008: 01 07 05 34 62 65 74 77 02 02 04 08 1b 88 80 80 ...4betw........ +| 3024: 80 80 0f 03 00 3c 00 00 00 16 04 04 33 72 6f 77 .....<......3row +| 3040: 02 06 01 01 05 01 03 74 68 65 02 08 05 0a 1b 88 .......the...... +| 3056: 80 80 80 80 0e 03 00 3c 00 00 00 16 01 01 02 04 .......<........ +| 3072: 33 61 72 65 02 02 03 01 03 62 65 74 02 02 07 08 3are.....bet.... +| 3088: 1b 88 80 80 80 80 0d 03 00 3c 00 00 00 16 13 32 .........<.....2 +| 3104: 74 68 02 08 02 01 01 07 00 04 33 61 6e 64 02 06 th........3and.. +| 3120: 04 0a 1b 88 80 80 80 80 0c 03 00 3c 00 00 00 16 ...........<.... +| 3136: 03 32 69 6e 02 06 01 01 06 01 02 72 6f 02 06 01 .2in.......ro... +| 3152: 01 05 04 09 18 88 80 80 80 80 0b 03 00 36 00 00 .............6.. +| 3168: 00 13 02 03 32 61 72 02 02 03 01 02 62 65 02 02 ....2ar.....be.. +| 3184: 04 05 07 1b 88 80 80 80 80 0a 03 00 3c 00 9e 00 ............<... +| 3200: 16 02 31 74 02 08 02 01 01 07 00 03 32 61 6e 02 ..1t........2an. +| 3216: 06 01 01 04 09 19 88 80 80 80 80 09 03 00 38 00 ..............8. +| 3232: 00 00 14 02 31 6e 02 06 01 01 03 01 01 72 02 06 ....1n.......r.. +| 3248: 01 01 05 04 08 17 88 80 80 80 80 08 03 00 34 00 ..............4. +| 3264: 00 00 12 02 31 62 02 02 04 01 01 69 02 06 01 01 ....1b.....i.... +| 3280: 06 04 06 19 88 80 80 80 80 07 03 00 38 00 00 00 ............8... +| 3296: 14 04 02 31 32 02 02 05 01 01 61 02 08 03 01 01 ...12.....a..... +| 3312: 02 05 06 1b 88 80 80 80 80 06 03 00 3c 00 00 00 ............<... +| 3328: 16 06 30 74 68 65 72 65 02 02 02 00 02 31 31 02 ..0there.....11. +| 3344: 06 01 01 04 0a 15 88 80 80 80 80 05 03 00 30 00 ..............0. +| 3360: 00 00 11 01 01 05 04 30 74 68 65 02 06 01 01 07 .......0the..... +| 3376: 07 1c 88 80 80 80 80 04 03 00 3e 00 00 00 17 01 ..........>..... +| 3392: 01 06 02 30 6e 02 06 01 01 03 01 04 72 6f 77 73 ...0n.......rows +| 3408: 02 06 07 08 1b 88 80 80 80 80 03 03 00 3c 00 00 .............<.. +| 3424: 00 16 08 30 62 65 74 77 65 65 6e 02 02 04 01 02 ...0between..... +| 3440: 69 6e 02 06 04 0c 1a 88 80 80 80 80 02 03 00 3a in.............: +| 3456: 00 00 00 15 04 30 61 6e 64 02 06 01 01 02 02 02 .....0and....... +| 3472: 72 65 02 02 03 04 0a 17 88 80 80 80 80 01 03 00 re.............. +| 3488: 34 00 00 00 12 02 30 31 02 06 01 01 04 01 01 32 4.....01.......2 +| 3504: 02 02 05 04 08 08 84 80 80 80 80 12 03 00 16 00 ................ +| 3520: 00 00 05 04 1b 84 80 80 80 80 11 03 00 3c 00 00 .............<.. +| 3536: 00 16 05 34 74 61 62 6c 01 06 01 01 05 02 03 65 ...4tabl.......e +| 3552: 72 6d 01 02 04 0b 1b 84 80 80 80 80 10 03 00 3c rm.............< +| 3568: 00 00 00 16 05 34 65 61 63 68 01 02 03 01 04 70 .....4each.....p +| 3584: 72 65 73 01 02 05 04 08 1a 84 80 80 80 80 0f 03 res............. +| 3600: 00 3a 00 00 00 15 04 33 74 65 72 01 02 04 02 02 .:.....3ter..... +| 3616: 68 65 01 06 01 01 03 04 08 1b 84 80 80 80 80 0e he.............. +| 3632: 03 00 3c 00 00 00 16 04 33 80 72 65 01 02 05 01 ..<.....3.re.... +| 3648: 03 74 61 62 01 06 01 01 05 04 08 1a 84 80 80 80 .tab............ +| 3664: 80 0d 03 00 3a 00 00 00 15 04 33 66 6f 72 01 02 ....:.....3for.. +| 3680: 02 02 02 74 73 01 06 01 01 04 04 08 1b 84 80 80 ...ts........... +| 3696: 80 80 0c 03 00 3c 00 00 00 17 03 32 74 68 01 06 .....<.....2th.. +| 3712: 01 01 03 00 04 33 65 61 63 01 02 03 04 09 18 84 .....3eac....... +| 3728: 80 80 80 80 0b 03 00 36 00 00 00 13 03 32 74 61 .......6.....2ta +| 3744: 01 06 01 01 05 02 01 65 01 02 04 04 09 19 84 80 .......e........ +| 3760: 80 80 80 0a 03 00 38 00 00 00 14 03 32 69 6e 01 ......8.....2in. +| 3776: 06 01 01 02 01 02 70 72 01 02 05 04 09 18 84 80 ......pr........ +| 3792: 80 80 80 09 03 00 36 00 00 00 13 03 32 66 6f 01 ......6.....2fo. +| 3808: 02 02 02 01 74 01 06 01 01 04 04 07 1b 84 80 80 ....t........... +| 3824: 80 80 08 03 00 3c 00 00 00 16 02 31 74 01 0a 04 .....<.....1t... +| 3840: 01 01 03 04 00 03 32 65 61 01 02 03 04 0a 17 84 ......2ea....... +| 3856: 80 80 80 80 07 03 00 34 00 00 00 12 02 31 69 01 .......4.....1i. +| 3872: 06 01 01 02 01 01 70 01 02 05 04 08 18 84 80 80 ......p......... +| 3888: 80 80 06 03 00 36 00 00 00 13 02 31 65 01 02 03 .....6.....1e... +| 3904: 01 01 66 01 08 02 01 01 04 04 06 1b 84 80 80 80 ..f............. +| 3920: 80 05 03 00 3c 00 00 00 16 05 30 74 65 72 6d 01 ....<.....0term. +| 3936: 02 04 02 02 68 65 01 06 01 01 03 04 09 14 84 80 ....he.......... +| 3952: 80 80 80 04 03 00 2e 00 00 00 10 06 30 64 61 62 ............0dab +| 3968: 6c 65 01 06 01 01 05 04 15 84 80 80 80 80 03 03 le.............. +| 3984: 00 30 00 00 00 11 02 08 30 70 72 65 73 65 6e 74 .0......0present +| 4000: 01 02 05 05 1b 84 80 80 80 80 02 03 00 3c 00 00 .............<.. +| 4016: 00 16 04 30 66 74 73 01 06 01 01 04 01 02 69 6e ...0fts.......in +| 4032: 01 06 01 01 04 0a 1a 84 80 80 80 80 01 03 00 3a ...............: +| 4048: 00 00 00 15 05 30 65 61 63 68 01 02 03 01 13 66 .....0each.....f +| 4064: 6f 72 01 02 02 04 09 06 01 03 00 12 03 0b 0f 00 or.............. +| 4080: 00 08 8c 80 80 80 80 11 03 00 16 00 00 00 05 04 ................ +| page 3 offset 8192 +| 0: 0a 00 00 00 32 0e 4f 00 0f fa 0f f1 0f e9 0f e1 ....2.O......... +| 16: 0f d8 0f d1 0f c9 0f c1 0f b9 0f b1 0f a9 0f a0 ................ +| 32: 0f 98 0f 90 0f 87 0f 80 0f 78 0f 71 0f 68 0f 5f .........x.q.h._ +| 48: 0f 56 0f 4d 0f 41 0f 38 0f 2f 0f 26 0f 1d 0f 13 .V.M.A.8./.&.... +| 64: 0f 0a 0f 01 0e f7 0e ee 0e e6 0e dd 0e d6 0e cd ................ +| 80: 0e c3 0e ba 0e 00 00 00 00 00 00 00 00 00 00 00 ................ +| 3648: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 ................ +| 3664: 04 01 10 01 03 34 74 20 07 04 01 0e 01 03 34 1e .....4t ......4. +| 3680: 09 04 01 12 01 03 33 74 68 1c 08 04 01 10 01 03 ......3th....... +| 3696: 33 6e 1a 08 04 01 10 01 03 32 77 18 08 04 01 10 3n.......2w..... +| 3712: 01 03 32 74 16 08 04 01 10 01 03 32 6e 14 07 04 ..2t.......2n... +| 3728: 01 0e 01 03 32 12 08 04 01 10 01 03 31 74 10 08 ....2.......1t.. +| 3744: 04 01 10 01 03 31 6e 0e 07 04 01 0e 01 03 31 0c .....1n.......1. +| 3760: 09 04 01 12 01 03 30 74 68 0a 08 04 01 10 01 03 ......0th....... +| 3776: 30 74 08 09 04 01 12 01 03 30 6e 75 06 08 04 01 0t.......0nu.... +| 3792: 10 01 03 30 6e 04 06 04 01 0c 01 03 02 08 04 01 ...0n........... +| 3808: 10 01 02 34 72 22 07 04 01 0e 01 02 34 20 08 04 ...4r.......4 .. +| 3824: 01 10 01 02 33 72 1e 09 04 01 12 01 02 33 61 72 ....3r.......3ar +| 3840: 1c 08 04 01 10 01 02 32 74 1a 08 04 01 10 01 02 .......2t....... +| 3856: 32 69 18 09 04 01 12 01 02 32 61 72 16 08 04 01 2i.......2ar.... +| 3872: 10 01 02 31 74 14 08 04 01 10 01 02 31 6e 12 08 ...1t.......1n.. +| 3888: 04 01 10 01 02 31 62 10 08 04 01 10 01 02 31 32 .....1b.......12 +| 3904: 0e 0b 04 01 16 01 02 30 74 68 65 72 0c 08 04 01 .......0ther.... +| 3920: 10 01 02 30 74 0a 08 04 01 10 01 02 30 6e 08 08 ...0t.......0n.. +| 3936: 14 01 10 01 02 30 62 06 08 04 01 10 01 02 30 61 .....0b.......0a +| 3952: 04 06 04 01 0c 01 02 02 07 04 09 10 01 34 74 22 .............4t. +| 3968: 06 04 09 0e 01 34 20 08 04 09 12 01 33 74 65 1e .....4 .....3te. +| 3984: 07 04 09 10 01 33 70 1c 07 04 09 10 01 33 66 1a .....3p......3f. +| 4000: 08 04 09 12 01 32 74 68 18 07 04 09 10 01 32 74 .....2th......2t +| 4016: 16 01 64 09 10 01 32 69 14 07 04 09 10 01 32 66 ..d...2i......2f +| 4032: 12 07 04 09 10 01 31 74 10 07 04 09 10 01 31 69 ......1t......1i +| 4048: 0e 06 04 09 0e 01 31 0c 08 04 09 12 01 30 74 65 ......1......0te +| 4064: 0a 06 04 09 10 01 30 74 08 07 04 09 10 01 30 70 ......0t......0p +| 4080: 06 08 04 09 12 00 00 00 00 00 00 00 00 00 00 00 ................ +| page 4 offset 12288 +| 4064: 00 00 00 00 00 00 00 00 00 00 00 05 03 03 00 10 ................ +| 4080: 03 05 05 02 03 00 10 04 06 05 01 03 00 10 04 04 ................ +| page 5 offset 16384 +| 0: 0a 00 00 00 02 0f eb 00 0f eb 0f f4 00 00 00 00 ................ +| 4064: 00 00 00 00 00 00 00 00 00 00 00 08 03 15 01 70 ...............p +| 4080: 67 73 7a 18 0b 03 1b 01 76 65 72 73 69 6f 6e 04 gsz.....version. +| page 6 offset 20480 +| 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +| 4080: 00 00 03 03 02 01 03 03 02 02 01 00 00 00 00 00 ................ +| end crash-0f47112aa7520c.db + }] +} {} + +do_catchsql_test 1.1 { + SELECT * FROM t1('R*') WHERE (a,b)<=(current_date,0) ORDER BY rowid DESC; +} {1 {database disk image is malformed}} + +#------------------------------------------------------------------------- +# +reset_db +do_test 2.0 { + sqlite3 db {} + db deserialize [decode_hexdb { + +.open --hexdb +| size 24576 pagesize 4096 filename sql047467.txt.db +| page 1 offset 0 +| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. +| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00 .....@ ........ +| 96: 00 00 00 00 0d 00 00 00 06 0e 0f 00 0f aa 0f 53 ...............S +| 112: 0e e8 0e 8b 0e 33 0e 0f 01 00 00 00 00 00 00 00 .....3.......... +| 3584: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 22 ................ +| 3600: 06 06 17 11 11 01 31 74 61 62 6c 65 62 62 62 62 ......1tablebbbb +| 3616: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 62 62 .CREATE TABLE bb +| 3632: 28 61 29 56 05 06 17 1f 1f 01 7d 74 61 62 6c 65 (a)V.......table +| 3648: 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 6f 6e 66 t1_configt1_conf +| 3664: 69 67 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 ig.CREATE TABLE +| 3680: 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b 20 50 52 't1_config'(k PR +| 3696: 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 20 57 49 IMARY KEY, v) WI +| 3712: 54 48 4f 55 54 20 52 4f 57 49 44 5b 04 07 17 21 THOUT ROWID[...! +| 3728: 21 01 81 01 74 61 62 6c 65 74 31 5f 64 6f 63 73 !...tablet1_docs +| 3744: 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 04 43 52 izet1_docsize.CR +| 3760: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 64 EATE TABLE 't1_d +| 3776: 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 54 45 47 ocsize'(id INTEG +| 3792: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY, +| 3808: 73 7a 20 42 4c 4f 42 29 69 03 07 17 19 19 01 81 sz BLOB)i....... +| 3824: 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 31 5f 69 -tablet1_idxt1_i +| 3840: 64 78 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 dx.CREATE TABLE +| 3856: 27 74 31 5f 69 64 78 27 28 73 65 67 69 64 2c 20 't1_idx'(segid, +| 3872: 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 52 49 4d term, pgno, PRIM +| 3888: 41 52 59 20 4b 45 59 28 73 65 67 69 64 2c 20 74 ARY KEY(segid, t +| 3904: 65 72 6d 29 29 20 57 49 54 48 4f 55 54 20 52 4f erm)) WITHOUT RO +| 3920: 57 49 44 55 02 07 17 1b 1b 01 81 01 74 61 62 6c WIDU........tabl +| 3936: 65 74 31 5f 64 61 74 61 74 31 5f 64 61 74 61 02 et1_datat1_data. +| 3952: 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 CREATE TABLE 't1 +| 3968: 5f 64 61 74 61 27 28 69 64 20 49 4e 54 45 47 45 _data'(id INTEGE +| 3984: 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 R PRIMARY KEY, b +| 4000: 6c 6f 63 6b 20 42 4c 4f 42 29 54 01 07 17 11 11 lock BLOB)T..... +| 4016: 08 81 15 74 61 62 6c 65 74 31 74 31 43 52 45 41 ...tablet1t1CREA +| 4032: 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 4c 45 TE VIRTUAL TABLE +| 4048: 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 28 61 t1 USING fts5(a +| 4064: 2c 62 2c 70 72 65 66 69 78 3d 22 31 2c 32 2c 33 ,b,prefix=.1,2,3 +| 4080: 2c 34 22 2c 20 63 6f 6e 74 65 6e 74 3d 22 22 29 ,4., content=..) +| page 2 offset 4096 +| 0: 0d 0b 6a 00 37 09 4c 02 0f e7 09 4c 0f c6 0f a4 ..j.7.L....L.... +| 16: 0f 88 0f 6d 0f 4b 0f 2c 0f 0e 0e ec 0e cd 0e ad ...m.K.,........ +| 32: 0e 8e 0e 6c 0e 4b 0e 29 0e 08 0d e6 0d c4 0d b5 ...l.K.)........ +| 48: 0d 97 0d 76 0d 54 0d 31 0d 15 0c f3 0c d3 0c b5 ...v.T.1........ +| 64: 0c 95 0c 73 0c 54 0c 32 0c 10 0b ee 0b cc 0b b0 ...s.T.2........ +| 80: 0b 8d 0b 7e 0b 48 0b 2e 0b 0b 0a ef 00 00 00 00 ...~.H.......... +| 2368: 00 00 00 00 00 00 00 00 00 00 00 00 15 0a 03 00 ................ +| 2384: 30 00 00 00 01 01 03 35 00 03 01 11 12 02 01 12 0......5........ +| 2400: 03 01 11 1c 8c 80 80 80 80 10 03 00 3e 00 00 00 ............>... +| 2416: 17 01 05 05 34 74 61 62 6c 03 02 03 01 04 77 68 ....4tabl.....wh +| 2432: 65 72 03 02 06 09 1b 8c 80 80 80 80 0f 03 00 3c er.............< +| 2448: 00 00 00 16 05 34 66 74 73 34 03 02 02 01 04 6e .....4fts4.....n +| 2464: 75 6d 62 03 06 01 04 09 1b 8c 80 80 80 80 0e 03 umb............. +| 2480: 00 3b ff f0 00 16 04 33 74 68 65 03 06 01 01 04 .;.....3the..... +| 2496: 01 03 77 68 65 03 02 04 04 0a 1b 8c 80 80 80 80 ..whe........... +| 2512: 0d 03 00 3c 00 00 00 16 04 33 6e 75 6d 03 06 01 ...<.....3num... +| 2528: 01 05 01 03 74 61 62 03 02 03 04 0a 19 8c 80 80 ....tab......... +| 2544: 80 80 0c 03 00 38 00 00 00 14 03 32 77 68 03 02 .....8.....2wh.. +| 2560: 04 00 04 33 66 74 73 03 02 02 04 07 18 8c 80 80 ...3fts......... +| 2576: 80 80 0b 03 00 36 00 00 00 13 03 32 74 61 03 02 .....6.....2ta.. +| 2592: 03 02 01 68 03 06 01 01 04 04 07 1b 8c 80 80 80 ...h............ +| 2608: 80 0a 03 00 3c 00 00 00 16 03 32 6e 75 03 06 01 ....<.....2nu... +| 2624: 01 05 01 02 6f 66 03 06 01 01 06 04 09 19 8c 80 ....of.......... +| 2640: 80 80 80 09 03 00 38 00 00 00 14 03 32 66 74 03 ......8.....2ft. +| 2656: 02 02 01 02 69 73 03 06 01 01 03 04 07 18 8c 80 ....is.......... +| 2672: 80 80 80 08 03 00 36 00 00 00 13 02 31 74 03 08 ......6.....1t.. +| 2688: 03 01 01 04 01 01 77 03 02 04 04 09 1a 8c 80 80 ......w......... +| 2704: 80 80 07 03 00 3a 00 00 00 15 02 31 6e 03 08 01 .....:.....1n... +| 2720: 01 02 05 01 00 6f 03 06 01 01 06 14 09 18 8c 80 .....o.......... +| 2736: 80 80 80 06 03 00 36 00 00 00 03 04 02 31 66 03 ......6......1f. +| 2752: 02 02 01 01 69 03 06 01 01 03 04 f6 1c 8c 80 80 ....i........... +| 2768: 80 80 05 03 00 3e 00 00 00 17 04 30 74 68 65 03 .....>.....0the. +| 2784: f6 01 01 04 01 05 77 68 65 72 65 03 02 04 0a 15 ......where..... +| 2800: 8c 80 80 80 80 04 03 00 30 00 00 00 11 01 01 06 ........0....... +| 2816: 06 30 74 61 62 6c 65 0f 42 03 07 1c 8c 81 80 80 .0table.B....... +| 2832: 80 03 03 00 3e 00 00 00 17 07 30 6e 75 6d 62 65 ....>.....0numbe +| 2848: 72 03 06 01 01 05 01 02 6f 66 03 06 04 0d 13 8c r.......of...... +| 2864: 80 80 80 80 02 03 00 2c 00 00 00 0f 01 01 03 02 .......,........ +| 2880: 30 6e 03 06 01 01 02 07 1b 8c 80 80 80 80 01 03 0n.............. +| 2896: 00 3c 00 00 00 16 08 30 66 74 73 34 61 75 78 03 .<.....0fts4aux. +| 2912: 02 02 01 02 69 73 03 06 04 0c 00 00 00 14 2a 00 ....is........*. +| 2928: 00 00 01 01 02 24 00 02 01 01 12 02 01 12 08 88 .....$.......... +| 2944: 80 80 80 80 12 03 00 16 00 00 00 05 02 1c 88 80 ................ +| 2960: 80 80 80 11 03 00 3e 00 00 00 17 05 34 72 6f 77 ......>.....4row +| 2976: 73 02 06 01 01 05 01 04 74 68 65 72 02 02 04 0b s.......ther.... +| 2992: 15 88 80 80 80 80 10 03 00 30 00 00 00 11 02 01 .........0...... +| 3008: 01 07 05 34 62 65 74 77 02 02 04 08 1b 88 80 80 ...4betw........ +| 3024: 80 80 0f 03 00 3c 00 00 00 16 04 04 33 72 6f 77 .....<......3row +| 3040: 02 06 01 01 05 01 03 74 68 65 02 08 05 0a 1b 88 .......the...... +| 3056: 80 80 80 80 0e 03 00 3c 00 00 00 16 01 01 02 04 .......<........ +| 3072: 33 61 72 65 02 02 03 01 03 62 65 74 02 02 07 08 3are.....bet.... +| 3088: 1b 88 80 80 80 80 0d 03 00 3c 00 00 00 16 13 32 .........<.....2 +| 3104: 74 68 02 08 02 01 01 07 00 04 33 61 6e 64 02 06 th........3and.. +| 3120: 04 0a 1b 88 80 80 80 80 0c 03 00 3c 00 00 00 16 ...........<.... +| 3136: 03 32 69 6e 02 06 01 01 06 01 02 72 6f 02 06 01 .2in.......ro... +| 3152: 01 05 04 09 18 88 80 80 80 80 0b 03 00 36 00 00 .............6.. +| 3168: 00 13 02 03 32 61 72 02 02 03 01 02 62 65 02 02 ....2ar.....be.. +| 3184: 04 05 07 1b 88 80 80 80 80 0a 03 00 3c 00 94 50 ............<..P +| 3200: 16 02 31 74 02 08 02 01 01 07 00 03 32 61 6e 02 ..1t........2an. +| 3216: 06 01 01 04 09 19 88 80 80 80 80 09 03 00 38 00 ..............8. +| 3232: 00 00 14 02 31 6e 02 06 01 01 03 01 01 72 02 06 ....1n.......r.. +| 3248: 01 01 05 04 08 17 88 80 80 80 80 08 03 00 34 00 ..............4. +| 3264: 00 00 12 02 31 62 02 02 04 01 01 69 02 06 01 01 ....1b.....i.... +| 3280: 06 04 06 19 88 80 80 80 80 07 03 00 38 00 00 00 ............8... +| 3296: 14 04 02 31 32 02 02 05 01 01 61 02 08 03 01 01 ...12.....a..... +| 3312: 02 05 06 1b 88 80 80 80 80 06 03 00 3c 00 00 00 ............<... +| 3328: 16 06 30 74 68 65 72 65 02 02 02 00 02 31 31 02 ..0there.....11. +| 3344: 06 01 01 04 0a 15 88 80 80 80 80 05 03 00 30 00 ..............0. +| 3360: 00 00 11 01 01 05 04 30 74 68 65 02 06 01 01 07 .......0the..... +| 3376: 07 1c 88 80 80 80 80 04 03 00 3e 00 00 00 17 01 ..........>..... +| 3392: 01 06 02 30 6e 02 06 01 01 03 01 04 72 6f 77 73 ...0n.......rows +| 3408: 02 06 07 08 1b 88 80 80 80 80 03 03 00 3c 00 00 .............<.. +| 3424: 00 16 08 30 62 65 74 77 65 65 6e 02 02 04 01 02 ...0between..... +| 3440: 69 6e 02 06 04 0c 1a 88 80 80 80 80 02 03 00 3a in.............: +| 3456: 00 00 00 15 04 30 61 6e 64 02 06 01 01 02 02 02 .....0and....... +| 3472: 72 65 02 02 03 04 0a 17 88 80 80 80 80 01 03 00 re.............. +| 3488: 34 00 00 00 12 02 30 31 02 06 01 01 04 01 01 32 4.....01.......2 +| 3504: 02 02 05 04 08 08 84 80 80 80 80 12 03 00 16 00 ................ +| 3520: 00 00 05 04 1b 84 80 80 80 80 11 03 00 3c 00 00 .............<.. +| 3536: 00 16 05 34 74 61 62 6c 01 06 01 01 05 02 03 65 ...4tabl.......e +| 3552: 72 6d 01 02 04 0b 1b 84 80 80 80 80 10 03 00 3c rm.............< +| 3568: 00 00 00 16 05 34 65 61 63 68 01 02 03 01 04 70 .....4each.....p +| 3584: 72 65 73 01 02 05 04 08 1a 84 80 80 80 80 0f 03 res............. +| 3600: 00 3a 00 00 00 15 04 33 74 65 72 01 02 04 02 02 .:.....3ter..... +| 3616: 68 65 01 06 01 01 03 04 08 1b 84 80 80 80 80 0e he.............. +| 3632: 03 00 3c 00 00 00 16 04 33 80 72 65 01 02 05 01 ..<.....3.re.... +| 3648: 03 74 61 62 01 06 01 01 05 04 08 1a 84 80 80 80 .tab............ +| 3664: 80 0d 03 00 3a 00 00 00 15 04 33 66 6f 72 01 02 ....:.....3for.. +| 3680: 02 02 02 74 73 01 06 01 01 04 04 08 1b 84 80 80 ...ts........... +| 3696: 80 80 0c 03 00 3c 00 00 00 17 03 32 74 68 01 06 .....<.....2th.. +| 3712: 01 01 03 00 04 33 65 61 63 01 02 03 04 09 18 84 .....3eac....... +| 3728: 80 80 80 80 0b 03 00 36 00 00 00 13 03 32 74 61 .......6.....2ta +| 3744: 01 06 01 01 05 02 01 65 01 02 04 04 09 19 84 80 .......e........ +| 3760: 80 80 80 0a 03 00 38 00 00 00 14 03 32 69 6e 01 ......8.....2in. +| 3776: 06 01 01 02 01 02 70 72 01 02 05 04 09 18 84 80 ......pr........ +| 3792: 80 80 80 09 03 00 36 00 00 00 13 03 32 66 6f 01 ......6.....2fo. +| 3808: 02 02 02 01 74 01 06 01 01 04 04 07 1b 84 80 80 ....t........... +| 3824: 80 80 08 03 00 3c 00 00 00 16 02 31 74 01 0a 04 .....<.....1t... +| 3840: 01 01 03 04 00 03 32 65 61 01 02 03 04 0a 17 84 ......2ea....... +| 3856: 80 80 80 80 07 03 00 34 00 00 00 12 02 31 69 01 .......4.....1i. +| 3872: 06 01 01 02 01 01 70 01 02 05 04 08 18 84 80 80 ......p......... +| 3888: 80 80 06 03 00 36 00 00 00 13 02 31 65 01 02 03 .....6.....1e... +| 3904: 01 01 66 01 08 02 01 01 04 04 06 1b 84 80 80 80 ..f............. +| 3920: 80 05 03 00 3c 00 00 00 16 05 30 74 65 72 6d 01 ....<.....0term. +| 3936: 02 04 02 02 68 65 01 06 01 01 03 04 09 14 84 80 ....he.......... +| 3952: 80 80 80 04 03 00 2e 00 00 00 10 06 30 64 61 62 ............0dab +| 3968: 6c 65 01 06 01 01 05 04 15 84 80 80 80 80 03 03 le.............. +| 3984: 00 30 00 00 00 11 02 08 30 70 72 65 73 65 6e 74 .0......0present +| 4000: 01 02 05 05 1b 84 80 80 80 80 02 03 00 3c 00 00 .............<.. +| 4016: 00 16 04 30 66 74 73 01 06 01 01 04 01 02 69 6e ...0fts.......in +| 4032: 01 06 01 01 04 0a 1a 84 80 80 80 80 01 03 00 3a ...............: +| 4048: 00 00 00 15 05 30 65 61 63 68 01 02 03 01 13 66 .....0each.....f +| 4064: 6f 72 01 02 02 04 09 06 01 03 00 12 03 0b 0f 00 or.............. +| 4080: 00 08 8c 80 80 80 80 11 03 00 16 00 00 00 05 04 ................ +| page 3 offset 8192 +| 0: 0a 00 00 00 32 0e 4f 00 0f fa 0f f1 0f e9 0f e1 ....2.O......... +| 16: 0f d8 0f d1 0f c9 0f c1 0f b9 0f b1 0f a9 0f a0 ................ +| 32: 0f 98 0f 90 0f 87 0f 80 0f 78 0f 71 0f 68 0f 5f .........x.q.h._ +| 48: 0f 56 0f 4d 0f 41 0f 38 0f 2f 0f 26 0f 1d 0f 13 .V.M.A.8./.&.... +| 64: 0f 0a 0f 01 0e f7 0e ee 0e e6 0e dd 0e d6 0e cd ................ +| 80: 0e c3 0e ba 0e 00 00 00 00 00 00 00 00 00 00 00 ................ +| 3648: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 ................ +| 3664: 04 01 10 01 03 34 74 20 07 04 01 0e 01 03 34 1e .....4t ......4. +| 3680: 09 04 01 12 01 03 33 74 68 1c 08 04 01 10 01 03 ......3th....... +| 3696: 33 6e 1a 08 04 01 10 01 03 32 77 18 08 04 01 10 3n.......2w..... +| 3712: 01 03 32 74 16 08 04 01 10 01 03 32 6e 14 07 04 ..2t.......2n... +| 3728: 01 0e 01 03 32 12 08 04 01 10 01 03 31 74 10 08 ....2.......1t.. +| 3744: 04 01 10 01 03 31 6e 0e 07 04 01 0e 01 03 31 0c .....1n.......1. +| 3760: 09 04 01 12 01 03 30 74 68 0a 08 04 01 10 01 03 ......0th....... +| 3776: 30 74 08 09 04 01 12 01 03 30 6e 75 06 08 04 01 0t.......0nu.... +| 3792: 10 01 03 30 6e 04 06 04 01 0c 01 03 02 08 04 01 ...0n........... +| 3808: 10 01 02 34 72 22 07 04 01 0e 01 02 34 20 08 04 ...4r.......4 .. +| 3824: 01 10 01 02 33 72 1e 09 04 01 12 01 02 33 61 72 ....3r.......3ar +| 3840: 1c 08 04 01 10 01 02 32 74 1a 08 04 01 10 01 02 .......2t....... +| 3856: 32 69 18 09 04 01 12 01 02 32 61 72 16 08 04 01 2i.......2ar.... +| 3872: 10 01 02 31 74 14 08 04 01 10 01 02 31 6e 12 08 ...1t.......1n.. +| 3888: 04 01 10 01 02 31 62 10 08 04 01 10 01 02 31 32 .....1b.......12 +| 3904: 0e 0b 04 01 16 01 02 30 74 68 65 72 0c 08 04 01 .......0ther.... +| 3920: 10 01 02 30 74 0a 08 04 01 10 01 02 30 6e 08 08 ...0t.......0n.. +| 3936: 14 01 10 01 02 30 62 06 08 04 01 10 01 02 30 61 .....0b.......0a +| 3952: 04 06 04 01 0c 01 02 02 07 04 09 10 01 34 74 22 .............4t. +| 3968: 06 04 09 0e 01 34 20 08 04 09 12 01 33 74 65 1e .....4 .....3te. +| 3984: 07 04 09 10 01 33 70 1c 07 04 09 10 01 33 66 1a .....3p......3f. +| 4000: 08 04 09 12 01 32 74 68 18 07 04 09 10 01 32 74 .....2th......2t +| 4016: 16 01 64 09 10 01 32 69 14 07 04 09 10 01 32 66 ..d...2i......2f +| 4032: 12 07 04 09 10 01 31 74 10 07 04 09 10 01 31 69 ......1t......1i +| 4048: 0e 06 04 09 0e 01 31 0c 08 04 09 12 01 30 74 65 ......1......0te +| 4064: 0a 06 04 09 10 01 30 74 08 07 04 09 10 01 30 70 ......0t......0p +| 4080: 06 08 04 09 12 00 00 00 00 00 00 00 00 00 00 00 ................ +| page 4 offset 12288 +| 4064: 00 00 00 00 00 00 00 00 00 00 00 05 03 03 00 10 ................ +| 4080: 03 05 05 02 03 00 10 04 06 05 01 03 00 10 04 04 ................ +| page 5 offset 16384 +| 0: 0a 00 00 00 02 0f eb 00 0f eb 0f f4 00 00 00 00 ................ +| 4064: 00 00 00 00 00 00 00 00 00 00 00 08 03 15 01 70 ...............p +| 4080: 67 73 7a 18 0b 03 1b 01 76 65 72 73 69 6f 6e 04 gsz.....version. +| page 6 offset 20480 +| 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +| 4080: 00 00 03 03 02 01 03 03 02 02 01 00 00 00 00 00 ................ +| end sql047467.txt.db +}]} {} + +do_catchsql_test 2.1 { +SELECT * FROM t1('R*R*R*R*') WHERE (a,b)<=(current_date,0) ORDER BY rowid DESC; +} {1 {database disk image is malformed}} + +#------------------------------------------------------------------------- +reset_db +do_test 3.0 { + sqlite3 db {} + db deserialize [decode_hexdb { +.open --hexdb +| size 32768 pagesize 4096 filename crash-c69fcaceff1e50.db +| page 1 offset 0 +| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. +| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 08 .....@ ........ +| 32: 00 00 00 02 00 00 00 01 00 00 00 09 00 00 00 04 ................ +| 96: 00 00 00 00 0d 0f c7 00 07 0d 92 00 0f 8d 0f 36 ...............6 +| 112: 0e cb 0e 6b 0e 0e 0d b6 0d 92 0d 92 00 00 00 00 ...k............ +| 3472: 00 00 22 08 06 17 11 11 01 31 74 61 62 6c 65 74 .........1tablet +| 3488: 32 74 32 08 43 52 45 41 54 45 20 54 41 42 4c 45 2t2.CREATE TABLE +| 3504: 20 74 32 28 78 29 56 07 06 17 1f 1f 01 7d 74 61 t2(x)V.......ta +| 3520: 62 6c 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 blet1_configt1_c +| 3536: 6f 6e 66 69 67 07 43 52 45 41 54 45 20 54 41 42 onfig.CREATE TAB +| 3552: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b LE 't1_config'(k +| 3568: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 PRIMARY KEY, v) +| 3584: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 06 WITHOUT ROWID[. +| 3600: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64 ..!!...tablet1_d +| 3616: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 ocsizet1_docsize +| 3632: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 .CREATE TABLE 't +| 3648: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 1_docsize'(id IN +| 3664: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 TEGER PRIMARY KE +| 3680: 59 2c 20 73 7a 20 42 4c 4f 42 29 5e 05 07 17 21 Y, sz BLOB)^...! +| 3696: 21 01 81 07 74 61 62 6c 65 74 31 5f 63 6f 6e 74 !...tablet1_cont +| 3712: 65 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 05 43 52 entt1_content.CR +| 3728: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 EATE TABLE 't1_c +| 3744: 6f 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47 ontent'(id INTEG +| 3760: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY, +| 3776: 63 30 2c 20 63 31 2c 20 63 32 29 69 04 07 17 19 c0, c1, c2)i.... +| 3792: 19 01 81 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 ...-tablet1_idxt +| 3808: 31 5f 69 64 78 04 43 52 45 41 54 45 20 54 41 42 1_idx.CREATE TAB +| 3824: 4c 45 20 27 74 31 5f 69 64 78 27 28 73 65 67 69 LE 't1_idx'(segi +| 3840: 64 2c 20 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 d, term, pgno, P +| 3856: 52 49 4d 41 52 59 20 4b 45 59 28 73 65 67 69 64 RIMARY KEY(segid +| 3872: 2c 20 74 65 72 6d 29 29 20 57 49 54 48 4f 55 54 , term)) WITHOUT +| 3888: 20 52 4f 57 49 44 55 03 07 17 1b 1b 01 81 01 74 ROWIDU........t +| 3904: 61 62 6c 65 74 31 5f 64 61 74 61 74 31 5f 64 61 ablet1_datat1_da +| 3920: 74 61 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 ta.CREATE TABLE +| 3936: 27 74 31 5f 64 61 74 61 27 28 69 64 20 49 4e 54 't1_data'(id INT +| 3952: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY +| 3968: 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 38 02 06 , block BLOB)8.. +| 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR +| 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB +| 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 LE t1 USING fts5 +| 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c)......... +| page 3 offset 8192 +| 0: 0d 00 00 00 03 0c 94 00 0f e6 0f ef 0c 94 00 00 ................ +| 3216: 00 00 00 00 86 4a 84 80 80 80 80 01 04 00 8d 18 .....J.......... +| 3232: 00 00 01 bb 02 30 30 01 02 06 01 02 06 01 02 06 .....00......... +| 3248: 1f 02 03 01 02 03 01 02 03 01 08 32 30 31 36 30 ...........20160 +| 3264: 36 30 39 01 02 07 01 02 07 01 02 07 01 01 34 01 609...........4. +| 3280: 02 05 01 02 05 01 02 05 01 01 35 01 02 04 01 02 ..........5..... +| 3296: 04 01 02 04 02 07 30 30 30 30 30 30 30 1c 02 04 ......0000000... +| 3312: 01 02 04 01 02 04 01 06 62 69 6e 61 72 79 03 06 ........binary.. +| 3328: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................ +| 3344: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................ +| 3360: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................ +| 3376: 03 06 01 02 02 03 06 01 02 02 01 08 63 6f 6d 70 ............comp +| 3392: 69 6c 65 72 01 02 02 01 02 02 01 02 02 01 06 64 iler...........d +| 3408: 62 73 74 61 74 07 02 03 01 02 03 01 02 03 02 04 bstat........... +| 3424: 65 62 75 67 04 02 02 01 02 02 01 02 02 01 06 65 ebug...........e +| 3440: 6b b1 62 6c 65 07 02 02 01 02 02 01 02 02 01 02 k.ble........... +| 3456: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 02 ................ +| 3472: 01 02 02 01 02 02 05 02 02 01 02 02 01 02 02 01 ................ +| 3488: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................ +| 3504: 02 01 02 02 02 08 78 74 65 6e 73 69 6f 6e 1f 02 ......xtension.. +| 3520: 04 01 02 04 01 02 04 01 04 66 74 73 34 1a 02 03 .........fts4... +| 3536: 01 02 03 01 02 03 04 01 35 0d 02 03 01 02 03 01 ........5....... +| 3552: 02 03 01 03 67 63 63 01 02 03 01 02 03 01 02 03 ....gcc......... +| 3568: 02 06 65 6f 70 6f 6c 79 10 02 03 01 02 03 01 02 ..eopoly........ +| 3584: 03 01 05 6a 73 6f 6e 31 13 02 03 01 02 03 01 02 ...json1........ +| 3600: 03 01 04 6c 6f 61 64 1f 02 03 01 02 03 01 02 03 ...load......... +| 3616: 01 03 6d 61 78 1c 02 02 01 02 02 01 02 02 02 05 ..max........... +| 3632: 65 6d 6f 72 79 1c 02 03 01 02 03 01 02 03 04 04 emory........... +| 3648: 73 79 73 35 16 02 03 01 02 03 01 02 03 01 06 6e sys5...........n +| 3664: 6f 63 61 73 65 02 06 01 02 02 03 06 01 02 02 03 ocase........... +| 3680: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 ................ +| 3696: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................ +| 3712: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................ +| 3728: 02 01 04 6f 6d 69 74 1f 02 02 01 02 02 01 02 01 ...omit......... +| 3744: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f1 02 ................ +| 3760: 58 81 96 4d 01 06 01 02 02 03 06 01 02 02 03 06 X..M............ +| 3776: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................ +| 3792: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................ +| 3808: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................ +| 3824: 01 0a 74 68 72 65 61 64 73 61 66 65 22 02 02 01 ..threadsafe.... +| 3840: 02 02 01 02 02 01 04 76 74 61 62 07 02 04 01 02 .......vtab..... +| 3856: 04 01 02 04 01 01 78 01 06 01 01 02 01 06 01 01 ......x......... +| 3872: 02 01 06 01 c6 02 01 06 01 01 02 01 06 01 01 02 ................ +| 3888: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................ +| 3904: 06 01 01 02 00 f6 01 01 02 01 06 01 01 02 01 06 ................ +| 3920: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................ +| 3936: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................ +| 3952: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................ +| 3968: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................ +| 3984: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................ +| 4000: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................ +| 4016: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................ +| 4032: 02 01 06 01 01 02 01 06 01 01 02 04 15 13 0c 0c ................ +| 4048: 12 44 13 11 0f 47 13 0f 0c 0e 11 10 0f 0e 10 0f .D...G.......... +| 4064: 44 0f 10 40 15 0f 07 01 03 00 14 24 5a 24 24 0f D..@.......$Z$$. +| 4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............ +| page 4 offset 12288 +| 0: 0a 00 00 00 01 0f fa 00 0f fa 00 00 00 00 00 00 ................ +| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................ +| page 7 offset 24576 +| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................ +| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version. +| end crash-c69fcaceff1e50.db +}]} {} + +do_catchsql_test 3.1 { + UPDATE t1 SET b=quote(zeroblob(200)) WHERE a MATCH 'thra*T'; +} {1 {database disk image is malformed}} + +#------------------------------------------------------------------------- +reset_db +do_test 4.0 { + sqlite3 db {} + db deserialize [decode_hexdb { +.open --hexdb +| size 24576 pagesize 4096 filename crash-ef6738247b1344.db +| page 1 offset 0 +| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. +| 16: 10 00 01 01 00 40 20 20 00 10 00 06 40 00 00 06 .....@ ....@... +| 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 00 ................ +| 96: 00 00 00 00 0d 00 00 00 06 0e 0f 00 0f aa 0f 53 ...............S +| 112: 0e e8 0e 8b 0e 33 0e 0f 00 00 00 00 00 00 00 00 .....3.......... +| 3584: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 22 ................ +| 3600: 06 06 17 11 11 01 31 74 61 62 6c 65 62 62 62 62 ......1tablebbbb +| 3616: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 62 62 .CREATE TABLE bb +| 3632: 28 61 29 56 05 06 17 1f 1f 01 7d 74 61 62 6c 65 (a)V.......table +| 3648: 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 6f 6e 66 t1_configt1_conf +| 3664: 69 67 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 ig.CREATE TABLE +| 3680: 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b 20 50 52 't1_config'(k PR +| 3696: 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 20 57 49 IMARY KEY, v) WI +| 3712: 54 48 4f 55 54 20 52 4f 57 49 44 5b 04 07 17 21 THOUT ROWID[...! +| 3728: 21 01 81 01 74 61 62 6c 65 74 31 5f 64 6f 63 73 !...tablet1_docs +| 3744: 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 04 43 52 izet1_docsize.CR +| 3760: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 64 EATE TABLE 't1_d +| 3776: 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 54 45 47 ocsize'(id INTEG +| 3792: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY, +| 3808: 73 7a 20 42 4c 4f 42 29 69 03 07 17 19 19 01 81 sz BLOB)i....... +| 3824: 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 31 5f 69 -tablet1_idxt1_i +| 3840: 64 78 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 dx.CREATE TABLE +| 3856: 27 74 31 5f 69 64 78 27 28 73 65 67 69 64 2c 20 't1_idx'(segid, +| 3872: 74 65 72 6d 2c 20 6f 67 6e 6f 2c 20 50 52 49 4d term, ogno, PRIM +| 3888: 41 52 59 20 4b 45 59 28 73 65 67 69 64 2c 20 74 ARY KEY(segid, t +| 3904: 65 72 6d 29 29 20 57 49 54 48 4f 55 54 20 52 4f erm)) WITHOUT RO +| 3920: 57 49 44 55 35 07 17 1b 1b 01 81 01 74 61 62 6c WIDU5.......tabl +| 3936: 65 74 31 5f 64 61 74 61 74 31 5f 64 61 74 61 02 et1_datat1_data. +| 3952: 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 CREATE TABLE 't1 +| 3968: 5f 64 61 74 61 27 28 69 64 20 49 4e 54 45 47 45 _data'(id INTEGE +| 3984: 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 R PRIMARY KEY, b +| 4000: 6c 6f 63 6b 20 42 4c 4f 42 29 54 01 07 17 11 11 lock BLOB)T..... +| 4016: 08 81 15 74 61 62 6c 65 74 31 74 31 43 52 45 41 ...tablet1t1CREA +| 4032: 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 4c 45 TE VIRTUAL TABLE +| 4048: 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 28 61 t1 USING fts5(a +| 4064: 2c 62 2c 70 72 65 66 69 78 3d 22 31 2c 32 2c 33 ,b,prefix=.1,2,3 +| 4080: 2c 34 22 2c 20 63 6f 6e 74 65 6e 74 3d 22 22 29 ,4., content=..) +| page 2 offset 4096 +| 0: 0d 0b 6a 00 37 09 4c 02 0f e7 09 4c 0f c6 0f a4 ..j.7.L....L.... +| 16: 0f 88 0f 6d 0f 4b 0f 2c 0f 0e 0e ec 0e cd 0e ad ...m.K.,........ +| 32: 0e 8e 0e 6c 0e 4b 0e 29 0e 08 0d e6 0d c4 0d b5 ...l.K.)........ +| 48: 0d 97 0d 76 0d 54 0d 31 0d 15 0c f3 0c d3 0c b5 ...v.T.1........ +| 64: 0c 95 0c 73 0c 54 0c 32 0c 10 0b ee 0b cc 0b b0 ...s.T.2........ +| 80: 0b 8d 0b 7e 0b 48 0b 2e 0b 0b 0a ef 0a cc 0a 00 ...~.H.......... +| 2368: 00 00 00 00 00 00 00 00 00 00 00 00 15 0a 03 00 ................ +| 2384: 30 00 00 00 01 01 03 35 00 03 01 01 12 02 01 12 0......5........ +| 2400: 03 01 11 1c 8c 80 80 80 80 10 02 9c 3e 00 00 00 ............>... +| 2416: 17 01 05 05 34 74 61 62 6c 03 02 03 01 04 77 68 ....4tabl.....wh +| 2432: 65 72 03 02 06 09 1b 8c 80 80 80 80 0f 03 00 3c er.............< +| 2448: 00 00 00 16 05 34 66 74 73 34 03 02 02 01 04 6e .....4fts4.....n +| 2464: 75 6d 62 03 06 01 04 09 1b 8c 80 80 80 80 0e 03 umb............. +| 2480: 00 3c 00 00 00 16 04 33 74 68 65 03 06 01 01 04 .<.....3the..... +| 2496: 01 03 77 68 65 03 02 04 04 0a 1b 8c 80 80 80 80 ..whe........... +| 2512: 0d 03 00 3c 00 00 00 16 04 33 6e 75 6d 03 06 01 ...<.....3num... +| 2528: 01 05 01 03 74 61 62 03 02 03 04 0a 19 8c 80 80 ....tab......... +| 2544: 80 80 0c 03 00 38 00 00 00 14 03 32 77 68 03 02 .....8.....2wh.. +| 2560: 04 00 04 33 66 74 73 03 12 02 04 07 18 8c 80 80 ...3fts......... +| 2576: 80 80 0b 03 00 36 00 00 00 13 03 32 74 61 03 02 .....6.....2ta.. +| 2592: 03 02 01 68 03 06 01 01 04 04 07 1b 8c 80 80 80 ...h............ +| 2608: 80 0a 03 00 3c 00 00 00 16 03 32 6e 75 03 06 01 ....<.....2nu... +| 2624: 01 05 01 02 6f 66 03 06 01 01 06 04 09 19 8c 80 ....of.......... +| 2640: 82 d0 80 09 03 00 38 00 00 00 14 03 32 66 74 03 ......8.....2ft. +| 2656: 02 02 01 02 69 73 03 06 01 01 03 04 07 18 8c 80 ....is.......... +| 2672: 80 80 80 08 03 00 36 00 00 00 13 02 31 74 03 08 ......6.....1t.. +| 2688: 03 01 01 04 01 01 77 03 02 04 04 09 1a 8c 80 80 ......w......... +| 2704: 80 80 07 03 00 3a 00 00 00 15 02 31 6e 03 08 01 .....:.....1n... +| 2720: 01 02 05 01 01 6f 03 06 01 01 06 04 09 18 8c 80 .....o.......... +| 2736: 81 80 80 06 03 00 36 00 00 00 13 04 12 31 66 03 ......6......1f. +| 2752: 02 02 01 01 69 03 06 01 01 03 05 06 1c 8c 80 80 ....i........... +| 2768: 80 80 05 03 00 3e 00 00 00 17 04 30 74 68 65 03 .....>.....0the. +| 2784: 06 01 01 04 01 05 77 68 65 72 65 03 02 04 0a 15 ......where..... +| 2800: 8c 80 65 80 80 04 03 00 30 00 00 00 11 01 01 06 ..e.....0....... +| 2816: 06 30 74 61 62 6c 65 03 02 03 07 1c 8c 80 80 80 .0table......... +| 2832: 80 03 03 00 3e 00 00 00 17 07 30 6e 75 6d 62 65 ....>.....0numbe +| 2848: 72 03 06 01 01 05 01 02 6f 66 03 06 04 0d 13 8c r.......of...... +| 2864: 80 80 80 80 02 03 00 2c 00 00 00 0f fc 01 03 02 .......,........ +| 2880: 30 6e 03 06 01 00 f2 07 1b 8c 80 80 80 80 01 03 0n.............. +| 2896: 00 3c 00 00 00 16 08 30 66 74 73 34 61 75 78 03 .<.....0fts4aux. +| 2912: 03 02 01 02 69 73 03 06 04 0c 00 00 00 18 ea 00 ....is.......... +| 2928: 00 00 01 01 02 24 00 02 01 01 12 02 01 12 08 88 .....$.......... +| 2944: 80 80 80 80 12 03 00 12 10 00 00 05 02 1c 88 80 ................ +| 2960: 80 80 80 11 03 00 3e 00 00 00 17 05 34 72 6f 77 ......>.....4row +| 2976: 73 02 06 01 01 05 01 04 74 68 65 72 02 02 04 0b s.......ther.... +| 2992: 15 88 80 80 80 80 10 03 00 2f ff ff f0 11 02 01 ........./...... +| 3008: 01 07 05 34 62 65 74 77 02 02 04 08 1b 88 80 80 ...4betw........ +| 3024: 80 80 0f cf 00 3c 00 00 00 16 04 04 33 72 6f 77 .....<......3row +| 3040: 02 06 01 01 05 01 03 74 68 65 02 08 05 0a 1b 88 .......the...... +| 3056: 80 80 80 80 0d 03 00 3c 00 00 00 16 00 01 02 04 .......<........ +| 3072: 33 61 72 65 02 02 03 01 03 62 65 74 02 02 07 08 3are.....bet.... +| 3088: 1b 88 80 80 80 80 0d 03 00 3c 00 00 00 16 03 32 .........<.....2 +| 3104: 74 68 02 08 02 01 01 07 00 04 33 61 6e 64 02 06 th........3and.. +| 3120: 04 0a 1b 88 80 80 80 80 0c 03 00 3c 00 00 00 16 ...........<.... +| 3136: 03 32 69 6e 02 06 01 01 06 01 02 72 6f 02 06 01 .2in.......ro... +| 3152: 01 05 04 09 18 88 80 80 80 80 0b 03 00 36 00 00 .............6.. +| 3168: 00 13 02 03 32 61 72 02 02 03 01 02 62 65 02 02 ....2ar.....be.. +| 3184: 04 05 07 1b 88 80 80 80 80 0a 03 00 3c 00 00 00 ............<... +| 3200: 16 12 31 74 02 08 02 01 01 07 00 03 32 61 6e 02 ..1t........2an. +| 3216: 06 01 01 04 09 19 88 80 80 80 80 09 03 00 38 00 ..............8. +| 3232: 00 00 14 02 31 6e 02 06 01 01 03 01 01 72 02 06 ....1n.......r.. +| 3248: 01 01 05 04 08 17 78 80 80 80 80 08 03 00 34 10 ......x.......4. +| 3264: 01 00 12 02 31 62 02 02 04 01 01 69 02 06 01 01 ....1b.....i.... +| 3280: 06 04 06 19 88 80 80 80 80 07 03 00 38 00 00 00 ............8... +| 3296: 14 04 02 31 32 02 02 05 01 01 61 02 08 03 01 01 ...12.....a..... +| 3312: 02 05 06 1b 88 80 80 80 80 06 03 00 3c 00 00 00 ............<... +| 3328: 16 06 30 74 68 65 72 65 e7 02 02 00 02 31 31 02 ..0there.....11. +| 3344: 06 01 01 04 0a 15 88 80 80 80 80 05 03 00 30 00 ..............0. +| 3360: 00 00 11 01 01 05 e5 30 74 68 65 02 06 01 01 07 .......0the..... +| 3376: 07 1c 88 80 80 80 80 04 03 00 3e 00 00 00 17 01 ..........>..... +| 3392: 01 06 02 30 6e 02 06 01 01 03 01 04 72 6f 77 73 ...0n.......rows +| 3408: 02 06 07 08 1b 88 80 80 80 80 03 03 00 3c 00 00 .............<.. +| 3424: 00 16 08 30 62 65 74 77 65 65 6e 02 02 04 01 02 ...0between..... +| 3440: 69 6e 02 06 04 0c 1a 88 80 80 80 80 02 03 00 3a in.............: +| 3456: 00 00 00 15 04 30 61 6e 64 02 06 01 01 02 02 02 .....0and....... +| 3472: 72 65 02 02 03 04 0a 17 88 80 80 80 80 01 03 00 re.............. +| 3488: 34 01 00 00 12 02 30 31 02 06 01 01 04 01 01 32 4.....01.......2 +| 3504: 02 02 05 04 08 08 84 80 80 80 80 12 03 00 16 00 ................ +| 3520: 00 00 05 04 1b 84 80 80 80 80 11 03 00 3c 00 00 .............<.. +| 3536: 00 16 05 34 74 61 62 6c 01 06 01 01 05 02 03 65 ...4tabl.......e +| 3552: 72 6d 01 02 04 0b 1b 84 80 80 80 80 10 03 00 3c rm.............< +| 3568: 00 00 00 16 05 34 65 61 63 68 01 02 02 01 04 70 .....4each.....p +| 3584: 72 65 73 01 02 05 04 09 1a 84 80 80 80 80 0f 03 res............. +| 3600: 00 3a 00 00 00 15 04 33 74 65 72 01 02 04 02 02 .:.....3ter..... +| 3616: 68 65 01 06 01 01 03 04 08 1b 84 80 80 80 80 0e he.............. +| 3632: 03 00 3c 00 00 00 16 04 33 70 72 65 01 02 05 01 ..<.....3pre.... +| 3648: 03 74 61 62 01 06 01 01 05 04 08 1a 84 80 80 80 .tab............ +| 3664: 80 0d 03 0d 1a 00 00 00 15 04 33 66 6e 72 01 02 ..........3fnr.. +| 3680: 02 02 02 74 73 01 06 01 01 04 04 08 1b 84 80 80 ...ts........... +| 3696: 80 80 0c 03 00 3c 00 00 00 16 03 32 74 68 01 06 .....<.....2th.. +| 3712: 01 01 03 00 04 33 65 61 63 01 02 03 04 09 18 84 .....3eac....... +| 3728: 80 80 80 80 0b 03 00 36 00 00 00 13 03 32 74 61 .......6.....2ta +| 3744: 01 06 01 01 05 02 01 65 01 02 04 04 09 19 84 80 .......e........ +| 3760: 80 80 80 0a 03 00 38 00 00 00 14 03 30 c9 6e 01 ......8.....0.n. +| 3776: 06 01 01 02 01 02 70 72 01 02 05 04 09 18 84 80 ......pr........ +| 3792: 80 80 80 09 03 00 36 00 00 00 13 03 32 66 6f 01 ......6.....2fo. +| 3808: 02 0b e2 01 74 01 06 01 01 04 04 07 1b 84 80 80 ....t........... +| 3824: 86 f0 08 03 00 3c 00 00 00 16 02 31 74 01 0a 04 .....<.....1t... +| 3840: 01 01 03 04 00 03 32 65 61 01 02 03 04 0a 17 84 ......2ea....... +| 3856: 80 80 80 80 07 03 00 34 00 00 00 12 02 31 69 01 .......4.....1i. +| 3872: 06 01 01 02 01 01 70 01 02 05 04 08 18 84 80 80 ......p......... +| 3888: 80 80 06 03 00 36 00 00 00 13 02 31 65 01 02 03 .....6.....1e... +| 3904: 01 01 66 01 08 02 01 01 04 04 06 1b 84 80 80 80 ..f............. +| 3920: 80 05 03 00 3c 00 00 00 16 05 30 74 65 72 6d 01 ....<.....0term. +| 3936: 02 04 02 02 68 65 01 06 01 01 03 04 09 14 84 80 ....he.......... +| 3952: 80 80 80 04 03 00 2e 00 00 00 10 06 30 74 61 62 ............0tab +| 3968: 6c 65 01 06 01 01 05 04 15 84 7f 80 80 80 03 03 le.............. +| 3984: 00 30 00 00 00 11 02 08 30 70 72 65 73 65 6e 74 .0......0present +| 4000: 01 02 05 05 1b 84 80 22 80 80 02 03 00 3c 00 00 .............<.. +| 4016: 00 16 04 30 66 74 73 01 06 01 01 04 01 02 69 6e ...0fts.......in +| 4032: 01 06 01 01 04 0a 1a 84 80 80 80 80 01 03 00 3a ...............: +| 4048: 00 00 00 15 05 30 65 61 63 68 01 02 03 01 03 66 .....0each.....f +| 4064: 6f 72 01 02 02 04 09 06 01 03 00 12 03 0b 0f 00 or.............. +| 4080: 00 08 8c 80 80 80 80 11 03 00 16 00 00 00 05 04 ................ +| page 3 offset 8192 +| 0: 0a 00 00 00 32 0e 4f 00 0f fa 0f f1 0f e9 0f e1 ....2.O......... +| 16: 0f d8 0f d1 0f c9 0f c1 0f b9 0f b1 0f a9 0f a0 ................ +| 32: 0f 98 0f 90 0f 87 0f 80 0f 78 0f 71 0f 68 0f 5f .........x.q.h._ +| 48: 0f 56 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 .V.............. +| 3392: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 ................ +| 3408: 04 01 10 01 03 34 74 20 07 04 01 0e 01 03 34 1e .....4t ......4. +| 3424: 09 04 01 12 01 03 33 74 68 1c 08 04 01 10 01 03 ......3th....... +| 3440: 34 6e 1a 08 04 01 10 01 03 32 67 18 08 04 01 10 4n.......2g..... +| 3456: 01 03 32 74 16 08 04 01 10 01 03 32 6e 14 07 04 ..2t.......2n... +| 3472: 01 0e 01 03 32 12 08 04 01 10 01 03 31 74 10 08 ....2.......1t.. +| 3488: 04 01 10 01 03 31 6e 0e 07 04 01 0e 01 03 31 0c .....1n.......1. +| 3504: 09 04 01 12 01 03 30 74 68 0a 08 04 01 10 01 03 ......0th....... +| 3520: 30 74 08 09 04 01 12 01 03 30 6e 75 06 08 04 01 0t.......0nu.... +| 3536: 10 01 03 30 6e 04 06 04 01 0c 01 03 02 08 04 01 ...0n........... +| 3552: 10 01 02 34 72 22 07 04 01 0e 01 02 34 20 08 04 ...4r.......4 .. +| 3568: 01 10 01 02 33 72 1e 09 04 01 12 01 02 33 61 72 ....3r.......3ar +| 3584: 1c 18 04 01 10 01 02 32 74 1a 08 04 01 10 01 02 .......2t....... +| 3600: 32 69 18 09 04 01 12 01 02 32 61 72 16 08 04 01 2i.......2ar.... +| 3616: 10 01 02 31 74 2a 08 04 01 0f 01 02 31 6e 12 0a ...1t*......1n.. +| 3632: d4 01 10 01 02 31 62 10 08 04 01 10 01 02 31 32 .....1b.......12 +| 3648: 0e 0b 04 01 16 01 02 30 74 68 65 72 0c 08 04 01 .......0ther.... +| 3664: 10 01 02 30 74 0a 08 04 01 10 01 02 30 6e 08 08 ...0t.......0n.. +| 3680: 04 01 10 01 02 30 62 06 08 04 01 10 01 02 30 61 .....0b.......0a +| 3696: 04 06 03 f1 0c 01 02 02 07 04 09 10 01 34 74 22 .............4t. +| 3712: 06 04 09 0e 01 34 20 08 04 09 12 01 33 74 65 1e .....4 .....3te. +| 3728: 07 04 09 10 01 33 70 1c 07 04 09 10 01 33 66 1a .....3p......3f. +| 3744: 08 04 09 12 01 32 74 68 18 07 04 09 10 01 32 74 .....2th......2t +| 3760: 16 07 04 09 10 01 32 69 14 07 04 09 10 01 32 66 ......2i......2f +| 3776: 12 07 04 09 10 01 31 74 10 07 04 09 10 01 31 69 ......1t......1i +| 3792: 0e 06 04 09 0e 01 31 0c 08 04 09 12 01 30 74 65 ......1......0te +| 3808: 0a 07 04 09 10 01 30 74 08 07 04 09 10 01 30 70 ......0t......0p +| 3824: 06 08 04 09 1e 61 30 66 74 04 05 00 00 00 00 00 .....a0ft....... +| page 4 offset 12288 +| 4064: 00 00 00 00 00 00 00 00 00 00 00 05 03 03 00 10 ................ +| 4080: 03 05 05 02 03 00 10 04 06 05 01 03 00 10 04 04 ................ +| page 5 offset 16384 +| 0: 0a 00 00 00 02 0f eb 00 0f eb 0f f4 00 00 00 00 ................ +| 4064: 00 00 00 00 00 00 00 00 00 00 00 08 03 15 01 70 ...............p +| 4080: 67 73 7a 18 0b 03 1b 01 76 65 72 73 69 6f 6e 04 gsz.....version. +| end crash-ef6738247b1344.db +}]} {} + + +do_catchsql_test 4.1 { + BEGIN; + REPLACE INTO t1(rowid,b,a,rowid) VALUES(200,1,2,3); +} {1 {database disk image is malformed}} + +do_catchsql_test 4.2 { + INSERT INTO t1(t1) VALUES('delete-all'); +} {1 {database disk image is malformed}} +do_catchsql_test 4.3 { + REPLACE INTO t1(rowid,b,rowid,a) VALUES(200,1,2,3); +} {1 {database disk image is malformed}} +do_catchsql_test 4.4 { + REPLACE INTO t1(rowid,b,a,rowid) VALUES(0,1,2,3); +} {1 {database disk image is malformed}} +do_catchsql_test 4.5 { + REPLACE INTO t1(rowid,a,b,rowid) VALUES(200,1,2,3); +} {1 {database disk image is malformed}} + +sqlite3_fts5_may_be_corrupt 0 +finish_test + diff --git a/ext/fts5/test/fts5corrupt6.test b/ext/fts5/test/fts5corrupt6.test new file mode 100644 index 00000000..6403d3a4 --- /dev/null +++ b/ext/fts5/test/fts5corrupt6.test @@ -0,0 +1,54 @@ +# 2015 Apr 24 +# +# 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 tests that FTS5 handles corrupt databases (i.e. internal +# inconsistencies in the backing tables) correctly. In this case +# "correctly" means without crashing. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5corrupt6 + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} +sqlite3_fts5_may_be_corrupt 1 +database_may_be_corrupt + +proc editblock {block} { + binary format Sa* 20000 [string range $block 2 end] +} +db func editblock editblock + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE ft USING fts5(abc, def); + WITH a(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM a WHERE i<1000 + ) + INSERT INTO ft SELECT + 'abc abc abc abc abc abc abc abc abc abc', + 'def def def def def def def def def def' + FROM a; + UPDATE ft_data SET block = editblock(block) WHERE id=( + SELECT id FROM ft_data ORDER BY id LIMIT 1 OFFSET 5 + ); +} + +do_catchsql_test 1.1 { + SELECT rowid FROM ft('def') ORDER BY rowid DESC LIMIT 1 OFFSET 9999; +} {1 {database disk image is malformed}} + + +sqlite3_fts5_may_be_corrupt 0 +finish_test + diff --git a/ext/fts5/test/fts5detail.test b/ext/fts5/test/fts5detail.test index cf4b718b..267ce618 100644 --- a/ext/fts5/test/fts5detail.test +++ b/ext/fts5/test/fts5detail.test @@ -212,6 +212,10 @@ do_catchsql_test 4.1 { SELECT * FROM t4('a:a') } {1 {fts5: column queries are not supported (detail=none)}} +do_catchsql_test 4.2 { + SELECT * FROM t4('a:a &') +} {1 {fts5: syntax error near "&"}} + #------------------------------------------------------------------------- # Test that for the same content detail=none uses less space than # detail=col, and that detail=col uses less space than detail=full diff --git a/ext/fts5/test/fts5misc.test b/ext/fts5/test/fts5misc.test index 9abc92b2..e354d20e 100644 --- a/ext/fts5/test/fts5misc.test +++ b/ext/fts5/test/fts5misc.test @@ -323,5 +323,34 @@ do_execsql_test 12.3 { SELECT * FROM t2 JOIN ft USING (ft) } {3 4 b b} +#------------------------------------------------------------------------- +# Forum post https://sqlite.org/forum/forumpost/21127c1160 +# +reset_db +sqlite3_db_config db DEFENSIVE 1 + +do_execsql_test 13.0 { + CREATE TABLE a (id INTEGER PRIMARY KEY, name TEXT); + CREATE VIRTUAL TABLE b USING fts5(name); + CREATE TRIGGER a_trigger AFTER INSERT ON a BEGIN + INSERT INTO b (name) VALUES ('foo'); + END; +} + +do_test 13.1 { + set ::STMT [ + sqlite3_prepare db "INSERT INTO a VALUES (1, 'foo') RETURNING id;" -1 dummy + ] + sqlite3_step $::STMT +} {SQLITE_ROW} + +do_test 13.2 { + sqlite3_finalize $::STMT +} {SQLITE_OK} + +do_test 13.3 { + sqlite3_errmsg db +} {not an error} + finish_test diff --git a/ext/fts5/test/fts5vocab2.test b/ext/fts5/test/fts5vocab2.test index 45d65714..6f7aad32 100644 --- a/ext/fts5/test/fts5vocab2.test +++ b/ext/fts5/test/fts5vocab2.test @@ -234,4 +234,53 @@ ifcapable fts3 { } {1 {no such fts5 table: main.nosuchtable}} } +#------------------------------------------------------------------------- +# Check that the fts5 table cannot be written while there are vocab +# cursors open. +reset_db +do_execsql_test 5.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a); + CREATE VIRTUAL TABLE v1 USING fts5vocab(t1, instance); + INSERT INTO t1 VALUES('one'), ('two'), ('three'), ('four'); +} + +do_test 5.1 { + list [catch { + db eval { SELECT * FROM v1 } { + db eval {INSERT INTO t1 VALUES('five')} + } + } msg] $msg +} {1 {query aborted}} + +do_execsql_test 5.2 { + SELECT * FROM t1 +} {one two three four five} + +#------------------------------------------------------------------------- +# Check that the fts5 table cannot be written while there are vocab +# cursors open. +reset_db +do_execsql_test 5.0 { + CREATE VIRTUAL TABLE t1 USING fts5(a); + CREATE VIRTUAL TABLE v1 USING fts5vocab(t1, instance); + WITH s(i) AS ( + VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<10000 + ) + INSERT INTO t1 SELECT + 'State Emergency Service (SES), Rural Fire Service (RFS) and Volunteers' + FROM s; +} + +do_catchsql_test 5.1 { + INSERT INTO t1 SELECT rowid FROM v1 +} {1 {query aborted}} + +do_catchsql_test 5.2 { + DELETE FROM t1 WHERE rowid>100; + INSERT INTO t1 SELECT randomblob(3000) FROM v1 +} {1 {query aborted}} + + finish_test + + diff --git a/ext/fts5/tool/mkfts5c.tcl b/ext/fts5/tool/mkfts5c.tcl index 797811d4..b1a55fa4 100644 --- a/ext/fts5/tool/mkfts5c.tcl +++ b/ext/fts5/tool/mkfts5c.tcl @@ -60,7 +60,8 @@ proc fts5_source_id {zDir} { set L [split [readfile [file join $top manifest]]] set date [lindex $L [expr [lsearch -exact $L D]+1]] - set date [string range $date 0 [string last . $date]-1] + set idx [expr {[string last . $date]-1}] + set date [string range $date 0 $idx] set date [string map {T { }} $date] return "fts5: $date $uuid" diff --git a/ext/misc/carray.c b/ext/misc/carray.c index b8cda21b..b6eb0453 100644 --- a/ext/misc/carray.c +++ b/ext/misc/carray.c @@ -56,14 +56,24 @@ SQLITE_EXTENSION_INIT1 #include #include - + /* Allowed values for the mFlags parameter to sqlite3_carray_bind(). ** Must exactly match the definitions in carray.h. */ -#define CARRAY_INT32 0 /* Data is 32-bit signed integers */ -#define CARRAY_INT64 1 /* Data is 64-bit signed integers */ -#define CARRAY_DOUBLE 2 /* Data is doubles */ -#define CARRAY_TEXT 3 /* Data is char* */ +#ifndef CARRAY_INT32 +# define CARRAY_INT32 0 /* Data is 32-bit signed integers */ +# define CARRAY_INT64 1 /* Data is 64-bit signed integers */ +# define CARRAY_DOUBLE 2 /* Data is doubles */ +# define CARRAY_TEXT 3 /* Data is char* */ +#endif + +#ifndef SQLITE_API +# ifdef _WIN32 +# define SQLITE_API __declspec(dllexport) +# else +# define SQLITE_API +# endif +#endif #ifndef SQLITE_OMIT_VIRTUALTABLE @@ -400,10 +410,7 @@ static void carrayBindDel(void *pPtr){ ** Invoke this interface in order to bind to the single-argument ** version of CARRAY(). */ -#ifdef _WIN32 -__declspec(dllexport) -#endif -int sqlite3_carray_bind( +SQLITE_API int sqlite3_carray_bind( sqlite3_stmt *pStmt, int idx, void *aData, @@ -457,7 +464,7 @@ int sqlite3_carray_bind( z += n+1; } }else{ - memcpy(pNew->aData, aData, sz*nData); + memcpy(pNew->aData, aData, sz); } pNew->xDel = sqlite3_free; }else{ @@ -498,10 +505,7 @@ static void inttoptrFunc( #endif /* SQLITE_OMIT_VIRTUALTABLE */ -#ifdef _WIN32 -__declspec(dllexport) -#endif -int sqlite3_carray_init( +SQLITE_API int sqlite3_carray_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi diff --git a/ext/misc/carray.h b/ext/misc/carray.h index e490bf24..63df0066 100644 --- a/ext/misc/carray.h +++ b/ext/misc/carray.h @@ -1,12 +1,32 @@ /* +** 2020-11-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. +** +************************************************************************* +** ** Interface definitions for the CARRAY table-valued function ** extension. */ +#ifndef _CARRAY_H +#define _CARRAY_H + +#include "sqlite3.h" /* Required for error code definitions */ + +#ifdef __cplusplus +extern "C" { +#endif + /* Use this interface to bind an array to the single-argument version ** of CARRAY(). */ -int sqlite3_carray_bind( +SQLITE_API int sqlite3_carray_bind( sqlite3_stmt *pStmt, /* Statement to be bound */ int i, /* Parameter index */ void *aData, /* Pointer to array data */ @@ -21,3 +41,10 @@ int sqlite3_carray_bind( #define CARRAY_INT64 1 /* Data is 64-bit signed integers */ #define CARRAY_DOUBLE 2 /* Data is doubles */ #define CARRAY_TEXT 3 /* Data is char* */ + +#ifdef __cplusplus +} /* end of the 'extern "C"' block */ +#endif + +#endif /* ifndef _CARRAY_H */ + diff --git a/ext/misc/fileio.c b/ext/misc/fileio.c index d977d41d..c9988f60 100644 --- a/ext/misc/fileio.c +++ b/ext/misc/fileio.c @@ -72,6 +72,11 @@ ** $path is a relative path, then $path is interpreted relative to $dir. ** And the paths returned in the "name" column of the table are also ** relative to directory $dir. +** +** Notes on building this extension for Windows: +** Unless linked statically with the SQLite library, a preprocessor +** symbol, FILEIO_WIN32_DLL, must be #define'd to create a stand-alone +** DLL form of this extension for WIN32. See its use below for details. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 @@ -225,6 +230,22 @@ static sqlite3_uint64 fileTimeToUnixTime( return (fileIntervals.QuadPart - epochIntervals.QuadPart) / 10000000; } + +#if defined(FILEIO_WIN32_DLL) && (defined(_WIN32) || defined(WIN32)) +# /* To allow a standalone DLL, use this next replacement function: */ +# undef sqlite3_win32_utf8_to_unicode +# define sqlite3_win32_utf8_to_unicode utf8_to_utf16 +# +LPWSTR utf8_to_utf16(const char *z){ + int nAllot = MultiByteToWideChar(CP_UTF8, 0, z, -1, NULL, 0); + LPWSTR rv = sqlite3_malloc(nAllot * sizeof(WCHAR)); + if( rv!=0 && 0 < MultiByteToWideChar(CP_UTF8, 0, z, -1, rv, nAllot) ) + return rv; + sqlite3_free(rv); + return 0; +} +#endif + /* ** This function attempts to normalize the time values found in the stat() ** buffer to UTC. This is necessary on Win32, where the runtime library @@ -998,3 +1019,11 @@ int sqlite3_fileio_init( } return rc; } + +#if defined(FILEIO_WIN32_DLL) && (defined(_WIN32) || defined(WIN32)) +/* To allow a standalone DLL, make test_windirent.c use the same + * redefined SQLite API calls as the above extension code does. + * Just pull in this .c to accomplish this. As a beneficial side + * effect, this extension becomes a single translation unit. */ +# include "test_windirent.c" +#endif diff --git a/ext/misc/ieee754.c b/ext/misc/ieee754.c index 6cdd79a4..66d946f3 100644 --- a/ext/misc/ieee754.c +++ b/ext/misc/ieee754.c @@ -194,7 +194,11 @@ static void ieee754func( e += 1075; if( e<=0 ){ /* Subnormal */ - m >>= 1-e; + if( 1-e >= 64 ){ + m = 0; + }else{ + m >>= 1-e; + } e = 0; }else if( e>0x7ff ){ e = 0x7ff; diff --git a/ext/misc/json1.c b/ext/misc/json1.c index 077d02d9..7fcd7342 100644 --- a/ext/misc/json1.c +++ b/ext/misc/json1.c @@ -96,7 +96,34 @@ static const char jsonIsSpace[] = { typedef unsigned int u32; typedef unsigned short int u16; typedef unsigned char u8; +# if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) +# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 +# endif +# if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) +# define ALWAYS(X) (1) +# define NEVER(X) (0) +# elif !defined(NDEBUG) +# define ALWAYS(X) ((X)?1:(assert(0),0)) +# define NEVER(X) ((X)?(assert(0),1):0) +# else +# define ALWAYS(X) (X) +# define NEVER(X) (X) +# endif +# define testcase(X) #endif +#if !defined(SQLITE_DEBUG) && !defined(SQLITE_COVERAGE_TEST) +# define VVA(X) +#else +# define VVA(X) X +#endif + +/* +** Some of the testcase() macros in this file are problematic for gcov +** in that they generate false-miss errors randomly. This is a gcov problem, +** not a problem in this case. But to work around it, we disable the +** problematic test cases for production builds. +*/ +#define json_testcase(X) /* Objects */ typedef struct JsonString JsonString; @@ -154,13 +181,14 @@ static const char * const jsonType[] = { struct JsonNode { u8 eType; /* One of the JSON_ type values */ u8 jnFlags; /* JNODE flags */ + u8 eU; /* Which union element to use */ u32 n; /* Bytes of content, or number of sub-nodes */ union { - const char *zJContent; /* Content for INT, REAL, and STRING */ - u32 iAppend; /* More terms for ARRAY and OBJECT */ - u32 iKey; /* Key for ARRAY objects in json_tree() */ - u32 iReplace; /* Replacement content for JNODE_REPLACE */ - JsonNode *pPatch; /* Node chain of patch for JNODE_PATCH */ + const char *zJContent; /* 1: Content for INT, REAL, and STRING */ + u32 iAppend; /* 2: More terms for ARRAY and OBJECT */ + u32 iKey; /* 3: Key for ARRAY objects in json_tree() */ + u32 iReplace; /* 4: Replacement content for JNODE_REPLACE */ + JsonNode *pPatch; /* 5: Node chain of patch for JNODE_PATCH */ } u; }; @@ -438,11 +466,14 @@ static void jsonRenderNode( JsonString *pOut, /* Write JSON here */ sqlite3_value **aReplace /* Replacement values */ ){ + assert( pNode!=0 ); if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){ - if( pNode->jnFlags & JNODE_REPLACE ){ + if( (pNode->jnFlags & JNODE_REPLACE)!=0 && ALWAYS(aReplace!=0) ){ + assert( pNode->eU==4 ); jsonAppendValue(pOut, aReplace[pNode->u.iReplace]); return; } + assert( pNode->eU==5 ); pNode = pNode->u.pPatch; } switch( pNode->eType ){ @@ -461,6 +492,7 @@ static void jsonRenderNode( } case JSON_STRING: { if( pNode->jnFlags & JNODE_RAW ){ + assert( pNode->eU==1 ); jsonAppendString(pOut, pNode->u.zJContent, pNode->n); break; } @@ -468,6 +500,7 @@ static void jsonRenderNode( } case JSON_REAL: case JSON_INT: { + assert( pNode->eU==1 ); jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n); break; } @@ -483,6 +516,7 @@ static void jsonRenderNode( j += jsonNodeSize(&pNode[j]); } if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; + assert( pNode->eU==2 ); pNode = &pNode[pNode->u.iAppend]; j = 1; } @@ -503,6 +537,7 @@ static void jsonRenderNode( j += 1 + jsonNodeSize(&pNode[j+1]); } if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; + assert( pNode->eU==2 ); pNode = &pNode[pNode->u.iAppend]; j = 1; } @@ -582,7 +617,9 @@ static void jsonReturn( } case JSON_INT: { sqlite3_int64 i = 0; - const char *z = pNode->u.zJContent; + const char *z; + assert( pNode->eU==1 ); + z = pNode->u.zJContent; if( z[0]=='-' ){ z++; } while( z[0]>='0' && z[0]<='9' ){ unsigned v = *(z++) - '0'; @@ -605,14 +642,17 @@ static void jsonReturn( sqlite3_result_int64(pCtx, i); int_done: break; - int_as_real: i=0; /* no break */ deliberate_fall_through + int_as_real: ; /* no break */ deliberate_fall_through } case JSON_REAL: { double r; #ifdef SQLITE_AMALGAMATION - const char *z = pNode->u.zJContent; + const char *z; + assert( pNode->eU==1 ); + z = pNode->u.zJContent; sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8); #else + assert( pNode->eU==1 ); r = strtod(pNode->u.zJContent, 0); #endif sqlite3_result_double(pCtx, r); @@ -623,6 +663,7 @@ static void jsonReturn( ** json_insert() and json_replace() and those routines do not ** call jsonReturn() */ if( pNode->jnFlags & JNODE_RAW ){ + assert( pNode->eU==1 ); sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n, SQLITE_TRANSIENT); }else @@ -630,15 +671,18 @@ static void jsonReturn( assert( (pNode->jnFlags & JNODE_RAW)==0 ); if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){ /* JSON formatted without any backslash-escapes */ + assert( pNode->eU==1 ); sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2, SQLITE_TRANSIENT); }else{ /* Translate JSON formatted string into raw text */ u32 i; u32 n = pNode->n; - const char *z = pNode->u.zJContent; + const char *z; char *zOut; u32 j; + assert( pNode->eU==1 ); + z = pNode->u.zJContent; zOut = sqlite3_malloc( n+1 ); if( zOut==0 ){ sqlite3_result_error_nomem(pCtx); @@ -759,12 +803,13 @@ static int jsonParseAddNode( const char *zContent /* Content */ ){ JsonNode *p; - if( pParse->nNode>=pParse->nAlloc ){ + if( pParse->aNode==0 || pParse->nNode>=pParse->nAlloc ){ return jsonParseAddNodeExpand(pParse, eType, n, zContent); } p = &pParse->aNode[pParse->nNode]; p->eType = (u8)eType; p->jnFlags = 0; + VVA( p->eU = zContent ? 1 : 0 ); p->n = n; p->u.zJContent = zContent; return pParse->nNode++; @@ -832,6 +877,7 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ /* Parse array */ iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); if( iThis<0 ) return -1; + memset(&pParse->aNode[iThis].u, 0, sizeof(pParse->aNode[iThis].u)); for(j=i+1;;j++){ while( safe_isspace(z[j]) ){ j++; } if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1; @@ -1096,6 +1142,7 @@ static JsonParse *jsonParseCached( ** a match. */ static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){ + assert( pNode->eU==1 ); if( pNode->jnFlags & JNODE_RAW ){ if( pNode->n!=nKey ) return 0; return strncmp(pNode->u.zJContent, zKey, nKey)==0; @@ -1161,6 +1208,7 @@ static JsonNode *jsonLookupStep( j += jsonNodeSize(&pRoot[j]); } if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; + assert( pRoot->eU==2 ); iRoot += pRoot->u.iAppend; pRoot = &pParse->aNode[iRoot]; j = 1; @@ -1175,8 +1223,10 @@ static JsonNode *jsonLookupStep( if( pParse->oom ) return 0; if( pNode ){ pRoot = &pParse->aNode[iRoot]; + assert( pRoot->eU==0 ); pRoot->u.iAppend = iStart - iRoot; pRoot->jnFlags |= JNODE_APPEND; + VVA( pRoot->eU = 2 ); pParse->aNode[iLabel].jnFlags |= JNODE_RAW; } return pNode; @@ -1199,6 +1249,7 @@ static JsonNode *jsonLookupStep( j += jsonNodeSize(&pBase[j]); } if( (pBase->jnFlags & JNODE_APPEND)==0 ) break; + assert( pBase->eU==2 ); iBase += pBase->u.iAppend; pBase = &pParse->aNode[iBase]; j = 1; @@ -1232,6 +1283,7 @@ static JsonNode *jsonLookupStep( j += jsonNodeSize(&pRoot[j]); } if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; + assert( pRoot->eU==2 ); iRoot += pRoot->u.iAppend; pRoot = &pParse->aNode[iRoot]; j = 1; @@ -1247,8 +1299,10 @@ static JsonNode *jsonLookupStep( if( pParse->oom ) return 0; if( pNode ){ pRoot = &pParse->aNode[iRoot]; + assert( pRoot->eU==0 ); pRoot->u.iAppend = iStart - iRoot; pRoot->jnFlags |= JNODE_APPEND; + VVA( pRoot->eU = 2 ); } return pNode; } @@ -1402,9 +1456,13 @@ static void jsonParseFunc( } jsonPrintf(100, &s,"node %3u: %7s n=%-4d up=%-4d", i, zType, x.aNode[i].n, x.aUp[i]); + assert( x.aNode[i].eU==0 || x.aNode[i].eU==1 ); if( x.aNode[i].u.zJContent!=0 ){ + assert( x.aNode[i].eU==1 ); jsonAppendRaw(&s, " ", 1); jsonAppendRaw(&s, x.aNode[i].u.zJContent, x.aNode[i].n); + }else{ + assert( x.aNode[i].eU==0 ); } jsonAppendRaw(&s, "\n", 1); } @@ -1587,6 +1645,7 @@ static JsonNode *jsonMergePatch( const char *zKey; assert( pPatch[i].eType==JSON_STRING ); assert( pPatch[i].jnFlags & JNODE_LABEL ); + assert( pPatch[i].eU==1 ); nKey = pPatch[i].n; zKey = pPatch[i].u.zJContent; assert( (pPatch[i].jnFlags & JNODE_RAW)==0 ); @@ -1603,6 +1662,12 @@ static JsonNode *jsonMergePatch( if( pNew==0 ) return 0; pTarget = &pParse->aNode[iTarget]; if( pNew!=&pTarget[j+1] ){ + assert( pTarget[j+1].eU==0 + || pTarget[j+1].eU==1 + || pTarget[j+1].eU==2 ); + testcase( pTarget[j+1].eU==1 ); + testcase( pTarget[j+1].eU==2 ); + VVA( pTarget[j+1].eU = 5 ); pTarget[j+1].u.pPatch = pNew; pTarget[j+1].jnFlags |= JNODE_PATCH; } @@ -1618,9 +1683,14 @@ static JsonNode *jsonMergePatch( if( pParse->oom ) return 0; jsonRemoveAllNulls(pPatch); pTarget = &pParse->aNode[iTarget]; + assert( pParse->aNode[iRoot].eU==0 || pParse->aNode[iRoot].eU==2 ); + testcase( pParse->aNode[iRoot].eU==2 ); pParse->aNode[iRoot].jnFlags |= JNODE_APPEND; + VVA( pParse->aNode[iRoot].eU = 2 ); pParse->aNode[iRoot].u.iAppend = iStart - iRoot; iRoot = iStart; + assert( pParse->aNode[iPatch].eU==0 ); + VVA( pParse->aNode[iPatch].eU = 5 ); pParse->aNode[iPatch].jnFlags |= JNODE_PATCH; pParse->aNode[iPatch].u.pPatch = &pPatch[i+1]; } @@ -1762,11 +1832,15 @@ static void jsonReplaceFunc( pNode = jsonLookup(&x, zPath, 0, ctx); if( x.nErr ) goto replace_err; if( pNode ){ + assert( pNode->eU==0 || pNode->eU==1 || pNode->eU==4 ); + json_testcase( pNode->eU!=0 && pNode->eU!=1 ); pNode->jnFlags |= (u8)JNODE_REPLACE; + VVA( pNode->eU = 4 ); pNode->u.iReplace = i + 1; } } if( x.aNode[0].jnFlags & JNODE_REPLACE ){ + assert( x.aNode[0].eU==4 ); sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]); }else{ jsonReturnJson(x.aNode, ctx, argv); @@ -1816,11 +1890,15 @@ static void jsonSetFunc( }else if( x.nErr ){ goto jsonSetDone; }else if( pNode && (bApnd || bIsSet) ){ + json_testcase( pNode->eU!=0 && pNode->eU!=1 && pNode->eU!=4 ); + assert( pNode->eU!=3 || pNode->eU!=5 ); + VVA( pNode->eU = 4 ); pNode->jnFlags |= (u8)JNODE_REPLACE; pNode->u.iReplace = i + 1; } } if( x.aNode[0].jnFlags & JNODE_REPLACE ){ + assert( x.aNode[0].eU==4 ); sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]); }else{ jsonReturnJson(x.aNode, ctx, argv); @@ -2171,6 +2249,9 @@ static int jsonEachNext(sqlite3_vtab_cursor *cur){ JsonNode *pUp = &p->sParse.aNode[iUp]; p->eType = pUp->eType; if( pUp->eType==JSON_ARRAY ){ + assert( pUp->eU==0 || pUp->eU==3 ); + json_testcase( pUp->eU==3 ); + VVA( pUp->eU = 3 ); if( iUp==p->i-1 ){ pUp->u.iKey = 0; }else{ @@ -2217,12 +2298,15 @@ static void jsonEachComputePath( pNode = &p->sParse.aNode[i]; pUp = &p->sParse.aNode[iUp]; if( pUp->eType==JSON_ARRAY ){ + assert( pUp->eU==3 || (pUp->eU==0 && pUp->u.iKey==0) ); + testcase( pUp->eU==0 ); jsonPrintf(30, pStr, "[%d]", pUp->u.iKey); }else{ assert( pUp->eType==JSON_OBJECT ); if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--; assert( pNode->eType==JSON_STRING ); assert( pNode->jnFlags & JNODE_LABEL ); + assert( pNode->eU==1 ); jsonPrintf(pNode->n+1, pStr, ".%.*s", pNode->n-2, pNode->u.zJContent+1); } } @@ -2244,6 +2328,7 @@ static int jsonEachColumn( u32 iKey; if( p->bRecursive ){ if( p->iRowid==0 ) break; + assert( p->sParse.aNode[p->sParse.aUp[p->i]].eU==3 ); iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey; }else{ iKey = p->iRowid; @@ -2293,6 +2378,7 @@ static int jsonEachColumn( if( p->eType==JSON_ARRAY ){ jsonPrintf(30, &x, "[%d]", p->iRowid); }else if( p->eType==JSON_OBJECT ){ + assert( pThis->eU==1 ); jsonPrintf(pThis->n, &x, ".%.*s", pThis->n-2, pThis->u.zJContent+1); } } @@ -2360,6 +2446,7 @@ static int jsonEachBestIndex( if( pConstraint->iColumn < JEACH_JSON ) continue; iCol = pConstraint->iColumn - JEACH_JSON; assert( iCol==0 || iCol==1 ); + testcase( iCol==0 ); iMask = 1 << iCol; if( pConstraint->usable==0 ){ unusableMask |= iMask; @@ -2457,6 +2544,8 @@ static int jsonEachFilter( p->iBegin = p->i = (int)(pNode - p->sParse.aNode); p->eType = pNode->eType; if( p->eType>=JSON_ARRAY ){ + assert( pNode->eU==0 ); + VVA( pNode->eU = 3 ); pNode->u.iKey = 0; p->iEnd = p->i + pNode->n + 1; if( p->bRecursive ){ diff --git a/ext/misc/regexp.c b/ext/misc/regexp.c index 99fb453c..f282e777 100644 --- a/ext/misc/regexp.c +++ b/ext/misc/regexp.c @@ -299,9 +299,9 @@ static int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){ } case RE_OP_CC_EXC: { if( c==0 ) break; - /* fall-through */ + /* fall-through */ goto re_op_cc_inc; } - case RE_OP_CC_INC: { + case RE_OP_CC_INC: re_op_cc_inc: { int j = 1; int n = pRe->aArg[x]; int hit = 0; diff --git a/ext/misc/series.c b/ext/misc/series.c index a4e92ace..e8d8c10a 100644 --- a/ext/misc/series.c +++ b/ext/misc/series.c @@ -323,11 +323,12 @@ static int seriesFilter( ** (8) output in descending order */ static int seriesBestIndex( - sqlite3_vtab *tabUnused, + sqlite3_vtab *pVTab, sqlite3_index_info *pIdxInfo ){ int i, j; /* Loop over constraints */ int idxNum = 0; /* The query plan bitmask */ + int bStartSeen = 0; /* EQ constraint seen on the START column */ int unusableMask = 0; /* Mask of unusable constraints */ int nArg = 0; /* Number of arguments that seriesFilter() expects */ int aIdx[3]; /* Constraints on start, stop, and step */ @@ -337,7 +338,7 @@ static int seriesBestIndex( ** are the last three columns in the virtual table. */ assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 ); assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 ); - (void)tabUnused; + aIdx[0] = aIdx[1] = aIdx[2] = -1; pConstraint = pIdxInfo->aConstraint; for(i=0; inConstraint; i++, pConstraint++){ @@ -347,6 +348,7 @@ static int seriesBestIndex( iCol = pConstraint->iColumn - SERIES_COLUMN_START; assert( iCol>=0 && iCol<=2 ); iMask = 1 << iCol; + if( iCol==0 ) bStartSeen = 1; if( pConstraint->usable==0 ){ unusableMask |= iMask; continue; @@ -361,6 +363,18 @@ static int seriesBestIndex( pIdxInfo->aConstraintUsage[j].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY; } } + /* The current generate_column() implementation requires at least one + ** argument (the START value). Legacy versions assumed START=0 if the + ** first argument was omitted. Compile with -DZERO_ARGUMENT_GENERATE_SERIES + ** to obtain the legacy behavior */ +#ifndef ZERO_ARGUMENT_GENERATE_SERIES + if( !bStartSeen ){ + sqlite3_free(pVTab->zErrMsg); + pVTab->zErrMsg = sqlite3_mprintf( + "first argument to \"generate_series()\" missing or unusable"); + return SQLITE_ERROR; + } +#endif if( (unusableMask & ~idxNum)!=0 ){ /* The start, stop, and step columns are inputs. Therefore if there ** are unusable constraints on any of start, stop, or step then @@ -434,7 +448,7 @@ int sqlite3_series_init( int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); #ifndef SQLITE_OMIT_VIRTUALTABLE - if( sqlite3_libversion_number()<3008012 ){ + if( sqlite3_libversion_number()<3008012 && pzErrMsg!=0 ){ *pzErrMsg = sqlite3_mprintf( "generate_series() requires SQLite 3.8.12 or later"); return SQLITE_ERROR; diff --git a/ext/misc/zipfile.c b/ext/misc/zipfile.c index b727f9f2..b7ceb939 100644 --- a/ext/misc/zipfile.c +++ b/ext/misc/zipfile.c @@ -57,6 +57,9 @@ typedef UINT16_TYPE u16; /* 2-byte unsigned integer */ #define MIN(a,b) ((a)<(b) ? (a) : (b)) #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) +# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 +#endif +#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) # define ALWAYS(X) (1) # define NEVER(X) (0) #elif !defined(NDEBUG) @@ -561,6 +564,7 @@ static u16 zipfileGetU16(const u8 *aBuf){ ** Read and return a 32-bit little-endian unsigned integer from buffer aBuf. */ static u32 zipfileGetU32(const u8 *aBuf){ + if( aBuf==0 ) return 0; return ((u32)(aBuf[3]) << 24) + ((u32)(aBuf[2]) << 16) + ((u32)(aBuf[1]) << 8) @@ -863,7 +867,7 @@ static int zipfileGetEntry( aRead = (u8*)&aBlob[pNew->cds.iOffset]; } - rc = zipfileReadLFH(aRead, &lfh); + if( rc==SQLITE_OK ) rc = zipfileReadLFH(aRead, &lfh); if( rc==SQLITE_OK ){ pNew->iDataOff = pNew->cds.iOffset + ZIPFILE_LFH_FIXED_SZ; pNew->iDataOff += lfh.nFile + lfh.nExtra; @@ -1139,13 +1143,13 @@ static int zipfileReadEOCD( int nRead; /* Bytes to read from file */ int rc = SQLITE_OK; + memset(pEOCD, 0, sizeof(ZipfileEOCD)); if( aBlob==0 ){ i64 iOff; /* Offset to read from */ i64 szFile; /* Total size of file in bytes */ fseek(pFile, 0, SEEK_END); szFile = (i64)ftell(pFile); if( szFile==0 ){ - memset(pEOCD, 0, sizeof(ZipfileEOCD)); return SQLITE_OK; } nRead = (int)(MIN(szFile, ZIPFILE_BUFFER_SIZE)); diff --git a/ext/rbu/rbu10.test b/ext/rbu/rbu10.test index a7c63cf6..aa4db8a2 100644 --- a/ext/rbu/rbu10.test +++ b/ext/rbu/rbu10.test @@ -50,7 +50,7 @@ do_test 1.1 { # ifcapable fts3 { do_execsql_test 2.0 { - CREATE VIRTUAL TABLE ft USING fts4(a, b, languageid='langid'); + create virtual TABLE ft USING fts4(a, b, languageid='langid'); } do_test 2.1 { apply_rbu { diff --git a/ext/rbu/rbuexlock.test b/ext/rbu/rbuexlock.test new file mode 100644 index 00000000..eddcdc11 --- /dev/null +++ b/ext/rbu/rbuexlock.test @@ -0,0 +1,207 @@ +# 2021 November 06 +# +# 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]] rbu_common.tcl] +set ::testprefix rbuexlock + +db close +sqlite3_shutdown +sqlite3_config_uri 1 + +# Create a simple RBU database. That expects to write to a table: +# +# CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); +# +proc create_rbu {filename} { + forcedelete $filename + sqlite3 rbu1 $filename + rbu1 eval { + CREATE TABLE data_t1(a, b, c, rbu_control); + INSERT INTO data_t1 VALUES(10, random(), random(), 0); + INSERT INTO data_t1 VALUES(20, random(), random(), 0); + INSERT INTO data_t1 VALUES(30, random(), random(), 0); + INSERT INTO data_t1 VALUES(40, random(), random(), 0); + INSERT INTO data_t1 VALUES(50, random(), random(), 0); + INSERT INTO data_t1 VALUES(60, random(), random(), 0); + INSERT INTO data_t1 VALUES(70, random(), random(), 0); + INSERT INTO data_t1 VALUES(80, random(), random(), 0); + } + rbu1 close + return $filename +} + +reset_db + +do_execsql_test 1.0 { + CREATE TABLE t1(a PRIMARY KEY, b INT, c INT); + CREATE INDEX t1b ON t1(b); + CREATE INDEX t1c ON t1(c); + INSERT INTO t1 VALUES(1, 2, 3); +} +create_rbu rbu1.db + +do_test 1.1.0 { + sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=1 rbu1.db + rbu step +} SQLITE_OK +do_catchsql_test 1.1.1 { SELECT * FROM t1 } {0 {1 2 3}} + +do_test 1.2.0 { + for {set ii 0} {$ii < 10} {incr ii} { + rbu step + } + rbu step +} SQLITE_OK +do_catchsql_test 1.2.1 { SELECT * FROM t1 } {0 {1 2 3}} +do_test 1.2.2 { + db eval {PRAGMA journal_mode} +} {delete} + +do_test 1.3.0 { + while {[file exists test.db-wal]==0} { + rbu step + } +} {} +do_catchsql_test 1.3.1 { SELECT * FROM t1 } {1 {database is locked}} +do_test 1.3.2 { + db eval {PRAGMA journal_mode} +} {delete} + + +do_test 1.4.0 { + rbu step +} SQLITE_OK +do_catchsql_test 1.4.1 { SELECT * FROM t1 } {1 {database is locked}} +do_test 1.4.2 { + db eval {PRAGMA journal_mode} +} {delete} + + +rbu close + +do_test 1.5.0 { + file exists test.db-wal +} {1} +do_test 1.5.1 { + sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=1 rbu1.db + file exists test.db-wal +} 1 +do_catchsql_test 1.5.2 { SELECT * FROM t1 } {1 {database is locked}} +do_test 1.5.2 { + db eval {PRAGMA journal_mode} +} {delete} + + +do_test 1.6.0 { + rbu step +} SQLITE_OK +do_catchsql_test 1.6.1 { SELECT * FROM t1 } {1 {database is locked}} +do_test 1.6.2 { + db eval {PRAGMA journal_mode} +} {delete} + +do_test 1.7.0 { + while {[rbu step]=="SQLITE_OK"} {} + rbu close +} SQLITE_DONE +do_catchsql_test 1.7.2 { SELECT count(*) FROM t1 } {0 9} +do_test 1.7.2 { + db eval {PRAGMA journal_mode} +} {delete} + +reset_db +do_execsql_test 2.0 { + CREATE TABLE t1(a PRIMARY KEY, b INT, c INT); + CREATE INDEX t1b ON t1(b); + CREATE INDEX t1c ON t1(c); + INSERT INTO t1 VALUES(1, 2, 3); +} +create_rbu rbu1.db + +do_test 2.1.0 { + sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=0 rbu1.db + rbu step +} SQLITE_OK +do_catchsql_test 2.1.1 { SELECT * FROM t1 } {0 {1 2 3}} + +do_test 2.2.0 { + for {set ii 0} {$ii < 10} {incr ii} { + rbu step + } + rbu step +} SQLITE_OK +do_catchsql_test 2.2.1 { SELECT * FROM t1 } {0 {1 2 3}} + +do_test 2.3.0 { + while {[file exists test.db-wal]==0} { + rbu step + } +} {} +do_test 2.3.1 { + llength [db eval {SELECT * FROM t1}] +} {27} +do_test 2.3.2 { + db eval {PRAGMA journal_mode} +} {wal} + +do_test 2.4.0 { + rbu step +} SQLITE_OK +do_test 2.4.1 { + llength [db eval {SELECT * FROM t1}] +} {27} +do_test 2.4.2 { + db eval {PRAGMA journal_mode} +} {wal} + +rbu close + +do_test 2.5.0 { + db eval {PRAGMA journal_mode} +} {wal} +do_execsql_test 2.5.1 { + DELETE FROM t1; +} {} + +create_rbu rbu1.db +do_test 3.1.0 { + sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=0 rbu1.db + rbu step +} SQLITE_ERROR + +do_test 3.1.1 { + set rc [catch {rbu close} msg] + lappend rc $msg +} {1 {SQLITE_ERROR - cannot update wal mode database}} +db eval {PRAGMA journal_mode=DELETE} + +create_rbu rbu1.db +do_test 3.2.0 { + sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=0 rbu1.db + rbu step +} SQLITE_OK + +do_test 3.3.1 { + set rc [catch {rbu close} msg] + lappend rc $msg +} {0 SQLITE_OK} + +db close +create_rbu rbu1.db +do_test 3.4.0 { + sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=0 rbu1.db + rbu step +} SQLITE_OK +rbu close + + +finish_test diff --git a/ext/rbu/rbuvacuum2.test b/ext/rbu/rbuvacuum2.test index 6d6dfde9..c8fba6a2 100644 --- a/ext/rbu/rbuvacuum2.test +++ b/ext/rbu/rbuvacuum2.test @@ -198,7 +198,11 @@ if {$::tcl_platform(platform)=="unix"} { } {SQLITE_OK} do_test 5.$tn.2 { file exists test.db-vacuum } 1 - do_test 5.$tn.3 { file attributes test.db-vacuum -permissions} $perm + # The result pattern might be 00xxx or 0oxxx depending on which + # version of TCL is being used. So make perm2 into a regexp that + # will match either + regsub {^00} $perm {0.} perm2 + do_test 5.$tn.3 { file attributes test.db-vacuum -permissions} /$perm2/ rbu close } } diff --git a/ext/rbu/sqlite3rbu.c b/ext/rbu/sqlite3rbu.c index 1a13b6c4..202712cc 100644 --- a/ext/rbu/sqlite3rbu.c +++ b/ext/rbu/sqlite3rbu.c @@ -111,6 +111,13 @@ #endif /* +** Name of the URI option that causes RBU to take an exclusive lock as +** part of the incremental checkpoint operation. +*/ +#define RBU_EXCLUSIVE_CHECKPOINT "rbu_exclusive_checkpoint" + + +/* ** The rbu_state table is used to save the state of a partially applied ** update so that it can be resumed later. The table consists of integer ** keys mapped to values as follows: @@ -1194,7 +1201,9 @@ static void rbuTableType( assert( p->rc==SQLITE_OK ); p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[0], &p->zErrmsg, sqlite3_mprintf( - "SELECT (sql LIKE 'create virtual%%'), rootpage" + "SELECT " + " (sql COLLATE nocase BETWEEN 'CREATE VIRTUAL' AND 'CREATE VIRTUAM')," + " rootpage" " FROM sqlite_schema" " WHERE name=%Q", zTab )); @@ -2727,7 +2736,7 @@ static RbuState *rbuLoadState(sqlite3rbu *p){ break; case RBU_STATE_OALSZ: - pRet->iOalSz = (u32)sqlite3_column_int64(pStmt, 1); + pRet->iOalSz = sqlite3_column_int64(pStmt, 1); break; case RBU_STATE_PHASEONESTEP: @@ -2754,13 +2763,19 @@ static RbuState *rbuLoadState(sqlite3rbu *p){ /* ** Open the database handle and attach the RBU database as "rbu". If an ** error occurs, leave an error code and message in the RBU handle. +** +** If argument dbMain is not NULL, then it is a database handle already +** open on the target database. Use this handle instead of opening a new +** one. */ -static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){ +static void rbuOpenDatabase(sqlite3rbu *p, sqlite3 *dbMain, int *pbRetry){ assert( p->rc || (p->dbMain==0 && p->dbRbu==0) ); assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 ); + assert( dbMain==0 || rbuIsVacuum(p)==0 ); /* Open the RBU database */ p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1); + p->dbMain = dbMain; if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){ sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p); @@ -3126,15 +3141,31 @@ static void rbuCheckpointFrame(sqlite3rbu *p, RbuFrame *pFrame){ /* -** Take an EXCLUSIVE lock on the database file. +** Take an EXCLUSIVE lock on the database file. Return SQLITE_OK if +** successful, or an SQLite error code otherwise. */ -static void rbuLockDatabase(sqlite3rbu *p){ - sqlite3_file *pReal = p->pTargetFd->pReal; - assert( p->rc==SQLITE_OK ); - p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_SHARED); - if( p->rc==SQLITE_OK ){ - p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_EXCLUSIVE); +static int rbuLockDatabase(sqlite3 *db){ + int rc = SQLITE_OK; + sqlite3_file *fd = 0; + 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); + } } + return rc; +} + +/* +** Return true if the database handle passed as the only argument +** was opened with the rbu_exclusive_checkpoint=1 URI parameter +** specified. Or false otherwise. +*/ +static int rbuExclusiveCheckpoint(sqlite3 *db){ + const char *zUri = sqlite3_db_filename(db, 0); + return sqlite3_uri_boolean(zUri, RBU_EXCLUSIVE_CHECKPOINT, 0); } #if defined(_WIN32_WCE) @@ -3192,18 +3223,24 @@ static void rbuMoveOalFile(sqlite3rbu *p){ ** In order to ensure that there are no database readers, an EXCLUSIVE ** lock is obtained here before the *-oal is moved to *-wal. */ - rbuLockDatabase(p); - if( p->rc==SQLITE_OK ){ - rbuFileSuffix3(zBase, zWal); - rbuFileSuffix3(zBase, zOal); + sqlite3 *dbMain = 0; + rbuFileSuffix3(zBase, zWal); + rbuFileSuffix3(zBase, zOal); + + /* Re-open the databases. */ + rbuObjIterFinalize(&p->objiter); + sqlite3_close(p->dbRbu); + sqlite3_close(p->dbMain); + p->dbMain = 0; + p->dbRbu = 0; - /* Re-open the databases. */ - rbuObjIterFinalize(&p->objiter); - sqlite3_close(p->dbRbu); - sqlite3_close(p->dbMain); - p->dbMain = 0; - p->dbRbu = 0; + dbMain = rbuOpenDbhandle(p, p->zTarget, 1); + if( dbMain ){ + assert( p->rc==SQLITE_OK ); + p->rc = rbuLockDatabase(dbMain); + } + if( p->rc==SQLITE_OK ){ #if defined(_WIN32_WCE) { LPWSTR zWideOal; @@ -3230,11 +3267,19 @@ static void rbuMoveOalFile(sqlite3rbu *p){ #else p->rc = rename(zOal, zWal) ? SQLITE_IOERR : SQLITE_OK; #endif + } - if( p->rc==SQLITE_OK ){ - rbuOpenDatabase(p, 0); - rbuSetupCheckpoint(p, 0); - } + if( p->rc!=SQLITE_OK + || rbuIsVacuum(p) + || rbuExclusiveCheckpoint(dbMain)==0 + ){ + sqlite3_close(dbMain); + dbMain = 0; + } + + if( p->rc==SQLITE_OK ){ + rbuOpenDatabase(p, dbMain, 0); + rbuSetupCheckpoint(p, 0); } } @@ -3985,9 +4030,9 @@ static sqlite3rbu *openRbuHandle( ** If this is the case, it will have been checkpointed and deleted ** when the handle was closed and a second attempt to open the ** database may succeed. */ - rbuOpenDatabase(p, &bRetry); + rbuOpenDatabase(p, 0, &bRetry); if( bRetry ){ - rbuOpenDatabase(p, 0); + rbuOpenDatabase(p, 0, 0); } } @@ -4082,6 +4127,14 @@ static sqlite3rbu *openRbuHandle( }else if( p->eStage==RBU_STAGE_MOVE ){ /* no-op */ }else if( p->eStage==RBU_STAGE_CKPT ){ + if( !rbuIsVacuum(p) && rbuExclusiveCheckpoint(p->dbMain) ){ + /* If the rbu_exclusive_checkpoint=1 URI parameter was specified + ** and an incremental checkpoint is being resumed, attempt an + ** exclusive lock on the db file. If this fails, so be it. */ + p->eStage = RBU_STAGE_DONE; + rbuLockDatabase(p->dbMain); + p->eStage = RBU_STAGE_CKPT; + } rbuSetupCheckpoint(p, pState); }else if( p->eStage==RBU_STAGE_DONE ){ p->rc = SQLITE_DONE; @@ -4119,7 +4172,6 @@ sqlite3rbu *sqlite3rbu_open( const char *zState ){ if( zTarget==0 || zRbu==0 ){ return rbuMisuseError(); } - /* TODO: Check that zTarget and zRbu are non-NULL */ return openRbuHandle(zTarget, zRbu, zState); } diff --git a/ext/repair/checkfreelist.c b/ext/repair/checkfreelist.c index 990be4af..d1d3d540 100644 --- a/ext/repair/checkfreelist.c +++ b/ext/repair/checkfreelist.c @@ -44,8 +44,19 @@ SQLITE_EXTENSION_INIT1 # include # include # include -# define ALWAYS(X) 1 -# define NEVER(X) 0 +# if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) +# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 +# endif +# if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) +# define ALWAYS(X) (1) +# define NEVER(X) (0) +# elif !defined(NDEBUG) +# define ALWAYS(X) ((X)?1:(assert(0),0)) +# define NEVER(X) ((X)?(assert(0),1):0) +# else +# define ALWAYS(X) (X) +# define NEVER(X) (X) +# endif typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c index b7759bbb..98ea718f 100644 --- a/ext/rtree/geopoly.c +++ b/ext/rtree/geopoly.c @@ -305,13 +305,14 @@ static GeoPoly *geopolyFuncParam( ){ GeoPoly *p = 0; int nByte; + testcase( pCtx==0 ); if( sqlite3_value_type(pVal)==SQLITE_BLOB && (nByte = sqlite3_value_bytes(pVal))>=(4+6*sizeof(GeoCoord)) ){ const unsigned char *a = sqlite3_value_blob(pVal); int nVertex; if( a==0 ){ - sqlite3_result_error_nomem(pCtx); + if( pCtx ) sqlite3_result_error_nomem(pCtx); return 0; } nVertex = (a[1]<<16) + (a[2]<<8) + a[3]; @@ -1138,11 +1139,11 @@ static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2){ }else{ /* Remove a segment */ if( pActive==pThisEvent->pSeg ){ - pActive = pActive->pNext; + pActive = ALWAYS(pActive) ? pActive->pNext : 0; }else{ for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){ if( pSeg->pNext==pThisEvent->pSeg ){ - pSeg->pNext = pSeg->pNext->pNext; + pSeg->pNext = ALWAYS(pSeg->pNext) ? pSeg->pNext->pNext : 0; break; } } @@ -1386,6 +1387,7 @@ static int geopolyFilter( RtreeCoord bbox[4]; RtreeConstraint *p; assert( argc==1 ); + assert( argv[0]!=0 ); geopolyBBox(0, argv[0], bbox, &rc); if( rc ){ goto geopoly_filter_end; @@ -1613,6 +1615,7 @@ static int geopolyUpdate( || !sqlite3_value_nochange(aData[2]) /* UPDATE _shape */ || oldRowid!=newRowid) /* Rowid change */ ){ + assert( aData[2]!=0 ); geopolyBBox(0, aData[2], cell.aCoord, &rc); if( rc ){ if( rc==SQLITE_ERROR ){ diff --git a/ext/rtree/rtree.c b/ext/rtree/rtree.c index 2151d5af..49053a2b 100644 --- a/ext/rtree/rtree.c +++ b/ext/rtree/rtree.c @@ -64,7 +64,11 @@ #endif int sqlite3GetToken(const unsigned char*,int*); /* In the SQLite core */ -#ifndef SQLITE_AMALGAMATION +/* +** If building separately, we will need some setup that is normally +** found in sqliteInt.h +*/ +#if !defined(SQLITE_AMALGAMATION) #include "sqlite3rtree.h" typedef sqlite3_int64 i64; typedef sqlite3_uint64 u64; @@ -77,7 +81,20 @@ typedef unsigned int u32; #if defined(NDEBUG) && defined(SQLITE_DEBUG) # undef NDEBUG #endif +#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) +# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 #endif +#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) +# define ALWAYS(X) (1) +# define NEVER(X) (0) +#elif !defined(NDEBUG) +# define ALWAYS(X) ((X)?1:(assert(0),0)) +# define NEVER(X) ((X)?(assert(0),1):0) +#else +# define ALWAYS(X) (X) +# define NEVER(X) (X) +#endif +#endif /* !defined(SQLITE_AMALGAMATION) */ #include #include @@ -135,7 +152,9 @@ struct Rtree { u8 nBytesPerCell; /* Bytes consumed per cell */ u8 inWrTrans; /* True if inside write transaction */ u8 nAux; /* # of auxiliary columns in %_rowid */ +#ifdef SQLITE_ENABLE_GEOPOLY u8 nAuxNotNull; /* Number of initial not-null aux columns */ +#endif #ifdef SQLITE_DEBUG u8 bCorrupt; /* Shadow table corruption detected */ #endif @@ -417,7 +436,12 @@ struct RtreeMatchArg { ** it is not, make it a no-op. */ #ifndef SQLITE_AMALGAMATION -# define testcase(X) +# if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) + unsigned int sqlite3RtreeTestcase = 0; +# define testcase(X) if( X ){ sqlite3RtreeTestcase += __LINE__; } +# else +# define testcase(X) +# endif #endif /* @@ -667,18 +691,6 @@ static void nodeBlobReset(Rtree *pRtree){ } /* -** Check to see if pNode is the same as pParent or any of the parents -** of pParent. -*/ -static int nodeInParentChain(const RtreeNode *pNode, const RtreeNode *pParent){ - do{ - if( pNode==pParent ) return 1; - pParent = pParent->pParent; - }while( pParent ); - return 0; -} - -/* ** Obtain a reference to an r-tree node. */ static int nodeAcquire( @@ -694,14 +706,7 @@ static int nodeAcquire( ** increase its reference count and return it. */ if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){ - if( pParent && !pNode->pParent ){ - if( nodeInParentChain(pNode, pParent) ){ - RTREE_IS_CORRUPT(pRtree); - return SQLITE_CORRUPT_VTAB; - } - pParent->nRef++; - pNode->pParent = pParent; - }else if( pParent && pNode->pParent && pParent!=pNode->pParent ){ + if( pParent && pParent!=pNode->pParent ){ RTREE_IS_CORRUPT(pRtree); return SQLITE_CORRUPT_VTAB; } @@ -759,7 +764,7 @@ static int nodeAcquire( ** are the leaves, and so on. If the depth as specified on the root node ** is greater than RTREE_MAX_DEPTH, the r-tree structure must be corrupt. */ - if( pNode && rc==SQLITE_OK && iNode==1 ){ + if( rc==SQLITE_OK && pNode && iNode==1 ){ pRtree->iDepth = readInt16(pNode->zData); if( pRtree->iDepth>RTREE_MAX_DEPTH ){ rc = SQLITE_CORRUPT_VTAB; @@ -1282,20 +1287,29 @@ static void rtreeNonleafConstraint( switch( p->op ){ case RTREE_TRUE: return; /* Always satisfied */ case RTREE_FALSE: break; /* Never satisfied */ + case RTREE_EQ: + RTREE_DECODE_COORD(eInt, pCellData, val); + /* val now holds the lower bound of the coordinate pair */ + if( p->u.rValue>=val ){ + pCellData += 4; + RTREE_DECODE_COORD(eInt, pCellData, val); + /* val now holds the upper bound of the coordinate pair */ + if( p->u.rValue<=val ) return; + } + break; case RTREE_LE: case RTREE_LT: - case RTREE_EQ: RTREE_DECODE_COORD(eInt, pCellData, val); /* val now holds the lower bound of the coordinate pair */ if( p->u.rValue>=val ) return; - if( p->op!=RTREE_EQ ) break; /* RTREE_LE and RTREE_LT end here */ - /* Fall through for the RTREE_EQ case */ + break; - default: /* RTREE_GT or RTREE_GE, or fallthrough of RTREE_EQ */ + default: pCellData += 4; RTREE_DECODE_COORD(eInt, pCellData, val); /* val now holds the upper bound of the coordinate pair */ if( p->u.rValue<=val ) return; + break; } *peWithin = NOT_WITHIN; } @@ -1365,11 +1379,12 @@ static int nodeRowidIndex( */ static int nodeParentIndex(Rtree *pRtree, RtreeNode *pNode, int *piIndex){ RtreeNode *pParent = pNode->pParent; - if( pParent ){ + if( ALWAYS(pParent) ){ return nodeRowidIndex(pRtree, pParent, pNode->iNode, piIndex); + }else{ + *piIndex = -1; + return SQLITE_OK; } - *piIndex = -1; - return SQLITE_OK; } /* @@ -1492,7 +1507,8 @@ static RtreeSearchPoint *rtreeSearchPointNew( pNew = rtreeEnqueue(pCur, rScore, iLevel); if( pNew==0 ) return 0; ii = (int)(pNew - pCur->aPoint) + 1; - if( iiaNode[ii]==0 ); pCur->aNode[ii] = pCur->aNode[0]; }else{ @@ -1553,7 +1569,7 @@ static void rtreeSearchPointPop(RtreeCursor *p){ if( p->bPoint ){ p->anQueue[p->sPoint.iLevel]--; p->bPoint = 0; - }else if( p->nPoint ){ + }else if( ALWAYS(p->nPoint) ){ p->anQueue[p->aPoint[0].iLevel]--; n = --p->nPoint; p->aPoint[0] = p->aPoint[n]; @@ -1694,7 +1710,7 @@ static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){ RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); int rc = SQLITE_OK; RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); - if( rc==SQLITE_OK && p ){ + if( rc==SQLITE_OK && ALWAYS(p) ){ *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell); } return rc; @@ -1712,7 +1728,7 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); if( rc ) return rc; - if( p==0 ) return SQLITE_OK; + if( NEVER(p==0) ) return SQLITE_OK; if( i==0 ){ sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell)); }else if( i<=pRtree->nDim2 ){ @@ -1911,8 +1927,11 @@ static int rtreeFilter( } if( rc==SQLITE_OK ){ RtreeSearchPoint *pNew; + assert( pCsr->bPoint==0 ); /* Due to the resetCursor() call above */ pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1)); - if( pNew==0 ) return SQLITE_NOMEM; + if( NEVER(pNew==0) ){ /* Because pCsr->bPoint was FALSE */ + return SQLITE_NOMEM; + } pNew->id = 1; pNew->iCell = 0; pNew->eWithin = PARTLY_WITHIN; @@ -1989,7 +2008,7 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii]; if( bMatch==0 && p->usable - && p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ + && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ /* We have an equality constraint on the rowid. Use strategy 1. */ int jj; @@ -2195,7 +2214,7 @@ static int ChooseLeaf( int nCell = NCELL(pNode); RtreeCell cell; - RtreeNode *pChild; + RtreeNode *pChild = 0; RtreeCell *aCell = 0; @@ -2242,12 +2261,19 @@ static int AdjustTree( ){ RtreeNode *p = pNode; int cnt = 0; + int rc; while( p->pParent ){ RtreeNode *pParent = p->pParent; RtreeCell cell; int iCell; - if( (++cnt)>1000 || nodeParentIndex(pRtree, p, &iCell) ){ + cnt++; + if( NEVER(cnt>100) ){ + RTREE_IS_CORRUPT(pRtree); + return SQLITE_CORRUPT_VTAB; + } + rc = nodeParentIndex(pRtree, p, &iCell); + if( NEVER(rc!=SQLITE_OK) ){ RTREE_IS_CORRUPT(pRtree); return SQLITE_CORRUPT_VTAB; } @@ -2536,12 +2562,17 @@ static int updateMapping( xSetMapping = ((iHeight==0)?rowidWrite:parentWrite); if( iHeight>0 ){ RtreeNode *pChild = nodeHashLookup(pRtree, iRowid); + RtreeNode *p; + for(p=pNode; p; p=p->pParent){ + if( p==pChild ) return SQLITE_CORRUPT_VTAB; + } if( pChild ){ nodeRelease(pRtree, pChild->pParent); nodeReference(pNode); pChild->pParent = pNode; } } + if( NEVER(pNode==0) ) return SQLITE_ERROR; return xSetMapping(pRtree, iRowid, pNode->iNode); } @@ -2631,11 +2662,12 @@ static int SplitNode( RtreeNode *pParent = pLeft->pParent; int iCell; rc = nodeParentIndex(pRtree, pLeft, &iCell); - if( rc==SQLITE_OK ){ + if( ALWAYS(rc==SQLITE_OK) ){ nodeOverwriteCell(pRtree, pParent, &leftbbox, iCell); rc = AdjustTree(pRtree, pParent, &leftbbox); + assert( rc==SQLITE_OK ); } - if( rc!=SQLITE_OK ){ + if( NEVER(rc!=SQLITE_OK) ){ goto splitnode_out; } } @@ -2710,7 +2742,7 @@ static int fixLeafParent(Rtree *pRtree, RtreeNode *pLeaf){ */ iNode = sqlite3_column_int64(pRtree->pReadParent, 0); for(pTest=pLeaf; pTest && pTest->iNode!=iNode; pTest=pTest->pParent); - if( !pTest ){ + if( pTest==0 ){ rc2 = nodeAcquire(pRtree, iNode, 0, &pChild->pParent); } } @@ -2741,6 +2773,7 @@ static int removeNode(Rtree *pRtree, RtreeNode *pNode, int iHeight){ pParent = pNode->pParent; pNode->pParent = 0; rc = deleteCell(pRtree, pParent, iCell, iHeight+1); + testcase( rc!=SQLITE_OK ); } rc2 = nodeRelease(pRtree, pParent); if( rc==SQLITE_OK ){ @@ -2963,7 +2996,7 @@ static int rtreeInsertCell( } }else{ rc = AdjustTree(pRtree, pNode, pCell); - if( rc==SQLITE_OK ){ + if( ALWAYS(rc==SQLITE_OK) ){ if( iHeight==0 ){ rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode); }else{ @@ -3069,7 +3102,7 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){ int rc2; RtreeNode *pChild = 0; i64 iChild = nodeGetRowid(pRtree, pRoot, 0); - rc = nodeAcquire(pRtree, iChild, pRoot, &pChild); + rc = nodeAcquire(pRtree, iChild, pRoot, &pChild); /* tag-20210916a */ if( rc==SQLITE_OK ){ rc = removeNode(pRtree, pChild, pRtree->iDepth-1); } @@ -3404,7 +3437,7 @@ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){ char *zSql; sqlite3_stmt *p; int rc; - i64 nRow = 0; + i64 nRow = RTREE_MIN_ROWEST; rc = sqlite3_table_column_metadata( db, pRtree->zDb, "sqlite_stat1",0,0,0,0,0,0 @@ -3421,20 +3454,10 @@ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){ if( rc==SQLITE_OK ){ if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0); rc = sqlite3_finalize(p); - }else if( rc!=SQLITE_NOMEM ){ - rc = SQLITE_OK; - } - - if( rc==SQLITE_OK ){ - if( nRow==0 ){ - pRtree->nRowEst = RTREE_DEFAULT_ROWEST; - }else{ - pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST); - } } sqlite3_free(zSql); } - + pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST); return rc; } @@ -3584,9 +3607,12 @@ static int rtreeSqlInit( sqlite3_str_appendf(p, "UPDATE \"%w\".\"%w_rowid\"SET ", zDb, zPrefix); for(ii=0; iinAux; ii++){ if( ii ) sqlite3_str_append(p, ",", 1); +#ifdef SQLITE_ENABLE_GEOPOLY if( iinAuxNotNull ){ sqlite3_str_appendf(p,"a%d=coalesce(?%d,a%d)",ii,ii+2,ii); - }else{ + }else +#endif + { sqlite3_str_appendf(p,"a%d=?%d",ii,ii+2); } } @@ -3851,6 +3877,7 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){ tree.nDim2 = tree.nDim*2; tree.nBytesPerCell = 8 + 8 * tree.nDim; node.zData = (u8 *)sqlite3_value_blob(apArg[1]); + if( node.zData==0 ) return; nData = sqlite3_value_bytes(apArg[1]); if( nData<4 ) return; if( nDataxGeom = 0; pGeomCtx->xQueryFunc = xQueryFunc; pGeomCtx->xDestructor = xDestructor; diff --git a/ext/rtree/rtree1.test b/ext/rtree/rtree1.test index c37a2a77..0423bf55 100644 --- a/ext/rtree/rtree1.test +++ b/ext/rtree/rtree1.test @@ -57,9 +57,12 @@ ifcapable !rtree { do_test rtree-1.1.1 { execsql { CREATE VIRTUAL TABLE t1 USING rtree(ii, x1, x2, y1, y2) } } {} -do_test rtree-1.1.2 { +do_test rtree-1.1.2a { execsql { SELECT name FROM sqlite_master ORDER BY name } } {t1 t1_node t1_parent t1_rowid} +do_execsql_test rtree-1.1.2b { + SELECT name FROM pragma_table_list WHERE type='shadow' ORDER BY name; +} {t1_node t1_parent t1_rowid} do_test rtree-1.1.3 { execsql { DROP TABLE t1; diff --git a/ext/rtree/rtree9.test b/ext/rtree/rtree9.test index a7cd344d..f39a82e5 100644 --- a/ext/rtree/rtree9.test +++ b/ext/rtree/rtree9.test @@ -36,7 +36,7 @@ do_execsql_test rtree9-1.4 { DELETE FROM rt; } {} - +unset -nocomplain x for {set i 0} {$i < 1000} {incr i} { set x [expr $i%10] set y [expr ($i/10)%10] diff --git a/ext/rtree/rtreeA.test b/ext/rtree/rtreeA.test index 8344863d..921ba0b5 100644 --- a/ext/rtree/rtreeA.test +++ b/ext/rtree/rtreeA.test @@ -145,7 +145,7 @@ populate_t1 do_test rtreeA-2.2.0 { truncate_node 1 200 } {} do_corruption_tests rtreeA-2.2 { 1 "SELECT * FROM t1" - 2 "SELECT * FROM t1 WHERE rowid=5" + 2 "SELECT * FROM t1 WHERE +rowid=5" 3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)" 4 "SELECT * FROM t1 WHERE x1<10 AND x2>12" } @@ -160,7 +160,7 @@ do_test rtreeA-3.1.0.1 { set_tree_depth t1 } {1} do_test rtreeA-3.1.0.2 { set_tree_depth t1 3 } {3} do_corruption_tests rtreeA-3.1 { 1 "SELECT * FROM t1" - 2 "SELECT * FROM t1 WHERE rowid=5" + 2 "SELECT * FROM t1 WHERE +rowid=5" 3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)" } @@ -171,7 +171,7 @@ do_execsql_test rtreeA-3.1.0.3 { do_test rtreeA-3.2.0 { set_tree_depth t1 1000 } {1000} do_corruption_tests rtreeA-3.2 { 1 "SELECT * FROM t1" - 2 "SELECT * FROM t1 WHERE rowid=5" + 2 "SELECT * FROM t1 WHERE +rowid=5" 3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)" } @@ -183,7 +183,7 @@ do_test rtreeA-3.3.0 { } {65535} do_corruption_tests rtreeA-3.3 { 1 "SELECT * FROM t1" - 2 "SELECT * FROM t1 WHERE rowid=5" + 2 "SELECT * FROM t1 WHERE +rowid=5" 3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)" } @@ -203,7 +203,7 @@ do_test rtreeA-4.1.0 { } {4000} do_corruption_tests rtreeA-4.1 { 1 "SELECT * FROM t1" - 2 "SELECT * FROM t1 WHERE rowid=5" + 2 "SELECT * FROM t1 WHERE +rowid=5" 3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)" 4 "SELECT * FROM t1 WHERE x1<10 AND x2>12" } @@ -216,7 +216,7 @@ create_t1 populate_t1 do_execsql_test rtreeA-5.1.0 { DELETE FROM t1_parent } {} do_corruption_tests rtreeA-5.1 { - 1 "DELETE FROM t1 WHERE rowid = 5" + 1 "DELETE FROM t1 WHERE +rowid = 5" 2 "DELETE FROM t1" } diff --git a/ext/rtree/rtreedoc.test b/ext/rtree/rtreedoc.test new file mode 100644 index 00000000..b64faa2e --- /dev/null +++ b/ext/rtree/rtreedoc.test @@ -0,0 +1,1583 @@ +# 2021 September 13 +# +# 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 r-tree extension. +# + +if {![info exists testdir]} { + set testdir [file join [file dirname [info script]] .. .. test] +} +source [file join [file dirname [info script]] rtree_util.tcl] +source $testdir/tester.tcl +set testprefix rtreedoc + +ifcapable !rtree { + finish_test + return +} + +# This command returns the number of columns in table $tbl within the +# database opened by database handle $db +proc column_count {db tbl} { + set nCol 0 + $db eval "PRAGMA table_info = $tbl" { incr nCol } + return $nCol +} + +proc column_name_list {db tbl} { + set lCol [list] + $db eval "PRAGMA table_info = $tbl" { + lappend lCol $name + } + return $lCol +} +unset -nocomplain res + +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +# Section 3 of documentation. +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +set testprefix rtreedoc-1 + +# EVIDENCE-OF: R-15060-13876 A 1-dimensional R*Tree thus has 3 columns. +do_execsql_test 1.1.1 { CREATE VIRTUAL TABLE rt1 USING rtree(id, x1,x2) } +do_test 1.1.2 { column_count db rt1 } 3 + +# EVIDENCE-OF: R-19353-19546 A 2-dimensional R*Tree has 5 columns. +do_execsql_test 1.2.1 { CREATE VIRTUAL TABLE rt2 USING rtree(id,x1,x2, y1,y2) } +do_test 1.2.2 { column_count db rt2 } 5 + +# EVIDENCE-OF: R-13615-19528 A 3-dimensional R*Tree has 7 columns. +do_execsql_test 1.3.1 { + CREATE VIRTUAL TABLE rt3 USING rtree(id, x1,x2, y1,y2, z1,z2) +} +do_test 1.3.2 { column_count db rt3 } 7 + +# EVIDENCE-OF: R-53479-41922 A 4-dimensional R*Tree has 9 columns. +do_execsql_test 1.4.1 { + CREATE VIRTUAL TABLE rt4 USING rtree(id, x1,x2, y1,y2, z1,z2, v1,v2) +} +do_test 1.4.2 { column_count db rt4 } 9 + +# EVIDENCE-OF: R-13981-28768 And a 5-dimensional R*Tree has 11 columns. +do_execsql_test 1.5.1 { + CREATE VIRTUAL TABLE rt5 USING rtree(id, x1,x2, y1,y2, z1,z2, v1,v2, w1,w2) +} +do_test 1.5.2 { column_count db rt5 } 11 + + +# Attempt to create r-tree tables with 6 and 7 dimensions. +# +# EVIDENCE-OF: R-61533-25862 The SQLite R*Tree implementation does not +# support R*Trees wider than 5 dimensions. +do_catchsql_test 2.1.1 { + CREATE VIRTUAL TABLE rt6 USING rtree( + id, x1,x2, y1,y2, z1,z2, v1,v2, w1,w2, a1,a2 + ) +} {1 {Too many columns for an rtree table}} +do_catchsql_test 2.1.2 { + CREATE VIRTUAL TABLE rt6 USING rtree( + id, x1,x2, y1,y2, z1,z2, v1,v2, w1,w2, a1,a2, b1, b2 + ) +} {1 {Too many columns for an rtree table}} + +# Attempt to create r-tree tables with no columns, a single column, or +# an even number of columns. This and the tests above establish that: +# +# EVIDENCE-OF: R-16717-50504 Each R*Tree index is a virtual table with +# an odd number of columns between 3 and 11. +foreach {tn cols err} { + 1 "" "Too few columns for an rtree table" + 2 "x" "Too few columns for an rtree table" + 3 "x,y" "Too few columns for an rtree table" + 4 "a,b,c,d" "Wrong number of columns for an rtree table" + 5 "a,b,c,d,e,f" "Wrong number of columns for an rtree table" + 6 "a,b,c,d,e,f,g,h" "Wrong number of columns for an rtree table" + 7 "a,b,c,d,e,f,g,h,i,j" "Wrong number of columns for an rtree table" + 8 "a,b,c,d,e,f,g,h,i,j,k,l" "Too many columns for an rtree table" +} { + do_catchsql_test 3.$tn " + CREATE VIRTUAL TABLE xyz USING rtree($cols) + " [list 1 $err] +} + +# EVIDENCE-OF: R-17874-21123 The first column of an SQLite R*Tree is +# similar to an integer primary key column of a normal SQLite table. +# +# EVIDENCE-OF: R-46619-65417 The first column is always a 64-bit signed +# integer primary key. +# +# EVIDENCE-OF: R-46866-24036 It may only store a 64-bit signed integer +# value. +# +# EVIDENCE-OF: R-00250-64843 If an attempt is made to insert any other +# non-integer value into this column, the r-tree module silently +# converts it to an integer before writing it into the database. +# +do_execsql_test 4.0 { CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2) } +foreach {tn val res} { + 1 10 10 + 2 10.6 10 + 3 10.99 10 + 4 '123' 123 + 5 X'313233' 123 + 6 -10 -10 + 7 9223372036854775807 9223372036854775807 + 8 -9223372036854775808 -9223372036854775808 + 9 '9223372036854775807' 9223372036854775807 + 10 '-9223372036854775808' -9223372036854775808 + 11 'hello+world' 0 +} { + do_execsql_test 4.$tn.1 " + DELETE FROM rt; + INSERT INTO rt VALUES($val, 10, 20); + " + do_execsql_test 4.$tn.2 { + SELECT typeof(id), id FROM rt + } [list integer $res] +} + +# EVIDENCE-OF: R-15544-29079 Inserting a NULL value into this column +# causes SQLite to automatically generate a new unique primary key +# value. +do_execsql_test 5.1 { + DELETE FROM rt; + INSERT INTO rt VALUES(100, 1, 2); + INSERT INTO rt VALUES(NULL, 1, 2); +} +do_execsql_test 5.2 { SELECT id FROM rt } {100 101} +do_execsql_test 5.3 { + INSERT INTO rt VALUES(9223372036854775807, 1, 2); + INSERT INTO rt VALUES(NULL, 1, 2); +} +do_execsql_test 5.4 { + SELECT count(*) FROM rt; +} 4 +do_execsql_test 5.5 { + SELECT id IN(100, 101, 9223372036854775807) FROM rt ORDER BY 1; +} {0 1 1 1} + + +# EVIDENCE-OF: R-64317-38978 The other columns are pairs, one pair per +# dimension, containing the minimum and maximum values for that +# dimension, respectively. +# +# Show this by observing that attempts to insert rows with max>min fail. +# +do_execsql_test 6.1 { + CREATE VIRTUAL TABLE rtF USING rtree(id, x1,x2, y1,y2); + CREATE VIRTUAL TABLE rtI USING rtree_i32(id, x1,x2, y1,y2, z1,z2); +} +foreach {tn x1 x2 y1 y2 ok} { + 1 10.3 20.1 30.9 40.2 1 + 2 10.3 20.1 40.2 30.9 0 + 3 10.3 30.9 20.1 40.2 1 + 4 20.1 10.3 30.9 40.2 0 +} { + do_test 6.2.$tn { + catch { db eval { INSERT INTO rtF VALUES(NULL, $x1, $x2, $y1, $y2) } } + } [expr $ok==0] +} +foreach {tn x1 x2 y1 y2 z1 z2 ok} { + 1 10 20 30 40 50 60 1 + 2 10 20 30 40 60 50 0 + 3 10 20 30 50 40 60 1 + 4 10 20 40 30 50 60 0 + 5 10 30 20 40 50 60 1 + 6 20 10 30 40 50 60 0 +} { + do_test 6.3.$tn { + catch { db eval { INSERT INTO rtI VALUES(NULL,$x1,$x2,$y1,$y2,$z1,$z2) } } + } [expr $ok==0] +} + +# EVIDENCE-OF: R-08054-15429 The min/max-value pair columns are stored +# as 32-bit floating point values for "rtree" virtual tables or as +# 32-bit signed integers in "rtree_i32" virtual tables. +# +# Show this by showing that large values are rounded in ways consistent +# with those two 32-bit types. +do_execsql_test 7.1 { + DELETE FROM rtI; + INSERT INTO rtI VALUES( + 0, -2000000000, 2000000000, -5000000000, 5000000000, + -1000000000000, 10000000000000 + ); + SELECT * FROM rtI; +} { + 0 -2000000000 2000000000 -705032704 705032704 727379968 1316134912 +} +do_execsql_test 7.2 { + DELETE FROM rtF; + INSERT INTO rtF VALUES( + 0, -2000000000, 2000000000, + -1000000000000, 10000000000000 + ); + SELECT * FROM rtF; +} { + 0 -2000000000.0 2000000000.0 -1000000126976.0 10000000876544.0 +} + +# EVIDENCE-OF: R-47371-54529 Unlike regular SQLite tables which can +# store data in a variety of datatypes and formats, the R*Tree rigidly +# enforce these storage types. +# +# EVIDENCE-OF: R-39153-14977 If any other type of value is inserted into +# such a column, the r-tree module silently converts it to the required +# type before writing the new record to the database. +do_execsql_test 8.1 { + DELETE FROM rtI; + INSERT INTO rtI VALUES( + 1, 'hello world', X'616263', NULL, 44.5, 1000, 9999.9999 + ); + SELECT * FROM rtI; +} { + 1 0 0 0 44 1000 9999 +} + +do_execsql_test 8.2 { + SELECT + typeof(x1), typeof(x2), typeof(y1), typeof(y2), typeof(z1), typeof(z2) + FROM rtI +} {integer integer integer integer integer integer} + +do_execsql_test 8.3 { + DELETE FROM rtF; + INSERT INTO rtF VALUES( + 1, 'hello world', X'616263', NULL, 44 + ); + SELECT * FROM rtF; +} { + 1 0.0 0.0 0.0 44.0 +} +do_execsql_test 8.4 { + SELECT + typeof(x1), typeof(x2), typeof(y1), typeof(y2) + FROM rtF +} {real real real real} + + + + +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +# Section 3.1 of documentation. +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +set testprefix rtreedoc-2 +reset_db + +foreach {tn name clist} { + 1 t1 "id x1 x2" + 2 t2 "id x1 x2 y1 y2 z1 z2" +} { +# EVIDENCE-OF: R-15142-18077 A new R*Tree index is created as follows: +# CREATE VIRTUAL TABLE USING rtree(); + do_execsql_test 1.$tn.1 " + CREATE VIRTUAL TABLE $name USING rtree([join $clist ,]) + " + +# EVIDENCE-OF: R-51698-09302 The is the name your +# application chooses for the R*Tree index and is a +# comma separated list of between 3 and 11 columns. + do_test 1.$tn.2 { column_name_list db $name } [list {*}$clist] + +# EVIDENCE-OF: R-50130-53472 The virtual table creates +# three shadow tables to actually store its content. + do_execsql_test 1.$tn.3 { + SELECT count(*) FROM sqlite_schema + } [expr 1+3] + +# EVIDENCE-OF: R-45256-35998 The names of these shadow tables are: +# _node _rowid _parent + do_execsql_test 1.$tn.4 { + SELECT name FROM sqlite_schema WHERE rootpage>0 ORDER BY 1 + } [list ${name}_node ${name}_parent ${name}_rowid] + + do_execsql_test 1.$tn.5 "DROP TABLE $name" +} + +# EVIDENCE-OF: R-11241-54478 As an example, consider creating a +# two-dimensional R*Tree index for use in spatial queries: CREATE +# VIRTUAL TABLE demo_index USING rtree( id, -- Integer primary key minX, +# maxX, -- Minimum and maximum X coordinate minY, maxY -- Minimum and +# maximum Y coordinate ); +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE demo_index USING rtree( + id, -- Integer primary key + minX, maxX, -- Minimum and maximum X coordinate + minY, maxY -- Minimum and maximum Y coordinate + ); + INSERT INTO demo_index VALUES(1,2,3,4,5); + INSERT INTO demo_index VALUES(6,7,8,9,10); +} + +# EVIDENCE-OF: R-02287-33529 The shadow tables are ordinary SQLite data +# tables. +# +# Ordinary tables. With ordinary sqlite_schema entries. +do_execsql_test 2.1 { + SELECT type, name, sql FROM sqlite_schema WHERE sql NOT LIKE '%virtual%' +} { + table demo_index_rowid + {CREATE TABLE "demo_index_rowid"(rowid INTEGER PRIMARY KEY,nodeno)} + table demo_index_node + {CREATE TABLE "demo_index_node"(nodeno INTEGER PRIMARY KEY,data)} + table demo_index_parent + {CREATE TABLE "demo_index_parent"(nodeno INTEGER PRIMARY KEY,parentnode)} +} + +# EVIDENCE-OF: R-10863-13089 You can query them directly if you like, +# though this unlikely to reveal anything particularly useful. +# +# Querying: +do_execsql_test 2.2 { + SELECT count(*) FROM demo_index_node; + SELECT count(*) FROM demo_index_rowid; + SELECT count(*) FROM demo_index_parent; +} {1 2 0} + +# EVIDENCE-OF: R-05650-46070 And you can UPDATE, DELETE, INSERT or even +# DROP the shadow tables, though doing so will corrupt your R*Tree +# index. +do_execsql_test 2.3 { + DELETE FROM demo_index_rowid; + INSERT INTO demo_index_parent VALUES(2, 3); + UPDATE demo_index_node SET data = 'hello world' +} +do_catchsql_test 2.4 { + SELECT * FROM demo_index WHERE minX>10 AND maxX<30 +} {1 {database disk image is malformed}} +do_execsql_test 2.5 { + DROP TABLE demo_index_rowid +} + +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +# Section 3.1.1 of documentation. +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +set testprefix rtreedoc-3 +reset_db + +# EVIDENCE-OF: R-44253-50720 In the argments to "rtree" in the CREATE +# VIRTUAL TABLE statement, the names of the columns are taken from the +# first token of each argument. All subsequent tokens within each +# argument are silently ignored. +# +foreach {tn cols lCol} { + 1 {(id TEXT, x1 TEXT, x2 TEXT, y1 TEXT, y2 TEXT)} {id x1 x2 y1 y2} + 2 {(id TEXT, x1 UNIQUE, x2 TEXT, y1 NOT NULL, y2 TEXT)} {id x1 x2 y1 y2} + 3 {(id, x1 DEFAULT 4, x2 TEXT, y1 NOT NULL, y2 TEXT)} {id x1 x2 y1 y2} +} { + do_execsql_test 1.$tn.1 " CREATE VIRTUAL TABLE abc USING rtree $cols " + do_test 1.$tn.2 { column_name_list db abc } $lCol + +# EVIDENCE-OF: R-52032-06717 This means, for example, that if you try to +# give a column a type affinity or add a constraint such as UNIQUE or +# NOT NULL or DEFAULT to a column, those extra tokens are accepted as +# valid, but they do not change the behavior of the rtree. + + # Show there are no UNIQUE constraints + do_execsql_test 1.$tn.3 { + INSERT INTO abc VALUES(1, 10.0, 20.0, 10.0, 20.0); + INSERT INTO abc VALUES(2, 10.0, 20.0, 10.0, 20.0); + } + + # Show the default values have not been modified + do_execsql_test 1.$tn.4 { + INSERT INTO abc DEFAULT VALUES; + SELECT * FROM abc WHERE rowid NOT IN (1,2) + } {3 0.0 0.0 0.0 0.0} + + # Show that there are no NOT NULL constraints + do_execsql_test 1.$tn.5 { + INSERT INTO abc VALUES(NULL, NULL, NULL, NULL, NULL); + SELECT * FROM abc WHERE rowid NOT IN (1,2,3) + } {4 0.0 0.0 0.0 0.0} + +# EVIDENCE-OF: R-06893-30579 In an RTREE virtual table, the first column +# always has a type affinity of INTEGER and all other data columns have +# a type affinity of REAL. + do_execsql_test 1.$tn.5 { + INSERT INTO abc VALUES('5', '5', '5', '5', '5'); + SELECT * FROM abc WHERE rowid NOT IN (1,2,3,4) + } {5 5.0 5.0 5.0 5.0} + do_execsql_test 1.$tn.6 { + SELECT type FROM pragma_table_info('abc') ORDER BY cid + } {INT REAL REAL REAL REAL} + + do_execsql_test 1.$tn.7 " CREATE VIRTUAL TABLE abc2 USING rtree_i32 $cols " + +# EVIDENCE-OF: R-06224-52418 In an RTREE_I32 virtual table, all columns +# have type affinity of INTEGER. + do_execsql_test 1.$tn.8 { + INSERT INTO abc2 VALUES('6.0', '6.0', '6.0', '6.0', '6.0'); + SELECT * FROM abc2 + } {6 6 6 6 6} + do_execsql_test 1.$tn.9 { + SELECT type FROM pragma_table_info('abc2') ORDER BY cid + } {INT INT INT INT INT} + + + do_execsql_test 1.$tn.10 { + DROP TABLE abc; + DROP TABLE abc2; + } +} + +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +# Section 3.2 of documentation. +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +set testprefix rtreedoc-4 +reset_db + +# EVIDENCE-OF: R-36195-31555 The usual INSERT, UPDATE, and DELETE +# commands work on an R*Tree index just like on regular tables. +# +# Create a regular table and an rtree table. Perform INSERT, UPDATE and +# DELETE operations, then observe that the contents of the two tables +# are identical. +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2); + CREATE TABLE t1(id INTEGER PRIMARY KEY, x1 REAL, x2 REAL); +} +foreach {tn sql} { + 1 "INSERT INTO %TBL% VALUES(5, 11,12)" + 2 "INSERT INTO %TBL% VALUES(11, -11,14.5)" + 3 "UPDATE %TBL% SET x1=-99 WHERE id=11" + 4 "DELETE FROM %TBL% WHERE x2=14.5" + 5 "DELETE FROM %TBL%" +} { + set sql1 [string map {%TBL% rt} $sql] + set sql2 [string map {%TBL% t1} $sql] + do_execsql_test 1.$tn.0 $sql1 + do_execsql_test 1.$tn.1 $sql2 + + set data1 [execsql {SELECT * FROM rt ORDER BY 1}] + set data2 [execsql {SELECT * FROM t1 ORDER BY 1}] + + set res [expr {$data1==$data2}] + do_test 1.$tn.2 {set res} 1 +} + +# EVIDENCE-OF: R-56987-45305 +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE demo_index USING rtree( + id, -- Integer primary key + minX, maxX, -- Minimum and maximum X coordinate + minY, maxY -- Minimum and maximum Y coordinate + ); + + INSERT INTO demo_index VALUES + (28215, -80.781227, -80.604706, 35.208813, 35.297367), + (28216, -80.957283, -80.840599, 35.235920, 35.367825), + (28217, -80.960869, -80.869431, 35.133682, 35.208233), + (28226, -80.878983, -80.778275, 35.060287, 35.154446), + (28227, -80.745544, -80.555382, 35.130215, 35.236916), + (28244, -80.844208, -80.841988, 35.223728, 35.225471), + (28262, -80.809074, -80.682938, 35.276207, 35.377747), + (28269, -80.851471, -80.735718, 35.272560, 35.407925), + (28270, -80.794983, -80.728966, 35.059872, 35.161823), + (28273, -80.994766, -80.875259, 35.074734, 35.172836), + (28277, -80.876793, -80.767586, 35.001709, 35.101063), + (28278, -81.058029, -80.956375, 35.044701, 35.223812), + (28280, -80.844208, -80.841972, 35.225468, 35.227203), + (28282, -80.846382, -80.844193, 35.223972, 35.225655); +} + +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +# Section 3.3 of documentation. +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +set testprefix rtreedoc-5 + +do_execsql_test 1.0 { + INSERT INTO demo_index + SELECT NULL, minX, maxX, minY+0.2, maxY+0.2 FROM demo_index; + INSERT INTO demo_index + SELECT NULL, minX+0.2, maxX+0.2, minY, maxY FROM demo_index; + INSERT INTO demo_index + SELECT NULL, minX, maxX, minY+0.4, maxY+0.4 FROM demo_index; + INSERT INTO demo_index + SELECT NULL, minX+0.4, maxX+0.4, minY, maxY FROM demo_index; + INSERT INTO demo_index + SELECT NULL, minX, maxX, minY+0.8, maxY+0.8 FROM demo_index; + INSERT INTO demo_index + SELECT NULL, minX+0.8, maxX+0.8, minY, maxY FROM demo_index; + + SELECT count(*) FROM demo_index; +} {896} + +proc do_vmstep_test {tn sql expr} { + execsql $sql + set step [db status vmstep] + do_test $tn.$step "expr {[subst $expr]}" 1 +} + +# EVIDENCE-OF: R-45880-07724 Any valid query will work against an R*Tree +# index. +do_execsql_test 1.1.0 { + CREATE TABLE demo_tbl AS SELECT * FROM demo_index; +} +foreach {tn sql} { + 1 {SELECT * FROM %TBL% ORDER BY 1} + 2 {SELECT max(minX) FROM %TBL% ORDER BY 1} + 3 {SELECT max(minX) FROM %TBL% GROUP BY round(minY) ORDER BY 1} +} { + set sql1 [string map {%TBL% demo_index} $sql] + set sql2 [string map {%TBL% demo_tbl} $sql] + + do_execsql_test 1.1.$tn $sql1 [execsql $sql2] +} + +# EVIDENCE-OF: R-60814-18273 The R*Tree implementation just makes some +# kinds of queries especially efficient. +# +# The second query is more efficient than the first. +do_vmstep_test 1.2.1 {SELECT * FROM demo_index WHERE +rowid=28269} {$step>2000} +do_vmstep_test 1.2.2 {SELECT * FROM demo_index WHERE rowid=28269} {$step<100} + +# EVIDENCE-OF: R-37800-50174 Queries against the primary key are +# efficient: SELECT * FROM demo_index WHERE id=28269; +do_vmstep_test 2.2 { SELECT * FROM demo_index WHERE id=28269 } {$step < 100} + +# EVIDENCE-OF: R-35847-18866 The big reason for using an R*Tree is so +# that you can efficiently do range queries against the coordinate +# ranges. +# +# EVIDENCE-OF: R-49927-54202 +do_vmstep_test 2.3 { + SELECT id FROM demo_index + WHERE minX<=-80.77470 AND maxX>=-80.77470 + AND minY<=35.37785 AND maxY>=35.37785; +} {$step < 100} + +# EVIDENCE-OF: R-12823-37176 The query above will quickly locate all +# zipcodes that contain the SQLite main office in their bounding box, +# even if the R*Tree contains many entries. +# +do_execsql_test 2.4 { + SELECT id FROM demo_index + WHERE minX<=-80.77470 AND maxX>=-80.77470 + AND minY<=35.37785 AND maxY>=35.37785; +} { + 28322 28269 +} + +# EVIDENCE-OF: R-07351-00257 For example, to find all zipcode bounding +# boxes that overlap with the 28269 zipcode: SELECT A.id FROM demo_index +# AS A, demo_index AS B WHERE A.maxX>=B.minX AND A.minX<=B.maxX +# AND A.maxY>=B.minY AND A.minY<=B.maxY AND B.id=28269; +# +# Also check that it is efficient +# +# EVIDENCE-OF: R-39094-01937 This second query will find both 28269 +# entry (since every bounding box overlaps with itself) and also other +# zipcode that is close enough to 28269 that their bounding boxes +# overlap. +# +# 28269 is there in the result. +# +do_vmstep_test 2.5.1 { + SELECT A.id FROM demo_index AS A, demo_index AS B + WHERE A.maxX>=B.minX AND A.minX<=B.maxX + AND A.maxY>=B.minY AND A.minY<=B.maxY + AND B.id=28269 +} {$step < 100} +do_execsql_test 2.5.2 { + SELECT A.id FROM demo_index AS A, demo_index AS B + WHERE A.maxX>=B.minX AND A.minX<=B.maxX + AND A.maxY>=B.minY AND A.minY<=B.maxY + AND B.id=28269; +} { + 28293 28216 28322 28286 28269 + 28215 28336 28262 28291 28320 + 28313 28298 28287 +} + +# EVIDENCE-OF: R-02723-34107 Note that it is not necessary for all +# coordinates in an R*Tree index to be constrained in order for the +# index search to be efficient. +# +# EVIDENCE-OF: R-22490-27246 One might, for example, want to query all +# objects that overlap with the 35th parallel: SELECT id FROM demo_index +# WHERE maxY>=35.0 AND minY<=35.0; +do_vmstep_test 2.6.1 { + SELECT id FROM demo_index + WHERE maxY>=35.0 AND minY<=35.0; +} {$step < 100} +do_execsql_test 2.6.2 { + SELECT id FROM demo_index + WHERE maxY>=35.0 AND minY<=35.0; +} {} + + +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +# Section 3.4 of documentation. +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +set testprefix rtreedoc-6 +reset_db + +# EVIDENCE-OF: R-08327-00674 By default, coordinates are stored in an +# R*Tree using 32-bit floating point values. +# +# EVIDENCE-OF: R-22000-53613 The default virtual table ("rtree") stores +# coordinates as single-precision (4-byte) floating point numbers. +# +# Show this by showing that rounding is consistent with 32-bit float +# rounding. +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE rt USING rtree(id, a,b); +} +do_execsql_test 1.1 { + INSERT INTO rt VALUES(14, -1000000000000, 1000000000000); + SELECT * FROM rt; +} {14 -1000000126976.0 1000000126976.0} + +# EVIDENCE-OF: R-39127-51288 When a coordinate cannot be exactly +# represented by a 32-bit floating point number, the lower-bound +# coordinates are rounded down and the upper-bound coordinates are +# rounded up. +foreach {tn val} { + 1 100000000000 + 2 200000000000 + 3 300000000000 + 4 400000000000 + + 5 -100000000000 + 6 -200000000000 + 7 -300000000000 + 8 -400000000000 +} { + set val [expr $val] + do_execsql_test 2.$tn.0 {DELETE FROM rt} + do_execsql_test 2.$tn.1 {INSERT INTO rt VALUES(23, $val, $val)} + do_execsql_test 2.$tn.2 { + SELECT $val>=a, $val<=b, a!=b FROM rt + } {1 1 1} +} + +do_execsql_test 3.0 { + DROP TABLE rt; + CREATE VIRTUAL TABLE rt USING rtree(id, x1,x2, y1,y2); +} + +# EVIDENCE-OF: R-45870-62834 Thus, bounding boxes might be slightly +# larger than specified, but will never be any smaller. +foreach {tn x1 x2 y1 y2} { + 1 100000000000 200000000000 300000000000 400000000000 +} { + set val [expr $val] + do_execsql_test 3.$tn.0 {DELETE FROM rt} + do_execsql_test 3.$tn.1 {INSERT INTO rt VALUES(23, $x1, $x2, $y1, $y2)} + do_execsql_test 3.$tn.2 { + SELECT (x2-x1)*(y2-y1) >= ($x2-$x1)*($y2-$y1) FROM rt + } {1} +} + +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +# Section 3.5 of documentation. +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +set testprefix rtreedoc-7 +reset_db + +# EVIDENCE-OF: R-55979-39402 It is the nature of the Guttman R-Tree +# algorithm that any write might radically restructure the tree, and in +# the process change the scan order of the nodes. +# +# In the test below, the INSERT marked "THIS INSERT!!" does not affect +# the results of queries with an ORDER BY, but does affect the results +# of one without an ORDER BY. Therefore the INSERT changed the scan +# order. +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE rt USING rtree(id, minX, maxX); + WITH s(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<51 + ) + INSERT INTO rt SELECT NULL, i%10, (i%10)+5 FROM s +} +do_execsql_test 1.1 { SELECT count(*) FROM rt_node } 1 +do_test 1.2 { + set res1 [db eval {SELECT * FROM rt WHERE maxX < 30}] + set res1o [db eval {SELECT * FROM rt WHERE maxX < 30 ORDER BY +id}] + + db eval { INSERT INTO rt VALUES(NULL, 50, 50) } ;# THIS INSERT!! + + set res2 [db eval {SELECT * FROM rt WHERE maxX < 30}] + set res2o [db eval {SELECT * FROM rt WHERE maxX < 30 ORDER BY +id}] + list [expr {$res1==$res2}] [expr {$res1o==$res2o}] +} {0 1} + +do_execsql_test 1.3 { SELECT count(*) FROM rt_node } 3 + +# EVIDENCE-OF: R-00683-48865 For this reason, it is not generally +# possible to modify the R-Tree in the middle of a query of the R-Tree. +# Attempts to do so will fail with a SQLITE_LOCKED "database table is +# locked" error. +# +# SQLITE_LOCKED==6 +# +do_test 1.4 { + set nCnt 3 + db eval { SELECT * FROM rt WHERE minX>0 AND maxX<12 } { + incr nCnt -1 + if {$nCnt==0} { + set rc [catch {db eval { + INSERT INTO rt VALUES(NULL, 51, 51); + }} msg] + set errorcode [db errorcode] + break + } + } + + list $errorcode $rc $msg +} {6 1 {database table is locked}} + +# EVIDENCE-OF: R-19740-29710 So, for example, suppose an application +# runs one query against an R-Tree like this: SELECT id FROM demo_index +# WHERE maxY>=35.0 AND minY<=35.0; Then for each "id" value +# returned, suppose the application creates an UPDATE statement like the +# following and binds the "id" value returned against the "?1" +# parameter: UPDATE demo_index SET maxY=maxY+0.5 WHERE id=?1; +# +# EVIDENCE-OF: R-52919-32711 Then the UPDATE might fail with an +# SQLITE_LOCKED error. +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE demo_index USING rtree( + id, -- Integer primary key + minX, maxX, -- Minimum and maximum X coordinate + minY, maxY -- Minimum and maximum Y coordinate + ); + INSERT INTO demo_index VALUES + (28215, -80.781227, -80.604706, 35.208813, 35.297367), + (28216, -80.957283, -80.840599, 35.235920, 35.367825), + (28217, -80.960869, -80.869431, 35.133682, 35.208233), + (28226, -80.878983, -80.778275, 35.060287, 35.154446); +} +do_test 2.1 { + db eval { SELECT id FROM demo_index WHERE maxY>=35.0 AND minY<=35.0 } { + set rc [catch { + db eval { UPDATE demo_index SET maxY=maxY+0.5 WHERE id=$id } + } msg] + set errorcode [db errorcode] + break + } + list $errorcode $rc $msg +} {6 1 {database table is locked}} + +# EVIDENCE-OF: R-32604-49843 Ordinary tables in SQLite are able to read +# and write at the same time. +# +do_execsql_test 3.0 { + CREATE TABLE x1(a INTEGER PRIMARY KEY, b, c); + INSERT INTO x1 VALUES(1, 1, 1); + INSERT INTO x1 VALUES(2, 2, 2); + INSERT INTO x1 VALUES(3, 3, 3); + INSERT INTO x1 VALUES(4, 4, 4); +} +do_test 3.1 { + unset -nocomplain res + set res [list] + db eval { SELECT * FROM x1 } { + lappend res $a $b $c + switch -- $a { + 1 { + db eval { INSERT INTO x1 VALUES(5, 5, 5) } + } + 2 { + db eval { UPDATE x1 SET c=20 WHERE a=2 } + } + 3 { + db eval { DELETE FROM x1 WHERE c IN (3,4) } + } + } + } + set res +} {1 1 1 2 2 2 3 3 3 5 5 5} +do_execsql_test 3.2 { + SELECT * FROM x1 +} {1 1 1 2 2 20 5 5 5} + +# EVIDENCE-OF: R-06177-00576 And R-Tree can appear to read and write at +# the same time in some circumstances, if it can figure out how to +# reliably run the query to completion before starting the update. +# +# In 8.2, it can, it 8.1, it cannot. +do_test 8.1 { + db eval { SELECT * FROM rt } { + set rc [catch { db eval { INSERT INTO rt VALUES(53,53,53) } } msg] + break; + } + list $rc $msg +} {1 {database table is locked}} +do_test 8.2 { + db eval { SELECT * FROM rt ORDER BY +id } { + set rc [catch { db eval { INSERT INTO rt VALUES(53,53,53) } } msg] + break + } + list $rc $msg +} {0 {}} + +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +# Section 4 of documentation. +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +set testprefix rtreedoc-8 +reset_db + +# EVIDENCE-OF: R-21062-30088 For the example above, one might create an +# auxiliary table as follows: CREATE TABLE demo_data( id INTEGER PRIMARY +# KEY, -- primary key objname TEXT, -- name of the object objtype TEXT, +# -- object type boundary BLOB -- detailed boundary of object ); +# +# One might. +# +do_execsql_test 1.0 { + CREATE TABLE demo_data( + id INTEGER PRIMARY KEY, -- primary key + objname TEXT, -- name of the object + objtype TEXT, -- object type + boundary BLOB -- detailed boundary of object + ); +} + +do_execsql_test 1.1 { + CREATE VIRTUAL TABLE demo_index USING rtree( + id, -- Integer primary key + minX, maxX, -- Minimum and maximum X coordinate + minY, maxY -- Minimum and maximum Y coordinate + ); + + INSERT INTO demo_index VALUES + (28215, -80.781227, -80.604706, 35.208813, 35.297367), + (28216, -80.957283, -80.840599, 35.235920, 35.367825), + (28217, -80.960869, -80.869431, 35.133682, 35.208233), + (28226, -80.878983, -80.778275, 35.060287, 35.154446), + (28227, -80.745544, -80.555382, 35.130215, 35.236916), + (28244, -80.844208, -80.841988, 35.223728, 35.225471), + (28262, -80.809074, -80.682938, 35.276207, 35.377747), + (28269, -80.851471, -80.735718, 35.272560, 35.407925), + (28270, -80.794983, -80.728966, 35.059872, 35.161823), + (28273, -80.994766, -80.875259, 35.074734, 35.172836), + (28277, -80.876793, -80.767586, 35.001709, 35.101063), + (28278, -81.058029, -80.956375, 35.044701, 35.223812), + (28280, -80.844208, -80.841972, 35.225468, 35.227203), + (28282, -80.846382, -80.844193, 35.223972, 35.225655); + + INSERT INTO demo_index + SELECT NULL, minX, maxX, minY+0.2, maxY+0.2 FROM demo_index; + INSERT INTO demo_index + SELECT NULL, minX+0.2, maxX+0.2, minY, maxY FROM demo_index; + INSERT INTO demo_index + SELECT NULL, minX, maxX, minY+0.4, maxY+0.4 FROM demo_index; + INSERT INTO demo_index + SELECT NULL, minX+0.4, maxX+0.4, minY, maxY FROM demo_index; + INSERT INTO demo_index + SELECT NULL, minX, maxX, minY+0.8, maxY+0.8 FROM demo_index; + INSERT INTO demo_index + SELECT NULL, minX+0.8, maxX+0.8, minY, maxY FROM demo_index; + + INSERT INTO demo_data(id) SELECT id FROM demo_index; + + SELECT count(*) FROM demo_index; +} {896} + +set ::contained_in 0 +proc contained_in {args} {incr ::contained_in ; return 0} +db func contained_in contained_in + +# EVIDENCE-OF: R-32671-43888 Then an efficient way to find the specific +# ZIP code for the main SQLite office would be to run a query like this: +# SELECT objname FROM demo_data, demo_index WHERE +# demo_data.id=demo_index.id AND contained_in(demo_data.boundary, +# 35.37785, -80.77470) AND minX<=-80.77470 AND maxX>=-80.77470 AND +# minY<=35.37785 AND maxY>=35.37785; +do_vmstep_test 1.2 { + SELECT objname FROM demo_data, demo_index + WHERE demo_data.id=demo_index.id + AND contained_in(demo_data.boundary, 35.37785, -80.77470) + AND minX<=-80.77470 AND maxX>=-80.77470 + AND minY<=35.37785 AND maxY>=35.37785; +} {$step<100} +set ::contained_in1 $::contained_in + +# EVIDENCE-OF: R-32761-23915 One would get the same answer without the +# use of the R*Tree index using the following simpler query: SELECT +# objname FROM demo_data WHERE contained_in(demo_data.boundary, +# 35.37785, -80.77470); +set ::contained_in 0 +do_vmstep_test 1.3 { + SELECT objname FROM demo_data + WHERE contained_in(demo_data.boundary, 35.37785, -80.77470); +} {$step>3200} + +# EVIDENCE-OF: R-40261-32799 The problem with this latter query is that +# it must apply the contained_in() function to all entries in the +# demo_data table. +# +# 896 of them, IIRC. +do_test 1.4 { + set ::contained_in +} 896 + +# EVIDENCE-OF: R-24212-52761 The use of the R*Tree in the penultimate +# query reduces the number of calls to contained_in() function to a +# small subset of the entire table. +# +# 2 is a small subset of 896. +# +# EVIDENCE-OF: R-39057-63901 The R*Tree index did not find the exact +# answer itself, it merely limited the search space. +# +# contained_in() filtered out those 2 rows. +do_test 1.5 { + set ::contained_in1 +} {2} + + +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +# Section 4.1 of documentation. +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +set testprefix rtreedoc-9 +reset_db + +# EVIDENCE-OF: R-46566-43213 Beginning with SQLite version 3.24.0 +# (2018-06-04), r-tree tables can have auxiliary columns that store +# arbitrary data. Auxiliary columns can be used in place of secondary +# tables such as "demo_data". +# +# EVIDENCE-OF: R-41287-48160 Auxiliary columns are marked with a "+" +# symbol before the column name. +# +# This interface cannot conveniently be used to prove anything about +# versions of SQLite prior to 3.24.0. +# +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE rta USING rtree( + id, u1,u2, v1,v2, +aux + ); + + INSERT INTO rta(aux) VALUES(NULL); + INSERT INTO rta(aux) VALUES(45); + INSERT INTO rta(aux) VALUES(22.3); + INSERT INTO rta(aux) VALUES('hello'); + INSERT INTO rta(aux) VALUES(X'ABCD'); + + SELECT typeof(aux), quote(aux) FROM rta; +} { + null NULL + integer 45 + real 22.3 + text 'hello' + blob X'ABCD' +} + +# EVIDENCE-OF: R-30514-26093 Auxiliary columns must come after all of +# the coordinate boundary columns. +foreach {tn cols} { + 1 "id x1,x2, +extra, y1,y2" + 2 "extra, +id x1,x2, y1,y2" + 3 "id, x1,+x2, extra, y1,y2" +} { + do_catchsql_test 2.$tn " + CREATE VIRTUAL TABLE rrr USING rtree($cols) + " {1 {Auxiliary rtree columns must be last}} +} +do_catchsql_test 3.0 { + CREATE VIRTUAL TABLE rrr USING rtree(+id, extra, x1, x2); +} {1 {near "+": syntax error}} + +# EVIDENCE-OF: R-01280-03635 An RTREE table can have no more than 100 +# columns total. In other words, the count of columns including the +# integer primary key column, the coordinate boundary columns, and all +# auxiliary columns must be 100 or less. +do_catchsql_test 3.1 { + CREATE VIRTUAL TABLE r1 USING rtree(intid, u1,u2, + +c00, +c01, +c02, +c03, +c04, +c05, +c06, +c07, +c08, +c09, + +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, +c66, +c67, +c68, +c69, + +c70, +c71, +c72, +c73, +c74, +c75, +c76, +c77, +c78, +c79, + +c80, +c81, +c82, +c83, +c84, +c85, +c86, +c87, +c88, +c89, + +c90, +c91, +c92, +c93, +c94, +c95, +c96 + ); +} {0 {}} +do_catchsql_test 3.2 { + DROP TABLE r1; + CREATE VIRTUAL TABLE r1 USING rtree(intid, u1,u2, + +c00, +c01, +c02, +c03, +c04, +c05, +c06, +c07, +c08, +c09, + +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, +c66, +c67, +c68, +c69, + +c70, +c71, +c72, +c73, +c74, +c75, +c76, +c77, +c78, +c79, + +c80, +c81, +c82, +c83, +c84, +c85, +c86, +c87, +c88, +c89, + +c90, +c91, +c92, +c93, +c94, +c95, +c96, +c97 + ); +} {1 {Too many columns for an rtree table}} +do_catchsql_test 3.3 { + CREATE VIRTUAL TABLE r1 USING rtree(intid, u1,u2, v1,v2, + +c00, +c01, +c02, +c03, +c04, +c05, +c06, +c07, +c08, +c09, + +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, +c66, +c67, +c68, +c69, + +c70, +c71, +c72, +c73, +c74, +c75, +c76, +c77, +c78, +c79, + +c80, +c81, +c82, +c83, +c84, +c85, +c86, +c87, +c88, +c89, + +c90, +c91, +c92, +c93, +c94, + ); +} {0 {}} +do_catchsql_test 3.4 { + DROP TABLE r1; + CREATE VIRTUAL TABLE r1 USING rtree(intid, u1,u2, v1,v2, + +c00, +c01, +c02, +c03, +c04, +c05, +c06, +c07, +c08, +c09, + +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, +c66, +c67, +c68, +c69, + +c70, +c71, +c72, +c73, +c74, +c75, +c76, +c77, +c78, +c79, + +c80, +c81, +c82, +c83, +c84, +c85, +c86, +c87, +c88, +c89, + +c90, +c91, +c92, +c93, +c94, +c95, + ); +} {1 {Too many columns for an rtree table}} + +# EVIDENCE-OF: R-05552-15084 +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE demo_index2 USING rtree( + id, -- Integer primary key + minX, maxX, -- Minimum and maximum X coordinate + minY, maxY, -- Minimum and maximum Y coordinate + +objname TEXT, -- name of the object + +objtype TEXT, -- object type + +boundary BLOB -- detailed boundary of object + ); +} +do_execsql_test 4.1 { + CREATE VIRTUAL TABLE demo_index USING rtree( + id, -- Integer primary key + minX, maxX, -- Minimum and maximum X coordinate + minY, maxY -- Minimum and maximum Y coordinate + ); + CREATE TABLE demo_data( + id INTEGER PRIMARY KEY, -- primary key + objname TEXT, -- name of the object + objtype TEXT, -- object type + boundary BLOB -- detailed boundary of object + ); + + INSERT INTO demo_index2(id) VALUES(1); + INSERT INTO demo_index(id) VALUES(1); + INSERT INTO demo_data(id) VALUES(1); +} +do_test 4.2 { + catch { array unset R } + db eval {SELECT * FROM demo_index2} R { set r1 [array names R] } + catch { array unset R } + db eval {SELECT * FROM demo_index NATURAL JOIN demo_data } R { + set r2 [array names R] + } + expr {$r1==$r2} +} {1} + +# EVIDENCE-OF: R-26099-32169 SELECT objname FROM demo_index2 WHERE +# contained_in(boundary, 35.37785, -80.77470) AND minX<=-80.77470 AND +# maxX>=-80.77470 AND minY<=35.37785 AND maxY>=35.37785; +do_execsql_test 4.3.1 { + DELETE FROM demo_index2; + INSERT INTO demo_index2(id,minX,maxX,minY,maxY) VALUES + (28215, -80.781227, -80.604706, 35.208813, 35.297367), + (28216, -80.957283, -80.840599, 35.235920, 35.367825), + (28217, -80.960869, -80.869431, 35.133682, 35.208233), + (28226, -80.878983, -80.778275, 35.060287, 35.154446), + (28227, -80.745544, -80.555382, 35.130215, 35.236916), + (28244, -80.844208, -80.841988, 35.223728, 35.225471), + (28262, -80.809074, -80.682938, 35.276207, 35.377747), + (28269, -80.851471, -80.735718, 35.272560, 35.407925), + (28270, -80.794983, -80.728966, 35.059872, 35.161823), + (28273, -80.994766, -80.875259, 35.074734, 35.172836), + (28277, -80.876793, -80.767586, 35.001709, 35.101063), + (28278, -81.058029, -80.956375, 35.044701, 35.223812), + (28280, -80.844208, -80.841972, 35.225468, 35.227203), + (28282, -80.846382, -80.844193, 35.223972, 35.225655); +} +set ::contained_in 0 +proc contained_in {args} { + incr ::contained_in + return 0 +} +db func contained_in contained_in +do_execsql_test 4.3.2 { + SELECT objname FROM demo_index2 + WHERE contained_in(boundary, 35.37785, -80.77470) + AND minX<=-80.77470 AND maxX>=-80.77470 + AND minY<=35.37785 AND maxY>=35.37785; +} +do_test 4.3.3 { + # Function invoked only once because r-tree filtering happened first. + set ::contained_in +} 1 +set ::contained_in 0 +do_execsql_test 4.3.4 { + SELECT objname FROM demo_index2 + WHERE contained_in(boundary, 35.37785, -80.77470) +} +do_test 4.3.3 { + # Function invoked 14 times because no r-tree filtering. Inefficient. + set ::contained_in +} 14 + +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +# Section 4.1.1 of documentation. +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +set testprefix rtreedoc-9 +reset_db + +# EVIDENCE-OF: R-24021-02490 For auxiliary columns, only the name of the +# column matters. The type affinity is ignored. +# +# EVIDENCE-OF: R-39906-44154 Constraints such as NOT NULL, UNIQUE, +# REFERENCES, or CHECK are also ignored. +do_execsql_test 1.0 { PRAGMA foreign_keys = on } +foreach {tn auxcol nm} { + 1 "+extra INTEGER" extra + 2 "+extra TEXT" extra + 3 "+extra BLOB" extra + 4 "+extra REAL" extra + + 5 "+col NOT NULL" col + 6 "+col CHECK (col IS NOT NULL)" col + 7 "+col REFERENCES tbl(x)" col +} { + do_execsql_test 1.$tn.1 " + CREATE VIRTUAL TABLE rt USING rtree_i32(k, a,b, $auxcol) + " + + # Check that the aux column has no affinity. Or NOT NULL constraint. + # And that the aux column is the child key of an FK constraint. + # + do_execsql_test 1.$tn.2 " + INSERT INTO rt($nm) VALUES(NULL), (45), (-123.2), ('456'), (X'ABCD'); + SELECT typeof($nm), quote($nm) FROM rt; + " { + null NULL + integer 45 + real -123.2 + text '456' + blob X'ABCD' + } + + # Check that there is no UNIQUE constraint either. + # + do_execsql_test 1.$tn.3 " + INSERT INTO rt($nm) VALUES('xyz'), ('xyz'), ('xyz'); + " + + do_execsql_test 1.$tn.2 { + DROP TABLE rt + } +} + +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +# Section 5 of documentation. +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +set testprefix rtreedoc-10 + +# EVIDENCE-OF: R-21011-43790 If integer coordinates are desired, declare +# the table using "rtree_i32" instead: CREATE VIRTUAL TABLE intrtree +# USING rtree_i32(id,x0,x1,y0,y1,z0,z1); +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE intrtree USING rtree_i32(id,x0,x1,y0,y1,z0,z1); + INSERT INTO intrtree DEFAULT VALUES; + SELECT typeof(x0) FROM intrtree; +} {integer} + +# EVIDENCE-OF: R-09193-49806 An rtree_i32 stores coordinates as 32-bit +# signed integers. +# +# Show that coordinates are cast in a way consistent with casting to +# a signed 32-bit integer. +do_execsql_test 1.1 { + DELETE FROM intrtree; + INSERT INTO intrtree VALUES(333, + 1<<44, (1<<44)+1, + 10000000000, 10000000001, + -10000000001, -10000000000 + ); + SELECT * FROM intrtree; +} { + 333 0 1 1410065408 1410065409 -1410065409 -1410065408 +} + +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +# Section 7.1 of documentation. +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +set testprefix rtreedoc-11 +reset_db + +# This command assumes that the argument is a node blob for a 2 dimensional +# i32 r-tree table. It decodes and returns a list of cells from the node +# as a list. Each cell is itself a list of the following form: +# +# {$rowid $minX $maxX $minY $maxY} +# +# For internal (non-leaf) nodes, the rowid is replaced by the child node +# number. +# +proc rnode {aData} { + set nDim 2 + + set nData [string length $aData] + set nBytePerCell [expr (8 + 2*$nDim*4)] + binary scan [string range $aData 2 3] S nCell + + set res [list] + for {set i 0} {$i < $nCell} {incr i} { + set iOff [expr $i*$nBytePerCell+4] + set cell [string range $aData $iOff [expr $iOff+$nBytePerCell-1]] + binary scan $cell WIIII rowid x1 x2 y1 y2 + lappend res [list $rowid $x1 $x2 $y1 $y2] + } + + return $res +} + +# aData must be a node blob. This command returns true if the node contains +# rowid $rowid, or false otherwise. +# +proc rnode_contains {aData rowid} { + set L [rnode $aData] + foreach cell $L { + set r [lindex $cell 0] + if {$r==$rowid} { return 1 } + } + return 0 +} + +proc rnode_replace_cell {aData iCell cell} { + set aCell [binary format WIIII {*}$cell] + set nDim 2 + set nBytePerCell [expr (8 + 2*$nDim*4)] + set iOff [expr $iCell*$nBytePerCell+4] + + set aNew [binary format a*a*a* \ + [string range $aData 0 $iOff-1] \ + $aCell \ + [string range $aData $iOff+$nBytePerCell end] \ + ] + return $aNew +} + +db function rnode rnode +db function rnode_contains rnode_contains +db function rnode_replace_cell rnode_replace_cell + +foreach {tn nm} { + 1 x1 + 2 asdfghjkl + 3 hello_world +} { + do_execsql_test 1.$tn.1 " + CREATE VIRTUAL TABLE $nm USING rtree(a,b,c,d,e); + " + + # EVIDENCE-OF: R-33789-46762 The content of an R*Tree index is actually + # stored in three ordinary SQLite tables with names derived from the + # name of the R*Tree. + # + # EVIDENCE-OF: R-39849-06566 This is their schema: CREATE TABLE + # %_node(nodeno INTEGER PRIMARY KEY, data) CREATE TABLE %_parent(nodeno + # INTEGER PRIMARY KEY, parentnode) CREATE TABLE %_rowid(rowid INTEGER + # PRIMARY KEY, nodeno) + # + # EVIDENCE-OF: R-07489-10051 The "%" in the name of each shadow table is + # replaced by the name of the R*Tree virtual table. So, if the name of + # the R*Tree table is "xyz" then the three shadow tables would be + # "xyz_node", "xyz_parent", and "xyz_rowid". + do_execsql_test 1.$tn.2 { + SELECT sql FROM sqlite_schema WHERE name!=$nm ORDER BY 1 + } [string map [list % $nm] " + {CREATE TABLE \"%_node\"(nodeno INTEGER PRIMARY KEY,data)} + {CREATE TABLE \"%_parent\"(nodeno INTEGER PRIMARY KEY,parentnode)} + {CREATE TABLE \"%_rowid\"(rowid INTEGER PRIMARY KEY,nodeno)} + "] + + do_execsql_test 1.$tn "DROP TABLE $nm" +} + + +# EVIDENCE-OF: R-51070-59303 There is one entry in the %_node table for +# each R*Tree node. +# +# The following creates a 6 node r-tree structure. +# +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE r1 USING rtree_i32(i, x1,x2, y1,y2); + WITH t(i) AS ( + VALUES(1) UNION SELECT i+1 FROM t WHERE i<110 + ) + INSERT INTO r1 SELECT i, (i%10), (i%10)+2, (i%6), (i%7)+6 FROM t; +} +do_execsql_test 2.1 { + SELECT count(*) FROM r1_node; +} 6 + +# EVIDENCE-OF: R-27261-09153 All nodes other than the root have an entry +# in the %_parent shadow table that identifies the parent node. +# +# In this case nodes 2-6 are the children of node 1. +# +do_execsql_test 2.3 { + SELECT nodeno, parentnode FROM r1_parent +} {2 1 3 1 4 1 5 1 6 1} + +# EVIDENCE-OF: R-02358-35037 The %_rowid shadow table maps entry rowids +# to the node that contains that entry. +# +do_execsql_test 2.4 { + SELECT 'failed' FROM r1_rowid WHERE 0==rnode_contains( + (SELECT data FROM r1_node WHERE nodeno=r1_rowid.nodeno), rowid + ) +} +do_test 2.5 { + db eval { SELECT nodeno, data FROM r1_node WHERE nodeno!=1 } { + set L [rnode $data] + foreach cell $L { + set rowid [lindex $cell 0] + set rowid_nodeno 0 + db eval {SELECT nodeno AS rowid_nodeno FROM r1_rowid WHERE rowid=$rowid} { + break + } + if {$rowid_nodeno!=$nodeno} { error "data mismatch!" } + } + } +} {} + +# EVIDENCE-OF: R-65201-22208 Extra columns appended to the %_rowid table +# hold the content of auxiliary columns. +# +# EVIDENCE-OF: R-44161-28345 The names of these extra %_rowid columns +# are probably not the same as the actual auxiliary column names. +# +# In this case, the auxiliary columns are named "e1" and "e2". The +# extra %_rowid columns are named "a0" and "a1". +# +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE rtaux USING rtree(id, x1,x2, y1,y2, +e1, +e2); + SELECT sql FROM sqlite_schema WHERE name='rtaux_rowid'; +} { + {CREATE TABLE "rtaux_rowid"(rowid INTEGER PRIMARY KEY,nodeno,a0,a1)} +} +do_execsql_test 3.1 { + INSERT INTO rtaux(e1, e2) VALUES('hello', 'world'), (123, 456); +} +do_execsql_test 3.2 { + SELECT a0, a1 FROM rtaux_rowid; +} { + hello world 123 456 +} + +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +# Section 7.2 of documentation. +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +set testprefix rtreedoc-12 +reset_db +forcedelete test.db2 + +db function rnode rnode +db function rnode_contains rnode_contains +db function rnode_replace_cell rnode_replace_cell + +# EVIDENCE-OF: R-13571-45795 The scalar SQL function rtreecheck(R) or +# rtreecheck(S,R) runs an integrity check on the rtree table named R +# contained within database S. +# +# EVIDENCE-OF: R-36011-59963 The function returns a human-language +# description of any problems found, or the string 'ok' if everything is +# ok. +# +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE rt1 USING rtree(id, a, b); + WITH s(i) AS ( + VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<200 + ) + INSERT INTO rt1 SELECT i, i, i FROM s; + + ATTACH 'test.db2' AS 'aux'; + CREATE VIRTUAL TABLE aux.rt1 USING rtree(id, a, b); + INSERT INTO aux.rt1 SELECT * FROM rt1; +} + +do_execsql_test 1.1.1 { SELECT rtreecheck('rt1'); } {ok} +do_execsql_test 1.1.2 { SELECT rtreecheck('main', 'rt1'); } {ok} +do_execsql_test 1.1.3 { SELECT rtreecheck('aux', 'rt1'); } {ok} +do_catchsql_test 1.1.4 { + SELECT rtreecheck('nosuchdb', 'rt1'); +} {1 {SQL logic error}} + +# Corrupt the table in database 'main': +do_execsql_test 1.2.1 { UPDATE rt1_node SET nodeno=21 WHERE nodeno=3; } +do_execsql_test 1.2.1 { SELECT rtreecheck('rt1')=='ok'; } {0} +do_execsql_test 1.2.2 { SELECT rtreecheck('main', 'rt1')=='ok'; } {0} +do_execsql_test 1.2.3 { SELECT rtreecheck('aux', 'rt1')=='ok'; } {1} +do_execsql_test 1.2.4 { UPDATE rt1_node SET nodeno=3 WHERE nodeno=21; } + +# Corrupt the table in database 'aux': +do_execsql_test 1.2.1 { UPDATE aux.rt1_node SET nodeno=21 WHERE nodeno=3; } +do_execsql_test 1.2.1 { SELECT rtreecheck('rt1')=='ok'; } {1} +do_execsql_test 1.2.2 { SELECT rtreecheck('main', 'rt1')=='ok'; } {1} +do_execsql_test 1.2.3 { SELECT rtreecheck('aux', 'rt1')=='ok'; } {0} +do_execsql_test 1.2.4 { UPDATE rt1_node SET nodeno=3 WHERE nodeno=21; } + +# EVIDENCE-OF: R-45759-33459 Example: To verify that an R*Tree named +# "demo_index" is well-formed and internally consistent, run: SELECT +# rtreecheck('demo_index'); +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE demo_index USING rtree(id, x1,x2, y1,y2); + INSERT INTO demo_index SELECT id, a, b, a, b FROM rt1; +} +do_execsql_test 2.1 { SELECT rtreecheck('demo_index') } {ok} +do_execsql_test 2.2 { + UPDATE demo_index_rowid SET nodeno=44 WHERE rowid=44; + SELECT rtreecheck('demo_index'); +} {{Found (44 -> 44) in %_rowid table, expected (44 -> 4)}} + + +do_execsql_test 3.0 { + CREATE VIRTUAL TABLE rt2 USING rtree_i32(id, a, b, c, d); + WITH s(i) AS ( + VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<200 + ) + INSERT INTO rt2 SELECT i, i, i+2, i, i+2 FROM s; +} + +# EVIDENCE-OF: R-02555-31045 for each dimension, (coord1 <= coord2). +# +execsql BEGIN +do_test 3.1 { + set cell [ + lindex [execsql {SELECT rnode(data) FROM rt2_node WHERE nodeno=3}] 0 3 + ] + set cell [list [lindex $cell 0] \ + [lindex $cell 2] [lindex $cell 1] \ + [lindex $cell 3] [lindex $cell 4] \ + ] + execsql { + UPDATE rt2_node SET data=rnode_replace_cell(data, 3, $cell) WHERE nodeno=3 + } + execsql { SELECT rtreecheck('rt2') } +} {{Dimension 0 of cell 3 on node 3 is corrupt}} +execsql ROLLBACK + +# EVIDENCE-OF: R-13844-15873 unless the cell is on the root node, that +# the cell is bounded by the parent cell on the parent node. +# +execsql BEGIN +do_test 3.2 { + set cell [ + lindex [execsql {SELECT rnode(data) FROM rt2_node WHERE nodeno=3}] 0 3 + ] + lset cell 3 450 + lset cell 4 451 + execsql { + UPDATE rt2_node SET data=rnode_replace_cell(data, 3, $cell) WHERE nodeno=3 + } + execsql { SELECT rtreecheck('rt2') } +} {{Dimension 1 of cell 3 on node 3 is corrupt relative to parent}} +execsql ROLLBACK + +# EVIDENCE-OF: R-02505-03621 for leaf nodes, that there is an entry in +# the %_rowid table corresponding to the cell's rowid value that points +# to the correct node. +# +execsql BEGIN +do_test 3.3 { + execsql { + UPDATE rt2_rowid SET rowid=452 WHERE rowid=100 + } + execsql { SELECT rtreecheck('rt2') } +} {{Mapping (100 -> 6) missing from %_rowid table}} +execsql ROLLBACK + +# EVIDENCE-OF: R-50927-02218 for cells on non-leaf nodes, that there is +# an entry in the %_parent table mapping from the cell's child node to +# the node that it resides on. +# +execsql BEGIN +do_test 3.4.1 { + execsql { + UPDATE rt2_parent SET parentnode=123 WHERE nodeno=3 + } + execsql { SELECT rtreecheck('rt2') } +} {{Found (3 -> 123) in %_parent table, expected (3 -> 1)}} +execsql ROLLBACK +execsql BEGIN +do_test 3.4.2 { + execsql { + UPDATE rt2_parent SET nodeno=123 WHERE nodeno=3 + } + execsql { SELECT rtreecheck('rt2') } +} {{Mapping (3 -> 1) missing from %_parent table}} +execsql ROLLBACK + +# EVIDENCE-OF: R-23235-09153 That there are the same number of entries +# in the %_rowid table as there are leaf cells in the r-tree structure, +# and that there is a leaf cell that corresponds to each entry in the +# %_rowid table. +execsql BEGIN +do_test 3.5 { + execsql { INSERT INTO rt2_rowid VALUES(1000, 1000) } + execsql { SELECT rtreecheck('rt2') } +} {{Wrong number of entries in %_rowid table - expected 200, actual 201}} +execsql ROLLBACK + +# EVIDENCE-OF: R-62800-43436 That there are the same number of entries +# in the %_parent table as there are non-leaf cells in the r-tree +# structure, and that there is a non-leaf cell that corresponds to each +# entry in the %_parent table. +execsql BEGIN +do_test 3.6 { + execsql { INSERT INTO rt2_parent VALUES(1000, 1000) } + execsql { SELECT rtreecheck('rt2') } +} {{Wrong number of entries in %_parent table - expected 9, actual 10}} +execsql ROLLBACK + + + +finish_test diff --git a/ext/rtree/rtreedoc2.test b/ext/rtree/rtreedoc2.test new file mode 100644 index 00000000..ca0c6b31 --- /dev/null +++ b/ext/rtree/rtreedoc2.test @@ -0,0 +1,346 @@ +# 2021 September 13 +# +# 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 r-tree extension. +# + +if {![info exists testdir]} { + set testdir [file join [file dirname [info script]] .. .. test] +} +source [file join [file dirname [info script]] rtree_util.tcl] +source $testdir/tester.tcl +set testprefix rtreedoc2 + +ifcapable !rtree { + finish_test + return +} + +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +# Section 6 of documentation. +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +set testprefix rtreedoc2-1 + +# EVIDENCE-OF: R-35254-48865 A call to one of the above APIs creates a +# new SQL function named by the second parameter (zQueryFunc or zGeom). +# +# [register_circle_geom db] registers new geometry callback "Qcircle" +# and legacy implementation "circle". Test that these do actually appear. +# +do_execsql_test 1.1.0 { + SELECT * FROM pragma_function_list WHERE name IN('circle', 'qcircle'); +} { +} +do_test 1.1 { + register_circle_geom db +} {SQLITE_OK} +do_execsql_test 1.1.2 { + SELECT * FROM pragma_function_list WHERE name = 'circle' AND enc='utf8'; +} { + circle 0 s utf8 -1 0 +} +do_execsql_test 1.1.3 { + SELECT * FROM pragma_function_list WHERE name = 'qcircle' AND enc='utf8'; +} { + qcircle 0 s utf8 -1 0 +} + +do_execsql_test 1.2.0 { SELECT circle(1, 2, 3); } {{}} +do_execsql_test 1.2.1 { SELECT qcircle(1, 2, 3); } {{}} + +# EVIDENCE-OF: R-61427-46983 +do_execsql_test 1.3.0 { + CREATE VIRTUAL TABLE demo_index USING rtree(id, x1,x2, y1,y2); + INSERT INTO demo_index VALUES(10, 45,45, 24,24); + INSERT INTO demo_index VALUES(20, 50,50, 28,28); + INSERT INTO demo_index VALUES(30, 43,43, 22,22); +} +do_execsql_test 1.3.1 { + SELECT id FROM demo_index WHERE id MATCH circle(45.3, 22.9, 5.0) +} {10 30} + +# EVIDENCE-OF: R-16907-50223 The SQL syntax for custom queries is the +# same regardless of which interface, sqlite3_rtree_geometry_callback() +# or sqlite3_rtree_query_callback(), is used to register the SQL +# function. +do_execsql_test 1.3.2 { + SELECT id FROM demo_index WHERE id MATCH qcircle(45.3, 22.9, 5.0, 1) +} {10 30} + + +# EVIDENCE-OF: R-59634-51678 When that SQL function appears on the +# right-hand side of the MATCH operator and the left-hand side of the +# MATCH operator is any column in the R*Tree virtual table, then the +# callback defined by the third argument (xQueryFunc or xGeom) is +# invoked to determine if a particular object or subtree overlaps the +# desired region. +proc box_geom {args} { + lappend ::box_geom [concat [lindex $args 0] [lrange $args 2 end-1]] + return "" +} +register_box_geom db box_geom +set box_geom [list] +do_execsql_test 1.3.2 { + SELECT id FROM demo_index WHERE id MATCH box(43,46, 21,25); +} {10 30} +do_test 1.3.3 { + set ::box_geom +} [list {*}{ + {box {43.0 46.0 21.0 25.0} {45.0 45.0 24.0 24.0}} + {box {43.0 46.0 21.0 25.0} {50.0 50.0 28.0 28.0}} + {box {43.0 46.0 21.0 25.0} {43.0 43.0 22.0 22.0}} +}] + +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +# Section 6 of documentation. +#------------------------------------------------------------------------- +#------------------------------------------------------------------------- +set testprefix rtreedoc2-2 + +# EVIDENCE-OF: R-02424-24769 The second argument is the number of +# coordinates in each r-tree entry, and is always the same for any given +# R*Tree. +# +# EVIDENCE-OF: R-40260-16838 The number of coordinates is 2 for a +# 1-dimensional R*Tree, 4 for a 2-dimensional R*Tree, 6 for a +# 3-dimensional R*Tree, and so forth. +# +# The second argument refered to above is the length of the list passed +# as the 3rd parameter to the Tcl script. +# +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE rt1 USING rtree(id, x1,x2); + CREATE VIRTUAL TABLE rt2 USING rtree(id, x1,x2, y1,y2); + CREATE VIRTUAL TABLE rt3 USING rtree(id, x1,x2, y1,y2, z1,z2); + + INSERT INTO rt1 DEFAULT VALUES; + INSERT INTO rt2 DEFAULT VALUES; + INSERT INTO rt3 DEFAULT VALUES; +} +foreach {tn tbl nCoord} { + 1 rt1 2 + 2 rt2 4 + 3 rt3 6 +} { + set ::box_geom [list] + do_catchsql_test 1.$tn.1 " + SELECT id FROM $tbl WHERE id MATCH box(); + " {1 {SQL logic error}} + + do_test 1.$tn.2 { + llength [lindex $::box_geom 0 2] + } $nCoord +} + +# EVIDENCE-OF: R-28051-48608 If xGeom returns anything other than +# SQLITE_OK, then the r-tree query will abort with an error. +proc box_geom {args} { + error "an error!" +} +do_catchsql_test 2.0 { + SELECT * FROM rt2 WHERE id MATCH box(22,23, 24,25); +} {1 {SQL logic error}} + +do_execsql_test 3.0 { + INSERT INTO rt1 VALUES(10, 10, 10); + INSERT INTO rt1 VALUES(11, 11, 11); + INSERT INTO rt1 VALUES(12, 12, 12); + INSERT INTO rt1 VALUES(13, 13, 13); + INSERT INTO rt1 VALUES(14, 14, 14); +} + +# EVIDENCE-OF: R-53759-57366 The exact same sqlite3_rtree_geometry +# structure is used for every callback for same MATCH operator in the +# same query. +proc box_geom {args} { + lappend ::ptr_list [lindex $args 4] + return 0 +} +set ::ptr_list [list] +do_execsql_test 3.1 { + SELECT * FROM rt1 WHERE id MATCH box(1,1); +} +do_test 3.2 { + set val [lindex $::ptr_list 0] + foreach p $::ptr_list { + if {$p!=$val} {error "pointer mismatch"} + } +} {} + +# EVIDENCE-OF: R-60247-35692 The contents of the sqlite3_rtree_geometry +# structure are initialized by SQLite but are not subsequently modified. +proc box_geom {args} { + lappend ::box_geom [concat [lindex $args 0] [lrange $args 2 end-1]] + if {[llength $::box_geom]==3} { + return "zero" + } + return "" +} +set ::box_geom [list] +do_catchsql_test 3.2 { + SELECT * FROM rt1 WHERE id MATCH box(1,1); +} {1 {SQL logic error}} +do_test 3.3 { + set ::box_geom +} [list {*}{ + {box {1.0 1.0} {0.0 0.0}} + {box {1.0 1.0} {10.0 10.0}} + {box {1.0 1.0} {11.0 11.0}} + {box 0.0 {12.0 12.0}} +}] + +# EVIDENCE-OF: R-31246-29731 The pContext member of the +# sqlite3_rtree_geometry structure is always set to a copy of the +# pContext argument passed to sqlite3_rtree_geometry_callback() when the +# callback is registered. +reset_db +do_execsql_test 4.0 { + CREATE VIRTUAL TABLE r1 USING rtree(id, minX,maxX, minY,maxY); + WITH s(i) AS ( + VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<120 + ) + INSERT INTO r1 SELECT i,i,i+1, 200,201 FROM s; +} +set ctx [register_box_geom db box_geom] +set ::box_geom [list] +proc box_geom {args} { + lappend ::box_geom [lindex $args 1] + return "" +} +do_execsql_test 4.1 { + SELECT count(*) FROM r1 WHERE id MATCH box(0,150,199,201) +} 120 +do_test 4.2 { + foreach g $::box_geom { + if {$g!=$ctx} {error "pointer mismatch"} + } +} {} + +# EVIDENCE-OF: R-09904-19077 The aParam[] array (size nParam) contains +# the parameter values passed to the SQL function on the right-hand side +# of the MATCH operator. +proc box_geom {args} { + set ::box_geom [lindex $args 2] +} +foreach {tn q vals} { + 1 "SELECT count(*) FROM r1 WHERE id MATCH box(1,2,3)" {1.0 2.0 3.0} + 2 "SELECT count(*) FROM r1 WHERE id MATCH box(10001)" {10001.0} + 3 "SELECT count(*) FROM r1 WHERE id MATCH box(-10001)" {-10001.0} +} { + do_catchsql_test 5.$tn.1 $q {1 {SQL logic error}} + do_test 5.$tn.2 { set ::box_geom } $vals +} + +do_execsql_test 5.0 { + CREATE VIRTUAL TABLE myrtree USING rtree(id, x1,x2); + INSERT INTO myrtree VALUES(1, 1, 1); + INSERT INTO myrtree VALUES(2, 2, 2); + INSERT INTO myrtree VALUES(3, 3, 3); +} + +# EVIDENCE-OF: R-44448-00687 The pUser and xDelUser members of the +# sqlite3_rtree_geometry structure are initially set to NULL. +set ::box_geom_calls 0 +proc box_geom {args} { + incr ::box_geom_calls + return user_is_zero +} +do_execsql_test 5.1.1 { + SELECT * FROM myrtree WHERE id MATCH box(4, 5); +} +do_test 5.1.2 { set ::box_geom_calls } 3 + + +# EVIDENCE-OF: R-55837-00155 The pUser variable may be set by the +# callback implementation to any arbitrary value that may be useful to +# subsequent invocations of the callback within the same query (for +# example, a pointer to a complicated data structure used to test for +# region intersection). +# +# EVIDENCE-OF: R-34745-08839 If the xDelUser variable is set to a +# non-NULL value, then after the query has finished running SQLite +# automatically invokes it with the value of the pUser variable as the +# only argument. +# +set ::box_geom_calls 0 +proc box_geom {args} { + incr ::box_geom_calls + switch -- $::box_geom_calls { + 1 { + return user_is_zero + } + 2 { + return [list user box_geom_finalizer] + } + } + return "" +} +proc box_geom_finalizer {} { + set ::box_geom_finalizer "::box_geom_calls is $::box_geom_calls" +} +do_execsql_test 5.1.1 { + SELECT * FROM myrtree WHERE id MATCH box(4, 5); +} +do_test 5.1.2 { set ::box_geom_calls } 3 +do_test 5.1.3 { + set ::box_geom_finalizer +} {::box_geom_calls is 3} + + +# EVIDENCE-OF: R-28176-28813 The xGeom callback always does a +# depth-first search of the r-tree. +# +# For a breadth first search, final test case would return "B L" only. +# +do_execsql_test 6.0 { + CREATE VIRTUAL TABLE xyz USING rtree(x, x1,x2, y1,y2); + WITH s(i) AS ( + VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<15 + ) + INSERT INTO xyz SELECT NULL, one.i,one.i+1, two.i,two.i+1 FROM s one, s two; +} +do_execsql_test 6.1 { + SELECT count(*) FROM xyz_node +} {10} +proc box_geom {args} { + set coords [lindex $args 3] + set area [expr { + ([lindex $coords 1]-[lindex $coords 0]) * + ([lindex $coords 3]-[lindex $coords 2]) + }] + if {$area==1} { + lappend ::box_geom_calls L + } else { + lappend ::box_geom_calls B + } +} +set ::box_geom_calls [list] +do_execsql_test 6.2 { + SELECT count(*) FROM xyz WHERE x MATCH box(0,20,0,20) +} 225 +do_test 6.3 { + set prev "" + set box_calls [list] + foreach c $::box_geom_calls { + if {$c!=$prev} { + lappend ::box_calls $c + set prev $c + } + } + set ::box_calls +} {B L B L B L B L B L B L B L B L B L} + + +finish_test + diff --git a/ext/rtree/rtreedoc3.test b/ext/rtree/rtreedoc3.test new file mode 100644 index 00000000..0403409f --- /dev/null +++ b/ext/rtree/rtreedoc3.test @@ -0,0 +1,292 @@ +# 2021 September 13 +# +# 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 r-tree extension. +# + +if {![info exists testdir]} { + set testdir [file join [file dirname [info script]] .. .. test] +} +source [file join [file dirname [info script]] rtree_util.tcl] +source $testdir/tester.tcl +set testprefix rtreedoc3 + +ifcapable !rtree { + finish_test + return +} + + +# This command assumes that the argument is a node blob for a 2 dimensional +# i32 r-tree table. It decodes and returns a list of cells from the node +# as a list. Each cell is itself a list of the following form: +# +# {$rowid $minX $maxX $minY $maxY} +# +# For internal (non-leaf) nodes, the rowid is replaced by the child node +# number. +# +proc rnode_cells {aData} { + set nDim 2 + + set nData [string length $aData] + set nBytePerCell [expr (8 + 2*$nDim*4)] + binary scan [string range $aData 2 3] S nCell + + set res [list] + for {set i 0} {$i < $nCell} {incr i} { + set iOff [expr $i*$nBytePerCell+4] + set cell [string range $aData $iOff [expr $iOff+$nBytePerCell-1]] + binary scan $cell WIIII rowid x1 x2 y1 y2 + lappend res [list $rowid $x1 $x2 $y1 $y2] + } + + return $res +} + +# Interpret the first two bytes of the blob passed as the only parameter +# as a 16-bit big-endian integer and return the value. If this blob is +# the root node of an r-tree, this value is the height of the tree. +# +proc rnode_height {aData} { + binary scan [string range $aData 0 1] S nHeight + return $nHeight +} + +# Return a blob containing node iNode of r-tree "rt". +# +proc rt_node_get {iNode} { + db one { SELECT data FROM rt_node WHERE nodeno=$iNode } +} + + +#-------------------------------------------------------------- +# API: +# +# pq_init +# Initialize a new test. +# +# pq_test_callback +# Invoked each time the xQueryCallback function is called. This Tcl +# command checks that the arguments that SQLite passed to xQueryCallback +# are as expected. +# +# pq_test_row +# Invoked each time a row is returned. Checks that the row returned +# was predicted by the documentation. +# +# DATA STRUCTURE: +# The priority queue is stored as a Tcl list. The order of elements in +# the list is unimportant - it is just used as a set here. Each element +# in the priority queue is itself a list. The first element is the +# priority value for the entry (a real). Following this is a list of +# key-value pairs that make up the entries fields. +# +proc pq_init {} { + global Q + set Q(pri_queue) [list] + + set nHeight [rnode_height [rt_node_get 1]] + set nCell [llength [rnode_cells [rt_node_get 1]]] + + # EVIDENCE-OF: R-54708-13595 An R*Tree query is initialized by making + # the root node the only entry in a priority queue sorted by rScore. + lappend Q(pri_queue) [list 0.0 [list \ + iLevel [expr $nHeight+1] \ + iChild 1 \ + iCurrent 0 \ + ]] +} + +proc pq_extract {} { + global Q + if {[llength $Q(pri_queue)]==0} { + error "priority queue is empty!" + } + + # Find the priority queue entry with the lowest score. + # + # EVIDENCE-OF: R-47257-47871 Smaller scores are processed first. + set iBest 0 + set rBestScore [lindex $Q(pri_queue) 0 0] + for {set ii 1} {$ii < [llength $Q(pri_queue)]} {incr ii} { + set rScore [expr [lindex $Q(pri_queue) $ii 0]] + if {$rScore<$rBestScore} { + set rBestScore $rScore + set iBest $ii + } + } + + # Extract the entry with the lowest score from the queue and return it. + # + # EVIDENCE-OF: R-60002-49798 The query proceeds by extracting the entry + # from the priority queue that has the lowest score. + set ret [lindex $Q(pri_queue) $iBest] + set Q(pri_queue) [lreplace $Q(pri_queue) $iBest $iBest] + + return $ret +} + +proc pq_new_entry {rScore iLevel cell} { + global Q + + set rowid_name "iChild" + if {$iLevel==0} { set rowid_name "iRowid" } + + set kv [list] + lappend kv aCoord [lrange $cell 1 end] + lappend kv iLevel $iLevel + + if {$iLevel==0} { + lappend kv iRowid [lindex $cell 0] + } else { + lappend kv iChild [lindex $cell 0] + lappend kv iCurrent 0 + } + + lappend Q(pri_queue) [list $rScore $kv] +} + +proc pq_test_callback {L res} { + #pq_debug "pq_test_callback $L -> $res" + global Q + + array set G $L ;# "Got" - as in stuff passed to xQuery + + # EVIDENCE-OF: R-65127-42665 If the extracted priority queue entry is a + # node (a subtree), then the next child of that node is passed to the + # xQueryFunc callback. + # + # If it had been a leaf, the row should have been returned, instead of + # xQueryCallback being called on a child - as is happening here. + foreach {rParentScore parent} [pq_extract] {} + array set P $parent ;# "Parent" - as in parent of expected cell + if {$P(iLevel)==0} { error "query callback mismatch (1)" } + set child_node [rnode_cells [rt_node_get $P(iChild)]] + set expected_cell [lindex $child_node $P(iCurrent)] + set expected_coords [lrange $expected_cell 1 end] + if {[llength $expected_coords] != [llength $G(aCoord)]} { + puts [array get P] + puts "E: $expected_coords G: $G(aCoord)" + error "coordinate mismatch in query callback (1)" + } + foreach a [lrange $expected_cell 1 end] b $G(aCoord) { + if {$a!=$b} { error "coordinate mismatch in query callback (2)" } + } + + # Check level is as expected + # + if {$G(iLevel) != $P(iLevel)-1} { + error "iLevel mismatch in query callback (1)" + } + + # Unless the callback returned NOT_WITHIN, add the entry to the priority + # queue. + # + # EVIDENCE-OF: R-28754-35153 Those subelements for which the xQueryFunc + # callback sets eWithin to PARTLY_WITHIN or FULLY_WITHIN are added to + # the priority queue using the score supplied by the callback. + # + # EVIDENCE-OF: R-08681-45277 Subelements that return NOT_WITHIN are + # discarded. + set r [lindex $res 0] + set rScore [lindex $res 1] + if {$r!="fully" && $r!="partly" && $r!="not"} { + error "unknown result: $r - expected \"fully\", \"partly\" or \"not\"" + } + if {$r!="not"} { + pq_new_entry $rScore [expr $P(iLevel)-1] $expected_cell + } + + # EVIDENCE-OF: R-07194-63805 If the node has more children then it is + # returned to the priority queue. Otherwise it is discarded. + incr P(iCurrent) + if {$P(iCurrent)<[llength $child_node]} { + lappend Q(pri_queue) [list $rParentScore [array get P]] + } +} + +proc pq_test_result {id x1 x2 y1 y2} { + #pq_debug "pq_test_result $id $x1 $x2 $y1 $y2" + foreach {rScore next} [pq_extract] {} + + # The extracted entry must be a leaf (otherwise, xQueryCallback would + # have been called on the extracted entries children instead of just + # returning the data). + # + # EVIDENCE-OF: R-13214-54017 If that entry is a leaf (meaning that it is + # an actual R*Tree entry and not a subtree) then that entry is returned + # as one row of the query result. + array set N $next + if {$N(iLevel)!=0} { error "result row mismatch (1)" } + + if {$x1!=[lindex $N(aCoord) 0] || $x2!=[lindex $N(aCoord) 1] + || $y1!=[lindex $N(aCoord) 2] || $y2!=[lindex $N(aCoord) 3] + } { + if {$N(iLevel)!=0} { error "result row mismatch (2)" } + } + + if {$id!=$N(iRowid)} { error "result row mismatch (3)" } +} + +proc pq_done {} { + global Q + # EVIDENCE-OF: R-57438-45968 The query runs until the priority queue is + # empty. + if {[llength $Q(pri_queue)]>0} { + error "priority queue is not empty!" + } +} + +proc pq_debug {caption} { + global Q + + puts "**** $caption ****" + set i 0 + foreach q [lsort -real -index 0 $Q(pri_queue)] { + puts "PQ $i: $q" + incr i + } +} + +#-------------------------------------------------------------- + +proc box_query {a} { + set res [list fully [expr rand()]] + pq_test_callback $a $res + return $res +} + +register_box_query db box_query + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE rt USING rtree_i32(id, x1,x2, y1,y2); + WITH s(i) AS ( + SELECT 0 UNION ALL SELECT i+1 FROM s WHERE i<64 + ) + INSERT INTO rt SELECT NULL, a.i, a.i+1, b.i, b.i+1 FROM s a, s b; +} + +proc box_query {a} { + set res [list fully [expr rand()]] + pq_test_callback $a $res + return $res +} + +pq_init +db eval { SELECT id, x1,x2, y1,y2 FROM rt WHERE id MATCH qbox() } { + pq_test_result $id $x1 $x2 $y1 $y2 +} +pq_done + +finish_test + + diff --git a/ext/rtree/test_rtreedoc.c b/ext/rtree/test_rtreedoc.c new file mode 100644 index 00000000..119be0e0 --- /dev/null +++ b/ext/rtree/test_rtreedoc.c @@ -0,0 +1,348 @@ +/* +** 2010 August 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. +** +************************************************************************* +** Code for testing all sorts of SQLite interfaces. This code +** is not included in the SQLite library. +*/ + +#include "sqlite3.h" +#if defined(INCLUDE_SQLITE_TCL_H) +# include "sqlite_tcl.h" +#else +# include "tcl.h" +#endif + +/* Solely for the UNUSED_PARAMETER() macro. */ +#include "sqliteInt.h" + +#ifdef SQLITE_ENABLE_RTREE + +typedef struct BoxGeomCtx BoxGeomCtx; +struct BoxGeomCtx { + Tcl_Interp *interp; + Tcl_Obj *pScript; +}; + +typedef struct BoxQueryCtx BoxQueryCtx; +struct BoxQueryCtx { + Tcl_Interp *interp; + Tcl_Obj *pScript; +}; + +static void testDelUser(void *pCtx){ + BoxGeomCtx *p = (BoxGeomCtx*)pCtx; + Tcl_EvalObjEx(p->interp, p->pScript, 0); + Tcl_DecrRefCount(p->pScript); + sqlite3_free(p); +} + +static int invokeTclGeomCb( + const char *zName, + sqlite3_rtree_geometry *p, + int nCoord, + sqlite3_rtree_dbl *aCoord +){ + int rc = SQLITE_OK; + if( p->pContext ){ + char aPtr[64]; + BoxGeomCtx *pCtx = (BoxGeomCtx*)p->pContext; + Tcl_Interp *interp = pCtx->interp; + Tcl_Obj *pScript = 0; + Tcl_Obj *pParam = 0; + Tcl_Obj *pCoord = 0; + int ii; + Tcl_Obj *pRes; + + + pScript = Tcl_DuplicateObj(pCtx->pScript); + Tcl_IncrRefCount(pScript); + Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj(zName,-1)); + + sqlite3_snprintf(sizeof(aPtr)-1, aPtr, "%p", (void*)p->pContext); + Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj(aPtr,-1)); + + pParam = Tcl_NewObj(); + for(ii=0; iinParam; ii++){ + Tcl_ListObjAppendElement( + interp, pParam, Tcl_NewDoubleObj(p->aParam[ii]) + ); + } + Tcl_ListObjAppendElement(interp, pScript, pParam); + + pCoord = Tcl_NewObj(); + for(ii=0; ii0 ){ + const char *zCmd = Tcl_GetString(aObj[0]); + if( 0==sqlite3_stricmp(zCmd, "zero") ){ + p->aParam[0] = 0.0; + p->nParam = 1; + } + else if( 0==sqlite3_stricmp(zCmd, "user") ){ + if( p->pUser || p->xDelUser ){ + rc = SQLITE_ERROR; + }else{ + BoxGeomCtx *pBGCtx = sqlite3_malloc(sizeof(BoxGeomCtx)); + if( pBGCtx==0 ){ + rc = SQLITE_NOMEM; + }else{ + pBGCtx->interp = interp; + pBGCtx->pScript = Tcl_DuplicateObj(pRes); + Tcl_IncrRefCount(pBGCtx->pScript); + Tcl_ListObjReplace(interp, pBGCtx->pScript, 0, 1, 0, 0); + p->pUser = (void*)pBGCtx; + p->xDelUser = testDelUser; + } + } + } + else if( 0==sqlite3_stricmp(zCmd, "user_is_zero") ){ + if( p->pUser || p->xDelUser ) rc = SQLITE_ERROR; + } + } + } + } + return rc; +} + +/* +# EVIDENCE-OF: R-00693-36727 The legacy xGeom callback is invoked with +# four arguments. + +# EVIDENCE-OF: R-50437-53270 The first argument is a pointer to an +# sqlite3_rtree_geometry structure which provides information about how +# the SQL function was invoked. + +# EVIDENCE-OF: R-00090-24248 The third argument, aCoord[], is an array +# of nCoord coordinates that defines a bounding box to be tested. + +# EVIDENCE-OF: R-28207-40885 The last argument is a pointer into which +# the callback result should be written. + +*/ +static int box_geom( + sqlite3_rtree_geometry *p, /* R-50437-53270 */ + int nCoord, /* R-02424-24769 */ + sqlite3_rtree_dbl *aCoord, /* R-00090-24248 */ + int *pRes /* R-28207-40885 */ +){ + int ii; + + if( p->nParam!=nCoord ){ + invokeTclGeomCb("box", p, nCoord, aCoord); + return SQLITE_ERROR; + } + if( invokeTclGeomCb("box", p, nCoord, aCoord) ) return SQLITE_ERROR; + + for(ii=0; iip->aParam[ii+1] || aCoord[ii+1]aParam[ii] ){ + /* R-28207-40885 */ + *pRes = 0; + return SQLITE_OK; + } + } + + /* R-28207-40885 */ + *pRes = 1; + + return SQLITE_OK; +} + +static int SQLITE_TCLAPI register_box_geom( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**); + extern const char *sqlite3ErrName(int); + sqlite3 *db; + BoxGeomCtx *pCtx; + char aPtr[64]; + + if( objc!=3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB SCRIPT"); + return TCL_ERROR; + } + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; + + pCtx = (BoxGeomCtx*)ckalloc(sizeof(BoxGeomCtx*)); + pCtx->interp = interp; + pCtx->pScript = Tcl_DuplicateObj(objv[2]); + Tcl_IncrRefCount(pCtx->pScript); + + sqlite3_rtree_geometry_callback(db, "box", box_geom, (void*)pCtx); + + sqlite3_snprintf(64, aPtr, "%p", (void*)pCtx); + Tcl_SetObjResult(interp, Tcl_NewStringObj(aPtr, -1)); + return TCL_OK; +} + +static int box_query(sqlite3_rtree_query_info *pInfo){ + const char *azParentWithin[] = {"not", "partly", "fully", 0}; + BoxQueryCtx *pCtx = (BoxQueryCtx*)pInfo->pContext; + Tcl_Interp *interp = pCtx->interp; + Tcl_Obj *pEval; + Tcl_Obj *pArg; + Tcl_Obj *pTmp = 0; + int rc; + int ii; + + pEval = Tcl_DuplicateObj(pCtx->pScript); + Tcl_IncrRefCount(pEval); + pArg = Tcl_NewObj(); + Tcl_IncrRefCount(pArg); + + /* aParam[] */ + pTmp = Tcl_NewObj(); + Tcl_IncrRefCount(pTmp); + for(ii=0; iinParam; ii++){ + Tcl_Obj *p = Tcl_NewDoubleObj(pInfo->aParam[ii]); + Tcl_ListObjAppendElement(interp, pTmp, p); + } + Tcl_ListObjAppendElement(interp, pArg, Tcl_NewStringObj("aParam", -1)); + Tcl_ListObjAppendElement(interp, pArg, pTmp); + Tcl_DecrRefCount(pTmp); + + /* aCoord[] */ + pTmp = Tcl_NewObj(); + Tcl_IncrRefCount(pTmp); + for(ii=0; iinCoord; ii++){ + Tcl_Obj *p = Tcl_NewDoubleObj(pInfo->aCoord[ii]); + Tcl_ListObjAppendElement(interp, pTmp, p); + } + Tcl_ListObjAppendElement(interp, pArg, Tcl_NewStringObj("aCoord", -1)); + Tcl_ListObjAppendElement(interp, pArg, pTmp); + Tcl_DecrRefCount(pTmp); + + /* anQueue[] */ + pTmp = Tcl_NewObj(); + Tcl_IncrRefCount(pTmp); + for(ii=0; ii<=pInfo->mxLevel; ii++){ + Tcl_Obj *p = Tcl_NewIntObj((int)pInfo->anQueue[ii]); + Tcl_ListObjAppendElement(interp, pTmp, p); + } + Tcl_ListObjAppendElement(interp, pArg, Tcl_NewStringObj("anQueue", -1)); + Tcl_ListObjAppendElement(interp, pArg, pTmp); + Tcl_DecrRefCount(pTmp); + + /* iLevel */ + Tcl_ListObjAppendElement(interp, pArg, Tcl_NewStringObj("iLevel", -1)); + Tcl_ListObjAppendElement(interp, pArg, Tcl_NewIntObj(pInfo->iLevel)); + + /* mxLevel */ + Tcl_ListObjAppendElement(interp, pArg, Tcl_NewStringObj("mxLevel", -1)); + Tcl_ListObjAppendElement(interp, pArg, Tcl_NewIntObj(pInfo->mxLevel)); + + /* iRowid */ + Tcl_ListObjAppendElement(interp, pArg, Tcl_NewStringObj("iRowid", -1)); + Tcl_ListObjAppendElement(interp, pArg, Tcl_NewWideIntObj(pInfo->iRowid)); + + /* rParentScore */ + Tcl_ListObjAppendElement(interp, pArg, Tcl_NewStringObj("rParentScore", -1)); + Tcl_ListObjAppendElement(interp, pArg, Tcl_NewDoubleObj(pInfo->rParentScore)); + + /* eParentWithin */ + assert( pInfo->eParentWithin==0 + || pInfo->eParentWithin==1 + || pInfo->eParentWithin==2 + ); + Tcl_ListObjAppendElement(interp, pArg, Tcl_NewStringObj("eParentWithin", -1)); + Tcl_ListObjAppendElement(interp, pArg, + Tcl_NewStringObj(azParentWithin[pInfo->eParentWithin], -1) + ); + + Tcl_ListObjAppendElement(interp, pEval, pArg); + rc = Tcl_EvalObjEx(interp, pEval, 0) ? SQLITE_ERROR : SQLITE_OK; + + if( rc==SQLITE_OK ){ + double rScore = 0.0; + int nObj = 0; + int eP = 0; + Tcl_Obj **aObj = 0; + Tcl_Obj *pRes = Tcl_GetObjResult(interp); + + if( Tcl_ListObjGetElements(interp, pRes, &nObj, &aObj) + || nObj!=2 + || Tcl_GetDoubleFromObj(interp, aObj[1], &rScore) + || Tcl_GetIndexFromObj(interp, aObj[0], azParentWithin, "value", 0, &eP) + ){ + rc = SQLITE_ERROR; + }else{ + pInfo->rScore = rScore; + pInfo->eParentWithin = eP; + } + } + + Tcl_DecrRefCount(pArg); + Tcl_DecrRefCount(pEval); + return rc; +} + +static void box_query_destroy(void *p){ + BoxQueryCtx *pCtx = (BoxQueryCtx*)p; + Tcl_DecrRefCount(pCtx->pScript); + ckfree((char*)pCtx); +} + +static int SQLITE_TCLAPI register_box_query( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**); + extern const char *sqlite3ErrName(int); + sqlite3 *db; + BoxQueryCtx *pCtx; + + if( objc!=3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB SCRIPT"); + return TCL_ERROR; + } + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; + + pCtx = (BoxQueryCtx*)ckalloc(sizeof(BoxQueryCtx*)); + pCtx->interp = interp; + pCtx->pScript = Tcl_DuplicateObj(objv[2]); + Tcl_IncrRefCount(pCtx->pScript); + + sqlite3_rtree_query_callback( + db, "qbox", box_query, (void*)pCtx, box_query_destroy + ); + + Tcl_ResetResult(interp); + return TCL_OK; +} +#endif /* SQLITE_ENABLE_RTREE */ + + +int Sqlitetestrtreedoc_Init(Tcl_Interp *interp){ +#ifdef SQLITE_ENABLE_RTREE + Tcl_CreateObjCommand(interp, "register_box_geom", register_box_geom, 0, 0); + Tcl_CreateObjCommand(interp, "register_box_query", register_box_query, 0, 0); +#endif /* SQLITE_ENABLE_RTREE */ + return TCL_OK; +} diff --git a/ext/session/session1.test b/ext/session/session1.test index 0eb850a7..bcd7b03d 100644 --- a/ext/session/session1.test +++ b/ext/session/session1.test @@ -152,6 +152,26 @@ do_changeset_test $tn.2.4.2 S {} do_changeset_invert_test $tn.2.4.3 S {} do_test $tn.2.4.4 { S delete } {} +do_execsql_test $tn.2.5.0 { + SELECT * FROM t1 ORDER BY x +} { + 2 Surin + 10 Sukhothai + 20 Thapae +} + +do_test $tn.2.5.1 { + sqlite3session S db main + S attach t1 + execsql { DELETE FROM t1 } +} {} +do_changeset_test $tn.2.5.2 S { + {DELETE t1 0 X. {i 10 t Sukhothai} {}} + {DELETE t1 0 X. {i 2 t Surin} {}} + {DELETE t1 0 X. {i 20 t Thapae} {}} +} +do_test $tn.2.5.3 { S delete } {} + #------------------------------------------------------------------------- # Test the application of simple changesets. These tests also test that # the conflict callback is invoked correctly. For these tests, the diff --git a/ext/session/session6.test b/ext/session/session6.test index 8a1f172c..22fa93cb 100644 --- a/ext/session/session6.test +++ b/ext/session/session6.test @@ -19,6 +19,7 @@ if {![info exists testdir]} { source [file join [file dirname [info script]] session_common.tcl] source $testdir/tester.tcl ifcapable !session {finish_test; return} +ifcapable !incrblob {finish_test; return} set testprefix session6 diff --git a/ext/session/sessionat.test b/ext/session/sessionat.test index 4a3f59a4..8141d923 100644 --- a/ext/session/sessionat.test +++ b/ext/session/sessionat.test @@ -20,9 +20,14 @@ if {![info exists testdir]} { source [file join [file dirname [info script]] session_common.tcl] source $testdir/tester.tcl ifcapable !session {finish_test; return} - set testprefix sessionat +# If SQLITE_OMIT_ALTERTABLE is defined, omit this file. +ifcapable !altertable { + finish_test + return +} + db close sqlite3_shutdown test_sqlite3_log log diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c index c96363b6..a892804b 100644 --- a/ext/session/sqlite3session.c +++ b/ext/session/sqlite3session.c @@ -420,7 +420,7 @@ static int sessionSerializeValue( if( aBuf ){ sessionVarintPut(&aBuf[1], n); - if( n ) memcpy(&aBuf[nVarint + 1], z, n); + if( n>0 ) memcpy(&aBuf[nVarint + 1], z, n); } nByte = 1 + nVarint + n; @@ -1025,16 +1025,32 @@ static int sessionTableInfo( }else if( rc==SQLITE_ERROR ){ zPragma = sqlite3_mprintf(""); }else{ + *pazCol = 0; + *pabPK = 0; + *pnCol = 0; + if( pzTab ) *pzTab = 0; return rc; } }else{ zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis); } - if( !zPragma ) return SQLITE_NOMEM; + if( !zPragma ){ + *pazCol = 0; + *pabPK = 0; + *pnCol = 0; + if( pzTab ) *pzTab = 0; + return SQLITE_NOMEM; + } rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0); sqlite3_free(zPragma); - if( rc!=SQLITE_OK ) return rc; + if( rc!=SQLITE_OK ){ + *pazCol = 0; + *pabPK = 0; + *pnCol = 0; + if( pzTab ) *pzTab = 0; + return rc; + } nByte = nThis + 1; while( SQLITE_ROW==sqlite3_step(pStmt) ){ @@ -1452,7 +1468,11 @@ static int sessionFindTable( ){ rc = sqlite3session_attach(pSession, zName); if( rc==SQLITE_OK ){ - for(pRet=pSession->pTable; pRet->pNext; pRet=pRet->pNext); + pRet = pSession->pTable; + while( ALWAYS(pRet) && pRet->pNext ){ + pRet = pRet->pNext; + } + assert( pRet!=0 ); assert( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) ); } } @@ -2225,6 +2245,7 @@ static int sessionAppendUpdate( int i; /* Used to iterate through columns */ u8 *pCsr = p->aRecord; /* Used to iterate through old.* values */ + assert( abPK!=0 ); sessionAppendByte(pBuf, SQLITE_UPDATE, &rc); sessionAppendByte(pBuf, p->bIndirect, &rc); for(i=0; ipTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){ if( pTab->nEntry ){ const char *zName = pTab->zName; - int nCol; /* Number of columns in table */ - u8 *abPK; /* Primary key array */ + int nCol = 0; /* Number of columns in table */ + u8 *abPK = 0; /* Primary key array */ const char **azCol = 0; /* Table columns */ int i; /* Used to iterate through hash buckets */ sqlite3_stmt *pSel = 0; /* SELECT statement to query table pTab */ @@ -2587,6 +2610,7 @@ static int sessionGenerateChangeset( sessionAppendCol(&buf, pSel, iCol, &rc); } }else{ + assert( abPK!=0 ); /* Because sessionSelectStmt() returned ok */ rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, abPK); } }else if( p->op!=SQLITE_INSERT ){ @@ -2647,7 +2671,10 @@ int sqlite3session_changeset( int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ void **ppChangeset /* OUT: Buffer containing changeset */ ){ - int rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset,ppChangeset); + int rc; + + if( pnChangeset==0 || ppChangeset==0 ) return SQLITE_MISUSE; + rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset,ppChangeset); assert( rc || pnChangeset==0 || pSession->bEnableSize==0 || *pnChangeset<=pSession->nMaxChangesetSize ); @@ -2662,6 +2689,7 @@ int sqlite3session_changeset_strm( int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ){ + if( xOutput==0 ) return SQLITE_MISUSE; return sessionGenerateChangeset(pSession, 0, xOutput, pOut, 0, 0); } @@ -2673,6 +2701,7 @@ int sqlite3session_patchset_strm( int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ){ + if( xOutput==0 ) return SQLITE_MISUSE; return sessionGenerateChangeset(pSession, 1, xOutput, pOut, 0, 0); } @@ -2688,6 +2717,7 @@ int sqlite3session_patchset( int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */ void **ppPatchset /* OUT: Buffer containing changeset */ ){ + if( pnPatchset==0 || ppPatchset==0 ) return SQLITE_MISUSE; return sessionGenerateChangeset(pSession, 1, 0, 0, pnPatchset, ppPatchset); } @@ -3651,11 +3681,11 @@ static int sessionChangesetInvert( } assert( rc==SQLITE_OK ); - if( pnInverted ){ + if( pnInverted && ALWAYS(ppInverted) ){ *pnInverted = sOut.nBuf; *ppInverted = sOut.aBuf; sOut.aBuf = 0; - }else if( sOut.nBuf>0 ){ + }else if( sOut.nBuf>0 && ALWAYS(xOutput!=0) ){ rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); } @@ -4111,7 +4141,7 @@ static int sessionBindRow( for(i=0; rc==SQLITE_OK && i0 ) rc = xOutput(pOut, buf.aBuf, buf.nBuf); - }else{ + }else if( ppOut ){ *ppOut = buf.aBuf; - *pnOut = buf.nBuf; + if( pnOut ) *pnOut = buf.nBuf; buf.aBuf = 0; } } @@ -5656,7 +5686,7 @@ static int sessionRebase( if( sOut.nBuf>0 ){ rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); } - }else{ + }else if( ppOut ){ *ppOut = (void*)sOut.aBuf; *pnOut = sOut.nBuf; sOut.aBuf = 0; diff --git a/main.mk b/main.mk index 16d72ff9..f1a4660a 100644 --- a/main.mk +++ b/main.mk @@ -1,3 +1,4 @@ + ############################################################################### # The following macros should be defined before this script is # invoked: @@ -386,7 +387,8 @@ TESTSRC += \ $(TOP)/ext/misc/zipfile.c \ $(TOP)/ext/fts5/fts5_tcl.c \ $(TOP)/ext/fts5/fts5_test_mi.c \ - $(TOP)/ext/fts5/fts5_test_tok.c + $(TOP)/ext/fts5/fts5_test_tok.c \ + $(TOP)/ext/rtree/test_rtreedoc.c #TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c @@ -663,7 +665,7 @@ sqlite3ext.h: target_source cp tsrc/sqlite3ext.h . sqlite3.c-debug: target_source $(TOP)/tool/mksqlite3c.tcl - tclsh $(TOP)/tool/mksqlite3c.tcl --linemacros + tclsh $(TOP)/tool/mksqlite3c.tcl --linemacros=1 echo '#ifndef USE_SYSTEM_SQLITE' >tclsqlite3.c cat sqlite3.c >>tclsqlite3.c echo '#endif /* USE_SYSTEM_SQLITE */' >>tclsqlite3.c @@ -748,6 +750,7 @@ SHELL_SRC = \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/regexp.c \ + $(TOP)/ext/misc/series.c \ $(TOP)/ext/misc/shathree.c \ $(TOP)/ext/misc/sqlar.c \ $(TOP)/ext/misc/uint.c \ diff --git a/manifest b/manifest index a2035875..8adddf8d 100644 --- a/manifest +++ b/manifest @@ -1,13 +1,13 @@ -C Version\s3.36.0 -D 2021-06-18T18:36:39.378 +C Version\s3.37.2 +D 2022-01-06T13:25:41.295 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 -F Makefile.in ff5ac24ec9cb700135ee4453fa14c18ea371e94250d3673bda1f2cb56e1108ce +F Makefile.in 0e91c42a1dd13a569b1fa4f4dfb7d3632f3164a1c05c71341533d67db5b641dd F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241 -F Makefile.msc 8285e1ea7264f32b08702866d69dd127c0f663bbc2002323d853c68c27c6b6e4 +F Makefile.msc 88f05063ee36a5fb77d69b877ef824d0743b5325c95bfbf74d6ff17bd1c9fb1f F README.md 27fb76aa7eb57ed63a53bbba7292b6bf71f51125554f79f16b5d040edd1e6110 -F VERSION 8c392f6d70d82e513a0eac622bdf23c43df3e084cb630288beba8cef3012c812 +F VERSION b8218d35896c0f381cf64a499abbab64eeb86b40116a7d35c5a39c6677e8bb89 F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2 F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90 @@ -29,13 +29,13 @@ F autoconf/tea/pkgIndex.tcl.in 3ef61715cf1c7bdcff56947ffadb26bc991ca39d F autoconf/tea/tclconfig/install-sh bdd5e293591621ae60d9824d86a4b1c5f22c3d00 F autoconf/tea/tclconfig/tcl.m4 66ddf0a5d5e4b1d29bff472c0985fd7fa89d0fb5 F autoconf/tea/win/makefile.vc a5ff708245260c2794c6aaa0151efe5403d5896566eaf096747be0d9075284e4 -F autoconf/tea/win/nmakehlp.c 190bf8b40f6f90eeb6cbc1e5c13a19fc7ad870e479e0314c88174f71bf9e28a7 +F autoconf/tea/win/nmakehlp.c b01f822eabbe1ed2b64e70882d97d48402b42d2689a1ea00342d1a1a7eaa19cb F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63 F config.guess 883205ddf25b46f10c181818bf42c09da9888884af96f79e1719264345053bd6 F config.h.in 6376abec766e9a0785178b1823b5a587e9f1ccbc F config.sub c2d0260f17f3e4bc0b6808fccf1b291cb5e9126c14fc5890efc77b9fd0175559 -F configure c658869fc056a2460a2212fb2960e410cd24e3fb9c55640fbc78d15b48810936 x -F configure.ac 4e4b58b32f88c8da9914a2f2c3158f80e69907eccc019fcc7e3ba14ffd91c640 +F configure f8a03394ccec572e76a570aa858ccd24e0d54fd76c995b7220a4dfda8b899d27 x +F configure.ac c8ba54bac7e73e000acdfef5e394fe21a3876aa09d0f5c07131bf5ac5a525299 F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd F doc/lemon.html efc0cd2345d66905505d98f862e1c571512def0ceb5b016cb658fd4918eb76a3 @@ -50,8 +50,8 @@ F ext/async/sqlite3async.c 6f247666b495c477628dd19364d279c78ea48cd90c72d9f9b98ad F ext/async/sqlite3async.h 46b47c79357b97ad85d20d2795942c0020dc20c532114a49808287f04aa5309a F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633caf2020c3 F ext/expert/expert.c d548d603a4cc9e61f446cc179c120c6713511c413f82a4a32b1e1e69d3f086a4 -F ext/expert/expert1.test 6703fd74711daf8230240680b0a348d0720e28819b602701adfbd32457fdcddd -F ext/expert/sqlite3expert.c de51b187c629a4c4264d5de0b77862641e11426f7a963a92abf2d4077085fc8c +F ext/expert/expert1.test 3c642a4e7bbb14f21ddab595436fb465a4733f47a0fe5b2855e1d5ff900ef08e +F ext/expert/sqlite3expert.c 921a00823a826150cbb9a3341285a8edec7533480b71281e77737f19559b4b14 F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72 F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e @@ -84,16 +84,16 @@ F ext/fts3/README.content b9078d0843a094d86af0d48dffbff13c906702b4c3558012e67b9c F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a F ext/fts3/README.tokenizers b92bdeb8b46503f0dd301d364efc5ef59ef9fa8e2758b8e742f39fa93a2e422d F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d -F ext/fts3/fts3.c 95f55e24550c01c2a325d09c9ea8fdff61e923a4675f8545b28bf3c470e57dfb +F ext/fts3/fts3.c 6bfdc941372ee431e3d362986674a8708eb0e700b28c3d35d46d953a9351155f F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe -F ext/fts3/fts3Int.h bde280294d56ff50ee29d03e5140f0b6953b44d1c969bb5831e8ae85e3e76715 -F ext/fts3/fts3_aux.c 1af58af8f2b00a49f4fb1c2602f8da2054ad60076f46c8ebf85c5410eccccb65 -F ext/fts3/fts3_expr.c 5853cd7a35a79d193614add9b4c461b2d56f465d90899ca4309f05d9d1536558 +F ext/fts3/fts3Int.h cff59b8b13dafe9d59924a5d710f771ed8b121a55cccbc99b6e2a723fcde14dc +F ext/fts3/fts3_aux.c f0dc9bd98582615b7750218899bd0c729879b6bbf94d1be57ca1833ff49afc6f +F ext/fts3/fts3_expr.c 903bfb9433109fffb10e910d7066c49cbf8eeae316adc93f0499c4da7dfc932a F ext/fts3/fts3_hash.c 8b6e31bfb0844c27dc6092c2620bdb1fca17ed613072db057d96952c6bdb48b7 F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf F ext/fts3/fts3_icu.c 305ce7fb6036484085b5556a9c8e62acdc7763f0f4cdf5fd538212a9f3720116 F ext/fts3/fts3_porter.c 3565faf04b626cddf85f03825e86056a4562c009 -F ext/fts3/fts3_snippet.c 57e1965906f3ecfcb5251a14aea98ac2d2dd1868a123bcd5a569601719ab9ead +F ext/fts3/fts3_snippet.c f9a8149173553113f3c495a503843e30028b5dc3723d0ca798c5ad6142e130e6 F ext/fts3/fts3_term.c f45a1e7c6ef464abb1231245d123dae12266b69e05cc56e14045b76591ae92d1 F ext/fts3/fts3_test.c d8d7b2734f894e8a489987447658e374cdd3a3bc8575c401decf1911cb7c6454 F ext/fts3/fts3_tokenize_vtab.c 8d15b148e7d88a4280389a200b26e8d52abda4c4ec2e9a35e9d7a1fa50e5aa03 @@ -102,7 +102,7 @@ F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3 F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004 F ext/fts3/fts3_unicode.c de426ff05c1c2e7bce161cf6b706638419c3a1d9c2667de9cb9dc0458c18e226 F ext/fts3/fts3_unicode2.c 416eb7e1e81142703520d284b768ca2751d40e31fa912cae24ba74860532bf0f -F ext/fts3/fts3_write.c 98edfd77aeb53afcb26d8de3ed0a87f16468ee05f84f8c1752e6e378c354cd7a +F ext/fts3/fts3_write.c 3109c1a232da86474e196cc7db754445a354409f141e08cb11c846cdb17bdf31 F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100 F ext/fts3/tool/fts3cov.sh c331d006359456cf6f8f953e37f2b9c7d568f3863f00bb5f7eb87fea4ac01b73 @@ -113,22 +113,22 @@ F ext/fts3/unicode/mkunicode.tcl d5aebf022fa4577ee8cdf27468f0d847879993959101f6d F ext/fts3/unicode/parseunicode.tcl a981bd6466d12dd17967515801c3ff23f74a281be1a03cf1e6f52a6959fc77eb F ext/fts5/extract_api_docs.tcl a36e54ec777172ddd3f9a88daf593b00848368e0 F ext/fts5/fts5.h c132a9323f22a972c4c93a8d5a3d901113a6e612faf30ca8e695788438c5ca2a -F ext/fts5/fts5Int.h 26c74dd5776f798436fbf604a0bf0e8de263b35b5060b05c15f9085845d9fda2 +F ext/fts5/fts5Int.h 36fd4a05e6e6307e3bac359a589d5f090b903afe0e7ae15db84f0ff90c79676a F ext/fts5/fts5_aux.c f558e1fb9f0f86a4f7489e258c162e1f947de5ff2709087fbb465fddb7092f98 -F ext/fts5/fts5_buffer.c 605f509f88c73e9ab41323cb6cf74932f936acf3f7d9c87bd0d3c599b4c90281 -F ext/fts5/fts5_config.c 8336d0ff6db0933f63cfec8ae0ab76e68393259cbccc0b46e1f79f7fa1842ff3 -F ext/fts5/fts5_expr.c 9462249a3bb82d0e49b163500f9d2197c2e4cd95bf440a9bbfc3906b22ea1e1b -F ext/fts5/fts5_hash.c 1aa93c9b5f461afba66701ee226297dc78402b3bdde81e90a10de5fe3df14959 -F ext/fts5/fts5_index.c eb1864c6abacf08d959956183a55a4f9767af76be289f2bb519bb0f197b3fd72 -F ext/fts5/fts5_main.c 35ebbcae681a4a40027c47bc2e94d7e7c81e331dc406bb9b23c546454ee8f98a -F ext/fts5/fts5_storage.c 58ba71e6cd3d43a5735815e7956ee167babb4d2cbfe206905174792af4d09d75 +F ext/fts5/fts5_buffer.c 3001fbabb585d6de52947b44b455235072b741038391f830d6b729225eeaf6a5 +F ext/fts5/fts5_config.c 501e7d3566bc92766b0e11c0109a7c5a6146bc41144195459af5422f6c2078aa +F ext/fts5/fts5_expr.c fcd0770d53028c2b53a15d0f53bf6d0e01b1bf3dd97630b9fedf0801f03aa3ec +F ext/fts5/fts5_hash.c d4fb70940359f2120ccd1de7ffe64cc3efe65de9e8995b822cd536ff64c96982 +F ext/fts5/fts5_index.c b1b2e5d4a9e3b54c740d8354cc47e3fa879f54c2176de55e0b882dab45ab7b07 +F ext/fts5/fts5_main.c 7c6092a53e6802962fa07b0fad3e61cb077b6c98b74b727d8d44ac2cf63bd914 +F ext/fts5/fts5_storage.c 76c6085239eb44424004c022e9da17a5ecd5aaec859fba90ad47d3b08f4c8082 F ext/fts5/fts5_tcl.c b1445cbe69908c411df8084a10b2485500ac70a9c747cdc8cda175a3da59d8ae F ext/fts5/fts5_test_mi.c 08c11ec968148d4cb4119d96d819f8c1f329812c568bac3684f5464be177d3ee F ext/fts5/fts5_test_tok.c a2bed8edb25f6432e8cdb62aad5916935c19dba8dac2b8324950cfff397e25ff F ext/fts5/fts5_tokenize.c 5e251efb0f1af99a25ed50010ba6b1ad1250aca5921af1988fdcabe5ebc3cb43 F ext/fts5/fts5_unicode2.c eca63dbc797f8ff0572e97caf4631389c0ab900d6364861b915bdd4735973f00 F ext/fts5/fts5_varint.c e64d2113f6e1bfee0032972cffc1207b77af63319746951bf1d09885d1dadf80 -F ext/fts5/fts5_vocab.c 7a071833064dc8bca236c3c323e56aac36f583aa2c46ce916d52e31ce87462c9 +F ext/fts5/fts5_vocab.c 12138e84616b56218532e3e8feb1d3e0e7ae845e33408dbe911df520424dc9d6 F ext/fts5/fts5parse.y eb526940f892ade5693f22ffd6c4f2702543a9059942772526eac1fde256bb05 F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba F ext/fts5/test/fts5_common.tcl b01c584144b5064f30e6c648145a2dd6bc440841 @@ -137,7 +137,7 @@ F ext/fts5/test/fts5ab.test 9205c839332c908aaad2b01ab8670ece8b161e8f2ec8a9fabf18 F ext/fts5/test/fts5ac.test a7aa7e1fefc6e1918aa4d3111d5c44a09177168e962c5fd2cca9620de8a7ed6d F ext/fts5/test/fts5ad.test e8cf959dfcd57c8e46d6f5f25665686f3b6627130a9a981371dafdf6482790de F ext/fts5/test/fts5ae.test 1142d16d9cc193894dc13cc8f9c7a8a21411ac61b5567a878514df6f9f0d7bb7 -F ext/fts5/test/fts5af.test 724247405b13f8f06cc6ce464dc4f152dc5dd4e86b12c2099685d8f19747bf7b +F ext/fts5/test/fts5af.test bea75184c0e63631b552c20ebe4a631699f357e00a2059c92538f7aeece8291e F ext/fts5/test/fts5ag.test 7816f25a0707578f08145ab539fc0ca025f8951e788b28a6a18a06b2099469dd F ext/fts5/test/fts5ah.test 27b5a33bfd0363ca8a4dc659e6e2a5df3dea1c3c5b04bc51ca6aeb1277bd9b21 F ext/fts5/test/fts5ai.test bc97e4758cc93e06bf851d61c98fdf4e8b8f8315ee28a84fb15f916360856414 @@ -160,10 +160,12 @@ F ext/fts5/test/fts5connect.test 08030168fc96fc278fa81f28654fb7e90566f33aff269c0 F ext/fts5/test/fts5content.test 213506436fb2c87567b8e31f6d43ab30aab99354cec74ed679f22aad0cdbf283 F ext/fts5/test/fts5corrupt.test 77ae6f41a7eba10620efb921cf7dbe218b0ef232b04519deb43581cb17a57ebe F ext/fts5/test/fts5corrupt2.test 7453752ba12ce91690c469a6449d412561cc604b1dec994e16ab132952e7805f -F ext/fts5/test/fts5corrupt3.test 79467b7c69a9c45ee3260507c4648d6449323aaa3c1e05b360c9479f1aa7dcce +F ext/fts5/test/fts5corrupt3.test 0e473620582a53ac61f468f364db8a151c1e18d2a879b16439d172c12c4c9828 F ext/fts5/test/fts5corrupt4.test f4c08e2182a48d8b70975fd869ee5391855c06d8a0ff87b6a2529e7c5a88a1d3 +F ext/fts5/test/fts5corrupt5.test 550d0884c14424f9acad051a741f1dd99ec9342277d938e91ff3daf9123d1209 +F ext/fts5/test/fts5corrupt6.test bf8eeae07825b088b9665d9d8e4accbd8dc9bf3cb85b6c64cf6c9e18ccc420a4 F ext/fts5/test/fts5delete.test 619295b20dbc1d840b403ee07c878f52378849c3c02e44f2ee143b3e978a0aa7 -F ext/fts5/test/fts5detail.test 31b240dbf6d44ac3507e2f8b65f29fdc12465ffd531212378c7ce1066766f54e +F ext/fts5/test/fts5detail.test 54015e9c43ec4ba542cfb93268abdf280e0300f350efd08ee411284b03595cc4 F ext/fts5/test/fts5determin.test 1b77879b2ae818b5b71c859e534ee334dac088b7cf3ff3bf76a2c82b1c788d11 F ext/fts5/test/fts5dlidx.test b90852c55881b29dbac6380b274de27beae623ac4b6d567c6c8fb9cdc315a86e F ext/fts5/test/fts5doclist.test faa9e9cc3c0645fa6203667cb5f007c359447c6ee66753f71a58175c2497cacd @@ -193,7 +195,7 @@ F ext/fts5/test/fts5leftjoin.test c0b4cafb9661379e576dc4405c0891d8fcc27826807405 F ext/fts5/test/fts5matchinfo.test 10c9a6f7fe61fb132299c4183c012770b10c4d5c2f2edb6df0b6607f683d737a F ext/fts5/test/fts5merge.test e92a8db28b45931e7a9c7b1bbd36101692759d00274df74d83fd29d25d53b3a6 F ext/fts5/test/fts5merge2.test 3ebad1a59d6ad3fb66eff6523a09e95dc6367cbefb3cd73196801dea0425c8e2 -F ext/fts5/test/fts5misc.test 088ac5f0f5de1ad45b0f83197ab5263bcae8130156cdc901bff2375ff2b8af86 +F ext/fts5/test/fts5misc.test 4d7d20372242cc618688de029b87d897d09fa1640302c254abee63cf3ffa2c10 F ext/fts5/test/fts5multi.test a15bc91cdb717492e6e1b66fec1c356cb57386b980c7ba5af1915f97fe878581 F ext/fts5/test/fts5multiclient.test 5ff811c028d6108045ffef737f1e9f05028af2458e456c0937c1d1b8dea56d45 F ext/fts5/test/fts5near.test 211477940142d733ac04fad97cb24095513ab2507073a99c2765c3ddd2ef58bd @@ -229,11 +231,11 @@ F ext/fts5/test/fts5unindexed.test 9021af86a0fb9fc616f7a69a996db0116e7936d0db638 F ext/fts5/test/fts5update.test b8affd796e45c94a4d19ad5c26606ea06065a0f162a9562d9f005b5a80ccf0bc F ext/fts5/test/fts5version.test c8f2cc105f0abf0224965f93e584633dee3e06c91478bc67e468f7cfdf97fd6a F ext/fts5/test/fts5vocab.test 7ed80d9af1ddaaa1637da05e406327b5aac250848bc604c1c1cc667908b87760 -F ext/fts5/test/fts5vocab2.test e0fdc3a3095f6eda68ac9bf9a443ff929a124d46f00af19933604085712e9d47 +F ext/fts5/test/fts5vocab2.test 681980e92e031c9f3fe8d9c149189e876c108da2fb0fb3a25bd8a9b94bff8f68 F ext/fts5/tool/fts5speed.tcl b0056f91a55b2d1a3684ec05729de92b042e2f85 F ext/fts5/tool/fts5txt2db.tcl c0d43c8590656f8240e622b00957b3a0facc49482411a9fdc2870b45c0c82f9f F ext/fts5/tool/loadfts5.tcl 95b03429ee6b138645703c6ca192c3ac96eaf093 -F ext/fts5/tool/mkfts5c.tcl d1c2a9ab8e0ec690a52316f33dd9b1d379942f45 +F ext/fts5/tool/mkfts5c.tcl 3eba8e9bee4221ed165f3304b51b2a74a705f4ec5df3d044573a2be539534af8 F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c F ext/icu/README.txt 1c48ffaf7f255bd73d00a35f68f6de357c2a6594f16cb00506a151be23694706 F ext/icu/icu.c 91c021c7e3e8bbba286960810fa303295c622e323567b2e6def4ce58e4466e60 @@ -289,8 +291,8 @@ F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a2 F ext/misc/appendvfs.c 9642c7a194a2a25dca7ad3e36af24a0a46d7702168c4ad7e59c9f9b0e16a3824 F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0edb2a F ext/misc/btreeinfo.c d28ce349b40054eaa9473e835837bad7a71deec33ba13e39f963d50933bfa0f9 -F ext/misc/carray.c b75a0f207391038bf1540d3372f482a95c3613511c7c474db51ede1196321c7c -F ext/misc/carray.h de74ac70b2338f416723f7d538026e8ec0b7f1d388319f8f140c9a4d7677f02e +F ext/misc/carray.c b752f46411e4e47e34dce6f0c88bc8e51bb821ba9e49bfcd882506451c928f69 +F ext/misc/carray.h d2b1b12486d531367c37832d3d0dad34eea4bdd83ed839d445521ef01f0bc4e3 F ext/misc/cksumvfs.c b42ef52eaaa510d54ec320c87bea149e934a3b06cd232be2093562bf669bd572 F ext/misc/closure.c dbfd8543b2a017ae6b1a5843986b22ddf99ff126ec9634a2f4047cd14c85c243 F ext/misc/completion.c 6dafd7f4348eecc7be9e920d4b419d1fb2af75d938cd9c59a20cfe8beb2f22b9 @@ -301,11 +303,11 @@ F ext/misc/dbdump.c b8592f6f2da292c62991a13864a60d6c573c47a9cc58362131b9e6a64f82 F ext/misc/decimal.c 09f967dcf4a1ee35a76309829308ec278d3648168733f4a1147820e11ebefd12 F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1 F ext/misc/explain.c 0086fab288d4352ea638cf40ac382aad3b0dc5e845a1ea829a694c015fd970fe -F ext/misc/fileio.c 9b69e25da3b51d4a1d905a464ccb96709792ad627a742ba09215bc0d1447e7bd +F ext/misc/fileio.c 57fefd0efc535e62bb8b07fa146875171481da81a759bbfbe2fc91bab90058e0 F ext/misc/fossildelta.c 1240b2d3e52eab1d50c160c7fe1902a9bd210e052dc209200a750bbf885402d5 F ext/misc/fuzzer.c eae560134f66333e9e1ca4c8ffea75df42056e2ce8456734565dbe1c2a92bf3d -F ext/misc/ieee754.c cd6ab89f85fda8a020559b3f4d03001a8a62dd856beda5af3f558621d12be913 -F ext/misc/json1.c 76c5d9e0960fd15b4be79dacb76d872b4d0d983ce13e72ebfe9481d82cb9345d +F ext/misc/ieee754.c 91a5594071143a4ab79c638fe9f059af1db09932faf2e704c3e29216a7d4f511 +F ext/misc/json1.c 89a988f06dcb3da0d0af9fdb2b09892452ad12dfd8f432600ee6437a6dcac310 F ext/misc/memstat.c 3017a0832c645c0f8c773435620d663855f04690172316bd127270d1a7523d4d F ext/misc/memtrace.c 7c0d115d2ef716ad0ba632c91e05bd119cb16c1aedf3bec9f06196ead2d5537b F ext/misc/memvfs.c 7dffa8cc89c7f2d73da4bd4ccea1bcbd2bd283e3bb4cea398df7c372a197291b @@ -315,11 +317,11 @@ F ext/misc/noop.c 81efe4cad9ec740e64388b14281cb983e6e2c223fed43eb77ab3e34946e0c1 F ext/misc/normalize.c bd84355c118e297522aba74de34a4fd286fc775524e0499b14473918d09ea61f F ext/misc/percentile.c b9086e223d583bdaf8cb73c98a6539d501a2fc4282654adbfea576453d82e691 F ext/misc/prefixes.c 0f4f8cff5aebc00a7e3ac4021fd59cfe1a8e17c800ceaf592859ecb9cbc38196 -F ext/misc/regexp.c 5853b0e5ed40c47f7ded2b0bf2ff73796f7cb21543089c5f07308e0032647b76 +F ext/misc/regexp.c 8cd0d2d904bf7014ba28beab8c1d502b5154e04a8c738b079d88e4ecca1b3981 F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946 -F ext/misc/series.c c6bd5d249e5199a1b55aeee4d0e6576ff3a68702fc475dbd64503a32903516c7 +F ext/misc/series.c f9896e76b029e3c6553c520552555e803e26e7dfe1890d5866243cf072d938d0 F ext/misc/sha1.c c8f2253c8792ffab9517695ea7d88c079f0395a5505eefef5c8198fe184ed5ac F ext/misc/shathree.c e984f31731de4cf302a0386be5fe664580f63d8204c47b9b41cc4b997745f9ec F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52 @@ -337,11 +339,11 @@ F ext/misc/vfsstat.c 474d08efc697b8eba300082cb1eb74a5f0f3df31ed257db1cb07e72ab0e F ext/misc/vtablog.c 5538acd0c8ddaae372331bee11608d76973436b77d6a91e8635cfc9432fba5ae F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd F ext/misc/wholenumber.c a838d1bea913c514ff316c69695efbb49ea3b8cb37d22afc57f73b6b010b4546 -F ext/misc/zipfile.c b7261ef6dbc2d18924ff80c40fb5d56c9ccfee3f822a7d3d43b7c87af3d27218 +F ext/misc/zipfile.c 5dcbbdae13ba45db5d3843b6f32a8f99df7ab0349a704857a3000618f9ea9ecb F ext/misc/zorder.c b0ff58fa643afa1d846786d51ea8d5c4b6b35aa0254ab5a82617db92f3adda64 F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8 F ext/rbu/rbu1.test c62904bd9526dcdc3496a21199aaf14ae191bbadbf67f076bf16be6b3f2115c2 -F ext/rbu/rbu10.test 0a201c32202143f23c81c0144503da339786fc20acb7a2fda11601b65659f314 +F ext/rbu/rbu10.test 06d2bc934a03a0978e750cc9c95b419d9b0bcbec1fc77128e33e377c3a73240b F ext/rbu/rbu11.test 5c834cf491086b45e071eabf71f708febc143e86a384a92de69e0b1a4cace144 F ext/rbu/rbu12.test 29f8b2118f6c96fac3755bd6d2b55c2db24f878b1f11fbfbe294f3a230a3dcdc F ext/rbu/rbu13.test 1285298e3360ec74511764841b3c174dcfe21da2f618c22febf1a20abd0365c2 @@ -361,6 +363,7 @@ F ext/rbu/rbucrash.test 000981a1fe8a6e4d9a684232f6a129e66a3ef595f5ed74655e2f9c68 F ext/rbu/rbucrash2.test efa143cc94228eb0266d3f1abfbee60a5838a84cef7cc3fcb8c145b74d96fd41 F ext/rbu/rbudiff.test abe895a8d479e4d33acb40e244e3d8e2cd25f55a18dfa8b9f83e13d00073f600 F ext/rbu/rbudor.test e3e8623926012f43eebe51fedf06a102df2640750d971596b052495f2536db20 +F ext/rbu/rbuexlock.test 4634a5526d02bf80b0c563f95774bd5af5783e3219ddeb30e413753c9a65510c F ext/rbu/rbuexpr.test 10d0420537c3bc7666e576d72adeffe7e86cfbb00dcc30aa9ce096c042415190 F ext/rbu/rbufault.test 2d7f567b79d558f6e093c58808cab4354f8a174e3802f69e7790a9689b3c09f8 F ext/rbu/rbufault2.test c81327a3ac2c385b9b954db3644d4e0df93eeebfc3de9f1f29975a1e73fd3d0c @@ -376,14 +379,14 @@ F ext/rbu/rbusave.test f4190a1a86fccf84f723af5c93813365ae33feda35845ba107b59683d F ext/rbu/rbusplit.test b37e7b40b38760881dc9c854bd40b4744c6b6cd74990754eca3bda0f407051e8 F ext/rbu/rbutemplimit.test 05ceefa90a2e26a99f40dd48282ed63a00df5e59c1f2bfd479c143e201a1b0ba F ext/rbu/rbuvacuum.test 55e101e90168c2b31df6c9638fe73dc7f7cc666b6142266d1563697d79f73534 -F ext/rbu/rbuvacuum2.test b8e5b51dc8b2c0153373d024c0936be3f66f9234acbd6d0baab0869d56b14e6b +F ext/rbu/rbuvacuum2.test 886add83fd74bcb02e6dd016ae5b585367bd58c5d0694c9d9ca7bdb1d1f578c2 F ext/rbu/rbuvacuum3.test 8addd82e4b83b4c93fa47428eae4fd0dbf410f8512c186f38e348feb49ba03dc F ext/rbu/rbuvacuum4.test a78898e438a44803eb2bc897ba3323373c9f277418e2d6d76e90f2f1dbccfd10 -F ext/rbu/sqlite3rbu.c badb52388467f58e67ef104c5276d1ac68b316a30f8ccb2f74eac733625ae236 +F ext/rbu/sqlite3rbu.c 3658f1c6603955c7426952b74a6896337b1f672d326cd565e5af20e18d5744f0 F ext/rbu/sqlite3rbu.h 1dc88ab7bd32d0f15890ea08d23476c4198d3da3056985403991f8c9cd389812 F ext/rbu/test_rbu.c 03f6f177096a5f822d68d8e4069ad8907fe572c62ff2d19b141f59742821828a F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15 -F ext/repair/checkfreelist.c 0dbae18c1b552f58d64f8969e4fb1e7f11930c60a8c2a9a8d50b7f15bdfd54bd +F ext/repair/checkfreelist.c e21f06995ff4efdc1622dcceaea4dcba2caa83ca2f31a1607b98a8509168a996 F ext/repair/checkindex.c 4383e4469c21e5b9ae321d0d63cec53e981af9d7a6564be6374f0eeb93dfc890 F ext/repair/sqlite3_checker.c.in 4a5a3af3f450fe503e5a2985e98516dc2a6b9ad247449e284c1cf140fc91720f F ext/repair/sqlite3_checker.tcl a9a2caa9660567257c177a91124d8c0dccdfa341e25c51e6da7f1fd9e601eafa @@ -392,10 +395,10 @@ F ext/repair/test/checkfreelist01.test 3e8aa6aeb4007680c94a8d07b41c339aa635cc782 F ext/repair/test/checkindex01.test b530f141413b587c9eb78ff734de6bb79bc3515c335096108c12c01bddbadcec F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 -F ext/rtree/geopoly.c 98d45533989e908bf65b43f36ff6eaad95a9ffe6f3b6b8658fbd47d45c58b10b -F ext/rtree/rtree.c f1ce6a86f7cbff634900653bec2dfeba732dd4450eec921c0ac3851d41f462b9 +F ext/rtree/geopoly.c a7021cb524621573ccda213a35b0339371849dd4acc4909f689786ee1f964b7f +F ext/rtree/rtree.c d7b4b8b81d8d54376a7f81de5be85ec58b37c11604bcf42984a8418b34158d93 F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412 -F ext/rtree/rtree1.test 00792b030a4e188ff1b22e8530e8aa0452bb5dd81c2b18cb004afc7dc63e040e +F ext/rtree/rtree1.test 35c3bc0def71317b7601ee0d1149e7df2cd8fc4f13ec89a64761ac3f46ca123f F ext/rtree/rtree2.test 9d9deddbb16fd0c30c36e6b4fdc3ee3132d765567f0f9432ee71e1303d32603d F ext/rtree/rtree3.test 4ee5d7df86040efe3d8d84f141f2962a7745452200a7cba1db06f86d97050499 F ext/rtree/rtree4.test 304de65d484540111b896827e4261815e5dca4ce28eeecd58be648cd73452c4b @@ -403,8 +406,8 @@ F ext/rtree/rtree5.test 49c9041d713d54560b315c2c7ef7207ee287eba1b20f8266968a06f2 F ext/rtree/rtree6.test 9ce3691c1aac43070a9f194f0ebf54372db346c5a82241fd11b525ed53ce9f3f F ext/rtree/rtree7.test c8fb2e555b128dd0f0bdb520c61380014f497f8a23c40f2e820acc9f9e4fdce5 F ext/rtree/rtree8.test 2d99006a1386663978c9e1df167554671e4f711c419175b39f332719deb1ce0e -F ext/rtree/rtree9.test c646f12c8c1c68ef015c6c043d86a0c42488e2e68ed1bb1b0771a7ca246cbabf -F ext/rtree/rtreeA.test ed2f1be9c06dde0b1ab93a95dd9e87eeaa02db2d30bcb4b9179b69ee3dc3319b +F ext/rtree/rtree9.test fd3c9384ef8aabbc127b3878764070398f136eebc551cd20484b570f2cc1956a +F ext/rtree/rtreeA.test c0d8e91e25052d5f3fbda17632ca843b82ca13c4181fb6000a0d63bd2d7e70ce F ext/rtree/rtreeB.test 4cec297f8e5c588654bbf3c6ed0903f10612be8a2878055dd25faf8c71758bc9 F ext/rtree/rtreeC.test c4bfa9a61c6788c03e4a9ce40ab2cfc6100982559effd9842d1b658e1d47aa5f F ext/rtree/rtreeD.test fe46aa7f012e137bd58294409b16c0d43976c3bb92c8f710481e577c4a1100dc @@ -418,8 +421,12 @@ F ext/rtree/rtree_util.tcl db734b4c5e75fed6acc56d9701f2235345acfdec750b5fc7b5879 F ext/rtree/rtreecheck.test d67d5b3e9e45bfa8cd90734e8e9302144ac415b8e9176c6f02d4f92892ee8a35 F ext/rtree/rtreecirc.test aec664eb21ae943aeb344191407afff5d392d3ae9d12b9a112ced0d9c5de298e F ext/rtree/rtreeconnect.test 225ad3fcb483d36cbee423a25052a6bbae762c9576ae9268332360c68c170d3d +F ext/rtree/rtreedoc.test 27a5703cb1200f6f69051de68da546cef3dfdcf59be73afadfc50b9f9c9960d9 +F ext/rtree/rtreedoc2.test 194ebb7d561452dcdc10bf03f44e30c082c2f0c14efeb07f5e02c7daf8284d93 +F ext/rtree/rtreedoc3.test 555a878c4d79c4e37fa439a1c3b02ee65d3ebaf75d9e8d96a9c55d66db3efbf8 F ext/rtree/rtreefuzz001.test 0fc793f67897c250c5fde96cefee455a5e2fb92f4feeabde5b85ea02040790ee F ext/rtree/sqlite3rtree.h 03c8db3261e435fbddcfc961471795cbf12b24e03001d0015b2636b0f3881373 +F ext/rtree/test_rtreedoc.c 5ad4029d6804eb9efafcac1598a9e0582f6119e48f818854f5b4db1788ca8bd4 F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de F ext/rtree/util/randomshape.tcl 54ee03d0d4a1c621806f7f44d5b78d2db8fac26e0e8687c36c4bd0203b27dbff F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024 @@ -427,12 +434,12 @@ F ext/rtree/visual01.txt e9c2564083bcd30ec51b07f881bffbf0e12b50a3f6fced0c222c5c1 F ext/session/changeset.c 7a1e6a14c7e92d36ca177e92e88b5281acd709f3b726298dc34ec0fb58869cb5 F ext/session/changesetfuzz.c 227076ab0ae4447d742c01ee88a564da6478bbf26b65108bf8fac9cd8b0b24aa F ext/session/changesetfuzz1.test 2e1b90d888fbf0eea5e1bd2f1e527a48cc85f8e0ff75df1ec4e320b21f580b3a -F ext/session/session1.test 0b2f88995832ea040ae8e83a1ad4afa99c00b85c779d213da73a95ea4113233e +F ext/session/session1.test e94f764fbfb672147c0ef7026b195988133b371dc8cf9e52423eba6cad69717e F ext/session/session2.test 7f53d755d921e0baf815c4258348e0ed460dfd8a772351bca5ad3ccbb1dc786e F ext/session/session3.test ce9ce3dfa489473987f899e9f6a0f2db9bde3479 F ext/session/session4.test 6778997065b44d99c51ff9cece047ff9244a32856b328735ae27ddef68979c40 F ext/session/session5.test 716bc6fafd625ce60dfa62ae128971628c1a1169 -F ext/session/session6.test 443789bc2fca12e4f7075cf692c60b8a2bea1a26 +F ext/session/session6.test 35279f2ec45448cd2e24a61688219dc6cf7871757716063acf4a8b5455e1e926 F ext/session/session8.test 8e194b3f655d861ca36de5d4de53f702751bab3b F ext/session/session9.test 5409d90d8141881d08285ed1c2c0d8d10fb92069 F ext/session/sessionA.test 1feeab0b8e03527f08f2f1defb442da25480138f @@ -445,7 +452,7 @@ F ext/session/sessionG.test 3828b944cd1285f4379340fd36f8b64c464fc84df6ff3ccbc955 F ext/session/sessionH.test b17afdbd3b8f17e9bab91e235acf167cf35485db2ab2df0ea8893fbb914741a4 F ext/session/session_common.tcl f613174665456b2d916ae8df3e5735092a1c1712f36f46840172e9a01e8cc53e F ext/session/session_speed_test.c dcf0ef58d76b70c8fbd9eab3be77cf9deb8bc1638fed8be518b62d6cbdef88b3 -F ext/session/sessionat.test efe88965e74ff1bc2af9c310b28358c02d420c1fb2705cc7a28f0c1cc142c3ec +F ext/session/sessionat.test 52993535f1230a42f70886643574ba7ae60ef854f8add9c8e3fcc3eb5c564bd2 F ext/session/sessionbig.test 890ade19e3f80f3d3a3e83821ff79c5e2af906a67ecb5450879f0015cadf101e F ext/session/sessiondiff.test ad13dd65664bae26744e1f18eb3cbd5588349b7e9118851d8f9364248d67bcec F ext/session/sessionfault.test da273f2712b6411e85e71465a1733b8501dbf6f7 @@ -457,7 +464,7 @@ F ext/session/sessionrebase.test ccfa716b23bd1d3b03217ee58cfd90c78d4b99f53e6a9a2 F ext/session/sessionsize.test 6f644aff31c7f1e4871e9ff3542766e18da68fc7e587b83a347ea9820a002dd8 F ext/session/sessionstat1.test 218d351cf9fcd6648f125a26b607b140310160184723c2666091b54450a68fb5 F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc -F ext/session/sqlite3session.c af0cb1163e224b286a9cba3c1ad877d927821e6a0e317c29b289a16e5da378a8 +F ext/session/sqlite3session.c 1d019c5caf51936ef24c761db63552b06e0e0d951c8740bba9639b17fa0cb107 F ext/session/sqlite3session.h 0907de79bc13a2e3af30a6dc29acc60792a3eaf7d33d44cf52500d0f3c2b2171 F ext/session/test_session.c f433f68a8a8c64b0f5bc74dc725078f12483301ad4ae8375205eef790274a787 F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3 @@ -466,7 +473,7 @@ F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 -F main.mk c0c95f0aa2e3b731eb0c5a85869d4d6abef91647ec8e87a4013059bd1b910c0a +F main.mk 002e77acdfeb08d1d8f4d360b01e130aa243fb5701728e81fac9085794f27155 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504 @@ -478,45 +485,45 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a -F src/alter.c 774a2a175ec747b55046ec62f5c1208d730ee22b10bdad5f182591fa247946a8 -F src/analyze.c 01c6c6765cb4d40b473b71d85535093730770bb186f2f473abac25f07fcdee5c -F src/attach.c a514e81758ba7b3a3a0501faf70af6cfc509de8810235db726cfc9f25165e929 -F src/auth.c 08954fdc4cc2da5264ba5b75cfd90b67a6fc7d1710a02ccf917c38eadec77853 +F src/alter.c 23743384e59f9d36df870ce41adfdf7934fd0adb619d7fa6fd1aac77c28a7533 +F src/analyze.c 7518b99e07c5494111fe3bd867f28f804b6c5c1ad0703ec3d116de9bab3fa516 +F src/attach.c e3f9d9a2a4a844750f3f348f37afb244535f21382cbfcd840152cb21cb41cfaf +F src/auth.c f4fa91b6a90bbc8e0d0f738aa284551739c9543a367071f55574681e0f24f8cf F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d -F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 +F src/bitvec.c 7c849aac407230278445cb069bebc5f89bf2ddd87c5ed9459b070a9175707b3d F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c 399e1ebcd6c4f9ad47f5457bfe3623441db287f0923433cf6539497791557be8 -F src/btree.h 096cc53baa58be22b02c896d1cf933c38cfc6d65f9253c1367ece8cc88a24de5 -F src/btreeInt.h 7bc15a24a02662409ebcd6aeaa1065522d14b7fda71573a2b0568b458f514ae0 -F src/build.c ea28944f65b04f771e7aa5d614d406faa1bde5fe4ce882e2ead73049f03ed568 -F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c +F src/btree.c 012772a0cbd1c8ee7ac34f5a9ff9861de989725cb26e7a07afbbb2d43deeccd9 +F src/btree.h 74d64b8f28cfa4a894d14d4ed64fa432cd697b98b61708d4351482ae15913e22 +F src/btreeInt.h ee9348c4cb9077243b049edc93a82c1f32ca48baeabf2140d41362b9f9139ff7 +F src/build.c c46bd4f5a69f398410c4472f7c1c4291fb8078d2c9758a2dad5916edd1d30ecc +F src/callback.c 106b585da1edd57d75fa579d823a5218e0bf37f191dbf7417eeb4a8a9a267dbc F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e -F src/ctime.c 3052b6b05ed9ef547a3dd66b8e01bfa9d582e78752ad6ed327da84652641e038 -F src/date.c e0632f335952b32401482d099321bbf12716b29d6e72836b53ae49683ebae4bf +F src/ctime.c 8159d5f706551861c18ec6c8f6bdf105e15ea00367f05d9ab65d31a1077facc1 +F src/date.c fa928630fecf1d436cdc7a7a5c950c781709023ca782c21b7a43cc7361a9451e F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a -F src/dbstat.c 3aa79fc3aed7ce906e4ea6c10e85d657299e304f6049861fe300053ac57de36c -F src/delete.c 62451bba9fe641159e9c0b7d9d2bab1c48d0cff11e16de2d14000603d2af1fcf -F src/expr.c 30a2abf526531ce6bd45fbc85bfec0fc3f6e5a0fb490cd2350855f2fc34dd789 +F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d +F src/delete.c 0c151975fa99560767d7747f9b60543d0093d9f8b89f13d2d6058e9c83ad19e7 +F src/expr.c 827179c78d2ca7cc318392811de8151c60eacf7ce804b13e61bb7ef38f954846 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 -F src/fkey.c e9063648396c58778f77583a678342fe4a9bc82436bf23c5f9f444f2df0fdaa4 -F src/func.c 9eb67f0aaf1cf439c21d6fc8afe270973d6e8345af3f1ebda98ad42186d30f5b -F src/global.c 25ba4d58476f6be29bba9d9d14f7f146b78476d3a4d75ebb8c3b736328afe0f9 +F src/fkey.c 5b73f7a7c00f06017531a5bd258cbc2c7a294e55a7f84a729fe27aa525242560 +F src/func.c 1cfb09d7ffca81238eccefdb0293e1f5b7cfebbd1816dfad5ec6024742a7496b +F src/global.c 1f56aead86e8a18c4415638f5e6c4d0a0550427f4b3f5d065ba5164cc09c22e8 F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 -F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 +F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51 F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c 2189e0e596010a0dc5405d9f14f78db1ee2fa71138c931f5b6ea96610b95bfc1 +F src/insert.c 04c9b133be6152b4f229aab8e38230b3bf6d2e7e76455a893bff5f70e566237b F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa -F src/loadext.c 12684b3f19cd103cea97cdf14d0758196d0c646e12a898d7245141a9abfde9a4 -F src/main.c 9c06f8dc6137aaa990692ce30db1c00c3e6a574c5a4756640625c19b507c65ec -F src/malloc.c cbc93cdd429c4594912017d92ab656e2579aca64dbd1c6888551275bed46f25b +F src/loadext.c e1dcff1c916bf6834e150b492eddda5d9792453182d2ad64294d2266b6e93c4c +F src/main.c 1ea70751e6005ab6a9f784730fa0919efaa6639440a287deb73cb711e5aae57a +F src/malloc.c ef796bcc0e81d845d59a469f1cf235056caf9024172fd524e32136e65593647b F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de -F src/mem2.c b93b8762ab999a29ae7751532dadf0a1ac78040308a5fb1d17fcc365171d67eb +F src/mem2.c c8bfc9446fd0798bddd495eb5d9dbafa7d4b7287d8c22d50a83ac9daa26d8a75 F src/mem3.c 30301196cace2a085cbedee1326a49f4b26deff0af68774ca82c1f7c06fda4f6 F src/mem5.c 9bf955937b07f8c32541c8a9991f33ce3173d944 -F src/memdb.c 2f2e8efc6e531c59cf8255f0bf4ad81f2e88e0a394581244154c8cf5141757ce -F src/memjournal.c a85f0dc5c02a42453d0bc3819ecfb5666cb6433e5deefcd93ccbe05c9f088b83 +F src/memdb.c c2dc88f97c410eb68a24468344b65526685e18354ddfd15906750c1eaf9dc2dd +F src/memjournal.c ff4336a98b05ede2adee7595f22d6f7d1cdc6bf0f0a5c3d77b0acdf017b2e8b2 F src/msvc.h 3a15918220367a8876be3fa4f2abe423a861491e84b864fb2b7426bf022a28f8 F src/mutex.c 5e3409715552348732e97b9194abe92fdfcd934cfb681df4ba0ab87ac6c18d25 F src/mutex.h a7b2293c48db5f27007c3bdb21d438873637d12658f5a0bf8ad025bb96803c4a @@ -524,37 +531,37 @@ F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4 F src/mutex_unix.c dd2b3f1cc1863079bc1349ac0fec395a500090c4fe4e11ab775310a49f2f956d F src/mutex_w32.c caa50e1c0258ac4443f52e00fe8aaea73b6d0728bd8856bedfff822cae418541 F src/notify.c 89a97dc854c3aa62ad5f384ef50c5a4a11d70fcc69f86de3e991573421130ed6 -F src/os.c 59ed1f503347e8b5434c0ce7d7d0f02a3f24a72fea8b26d0bba2de8dfaef778b +F src/os.c b1c4f2d485961e9a5b6b648c36687d25047c252222e9660b7cc25a6e1ea436ab F src/os.h 26890f540b475598cd9881dcc68931377b8d429d3ea3e2eeb64470cde64199f8 F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85 F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586 -F src/os_unix.c feac74a0ba7652c405ba30f61d9e738be717d15899f2915a129ef160a3e5b26b +F src/os_unix.c f5ad51cfd024116db8531feab9efd831c2621436dca1464e4ff1e8af9bf3252e F src/os_win.c 77d39873836f1831a9b0b91894fec45ab0e9ca8e067dc8c549e1d1eca1566fe9 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a -F src/pager.c 95c255256b13827caf038c8f963d334784073f38ab6ef9d70371d9d04f3c43e0 +F src/pager.c 5b79a1c09bc19628a763c822ef96326832090703a6608c64dc5fc166ab8dda79 F src/pager.h 4bf9b3213a4b2bebbced5eaa8b219cf25d4a82f385d093cd64b7e93e5285f66f -F src/parse.y 8920f4444957d7827ca458029b2e41ffa32dd3b72917be0b52cae0aace3eadb5 -F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177 +F src/parse.y 0bd7971a7489bbf6c3726f1b50da6e508bdff8fa493e9cc3f5a96b12cbb2361e +F src/pcache.c 084e638432c610f95aea72b8509f0845d2791293f39d1b82f0c0a7e089c3bb6b F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 -F src/pcache1.c 388304fd2d91c39591080b5e0f3c62cfba87db20370e7e0554062bfb29740e9f -F src/pragma.c eb42cb9bec189cf18cef5d8fcae56e13bb73ef2b019b198fb48740ced81bce95 -F src/pragma.h 8dc78ab7e9ec6ce3ded8332810a2066f1ef6267e2e03cd7356ee00276125c6cf -F src/prepare.c 0d53d20532aada295c1690792a125adbd6435f5ce703ff0adf1b9b3605238b67 -F src/printf.c 78fabb49b9ac9a12dd1c89d744abdc9b67fd3205e62967e158f78b965a29ec4b +F src/pcache1.c 54881292a9a5db202b2c0ac541c5e3ef9a5e8c4f1c1383adb2601d5499a60e65 +F src/pragma.c c536665ce8431c8b1efbf7e0a5c01852f49f7bf28f1954f8118b2d28e4a3797f +F src/pragma.h 87330ed2fbfa2a1274de93ca0ab850fba336189228cb256089202c3b52766fad +F src/prepare.c dab0c2995a33ee2c458354cb7dd13b2b33362425c52301e41d833add7660e7ca +F src/printf.c 5901672228f305f7d493cbc4e7d76a61a5caecdbc1cd06b1f9ec42ea4265cf8d F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c -F src/resolve.c 35630effd4d16d2373caa41bae40a3d71f853f3ad0cb4f572f2ed4b8c350c1e9 +F src/resolve.c 4a1db4aadd802683db40ca2dbbb268187bd195f10cbdb7206dbd8ac988795571 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c 4fa607bab6bcc580f12dbaf9c800b2250a1e408f10321a1d3bcb1dd30c447e62 -F src/shell.c.in f3e91c697f33daae14923355dcadfc26bb0c1eabdb343e5508706893e017a0a6 -F src/sqlite.h.in 8549395aa13361d5dcea04e3a57d680af10f7ee0989c45ebfffe3a3bcb2cdc3d +F src/select.c a7a3d9f54eb24821ec5f67f2e5589b68a5d42d46fc5849d7376886777d93a85a +F src/shell.c.in 1458b700144c8326fda2514aaddeda49d6f01f1d1ccf7b9b696c53a3535a119c +F src/sqlite.h.in 5cd209ac7dc4180f0e19292846f40440b8488015849ca0110c70b906b57d68f0 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 -F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e -F src/sqliteInt.h ab37a8dd95884fc25ef1eb7b6d53d6674905c67298affc2b5bf947f739096504 +F src/sqlite3ext.h 8ff2fd2c166150b2e48639f5e506fb44e29f1a3f65031710b9e89d1c126ac839 +F src/sqliteInt.h 4bf21edf5c330299d1b7399d604da1787001725dbb1c675fe0989ceb1ee8043f F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 -F src/tclsqlite.c 97645e4a15dde6a6ad6de8d81057ff9869413b866015a89e208fedacd709493e -F src/test1.c 2100f4c28bae21ce83a9a0c5ec6827efd0e15d11b93b569b614daa5654b3fcf6 +F src/tclsqlite.c 48f291e1a7e672a7204884d4c164a8ed3a522ff087c361ada2991f5d54e987f6 +F src/test1.c d6c945a8bb211ed72ea515f0b9743caeaf38c66da6418a7b1dcf3764e1368bbb F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5 F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644 F src/test4.c 7c4420e01c577b5c4add2cb03119743b1a357543d347773b9e717195ea967159 @@ -569,7 +576,7 @@ F src/test_backup.c bf5da90c9926df0a4b941f2d92825a01bbe090a0 F src/test_bestindex.c 78809f11026f18a93fcfd798d9479cba37e1201c830260bf1edc674b2fa9b857 F src/test_blob.c ae4a0620b478548afb67963095a7417cd06a4ec0a56adb453542203bfdcb31ce F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274 -F src/test_config.c 9c8e12823c46082a01765addf43be9309889f4e9dfb5a512a6c974e1c4efb413 +F src/test_config.c 284c29912736f68b0a583a920bf63fd8f9125dffb8a75cb0676e58502b2f7908 F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf9f8f F src/test_demovfs.c 86142ba864d4297d54c5b2e972e74f3141ae4b30f05b3a95824184ed2d3d7f91 F src/test_devsym.c aff2255ea290d7718da08af30cdf18e470ff7325a5eff63e0057b1496ed66593 @@ -583,7 +590,7 @@ F src/test_journal.c a0b9709b2f12b1ec819eea8a1176f283bca6d688a6d4a502bd6fd79786f F src/test_loadext.c 337056bae59f80b9eb00ba82088b39d0f4fe6dfd F src/test_malloc.c 21121ea85b49ec0bdb69995847cef9036ef9beca3ce63bbb776e4ea2ecc44b97 F src/test_md5.c 7268e1e8c399d4a5e181b64ac20e1e6f3bc4dd9fc87abac02db145a3d951fa8c -F src/test_multiplex.c 2ccf35551c094e353af20b0cdfac053a37bf3e96e10e7cf9f4abd1d279890a78 +F src/test_multiplex.c 1b23782212a01349fac382913ef82b8de4ae8a4cb46556602c2ee733edabbbc9 F src/test_multiplex.h 5436d03f2d0501d04f3ed50a75819e190495b635 F src/test_mutex.c abf486e91bd65e2448027d4bb505e7cce6ba110e1afb9bd348d1996961cadf0d F src/test_onefile.c f31e52e891c5fef6709b9fcef54ce660648a34172423a9cbdf4cbce3ba0049f4 @@ -597,7 +604,7 @@ F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe F src/test_sqllog.c 540feaea7280cd5f926168aee9deb1065ae136d0bbbe7361e2ef3541783e187a F src/test_superlock.c 4839644b9201da822f181c5bc406c0b2385f672e F src/test_syscall.c 1073306ba2e9bfc886771871a13d3de281ed3939 -F src/test_tclsh.c eeafce33ad2136d57e5dec10f1e9a4347447eb72ffd504a1c7b9c6bfe2e71578 +F src/test_tclsh.c c4065ced25126e25c40122c5ff62dc89902ea617d72cdd27765151cdd7fcc477 F src/test_tclvar.c 33ff42149494a39c5fbb0df3d25d6fafb2f668888e41c0688d07273dcb268dfc F src/test_thread.c 269ea9e1fa5828dba550eb26f619aa18aedbc29fd92f8a5f6b93521fbb74a61c F src/test_vdbecov.c f60c6f135ec42c0de013a1d5136777aa328a776d33277f92abac648930453d43 @@ -608,63 +615,64 @@ F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a9 F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394ba3f F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c -F src/tokenize.c bae853ad129d1129c063de8630a3e99e306283bc40146f359b1bb91be2c08f1e -F src/treeview.c 21449a944d5abd3ac07b7eab76f7221e20c9480d06f01798f8dc66d9bc361769 -F src/trigger.c e0fd347b2571a2d956318cdc6d011ccca7ce862d10a0ca04188a37920ef5440c -F src/update.c 56fa0458b1ffc1042629f926443e8ed44203983df3ab2b0db2ba556e6ceed68c -F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 +F src/tokenize.c 865911afa00fed589cd03b25c140ca88544842aaef7b81f7d41ed769a7a54120 +F src/treeview.c 9dfdb7ff7f6645d0a6458dbdf4ffac041c071c4533a6db8bb6e502b979ac67bc +F src/trigger.c 043d66ecb25a223c614681c8ab758f1aaf6e507c901d3a4668113afab1cc2dc7 +F src/update.c 69c4c10bc6873a80c0a77cb578f9fc60ee90003d03f9530bc3370fa24615772d +F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 -F src/util.c 41c7a72da1df47864faa378a1c720b38adb288c6838cb6be5594511b6287a048 -F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286 -F src/vdbe.c 6ece0ee94fa3a95601372efdc4ec6d068cd6cc58e28af8852f3407b90be4b7f8 +F src/util.c 30df8356e231dad33be10bb27897655002668343280004ba28c734489414a167 +F src/vacuum.c 6c38ddc52f0619865c91dae9c441d4d48bf3040d7dc1bc5b22da1e45547ed0b3 +F src/vdbe.c 84cc51edc36f773a97433c0a1388833557806f56562b6a2cb9fefeadc5e236b0 F src/vdbe.h 25dabb25c7e157b84e59260cfb5b466c3ac103ede9f36f4db371332c47601abe -F src/vdbeInt.h 465fcb494db4ca6630fb9c19b2f3dfed597fbe885b0d4204193a5093b0dd7dc6 -F src/vdbeapi.c aa5aaf2c37676b83af5724c6cd8207a3064ed46a217fd180957f75ac84f7a2a5 -F src/vdbeaux.c 065a10392378109f08435bd50d03dff315e384cde2831d6b8dbaec05f33b10af -F src/vdbeblob.c c6b8db50b227f66fb404215732068df76485b5b433e5f9d4d9ac27410b218193 -F src/vdbemem.c 53881aa0a7845922a075b3f375695588618098871a7a4120af4c297b80fa3e64 -F src/vdbesort.c cd5130f683706c1a43e165a74187745fb3351cb56052cf9dc91de820634bbde2 -F src/vdbetrace.c 666c6fd9f1b62be6999e072a45b913e3c2c3518bc60dfd4d54fe304130acb724 +F src/vdbeInt.h 31fbabdc1ed61d9695337dfe5269ea94e1cf615c17f5cafeaa1bb01066820bab +F src/vdbeapi.c 22c79072ae7d8a01e9bcae8ba16e918d60d202eaa9553b5fda38f99f7464d99a +F src/vdbeaux.c 9e16b5cb02f9e95df008369880332b6551feea6a3495b44c20da96c381508042 +F src/vdbeblob.c 29c4118f7ee615cdee829e8401f6ead1b96b95d545b4de0042f6de39c962c652 +F src/vdbemem.c a3d91dc9bb9ef725db77e4e9de7e1acef43192c9f8406c307665d503e3c2837c +F src/vdbesort.c 513b481c8bab4a6578c92194a60cf3bc3b48736e4a53f8d2d7918121c5b594e7 +F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823 F src/vdbevtab.c f99b275366c5fc5e2d99f734729880994ab9500bdafde7fae3b02d562b9d323c -F src/vtab.c b928405ccb66040fc6c3a11eaa93ddb02cbf20f9ab6860b301b222b9b50dc089 +F src/vtab.c 9d5c3f49d3a6959b6eef287bb8fa773563102a80a835c3314c57144412709e78 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 -F src/wal.c c8ec20a1ca161d5635a4f19c2a4efec2e006e19a8a61f272bf6bce1c80ab7436 +F src/wal.c ed0398a7adf02c31e34aada42cc86c58f413a7afe5f741a5d373ad087abde028 F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a -F src/walker.c 7342becedf3f8a26f9817f08436bdf8b56ad69af83705f6b9320a0ad3092c2ac -F src/where.c 4caf843825c6292440113258fefaa6f747fd570c6915628957e42e39529988f5 -F src/whereInt.h 9248161dd004f625ce5d3841ca9b99fed3fc8d61522cf76340fc5217dbe1375b -F src/wherecode.c 9f1f65d11437b25cd0a1497a170514c785f19ce6ad9d3e6fc73719cb5a49012f -F src/whereexpr.c 5a9c9f5d2dac4bcdcaae3035034b4667523f731df228e0bb1d4efc669efa9da5 -F src/window.c a6d624d83b2d5b3cfb82bb437a2fbae759c928d47dc9ad1338a9419269181bb2 +F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b +F src/where.c de0d4ff409c7b62a8803f9f267cc2c7fedddbc00de9ab7b5382c507383c18665 +F src/whereInt.h 83877a75a1bce056ea44aff02f1dfa958ad1d6038c213ddadb8652003b45151d +F src/wherecode.c 1f5b62f46d284c8886945eb7438415bc27e23e87bb60b9ee468fa6bd31268f33 +F src/whereexpr.c 17bdbf4f5b490e70a18635498f0b910a558f953a9bf80af7f19cbde6e60e6825 +F src/window.c 5d3b397b0c026d0ff5890244ac41359e524c01ae31e78782e1ff418c3e271a9e F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 F test/affinity3.test eecb0dabee4b7765a8465439d5e99429279ffba23ca74a7eae270a452799f9e7 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 -F test/aggnested.test 2f65ec8132e0ca896de550b9908094d49ad65a99116a9d79deeb6017604ad4f6 +F test/aggnested.test cc47afa5e11e0d6771a85a4993fa6ff721480ddb53ea538ec3fdbafb720bd505 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 F test/all.test 2ecb8bbd52416642e41c9081182a8df05d42c75637afd4488aace78cc4b69e13 -F test/alter.test f53d8a4ecd35f051c07e54a36beec5d0a30d30a9d98bc723f6cde6afbfb3c5ca +F test/alter.test 313073774ab5c3f2ef1d3f0d03757c9d3a81284ae7e1b4a6ca34db088f886896 F test/alter2.test a966ccfcddf9ce0a4e0e6ff1aca9e6e7948e0e242cd7e43fc091948521807687 -F test/alter3.test e487958dec7932453e0b83baf21d6b1e71d5e7d9a55bc20eadfa62a51ddffc29 +F test/alter3.test ffc4ab29ce78a3517a66afd69b2730667e3471622509c283b2bd4c46f680fba3 F test/alter4.test 716caa071dd8a3c6d57225778d15d3c3cbf5e34b2e84ae44199aeb2bbf50a707 F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256bafc959 F test/alterauth2.test 381b1ab603c9ef96314a3158528ea17f7964449385a28eeaf8191120b2e24a8d F test/altercol.test b11fa1b131e80ab5b6ecfb3b725fb0419c14ca6efba5adb57aeabfc9baa0c8f3 -F test/altercorrupt.test 584d707a80e106952d6382790c8919bcf9f0db678ed3a1c09fd98b7f9d1d3a10 +F test/altercorrupt.test 2e1d705342cf9d7de884518ddbb053fd52d7e60d2b8869b7b63b2fda68435c12 F test/alterdropcol.test a653a3945f964d26845ec0cd0a8e74189f46de3119a984c5bc45457da392612e F test/alterdropcol2.test 527fce683b200d620f560f666c44ae33e22728e990a10a48a543280dfd4b4d41 +F test/alterfault.test 289067108947bedca27534edd4ff251bcd298cf84402d7b24eaa3749305418c6 F test/alterlegacy.test f38c6d06cda39e1f7b955bbce57f2e3ef5b7cb566d3d1234502093e228c15811 F test/altermalloc.test 167a47de41b5c638f5f5c6efb59784002b196fff70f98d9b4ed3cd74a3fb80c9 F test/altermalloc2.test ca3ebc01670d9313953a2b7628d8cc00dc5ea9988f229b3cbbbe1cca506dae45 -F test/altermalloc3.test 059841a3de6b6780efd9f0b30bf1d9b4443c555f68d39975cbcac2583167b239 -F test/alterqf.test 67568ad152db8c1187b15633b801242cf960f1beafc51261a3d1725d910baeb2 -F test/altertab.test 466b9757630d68455080690b6e99c5ff11b199df4b3530e17f3df10a63aa05d3 +F test/altermalloc3.test 4660ac6240a8c82ba3947b927612dcc7c05a8eec3fe3c9f38e047ca69a789a33 +F test/alterqf.test 6b2482a957692606b23567ebd2cf80eb773e3c826086f5f151eee9c5a962623d +F test/altertab.test 7273b8506eab46342be016af78028df49f3bd99037412f997a8f1011b37a6912 F test/altertab2.test b0d62f323ca5dab42b0bc028c52e310ebdd13e655e8fac070fe622bad7852c2b -F test/altertab3.test 2b82fa2236a3a91553d53ae5555d8e723c7eec174c41f1fa62ff497355398479 +F test/altertab3.test 5929f522fd6fd708396ad9f317d4af9ff1a93e460df85bb1d54d4499eeb94960 F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f F test/analyze.test 547bb700f903107b38611b014ca645d6b5bb819f5210d7bf39c40802aafeb7d7 F test/analyze3.test 4440c4932247adb2b4e0c838f657c19dc7af4f56859255436dc4e855f39b9324 -F test/analyze4.test 293ec8ea21525f3435beaf9d6b1efb29e719415f03a0cd2a70589d59098e8464 +F test/analyze4.test 68bd069f3ac7ac1e652ddd9f04f57d5606ddb4208450f5297005db7aa0dd707d F test/analyze5.test fa5131952303ac4146aba101b116b9c8cb89e2637531c334a6df7f7d19dddc0d F test/analyze6.test 028f5bdfc9e5b5294768fa9a7185b8cd1d019aa7aab5b2f8ee42d7271d9a3b28 F test/analyze7.test 079d17c495e396bdbd6cc6a083112788a6fbfb3b95c42e760e4270a53c9ead8f @@ -681,7 +689,7 @@ F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7 F test/async4.test 1787e3952128aa10238bf39945126de7ca23685a F test/async5.test 383ab533fdb9f7ad228cc99ee66e1acb34cc0dc0 -F test/atof1.test 10049623e77006691c4c2978c1dc8a3f75276377a53417811aa85bda7493f963 +F test/atof1.test 77e8517df10cb39f2e4e65dbefe1e81c8d8e65f29f68b09265ca6e534c68227e F test/atomic.test 065a453dde33c77ff586d91ccaa6ed419829d492dbb1a5694b8a09f3f9d7d061 F test/atomic2.test b6863b4aa552543874f80b42fb3063f1c8c2e3d8e56b6562f00a3cc347b5c1da F test/atrc.c c388fac43dbba05c804432a7135ae688b32e8f25818e9994ffba4b64cf60c27c @@ -692,15 +700,16 @@ F test/attach4.test 00e754484859998d124d144de6d114d920f2ed6ca2f961e6a7f4183c714f F test/attachmalloc.test 12c4f028e570acf9e0a4b0b7fe6f536e21f3d5ebddcece423603d0569beaf438 F test/auth.test 567d917e0baddb6d0026a251cff977a3ab2c805a3cef906ba8653aafe7ad7240 F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1 -F test/auth3.test db21405b95257c24d29273b6b31d0efc59e1d337e3d5804ba2d1fd4897b1ae49 +F test/auth3.test 76d20a7fa136d63bcfcf8bcb65c0b1455ed71078d81f22bcd0550d3eb18594ab F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec F test/autoinc.test 997d6f185f138229dc4251583a1d04816423dddc2fc034871a01aeb1d728cb39 F test/autoindex1.test fe27af92eaf884bd9c38f94be3e8afa04ec494e5eefb189902026181a6175f5e F test/autoindex2.test 12ef578928102baaa0dc23ad397601a2f4ecb0df F test/autoindex3.test 2d13958a5617e987624a428d7aed91bf51f322b49b476e3573fadec697ce6da5 F test/autoindex4.test 49d3cd791a9baa16fb461d7ea3de80d019a819cf -F test/autoindex5.test ee0aa95e3f44190347a29a672c3d4ecf042e3f33c5fa3dc29f0ab6be057bbded -F test/autovacuum.test 0831cd34e14695d297187f7f6519265e3121c5b0a1720e548e86829e796129e9 +F test/autoindex5.test 2ee94f033b87ca0160e08d81034c507aff8e230df2627f0304fa309b2fee19a3 +F test/autovacuum.test 00671369bbf96c6a49989a9425f5b78b94075d6a4b031e5e00000c2c32f365df +F test/autovacuum2.test 76f7eb4fe6a6bf6d33a196a7141dba98886d2fb53a268d7feca285d5da4759d7 F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4 F test/avfs.test 0c3a38e03cccb0fc3127838462dc05dc3f4c1480d770c084b388304c25de3652 F test/avtrans.test b7dc25459ecbd86c6fa9c606ee3068f59d81e225118617dcf2bbb6ded2ade89e @@ -714,7 +723,7 @@ F test/backup_malloc.test 0c9abdf74c51e7bedb66d504cd684f28d4bd4027 F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f F test/badutf2.test f310fd3b24a491b6b77bccdf14923b85d6ebcce751068c180d93a6b8ff854399 F test/bc_common.tcl b5e42d80305be95697e6370e015af571e5333a1c -F test/bestindex1.test 2e92e046148b3f8a2be62af9c0f307413547a33677af0df159c0fcc76e5134a2 +F test/bestindex1.test 7cc626f1f4a7483bb6b38487d467db4477083be5cd93958aeda5d5127640dc81 F test/bestindex2.test 60266e2854055788459cbfd86cef575601eabe74a2c61faba72601739fea4398 F test/bestindex3.test e061a6ed0f519beee037ba7e7a4c37f80c8a7e4a303e2559ed1f760e4b0235eb F test/bestindex4.test 82250e7dcc6d5b15244edc9d6554b1760583af1b8548c2a255a1c4f28e744c0e @@ -747,15 +756,16 @@ F test/busy2.test dbfb61b3265e7a962d3bcd32cd542bbe3d7801edbda6438d35af5aa707cae9 F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de F test/cacheflush.test af25bb1509df04c1da10e38d8f322d66eceedf61 F test/cachespill.test 895997f84a25b323b166aecb69baab2d6380ea98f9e0bcc688c4493c535cfab9 -F test/capi2.test 34a1a9a96d543a2ec2c209696b11b164444f57253b1f2cba1c2e53fadede6c7b +F test/capi2.test 4ee545824adc3eb33bf57ef89f77440b28188ec3da72e5425ff0fcdba32e8d5a F test/capi3.test 3910a73c38ac76d69778dd9eb481ab7cd6ed59117fc047b4f6056a5c72529de1 F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4 F test/capi3c.test 54e2dc0c8fd7c34ad1590d1be6864397da2438c95a9f5aee2f8fbc60c112e44b F test/capi3d.test aba917805573a03deed961a21f07a5a84505ad0a616f7e3fc1508844a15bccc4 F test/capi3e.test 3d49c01ef2a1a55f41d73cba2b23b5059ec460fe -F test/carray01.test 3f2658bbddd75a013735a296ae2178ff441aca3f00ba623cfbae00b732ede792 +F test/carray01.test d55d57bf66b1af1c7ac55fae66ff4910884a8f5d21a90a18797ce386212a2634 F test/cast.test 336fa21989b5170ebcaf90c24266be22dd97b3e23d1fad5ecf6ad4efb04c4423 F test/cffault.test 9d6b20606afe712374952eec4f8fd74b1a8097ef +F test/changes.test 9dd8e597d84072122fc8a4fcdea837f4a54a461e6e536053ea984303e8ca937b F test/check.test 4a2a91ed67eee84a6be16057c48d5198b6fb24849cd6da6cd855981de3fbb416 F test/checkfault.test da6cb3d50247169efcb20bdf57863a3ccfa1d27d9e55cd324f0680096970f014 F test/chunksize.test 427d87791743486cbf0c3b8c625002f3255cb3a89c6eba655a98923b1387b760 @@ -775,7 +785,7 @@ F test/collateA.test b8218ab90d1fa5c59dcf156efabb1b2599c580d6 F test/collateB.test 1e68906951b846570f29f20102ed91d29e634854ee47454d725f2151ecac0b95 F test/colmeta.test 2c765ea61ee37bc43bbe6d6047f89004e6508eb1 F test/colname.test 87ad5458bb8709312dac0d6755fd30e8e4ca83298d0a9ef6e5c24277a3c3390e -F test/columncount.test d86fb6307261186370698962790ad2088ed419e4a4e823512b502f17d443b1b7 +F test/columncount.test 6fe99c2f35738b0129357a1cf3fa483f76140f4cd8a89014c88c33c876d2638f F test/conflict.test ac0667090f66130ac77d5fb764655558ca6600dd6d88f670ca9123b61c448337 F test/conflict2.test 5557909ce683b1073982f5d1b61dfb1d41e369533bfdaf003180c5bc87282dd1 F test/conflict3.test 81865d9599609aca394fb3b9cd5f561d4729ea5b176bece3644f6ecb540f88ac @@ -800,11 +810,11 @@ F test/corruptH.test 79801d97ec5c2f9f3c87739aa1ec2eb786f96454 F test/corruptI.test a17bbf54fdde78d43cf3cc34b0057719fd4a173a3d824285b67dc5257c064c7b F test/corruptJ.test 4d5ccc4bf959464229a836d60142831ef76a5aa4 F test/corruptK.test 5b4212fe346699831c5ad559a62c54e11c0611bdde1ea8423a091f9c01aa32af -F test/corruptL.test df132ba9ffd6fa15038380b4154998b9904ab8f1ea78400d7da53c920cb3b13d +F test/corruptL.test 7d3440831ca24ba64305583c4d4506d417d3f89f5775c0b7cc8102db078f8ff5 F test/corruptM.test 7d574320e08c1b36caa3e47262061f186367d593a7e305d35f15289cc2c3e067 -F test/corruptN.test c2a96ff81386027f7d7e95858783aa36f82ba1532106969575e3c8f90903a5bb +F test/corruptN.test 60b5a62944b4f0029ba07edaa5fd8e670539d6b0a8d99db26c068d435675cbfe F test/cost.test b11cdbf9f11ffe8ef99c9881bf390e61fe92baf2182bad1dbe6de59a7295c576 -F test/count.test 5364003488249957750a5f15ee42ca1cd7b100b1131c2dc71fff266a1250bf55 +F test/count.test 013d64569c15563c59472d17ec4ddc681034aaee65e8b01880bc88315fd4c673 F test/countofview.test e17d6e6688cf74f22783c9ec6e788c0790ee4fbbaee713affd00b1ac0bb39b86 F test/coveridxscan.test f35c7208dedc4f98e471c569df64c0f95a49f6e072d8dc7c8f99bdee2697de1b F test/crash.test fb9dc4a02dcba30d4aa5c2c226f98b220b2b959f @@ -836,7 +846,7 @@ F test/dbstatus.test 4a4221a883025ffd39696b3d1b3910b928fb097d77e671351acb35f3aed F test/dbstatus2.test f5fe0afed3fa45e57cfa70d1147606c20d2ba23feac78e9a172f2fe8ab5b78ef F test/decimal.test fcf403fd5585f47342234e153c4a4338cd737b8e0884ac66fc484df47dbcf1a7 F test/default.test 9687cfb16717e4b8238c191697c98be88c0b16e568dd5368cd9284154097ef50 -F test/delete.test 438c14fdf2f2a520b63f892ea645896acf8832e2a2308578593d8e05274314b1 +F test/delete.test 31832b0c45ecb51a54348c68db173be462985901e6ed7f403d6d7a8f70ab4ef0 F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa F test/delete3.test 555e84a00a99230b7d049d477a324a631126a6ab F test/delete4.test 51fafebe9503a40796d1aae1565c60524cada720e50eecac01b7fd0419d9ea0b @@ -848,26 +858,26 @@ F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e F test/distinct.test 3e4210ef9cd1985aeec44939ad912c4621fbea9bb4a9c565696cebfe184b2ec5 F test/distinct2.test cd1d15a4a2abf579298f7161e821ed50c0119136fe0424db85c52cf0adc230d1 F test/distinctagg.test d76ef2e91fe810630c176d6bd0a58c14d5851c3125f0a1d977db87ba76359639 -F test/e_blobbytes.test 439a945953b35cb6948a552edaec4dc31fd70a05 -F test/e_blobclose.test 4b3c8c60c2171164d472059c73e9f3c1844bb66d -F test/e_blobopen.test e95e1d40f995056f6f322cd5e1a1b83a27e1a145 -F test/e_blobwrite.test f87ff598b67af5b3ec002a8d83e804dc8d23808e88cf0080c176612fc9ffce14 -F test/e_changes.test fd66105385153dbf21fdb35eb8ef6c3e1eade579 -F test/e_createtable.test 7997c0106c181243e0ac7db7ba8b9ae7233d0bfb0188605650322a7a02ea326e +F test/e_blobbytes.test 4c01dfe4f12087b92b20705a3fdfded45dc4ed16d5a211fed4e1d2786ba68a52 +F test/e_blobclose.test 692fc02a058476c2222a63d97e3f3b2b809c1842e5525ded7f854d540ac2e075 +F test/e_blobopen.test 29f6055ee453b8e679fe9570c4d3acfedbef821622c5dad16875148c5952ef50 +F test/e_blobwrite.test 3075ff539827576d9a34cbb5a2ac75eb65fb49cd5aadc27686b0719fbf99c156 +F test/e_changes.test 0f8c3e6aab7335cb772d5a3ea34ca4c82f98d0eb896e2eb3add971c16984b405 +F test/e_createtable.test 04c50b7fe41c12ed9cd88fbbc09b4900bcfc66f98ad198874fc993a2771f3913 F test/e_delete.test ab39084f26ae1f033c940b70ebdbbd523dc4962e F test/e_droptrigger.test 235c610f8bf8ec44513e222b9085c7e49fad65ad0c1975ac2577109dd06fd8fa F test/e_dropview.test 74e405df7fa0f762e0c9445b166fe03955856532e2bb234c372f7c51228d75e7 -F test/e_expr.test 6ba7a51ece7b3e7fc145f14f924eed25ebb5a24e7b8596c78f3838d372cf0385 -F test/e_fkey.test 351c7b989e5aefcc339ef5fc78dc4738442bd247a392cd67d81c2881000c369e +F test/e_expr.test e164550b9f8fd9c130283d1eae692dff9e2ba67f4dbd35f7325021f5d4b8851c +F test/e_fkey.test ee321dbca3c53204da46cb40b8ec80192e995035f9ea26576ddcd842b1f0877f F test/e_fts3.test 17ba7c373aba4d4f5696ba147ee23fd1a1ef70782af050e03e262ca187c5ee07 F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e F test/e_reindex.test 2b0e29344497d9a8a999453a003cb476b6b1d2eef2d6c120f83c2d3a429f3164 F test/e_resolve.test a61751c368b109db73df0f20fc75fb47e166b1d8 F test/e_select.test c5425a423da06d0494119db8361ebfc6de302929f7546ca596d56224137e0360 F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f -F test/e_totalchanges.test b12ee5809d3e63aeb83238dd501a7bca7fd72c10 +F test/e_totalchanges.test c927f7499dc3aa28b9b556b7d6d115a2f0fe41f012b128d16bf1f3b30e9b41e4 F test/e_update.test f46c2554d915c9197548681e8d8c33a267e84528 -F test/e_uri.test 47eeb2960e74613f0f8722b2f13aef08fde69daa16e5380ac93df84dac8b1f72 +F test/e_uri.test a3d30c7d6d7700150055b6660ee42da7f05dee2c150ce08bf6a9ededc26468cc F test/e_vacuum.test 0d8832a2ce92350db0d0cff47b419465fd9772562e1f77ff7d9478c07a4980d2 F test/e_wal.test ae9a593207a77d711443ee69ffe081fda9243625 F test/e_walauto.test 248af31e73c98df23476a22bdb815524c9dc3ba8 @@ -898,7 +908,7 @@ F test/filter1.test 6c483ecf7886c8843a8612c021aa23f33c581f584151f251842b3a3592c9 F test/filter2.tcl 44e525497ce07382915f01bd29ffd0fa49dab3adb87253b5e5103ba8f93393e8 F test/filter2.test 485cf95d1f6d6ceee5632201ca52a71868599836f430cdee42e5f7f14666e30a F test/filterfault.test c08fb491d698e8df6c122c98f7db1c65ffcfcad2c1ab0e07fa8a5be1b34eaa8b -F test/fkey1.test d11dbb8a93ead9b5c46ae5d02da016d61245d47662fb2d844c99214f6163f768 +F test/fkey1.test 55663090ab6735319a52647057b9f19f8ec8c6c7d7da25170b71a75e3e5bdeb7 F test/fkey2.test 1063d65e5923c054cfb8f0555a92a3ae0fa8c067275a33ee1715bd856cdb304c F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49 F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d @@ -972,7 +982,7 @@ F test/fts3conf.test c84bbaec81281c1788aa545ac6e78a6bd6cde2bdbbce2da261690e3659f F test/fts3corrupt.test 79a32ffdcd5254e2f7fa121d9656e61949ad049c3c6554229911b7ceac37c9c6 F test/fts3corrupt2.test e318f0676e5e78d5a4b702637e2bb25265954c08a1b1e4aaf93c7880bb0c67d0 F test/fts3corrupt3.test 0d5b69a0998b4adf868cc301fc78f3d0707745f1d984ce044c205cdb764b491f -F test/fts3corrupt4.test 1b3333822577b0888c95de8490a1a6152c47cb33a763fe62c54825202c31812f +F test/fts3corrupt4.test 799ff994b964fed7201be6b6b62c7ff2ef7bb3da6c02b9eaf0d96a5a4d9b6ca3 F test/fts3corrupt5.test 0549f85ec4bd22e992f645f13c59b99d652f2f5e643dac75568bfd23a6db7ed5 F test/fts3corrupt6.test 657b4b8e5791d8d4adc93c90588fb25f1c7346544dd877c6c298a0746749146d F test/fts3cov.test 7eacdbefd756cfa4dc2241974e3db2834e9b372ca215880e00032222f32194cf @@ -987,6 +997,7 @@ F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a F test/fts3expr3.test c4d4a7d6327418428c96e0a3a1137c251b8dfbf8 F test/fts3expr4.test f5b2832549f01b1f7f73389fa21d4b875499bc95bf7c8b36271844888c6a0938 F test/fts3expr5.test a5b9a053becbdb8e973fbf4d6d3abaabeb42d511d1848bd57931f3e0a1cf983e +F test/fts3f.test 8c438d5e1cab526b0021988fb1dc70cf3597b006a33ffd6c955ee89929077fe3 F test/fts3fault.test 798e45af84be7978ca33d5bdc94246eb44724db24174b5d8e9b1ac46c57fb08d F test/fts3fault2.test 6a17a11d8034b1c4eca9f3091649273d56c49ff049e2173df8060f94341e9da0 F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641 @@ -997,7 +1008,7 @@ F test/fts3matchinfo.test aa66cc50615578b30f6df9984819ae5b702511cf8a94251ec7c594 F test/fts3matchinfo2.test 00144e841704b8debfcdf6097969cd9f2a1cf759e2203cda42583648f2e6bf58 F test/fts3misc.test 9ec15e7c0b5831a6353bd4c46bf3acdf1360eda5d9f396f667db4d05bcf92ecf F test/fts3near.test 7e3354d46f155a822b59c0e957fd2a70c1d7e905 -F test/fts3offsets.test b85fd382abdc78ebce721d8117bd552dfb75094c +F test/fts3offsets.test eb114b16e4d2495133bc2710d9c05ccd5ac90319718248fdf2dd379cdaa85358 F test/fts3prefix.test fa794eaab0bdae466494947b0b153d7844478ab2 F test/fts3prefix2.test e1f0a822ca661dced7f12ce392e14eaf65609dce F test/fts3query.test 45806a302921b245a9dba5d85c9d51fb98b3f137eea6e6bf6eae4883e041ab72 @@ -1034,9 +1045,9 @@ F test/fts4umlaut.test fcaca4471de7e78c9d1f7e8976e3e8704d7d8ad979d57a739d00f3f75 F test/fts4unicode.test 82a9c16b68ba2f358a856226bb2ee02f81583797bc4744061c54401bf1a0f4c9 F test/fts4upfrom.test f25835162c989dffd5e2ef91ec24c4848cc9973093e2d492d1c7b32afac1b49d F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d -F test/func.test 77f6ea02c97d9ea64074461d347276a75df22d2cf51045a40f90857569e985f0 +F test/func.test 3a65ddb6c1998f71aa86492501a6be87904197e62bfb5b70b2493552b558abd1 F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f -F test/func3.test 2bb0f31ab7baaed690b962a88544d7be6b34fa389364bc36a44e441ed3e3f1e6 +F test/func3.test 600a632c305a88f3946d38f9a51efe145c989b2e13bd2b2a488db47fe76bab6a F test/func4.test 2285fb5792d593fef442358763f0fd9de806eda47dbc7a5934df57ffdc484c31 F test/func5.test 863e6d1bd0013d09c17236f8a13ea34008dd857d87d85a13a673960e4c25d82a F test/func6.test 90e42b64c4f9fb6f04f44cb8a1da586c8542502e926b19c76504fe74ff2a9b7c @@ -1048,7 +1059,7 @@ F test/fuzz3.test 9c813e6613b837cb7a277b0383cd66bfa07042b4cf0317157c35852f30043c F test/fuzz4.test c229bcdb45518a89e1d208a21343e061503460ac69fae1539320a89f572eb634 F test/fuzz_common.tcl b7197de6ed1ee8250a4f82d67876f4561b42ee8cbbfc6160dcb66331bad3f830 F test/fuzz_malloc.test f348276e732e814802e39f042b1f6da6362a610af73a528d8f76898fde6b22f2 -F test/fuzzcheck.c 37f09efcd982048694d8b06fa3ef817df17f2a82e90af85cb3fb8eddd0f57ec4 +F test/fuzzcheck.c bdb852815048a0beebbe5768bca61e75295324a811a8d7216f97b96501befd1e F test/fuzzdata1.db d36e88741b4f23bcbaaf55b006290669d03c6c891cf13c7b3a53bc1b097b693f F test/fuzzdata2.db 128b3feeb78918d075c9b14b48610145a0dd4c8d6f1ca7c2870c7e425f5bf31f F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba @@ -1056,17 +1067,17 @@ F test/fuzzdata4.db b502c7d5498261715812dd8b3c2005bad08b3a26e6489414bd13926cd3e4 F test/fuzzdata5.db e35f64af17ec48926481cfaf3b3855e436bd40d1cfe2d59a9474cb4b748a52a5 F test/fuzzdata6.db 92a80e4afc172c24f662a10a612d188fb272de4a9bd19e017927c95f737de6d7 F test/fuzzdata7.db 0166b56fd7a6b9636a1d60ef0a060f86ddaecf99400a666bb6e5bbd7199ad1f2 -F test/fuzzdata8.db 9e0123ce3df47d1f159f7b71d60b96bd8b89800a40ab081c5402167d7239ead7 +F test/fuzzdata8.db ef4d280ee69d6da0ebda7f81c0c66839fa577a97b29cc5790a564fde88be7183 F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8 F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14 F test/fuzzerfault.test f64c4aef4c9e9edf1d6dc0d3f1e65dcc81e67c996403c88d14f09b74807a42bc F test/gcfault.test dd28c228a38976d6336a3fc42d7e5f1ad060cb8c -F test/gencol1.test b05e6c5edb9b10d48efb634ed07342441bddc89d225043e17095c36e567521a0 +F test/gencol1.test cc0dbb0ee116e5602e18ea7d47f2a0f76b26e09a823b7c36ef254370c2b0f3c1 F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98 F test/having.test a89236dd8d55aa50c4805f82ac9daf64d477a44d712d8209c118978d0ca21ec9 F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751 F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711 -F test/hook.test 55b6d605d06dadbb04416eae8ad79889aea3521d119c87f04353c25f9c1450a4 +F test/hook.test bb9e03b93fa4bc3bf0f164e455ddaee3603dee0501cb61119baed557c8f936be F test/hook2.test b9ff3b8c6519fb67f33192f1afe86e7782ee4ac8 F test/icu.test 716a6b89fbabe5cc63e0cd4c260befb08fd7b9d761f04d43669233292f0753b1 F test/ieee754.test b0945d12be7d255f3dfa18e2511b17ca37e0edd2b803231c52d05b86c04ab26e @@ -1074,15 +1085,15 @@ F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8 F test/in.test 688ed2011d922d83141a45af431601738674a4c0bdde34b6351f688b82a169b3 F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75 F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0 -F test/in4.test addf1416fdbbcf2f082ab7974e4813f38b4759b95699a683a31c37a3fffe7b57 +F test/in4.test fdd1d8134da8376985c2edba6035a2de1f6c731524d2ffa651419e8fe2cd1c5a F test/in5.test b32ce7f4a93f44c5dee94af16886d922cc16ebe33c8e1765c73d4049d0f4b40f F test/in6.test f5f40d6816a8bb7c784424b58a10ac38efb76ab29127a2c17399e0cbeeda0e4b F test/incrblob.test c9b96afc292aeff43d6687bcb09b0280aa599822 F test/incrblob2.test a494c9e848560039a23974b9119cfc2cf3ad3bd15cc2694ee6367ae537ef8f1f -F test/incrblob3.test d8d036fde015d4a159cd3cbae9d29003b37227a4 +F test/incrblob3.test d47be78a46da142dd60b93772db6e03936a8a36a3b6129dff8d11923dfdc6d63 F test/incrblob4.test 21a52a6843a56cdcce968c6a86b72a7066d0e6ba F test/incrblob_err.test 89372a28f1d98254f03fed705f9efcd34ef61a674df16d2dbb4726944a2de5e9 -F test/incrblobfault.test 74dd8ac108304cea0b4a0df6df63a1567e558758 +F test/incrblobfault.test de274b1e329169c2c3438f9528994807ea8201ebf38ae9f157d34bf3ec0cc549 F test/incrcorrupt.test 6c567fbf870aa9e91866fe52ce6f200cd548939a F test/incrvacuum.test 3fa6145f5e71f603554fd7b8ec3da4290b1341029682313285cb5f9e1893d6ba F test/incrvacuum2.test 7d26cfda66c7e55898d196de54ac4ec7d86a4e3d @@ -1098,7 +1109,7 @@ F test/index7.test b238344318e0b4e42126717f6554f0e7dfd0b39cecad4b736039b43e1e3b6 F test/index8.test caa097735c91dbc23d8a402f5e63a2a03c83840ba3928733ed7f9a03f8a912a3 F test/index9.test 0aa3e509dddf81f93380396e40e9bb386904c1054924ba8fa9bcdfe85a8e7721 F test/indexedby.test f21eca4f7a6ffe14c8500a7ad6cd53166666c99e5ccd311842a28bc94a195fe0 -F test/indexexpr1.test 7e0e7a33acb4d9b3524398e6ce90cc05c26603fabbaf3062083a036c8874bc12 +F test/indexexpr1.test 8f7241410e351679010f14cd7cd30357622d04a784508ff54ba5ce99f64a2228 F test/indexexpr2.test 2c7abe3c48f8aaa5a448615ab4d13df3662185d28419c00999670834a3f0b484 F test/indexfault.test 98d78a8ff1f5335628b62f886a1cb7c7dac1ef6d48fa39c51ec871c87dce9811 F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7 @@ -1115,14 +1126,14 @@ F test/interrupt.test 16ea879ec728cb76414c148c5f24afd5d1f91054 F test/interrupt2.test e4408ca770a6feafbadb0801e54a0dcd1a8d108d F test/intpkey.test aee694afed1a65c86c4e69ad030224b3fc268113d00685234d40079fca16bad3 F test/intreal.test 2a87e85a5949bd55e41ef04c58f5800587c5380bdbc559ff1c79b614b0e6a533 -F test/io.test f95bca1783b01ea7761671560d023360d2dfa4cc -F test/ioerr.test 470fcc78e9cd352d162baf782fe301ea807d764241f58a48fc58109c2dfcdb6b +F test/io.test f138f3fe696d1ed8c51dfea5b325910d319a1b29e1d25ea57231a02092f02cca +F test/ioerr.test 530d05801ff1b6327018b2e140da34a74effa2773a844ddb8dc79c32e9567318 F test/ioerr2.test 2593563599e2cc6b6b4fcf5878b177bdd5d8df26 F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4 F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b -F test/istrue.test 9619a2d77580f676048aaff7a16a0bcfea2b96c6c660dfaded2e53c873418899 +F test/istrue.test e7f285bb70282625c258e866ce6337d4c762922f5a300e1b50f958aef6e7d9c9 F test/join.test 25da4f53523a4aa17c893134b47fba6aa4799bb33350517b157785878290e238 F test/join2.test 9bdc615841b91c97a16d68bad9508aea11fa0c6b34e5689847bcc4dac70e4990 F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 @@ -1138,7 +1149,7 @@ F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa F test/json101.test bb71538005f2d9e18620bdd3b76839a93ca0be61903eb8d751a64e78cf99b8fb F test/json102.test eeb54efa221e50b74a2d6fb9259963b48d7414dca3ce2fdfdeed45cb28487bc1 F test/json103.test aff6b7a4c17d5a20b487a7bc1a274bfdc63b829413bdfb83bedac42ec7f67e3b -F test/json104.test 317f4ec4b2d87afbba4d2460cf5be297aea76f2285eb618d276dbcd40a50950f +F test/json104.test 2cb7ff2cca2c8214d3e5260eeb9ce45faec0926f68b3e40c1aaa6ca247284144 F test/json105.test 45f7d6a9a54c85f8a9589b68d3e7a1f42d02f2359911a8cdbad1f9988f571173 F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff F test/kvtest.c feb4358fb022da8ebd098c45811f2f6507688bb6c43aa72b3e840df19026317b @@ -1190,16 +1201,17 @@ F test/malloctraceviewer.tcl b7a54595270c1d201abf1c3f3d461f27eaf24cdef623ad08a0f F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f F test/memdb.test c1f2a343ad14398d5d6debda6ea33e80d0dafcc7 -F test/memdb1.test 7b76c3262d63c46dd6b408d18f5721071776f2df4ffeb11e668824e427127594 +F test/memdb1.test 2c4e9cc10d21c6bf4e217d72b7f6b8ba9b2605971bb2c5e6df76018e189f98f5 F test/memjournal.test 70f3a00c7f84ee2978ad14e831231caa1e7f23915a2c54b4f775a021d5740c6c +F test/memjournal2.test 89a4e0d1084170a281efa4d54c2677599f986f44227f98f7dfae282802737b65 F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2 F test/memsubsys1.test 9e7555a22173b8f1c96c281ce289b338fcba2abe8b157f8798ca195bbf1d347e F test/memsubsys2.test 3e4a8d0c05fd3e5fa92017c64666730a520c7e08 -F test/minmax.test 0015e5cd5e7af48bb3364f26d9f3a9cdbea2a442d4774281c39e2229591b7351 +F test/minmax.test fe638b55d77d2375531a8f549b338eafcd9adfbd2f72df37ed77d9b26ca0a71a F test/minmax2.test cf9311babb6f0518d04e42fd6a42c619531c4309a9dd790a2c4e9b3bc595e0de F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354 F test/minmax4.test 272ca395257f05937dc96441c9dde4bc9fbf116a8d4fa02baeb0d13d50e36c87 -F test/misc1.test 7ce84b25df9872e7d7878613a96815d2ba5bc974ac4e15a50118dde8f3917599 +F test/misc1.test e3fa5732080cc9a2b77bd5dd4ebb55bd6785b02565f8806092686b83ac58d600 F test/misc2.test 71e746af479119386ac2ed7ab7d81d99970e75b49ffd3e8efffee100b4b5f350 F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d F test/misc4.test 10cd6addb2fa9093df4751a1b92b50440175dd5468a6ec84d0386e78f087db0e @@ -1209,13 +1221,13 @@ F test/misc7.test d912f3d45c2989191b797504a220ca225d6be80b21acad22ba0d35f4a9ee45 F test/misc8.test 4db9f8be59834cea08c87e9658014080efa02678ef54a088f84fa5647e81fee0 F test/misuse.test 9e7f78402005e833af71dcab32d048003869eca5abcaccc985d4f8dc1d86bcc7 F test/mjournal.test 28a08d5cb5fb5b5702a46e19176e45e964e0800d1f894677169e79f34030e152 -F test/mmap1.test fb04e0c10492455007624ade884ca0c8852ff3e4e11d95408f9709ca2ef7f626 +F test/mmap1.test 5c1f768828094b0dd94e55ae7f10489a1ded74772682be2c4c78679d0acaf7ef F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022 F test/mmap3.test b3c297e78e6a8520aafcc1a8f140535594c9086e F test/mmap4.test 2e2b4e32555b58da15176e6fe750f17c9dcf7f93 F test/mmapfault.test d4c9eff9cd8c2dc14bc43e71e042f175b0a26fe3 F test/mmapwarm.test 2272005969cd17a910077bd5082f70bc1fefad9a875afec7fc9af483898ecaf3 -F test/multiplex.test dc0d67b66f84b484a83cb8bbdf3f0a7f49562ccd +F test/multiplex.test d74c034e52805f6de8cc5432cef8c9eb774bb64ec29b83a22effc8ca4dac1f08 F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101 F test/multiplex4.test e8ae4c4bd70606a5727743241f13b5701990abe4 @@ -1229,7 +1241,7 @@ F test/notify1.test 669b2b743618efdc18ca4b02f45423d5d2304abf F test/notify2.test 2ecabaa1305083856b7c39cf32816b612740c161 F test/notify3.test 10ff25cde502e72a92053a2f215d64bece4ef934 F test/notnull.test a37b663d5bb728d66fc182016613fb8e4a0a4bbf3d75b8876a7527f7d4ed3f18 -F test/notnull2.test 131365171d973c57fe694fcc46c1e645f6e24ceb43b230ad5011a0ea2182f215 +F test/notnull2.test 8e1aa4f311df37f9d2cd4f5563eea955b8028c692151404e9cc896420a01a3dc F test/notnullfault.test fc4bb7845582a2b3db376001ef49118393b1b11abe0d24adb03db057ee2b73d5 F test/null.test b7ff206a1c60fe01aa2abd33ef9ea83c93727d993ca8a613de86e925c9f2bc6f F test/nulls1.test 7a5e4346ee4285034100b4cd20e6784f16a9d6c927e44ecdf10034086bbee9c9 @@ -1254,7 +1266,7 @@ F test/oserror.test 1fc9746b83d778e70d115049747ba19c7fba154afce7cc165b09feb6ca6a F test/ossfuzz.c 9636dad2092a05a32110df0ca06713038dd0c43dd89a77dabe4b8b0d71096715 F test/ossshell.c f125c5bd16e537a2549aa579b328dd1c59905e7ab1338dfc210e755bb7b69f17 F test/ovfl.test 199c482696defceacee8c8e0e0ef36da62726b2f -F test/pager1.test a4e438c344663ad7f0bf6e880cacae7531bdf7d960db15a3db4751273ecee06d +F test/pager1.test 8cb45ccbdb3ba423fc8158701c8f010a1d104336b8f14ef14bbfbadf14bad700 F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71 F test/pager3.test 4e9a83d6ca0838d7c602c9eb93d1357562d9059c1e02ffb138a8271020838370 F test/pager4.test a122e9e6925d5b23b31e3dfef8c6a44bbf19590e @@ -1267,9 +1279,9 @@ F test/parser1.test 6ccdf5e459a5dc4673d3273dc311a7e9742ca952dd0551a6a6320d27035c F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442 F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff -F test/permutations.test 63da39a4234eed2ccd10bf7872de58e24d53a50d11014dc8a8ab9f252368e880 +F test/permutations.test 68b6dcd2667acdc643140d502c0b6c503abe444495cf5d16aa3a4f0391604020 F test/pg_common.tcl 3b27542224db1e713ae387459b5d117c836a5f6e328846922993b6d2b7640d9f -F test/pragma.test 50b91bedea9324d3ab48e793f908ee7d2c7dcf84bfa2281e792838be59641ec8 +F test/pragma.test cae534c12a033a5c319ccc94f50b32811acdef9f67bf19a82ff42697caccd69f F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f F test/pragma3.test 92a46bbea12322dd94a404f49edcfbfc913a2c98115f0d030a7459bb4712ef31 F test/pragma4.test ca5e4dfc46adfe490f75d73734f70349d95a199e6510973899e502eef2c8b1f8 @@ -1286,7 +1298,7 @@ F test/quick.test 1681febc928d686362d50057c642f77a02c62e57 F test/quota-glob.test 32901e9eed6705d68ca3faee2a06b73b57cb3c26 F test/quota.test bfb269ce81ea52f593f9648316cd5013d766dd2a F test/quota2.test 7dc12e08b11cbc4c16c9ba2aa2e040ea8d8ab4b8 -F test/quote.test b8ddaba6b81dcf63bb31243219e28a2f96e04396adc50108cc7e5593019c3eb5 +F test/quote.test f33f95990e4032d1227b98c0ef314c0a077d162f3f2e61b3039ed69e6f8adbbf F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459 F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df F test/rbu.test 168573d353cd0fd10196b87b0caa322c144ef736 @@ -1295,18 +1307,18 @@ F test/recover.test ccb8c2623902a92ebb76770edd075cb4f75a4760bb7afde38026572c6e79 F test/regexp1.test 0c3ff80f66b0eff80e623eb5db7a3dad512095c573d78ac23009785f6d8f51ce F test/regexp2.test 55ed41da802b0e284ac7e2fe944be3948f93ff25abbca0361a609acfed1368b5 F test/reindex.test cd9d6021729910ece82267b4f5e1b5ac2911a7566c43b43c176a6a4732e2118d -F test/releasetest.tcl 6f803ef0b896f8f3f4c26eb072c0399963a5987a509a64d45f5dfbc1ebae2951 x -F test/releasetest_data.tcl f88ed29aa18366ed3956ace36c96ec6868ef5b9ee04cc05d32f4d81031e19e28 +F test/releasetest_data.tcl 7cea6c852ae6bb3a9ff1a2b910e4dd13c16a05f74443984dfd52159b0b01ea55 F test/resetdb.test 8062cf10a09d8c048f8de7711e94571c38b38168db0e5877ba7561789e5eeb2b F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb -F test/returning1.test 52b4ed60f104a4ce85b38417e5319b2078b2b908c71a768d539cee3c0ce8bdc9 +F test/returning1.test f96c7245f6ac16038e802760cd90b93479369939a8a7a44e2329ee5aed28239c +F test/returningfault.test ae4c4b5e8745813287a359d9ccdb9d5c883c2e68afb18fb0767937d5de5692a4 F test/rollback.test 06680159bc6746d0f26276e339e3ae2f951c64812468308838e0a3362d911eaa F test/rollback2.test 3f3a4e20401825017df7e7671e9f31b6de5fae5620c2b9b49917f52f8c160a8f F test/rollbackfault.test 0e646aeab8840c399cfbfa43daab46fd609cf04a F test/round1.test 768018b04522ca420b1aba8a24bd76091d269f3bce3902af3ec6ebcee41ab21e F test/rowallock.test 3f88ec6819489d0b2341c7a7528ae17c053ab7cc F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81 -F test/rowid.test bfbd7b97d9267660be3c8f28507c4ed7f205196b8877c0db42df347c2e8845e3 +F test/rowid.test e29025be95baf6b32f0d5edef59a7633028325896a98f1caa8019559ca910350 F test/rowvalue.test 37effea4dd83555ea969a9461dfcffb25e6731a5db7c388e232410999c100853 F test/rowvalue2.test 060d238b7e5639a7c5630cb5e63e311b44efef2b F test/rowvalue3.test 3068f508753af69884b12125995f023da0dbb256 @@ -1316,7 +1328,8 @@ F test/rowvalue6.test d19b54feb604d5601f8614b15e214e0774c01087 F test/rowvalue7.test c1cbdbf407029db01f87764097c6ac02a1c5a37efd2776eff32a9cdfdf6f2dba F test/rowvalue8.test 5900eddad9e2c3c2e26f1a95f74aafc1232ee5e0 F test/rowvalue9.test cb5380df82dca9db463081e26952c1e097b34fc2c2ac87453970c048d97df687 -F test/rowvaluefault.test 7cd9ccc6c2fbdd881672984087aad0491bb75504 +F test/rowvalueA.test 51f79b6098c193f838168752c9640f4eae6c63346bf64b5bed4f4e22fe2c71d0 +F test/rowvaluefault.test 963ae9cdaed30a85a29668dd514e639f3556cae903ee9f172ea972d511c54fff F test/rowvaluevtab.test cd9747bb3f308086944c07968f547ad6b05022e698d80b9ffbdfe09ce0b8da6f F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798 F test/run-wordcount.sh 891e89c4c2d16e629cd45951d4ed899ad12afc09 @@ -1330,7 +1343,7 @@ F test/savepointfault.test f044eac64b59f09746c7020ee261734de82bf9b2 F test/scanstatus.test 9a0ed37ab6d57b50567282788fffdf832d9b16739ecc41bff9d77a8d767cf317 F test/schema.test 5dd11c96ba64744de955315d2e4f8992e447533690153b93377dffb2a5ef5431 F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5 -F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38 +F test/schema3.test 8ed4ae66e082cdd8b1b1f22d8549e1e7a0db4527a8e6ee8b6193053ee1e5c9ce F test/schema4.test 3b26c9fa916abb6dadf894137adcf41b7796f7b9 F test/schema5.test 29699b4421f183c8f0e88bd28ce7d75d13ea653e F test/schema6.test e4bd1f23d368695eb9e7b51ef6e02ca0642ea2ab4a52579959826b5e7dce1f9b @@ -1369,21 +1382,21 @@ F test/sharedA.test 49d87ec54ab640fbbc3786ee3c01de94aaa482a3a9f834ad3fe92770eb69 F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939 F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304 -F test/shell1.test 56a7358a2a05e850e9e4aa24629db9c8975e8038dbe8debd2d95be22a5f03612 -F test/shell2.test e242a9912f44f4c23c3d1d802a83e934e84c853b -F test/shell3.test ac8c2b744014c3e9a0e26bfd829ab65f00923dc1a91ffd044863e9423cc91494 +F test/shell1.test c354008b27c904f0166c2138abd7382013ea070b41114114ecbdfb32c726a807 +F test/shell2.test f00a0501c00583cbc46f7510e1d713366326b2b3e63d06d15937284171a8787c +F test/shell3.test cb4b835a901742c9719437a89171172ecc4a8823ad97349af8e4e841e6f82566 F test/shell4.test 3ed6c4b42fd695efcbc25d69ef759dbb15855ca8e52ba6c5ee076f8b435f48be -F test/shell5.test 84a30b55722a95a5b72989e691c469a999ca7591e7aa00b7fabc783ea5c9a6fe +F test/shell5.test 6e4aa0e531dcb8dcf74b7920a2a7442c6712d4dff8422bbc81f768f9dee8a0e3 F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3 F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f -F test/shell8.test 96be02ea0c21f05b24c1883d7b711a1fa8525a68ab7b636aacf6057876941013 +F test/shell8.test 388471d16e4de767333107e30653983f186232c0e863f4490bb230419e830aae F test/shmlock.test 3dbf017d34ab0c60abe6a44e447d3552154bd0c87b41eaf5ceacd408dd13fda5 F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3 F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5 -F test/shrink.test 1b4330b1fd9e818c04726d45cb28db73087535ce +F test/shrink.test 9521e5e0d74c0b6192794f3de3a3e5e3190d465527ae365d96763ef753c7229c F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329 F test/skipscan1.test 1a9972e1dc15ca3887f306d3cd9a29679afb382eca0f3539f3b746f3c2ccaf68 -F test/skipscan2.test c588cb7ed947db724d300f2a0dc537dd2ad292b0f812641d8481bc0b95dd3f49 +F test/skipscan2.test b032ed3e0ba5caa4df6c43ef22c31566aac67783bc031869155989a7ccdb5bd5 F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5 F test/skipscan5.test 0672103fd2c8f96bd114133f356192b35ece45c794fe3677e1d9e5e3104a608e F test/skipscan6.test bddbb35dd335e2d21b7791a61e3b2e1f3255dc307ce80aa6fe19cc298e6feb13 @@ -1400,7 +1413,7 @@ F test/sort2.test cc23b7c19d684657559e8a55b02f7fcee03851d0 F test/sort3.test 1480ed7c4c157682542224e05e3b75faf4a149e5 F test/sort4.test 5c34d9623a4ae5921d956dfa2b70e77ed0fc6e5c F test/sort5.test 6b43ae0e2169b5ceed441844492e55ba7f1ae0790528395ddf7888ab3094525d -F test/sorterref.test a13ed207a0eea3c7898f308f979bfb518f68c598ec737d2c494dfd3deaa83506 +F test/sorterref.test 9a606c86a4c682db5eeaaefa0565b52102778db53e48ca7101cd4f9ebcc0ad94 F test/sortfault.test d4ccf606a0c77498e2beb542764fd9394acb4d66 F test/speed1.test f2974a91d79f58507ada01864c0e323093065452 F test/speed1p.explain d841e650a04728b39e6740296b852dccdca9b2cb @@ -1410,19 +1423,21 @@ F test/speed3.test 694affeb9100526007436334cf7d08f3d74b85ef F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715 F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa F test/speed4p.test 377a0c48e5a92e0b11c1c5ebb1bc9d83a7312c922bc0cb05970ef5d6a96d1f0c -F test/speedtest1.c 5e5b805f24cc939656058f6a498f5a2160f9142e4815c54faf758ec798d4cdad +F test/speedtest1.c 61f8a72bbcc80edb0b95e957f108feb4013ff3d08721cc87ae1865fd4d20652d F test/spellfix.test 951a6405d49d1a23d6b78027d3877b4a33eeb8221dcab5704b499755bb4f552e F test/spellfix2.test dfc8f519a3fc204cb2dfa8b4f29821ae90f6f8c3 F test/spellfix3.test 0f9efaaa502a0e0a09848028518a6fb096c8ad33 F test/spellfix4.test 51c7c26514ade169855c66bcf130bd5acfb4d7fd090cc624645ab275ae6a41fb -F test/sqldiff1.test 28cd737cf1b0078b1ec1bbf425e674c47785835e -F test/sqllimits1.test 3f9030e5d35375ad3b912b4908094aa806335c8e9d804b8ffff70c5e9c664ab2 +F test/sqldiff1.test 182058e09c7082de5c6a470ff9c291337bbeb650052c2cc68fbb3d7e25861d91 +F test/sqllimits1.test f46f405d754e702227dcdf5b73f94fffcd48c676e845afa37329e4ce2e32ccbf F test/sqllog.test 6af6cb0b09f4e44e1917e06ce85be7670302517a F test/startup.c 1beb5ca66fcc0fce95c3444db9d1674f90fc605499a574ae2434dcfc10d22805 -F test/stat.test 15a3106eddedfc882f64bc09f237b4169be4b92dd57c93031b8ff8b13af3e7c5 -F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1 +F test/stat.test 123212a20ceb496893d5254a5f6c76442ce549fdc08d1702d8288a2bbaac8408 +F test/statfault.test 55f86055f9cd7b2d962a621b8a04215c1cebd4eaaecde92d279442327fe648a0 F test/stmt.test 54ed2cc0764bf3e48a058331813c3dbd19fc1d0827c3d8369914a5d8f564ec75 F test/stmtvtab1.test 6873dfb24f8e79cbb5b799b95c2e4349060eb7a3b811982749a84b359468e2d5 +F test/strict1.test a3ec495471f24c1a6e1a1664bd23e24ccdb27ae93b1a763ee1942ec955b68e71 +F test/strict2.test b22c7a98b5000aef937f1990776497f0e979b1a23bc4f63e2d53b00e59b20070 F test/subjournal.test 8d4e2572c0ee9a15549f0d8e40863161295107e52f07a3e8012a2e1fdd093c49 F test/subquery.test d7268d193dd33d5505df965399d3a594e76ae13f F test/subquery2.test 90cf944b9de8204569cf656028391e4af1ccc8c0cc02d4ef38ee3be8de1ffb12 @@ -1440,11 +1455,11 @@ F test/sync.test 89539f4973c010eda5638407e71ca7fddbcd8e0594f4c9980229f804d433309 F test/sync2.test 8f9f7d4f6d5be8ca8941a8dadcc4299e558cb6a1ff653a9469146c7a76ef2039 F test/syscall.test a39d9a36f852ae6e4800f861bc2f2e83f68bbc2112d9399931ecfadeabd2d69d F test/sysfault.test c9f2b0d8d677558f74de750c75e12a5454719d04 -F test/tabfunc01.test acb5be558868c65d8cf3495539fff23093d77139eb1e4e8c4580568099f98645 +F test/tabfunc01.test d6821e7042e5653104dac0c63d75eff24a2415ab1889fc68b5db7fde59464c59 F test/table.test eb3463b7add9f16a5bb836badf118cf391b809d09fdccd1f79684600d07ec132 F test/tableapi.test ecbcc29c4ab62c1912c3717c48ea5c5e59f7d64e4a91034e6148bd2b82f177f4 F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930 -F test/tclsqlite.test 79a473f5797e317c08f2c4f8192edb3eea6a67329b1087453328b66a7cb31070 +F test/tclsqlite.test 97cda6e4843e9f3e06c56f656d9b77ee0178fe1ee33fb09a6eeae8f125757ac1 F test/tempdb.test 4cdaa23ddd8acb4d79cbb1b68ccdfd09b0537aaba909ca69a876157c2a2cbd08 F test/tempdb2.test 353864e96fd3ae2f70773d0ffbf8b1fe48589b02c2ec05013b540879410c3440 F test/tempfault.test 0c0d349c9a99bf5f374655742577f8712c647900 @@ -1452,7 +1467,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30 F test/temptable2.test d2940417496e2b9548e01d09990763fbe88c316504033256d51493e1f1a5ce6a F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637 F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc -F test/tester.tcl 19d2a19a6dd55a2b4e2b943963959a05a2c088495dd5f5274b04e0494ce86d66 +F test/tester.tcl f577d040078dd4fb56ea1ccaa71f6bfd0ebf0bd0ac373304db4269b5474f9cb7 F test/thread001.test b61a29dd87cf669f5f6ac96124a7c97d71b0c80d9012746072055877055cf9ef F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 @@ -1463,7 +1478,7 @@ F test/thread2.test f35d2106452b77523b3a2b7d1dcde2e5ee8f9e46 F test/thread_common.tcl 334639cadcb9f912bf82aa73f49efd5282e6cadd F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b F test/threadtest2.c a70a8e94bef23339d34226eb9521015ef99f4df8 -F test/threadtest3.c e63013af10cf236c7610eb06d33bde08c861806dc64be811940ff4d9ddd34a4f +F test/threadtest3.c 655bff6c0895ec03f014126aa65e808fac9aae8c5a7a7da58a510cbe8b43b781 F test/threadtest4.c c1e67136ceb6c7ec8184e56ac61db28f96bd2925 F test/threadtest5.c 9b4d782c58d8915d7e955ff8051f3d03628bda0d33b82971ea8c0f2f2808c421 F test/time-wordcount.sh 8e0b0f8109367827ad5d58f5cc849705731e4b90 @@ -1471,7 +1486,7 @@ F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c F test/tkt-18458b1a.test 6a62cb1ee50fa3c620da59e3a6f531eb38fceaf7e2166203816b724524e6f1d6 F test/tkt-26ff0c2d1e.test c15bec890c4d226c0da2f35ff30f9e84c169cfef90e73a8cb5cec11d723dfa96 F test/tkt-2a5629202f.test 0521bd25658428baa26665aa53ffed9367d33af2 -F test/tkt-2d1a5c67d.test be1326f3061caec85085f4c9ee4490561ca037c0 +F test/tkt-2d1a5c67d.test f143872a2102c62e777be3486b38ac2744c18ece31585ed3d0afcb573ca3b4f5 F test/tkt-2ea2425d34.test 1cf13e6f75d149b3209a0cb32927a82d3d79fb28 F test/tkt-31338dca7e.test 6fb8807851964da0d24e942f2e19c7c705b9fb58 F test/tkt-313723c356.test 4b306ad45c736cedf2f5221f6155b92143244b6d @@ -1495,7 +1510,7 @@ F test/tkt-7a31705a7e6.test 9e9c057b6a9497c8f7ba7b16871029414ccf6550e7345d9085d6 F test/tkt-7bbfb7d442.test 7b2cd79c7a17ae6750e75ec1a7846712a69c9d18 F test/tkt-80ba201079.test 105a721e6aad0ae3c5946d7615d1e4d03f6145b8 F test/tkt-80e031a00f.test 9ee36348b761bf7c14261e002b75a4c0d5a04d4c -F test/tkt-8454a207b9.test c583a9f814a82a2b5ba95207f55001c9f0cd816c +F test/tkt-8454a207b9.test aff2e76143cfa443ddce6f7d85968a2e9b57a3deb0b881b730120740555f9e2f F test/tkt-868145d012.test a5f941107ece6a64410ca4755c6329b7eb57a356 F test/tkt-8c63ff0ec.test 258b7fc8d7e4e1cb5362c7d65c143528b9c4cbed F test/tkt-91e2e8ba6f.test 08c4f94ae07696b05c9b822da0b4e5337a2f54c5 @@ -1520,7 +1535,7 @@ F test/tkt-d11f09d36e.test d999b548fef885d1d1afa49a0e8544ecf436869d F test/tkt-d635236375.test 9d37e988b47d87505bc9445be0ca447002df5d09 F test/tkt-d82e3f3721.test bcc0dfba658d15bab30fd4a9320c9e35d214ce30 F test/tkt-f3e5abed55.test d5a0126118142d13e27f6ce9f4c47096e9321c00 -F test/tkt-f67b41381a.test a23bc124c981662db712167bacd0ed8ad11abac9 +F test/tkt-f67b41381a.test 9120eab5e949969a29087e01bf57ac6a52b6c06c16be41091a74c2a863ffc660 F test/tkt-f777251dc7a.test d1a8fc3eefb7a9e64d19ff24d5c8c94c34a632fb F test/tkt-f7b4edec.test d998a08ff2b18b7f62edce8e3044317c45efe6c7 F test/tkt-f973c7ac31.test 28ef85c7f015477916795246d8286aeda39d4ead @@ -1618,7 +1633,7 @@ F test/trace3.test ae2004df24b585fed9046cc0bae4601762bc6fc4aa321d475f1350bba5047 F test/trans.test 45f6f9ab6f66a7b5744f1caac06b558f95da62501916906cf55586a896f9f439 F test/trans2.test 62bd045bfc7a1c14c5ba83ba64d21ade31583f76 F test/trans3.test 91a100e5412b488e22a655fe423a14c26403ab94 -F test/transitive1.test 06bcfeeb2ed719abf6ae582f9f65a6b07642dd1363fa648ae9a74a35e83a825c +F test/transitive1.test f8ee983600b33d167da1885657f064aec404e1c0d0bc8765fdf163f4c749237a F test/trigger1.test d30cd09ae8ac365a088f09daba583cc5c0b8fc7d4e1d70809d0b4be3bf6ae2ab F test/trigger2.test 6e35bd7321c49e63d540aee980eb95dec63e1d1caca175224101045bcc80871f F test/trigger3.test aa640bb2bbb03edd5ff69c055117ea088f121945 @@ -1637,12 +1652,12 @@ F test/triggerF.test 5d76f0a8c428ff87a4d5ed52da06f6096a2c787a1e21b846111dfac4123 F test/triggerG.test 2b816093c91ba73c733cfa8aedcc210ad819d72a98b1da30768a3c56505233e9 F test/triggerupfrom.test d1f9e56090408115c522bee626cc33a2f3370f627a5e341d832589d72e3aa271 F test/trustschema1.test 4e970aef0bfe0cee139703cc7209d0e0f07725d999b180ba50770f49edef1494 -F test/tt3_checkpoint.c 9e75cf7c1c364f52e1c47fd0f14c4340a9db0fe1 +F test/tt3_checkpoint.c ac7ca661d739280c89d9c253897df64a59a49369bd1247207ac0f655b622579d F test/tt3_index.c 39eec10a35f57672225be4d182862152896dee4a F test/tt3_lookaside1.c 0377e202c3c2a50d688cb65ba203afeda6fafeb9 F test/tt3_shared.c b37d22defc944a2ac4c91c927fd06c1d48cd51e2ce9d004fe868625bd2399f93 F test/tt3_stress.c f9a769ca8b026ecc76ee93ca8c9700a5619f8e51c581107c4053ba6ac97f616f -F test/tt3_vacuum.c 1753f45917699c9c1f66b64c717a717c9379f776 +F test/tt3_vacuum.c 71b254cde1fc49d6c8c44efd54f4668f3e57d7b3a8f4601ade069f75a999ba39 F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff F test/types2.test 1aeb81976841a91eef292723649b5c4fe3bc3cac F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a @@ -1655,14 +1670,14 @@ F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264 F test/unique2.test 3674e9f2a3f1fbbfd4772ac74b7a97090d0f77d2 F test/unixexcl.test d936ba2b06794018e136418addd59a2354eeae97 F test/unordered.test 0edaf3411d300693bca595897c5201421c6c5ec787990a1dfe2f7f60ae93f1e2 -F test/update.test e906ca7cb1dc6f52af1ea243e08f727edfa79f924c2691f2f9e72481f847310d +F test/update.test ef3ebbafeb4be5c96db831f40796e2e77ee846da5ee8b61cfedb1ff1b9e0cc23 F test/update2.test 67455bc61fcbcf96923c45b3bc4f87bc72be7d67575ad35f134906148c7b06d3 F test/upfrom1.tcl 8859d9d437f03b44174c4524a7a734a391fd4526fcff65be08285dafc9dc9041 F test/upfrom1.test 8cb06689e99cd707d884faa16da0e8eb26ff658bb01c47ddf72fadade666e6e1 -F test/upfrom2.test f92e47bfc35e9410d3e8716ee626384e89ad026c55fd6148508ca9d707521673 +F test/upfrom2.test 88d39cb755db5789541e645d4e2764abc697a56958f28a3f8451a0e9342bbd6b F test/upfrom3.test 6130f24ebf97f5ea865e5d2a14a2d543fe5428a62e87cc60f62d875e45c1f5f0 F test/upfromfault.test 3a10075a0043f0c4fad6614b2c371f88a8ba5a4acab68b907438413865d6a8d6 -F test/upsert1.test 88f9e258c6a0eeeb85937b08831e8daad440ba41f125af48439e9d33f266fb18 +F test/upsert1.test b0ae2f58680c5205b4bc1cdeed3c3d444057c506f6c44494fa3eac60731d68a2 F test/upsert2.test 9c3cdbb1a890227f6504ce4b0e3de68f4cdfa16bb21d8641208a9239896c5a09 F test/upsert3.test 88d7d590a1948a9cb6eac1b54b0642f67a9f35a1fc0f19b200e97d5d39e3179c F test/upsert4.test 25d2a1da92f149331ae0c51ca6e3eee78189577585eab92de149900d62994fa5 @@ -1672,19 +1687,19 @@ F test/uri.test 3481026f00ade6dfe8adb7acb6e1e47b04369568 F test/uri2.test 9d3ba7a53ee167572d53a298ee4a5d38ec4a8fb7 F test/userauth01.test e740a2697a7b40d7c5003a7d7edaee16acd349a9 F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae -F test/vacuum-into.test 48f4cec354fb6f27c98ef58d2fe49a11b71ff131af0cd9140efacc9858b9f670 +F test/vacuum-into.test f0b8c091df5305728b6973e9cce4166c861955b650dd3c599cb045d7160d3971 F test/vacuum.test ce91c39f7f91a4273bf620efad21086b5aa6ef1d F test/vacuum2.test 9fd45ce6ce29f5614c249e03938d3567c06a9e772d4f155949f8eafe2d8af520 -F test/vacuum3.test 77ecdd54592b45a0bcb133339f99f1ae0ae94d0d +F test/vacuum3.test d9d9a04ee58c485b94694fd4f68cffaba49c32234fdefe1ac1a622c5e17d4ce3 F test/vacuum4.test 7ea76b769fffeb41f925303b04cbcf5a5bbeabe55e4c60ae754ff24eeeb7c010 F test/vacuum5.test 263b144d537e92ad8e9ca8a73cc6e1583f41cfd0dda9432b87f7806174a2f48c F test/vacuum6.test d3173a54edc81d13d99e4cf4972232b3cbb52f1d56ed48c3a939ef4e751c1ee8 F test/vacuummem.test 7b42abb3208bd82dd23a7536588396f295a314f2 F test/varint.test bbce22cda8fc4d135bcc2b589574be8410614e62 F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661 -F test/view.test ea88361d5e9bc8eabf9f573185a16aea73a885be9b6c6a95ae84908913416a80 +F test/view.test d654fbadae82f936c2a820bbc892592085467548ff59e88acef201416e9fe48a F test/view2.test db32c8138b5b556f610b35dfddd38c5a58a292f07fda5281eedb0851b2672679 -F test/vtab1.test 99c0c13b5336ca7f87f137459de144b2f396bb8563fbd602e46bfaa425e3d8cc +F test/vtab1.test 09a72330d0f31eda2ffaa828b06a6b917fb86250ee72de0301570af725774c07 F test/vtab2.test 14d4ab26cee13ba6cf5c5601b158e4f57552d3b055cdd9406cf7f711e9c84082 F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e F test/vtab4.test 8e73ed268f3d596bc3590f45fc948fb40f28e9c3 @@ -1693,7 +1708,7 @@ F test/vtab6.test 8e789f526e6594cf7ae933d1adee0caa87dc9f78 F test/vtab7.test 70c6f4a1d6177144a8236e4172d5fba92e683440374664ad1f04851fbb335d3c F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583 F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b -F test/vtabA.test 1317f06a03597eee29f40a49b6c21e1aaba4285f +F test/vtabA.test 325a77e7f0f80aa78ab388875c0ad6fb853acc6ac54d85514650b0ae15da24ff F test/vtabB.test 04df5dc531b9f44d9ca65b9c1b79f12b5922a796 F test/vtabC.test 4528f459a13136f982e75614d120aef165f17292 F test/vtabD.test 05b3f1d77117271671089e48719524b676842e96 @@ -1702,6 +1717,7 @@ F test/vtabF.test 1918844c7c902f6a16c8dacf1ec8f84886d6e78b F test/vtabH.test 2efb5a24b0bb50796b21eca23032cfb77abfa4b0c03938e38ce5897abac404ca F test/vtabI.test 751b07636700dbdea328e4265b6077ccd6811a3f F test/vtabJ.test a6aef49d558af90fae10565b29501f82a95781cb4f797f2d13e2d19f9b6bc77b +F test/vtabK.test 13293177528fada1235c0112db0d187d754af1355c5a39371abd365104e3afbf F test/vtab_alter.test 736e66fb5ec7b4fee58229aa3ada2f27ec58bc58c00edae4836890c3784c6783 F test/vtab_err.test dcc8b7b9cb67522b3fe7a272c73856829dae4ab7fdb30399aea1b6981bda2b65 F test/vtab_shared.test 5253bff2355a9a3f014c15337da7e177ab0ef8ad @@ -1744,7 +1760,7 @@ F test/walthread.test 14b20fcfa6ae152f5d8e12f5dc8a8a724b7ef189f5d8ef1e2ceab79f2a F test/walvfs.test bccb3e0d235ef85e276f491d34db32c9ada1ea67be8d9f10aabe7b30319ec656 F test/wapp.tcl b440cd8cf57953d3a49e7ee81e6a18f18efdaf113b69f7d8482b0710a64566ec F test/wapptest.tcl 899594e25684861d5b0c0880fb012364def50ef8097041b8ddf74be5ba7fa270 x -F test/where.test 4f7a3939e5190845ef42142031a1819070f65e065e6a840a09adc54dccfef01f +F test/where.test f114842c1851d257a26770f2ad55119b084001c0e1b8c214f886f45152d37cd8 F test/where2.test 03c21a11e7b90e2845fc3c8b4002fc44cc2797fa74c86ee47d70bd7ea4f29ed6 F test/where3.test 5b4ffc0ac2ea0fe92f02b1244b7531522fe4d7bccf6fa8741d54e82c10e67753 F test/where4.test 4a371bfcc607f41d233701bdec33ac2972908ba8 @@ -1757,7 +1773,7 @@ F test/whereA.test 9d1077b117f1b68d5f739d94f36956c36cf995eb87bb19b77b2e81af020ed F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5 F test/whereC.test cae295158703cb3fc23bf1a108a9ab730efff0f6 F test/whereD.test c1c335e914e28b122e000e9310f02d2be83e1c9dbca2e29f46bd732703944d1b -F test/whereE.test 0ac7e61c6225354a980666996539da154991b4325af943a25a9079079c82fb03 +F test/whereE.test 7a727b5d5b6bc8fa4cef5206e90cc0363e55ca7f0566f6fbad0206e43170f59e F test/whereF.test 926b65519608e3f2aa28720822b9154fb5c7b13519dd78194f434a511ab3dac5 F test/whereG.test b2a479f425f7d0a432df7e842e8484560908ef703fe0fd407888ff85e7097238 F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2 @@ -1774,7 +1790,7 @@ F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2 F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972 F test/win32longpath.test 4baffc3acb2e5188a5e3a895b2b543ed09e62f7c72d713c1feebf76222fe9976 F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc -F test/window1.test 49eadb28b0bae0f916518c9983b1fb7450c198915664f323b2bfc480cc98c431 +F test/window1.test 18aadea36d7a9fab1474b1d80002d82304a342e0471793841c66afde14a381b8 F test/window2.tcl 492c125fa550cda1dd3555768a2303b3effbeceee215293adf8871efc25f1476 F test/window2.test e466a88bd626d66edc3d352d7d7e1d5531e0079b549ba44efb029d1fbff9fd3c F test/window3.tcl acea6e86a4324a210fd608d06741010ca83ded9fde438341cb978c49928faf03 @@ -1789,28 +1805,30 @@ F test/window8.tcl 5e02e41d9d9a80f597063aed1a381eb19d1d0ef677a4f0df352c5365cf23f F test/window8.test 4ab16817414af0c904abe2ebdf88eb6c2b00058b84f9748c6174ff11fc45f1ed F test/window9.test 349c71eab4288a1ffc19e2f65872ec2c37e6cf8a1dda2ad300364b7450ae4836 F test/windowA.test 6d63dc1260daa17141a55007600581778523a8b420629f1282d2acfc36af23be -F test/windowB.test 6e601f8178ba8ba28b2f19e74fe613815084bb4a8d2ad942defc7d42e191e521 +F test/windowB.test b67bda5645f3226790e1a360c4225241840b84adb5aa2e69bfb0b27eef3b84d9 +F test/windowC.test 6fd75f5bb2f1343d34e470e36e68f0ff638d8a42f6aa7d99471261b31a0d42f2 F test/windowerr.tcl f5acd6fbc210d7b5546c0e879d157888455cd4a17a1d3f28f07c1c8a387019e0 F test/windowerr.test a8b752402109c15aa1c5efe1b93ccb0ce1ef84fa964ae1cd6684dd0b3cc1819b -F test/windowfault.test 21919e601f20b976ea2a73aa401220c89ed0e8d203c4f69476ea55bce3726496 +F test/windowfault.test 15094c1529424e62f798bc679e3fe9dfab6e8ba2f7dfe8c923b6248c31660a7c F test/windowpushd.test d8895d08870b7226f7693665bd292eb177e62ca06799184957b3ca7dc03067df F test/with1.test 7bc5abfe4c80c0cef8a90f5a66d60b9982e8ccd7350c8eb70611323a3b8e07ba -F test/with2.test bbf82609bbacc0a7a01d822022aed7b2fa702436dd3d0ecf942023564d2bba13 +F test/with2.test a1df41b987198383b9b70bf5e5fda390582e46398653858dbc6ceb24253b28df F test/with3.test ad32d13ad50661e6fa305f62a0717649c348792e7b658bf2644976227a9e0373 F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f198205 F test/with5.test 6248213c41fab36290b5b73aa3f937309dfba337004d9d8434c3fabc8c7d4be8 F test/with6.test 661d7e416bef6c0a2556b2c9f0c8178a5b15932bed65246abed99723a8d4e7c0 F test/withM.test 693b61765f2b387b5e3e24a4536e2e82de15ff64 -F test/without_rowid1.test 6abc5d497f634520944dac0a89a6c240a48d2ee0f8353356a750eb70dc1db41a +F test/without_rowid1.test 78fd9b437f4cdb46f76e6a510d545334e4f58e3e4ce37aaf19384eda5b27de8c F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99 F test/without_rowid3.test 39ab0dd773eaa62e59b17093f875327630f54c4145458f6d2b053d68d4b2f67b F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a -F test/without_rowid5.test 89b1c587bd92a0590e440da33e7666bf4891572a +F test/without_rowid5.test f14298eb5ac8013894b75141c3f4f5f325a6ad0eded55516eef72c49e60a67cb F test/without_rowid6.test efbd7add62c59bf5ca97bf8da674e734e6a70ef979234e816166824b4d258f68 F test/without_rowid7.test d7c59a93d726b55812d620f8f284e01904a5b85f9ee9eea8f2f68571a5e8c40e F test/wordcount.c d721a4b6fae93e6e33449700bce1686bc23257c27425bc3ef1599dc912adec66 F test/writecrash.test f1da7f7adfe8d7f09ea79b42e5ca6dcc41102f27f8e334ad71539501ddd910cc -F test/zeroblob.test 07a5b11ab591d1f26c626945fb7f228f68b993533b2ada77273edf6ee29db174 +F test/zeroblob.test 7b74cefc7b281dfa2b07cd237987fbe94b4a2037a7771e9e83f2d5f608b1d99e +F test/zeroblobfault.test 861d8191a0d944dfebb3cb4d2c5b4e46a5a119eaec5a63dd996c2389f8063441 F test/zerodamage.test 9c41628db7e8d9e8a0181e59ea5f189df311a9f6ce99cc376dc461f66db6f8dc F test/zipfile.test 0d8758d8c0d63f16644f959689f78969d223789d998964276554039f067b4548 F test/zipfile2.test 9903388a602a3834189857a985106ff95c3bba6a3969e0134127df991889db5d @@ -1836,27 +1854,27 @@ F tool/genfkey.test b6afd7b825d797a1e1274f519ab5695373552ecad5cd373530c63533638a F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce F tool/index_usage.c f62a0c701b2c7ff2f3e21d206f093c123f222dbf07136a10ffd1ca15a5c706c5 F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f -F tool/lemon.c a5acddd3eec6a388872aae6efc7563336348a9c45e5563642f77e8e3a50e859d -F tool/lempar.c 1d3d075da18681c67ecc66c1f171e7094e18cd2cfba6a8a1bd4f3f639d6656e1 +F tool/lemon.c 258881835bd5bccd0c74fb110fe54244ff18e8e7ef3d949cbdab7187f02132bb +F tool/lempar.c 57478ea48420da05faa873c6d1616321caa5464644588c97fbe8e0ea04450748 F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9 F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862 -F tool/logest.c 11346aa019e2e77a00902aa7d0cabd27bd2e8cca +F tool/logest.c 06446d42942a7128ab4963eb438eb3f528e07095d5d1080f9105a6f337238d33 F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439 F tool/merge-test.tcl de76b62f2de2a92d4c1ca4f976bce0aea6899e0229e250479b229b2a1914b176 F tool/mkautoconfamal.sh f62353eb6c06ab264da027fd4507d09914433dbdcab9cb011cdc18016f1ab3b8 F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x -F tool/mkctimec.tcl 06b0d503ee0e6c2d4abe83563b43d4925a12e31ec9fb3249ce39661f53fbd1ce -F tool/mkkeywordhash.c 08b6e4d7a482a7f37a9a0032e7ba968e26624a027b6b2e9ba589be6f5e3d8c2c +F tool/mkctimec.tcl 5ef1891ed3d0e8143ff39bad7c01ed60c2817a2fb2d9a09487f7ccad2df621e4 +F tool/mkkeywordhash.c 35bfc41adacc4aa6ef6fca7fd0c63e0ec0534b78daf4d0cfdebe398216bbffc3 F tool/mkmsvcmin.tcl 6ecab9fe22c2c8de4d82d4c46797bda3d2deac8e763885f5a38d0c44a895ab33 -F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c +F tool/mkopcodec.tcl 33d20791e191df43209b77d37f0ff0904620b28465cca6990cf8d60da61a07ef F tool/mkopcodeh.tcl 130b88697da6ec5b89b41844d955d08fb62c2552e889dec8c7bcecb28d8f50bd F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa -F tool/mkpragmatab.tcl ae5585ae76ca26e4d6ccd5ea9cdebaf5efefb318bf989497a0e846cd711d9ab1 -F tool/mkshellc.tcl 5fe7e518112b262e25726f248c0f33dd153192867453984b6af0a76a88e97cb2 +F tool/mkpragmatab.tcl de206c64b6e9ac8cd5e3cbd0ffe456f07d5710605ef8385d677e60ce3335ea12 +F tool/mkshellc.tcl df5d249617f9cc94d5c48eb0401673eb3f31f383ecbc54e8a13ca3dd97e89450 F tool/mksourceid.c 36aa8020014aed0836fd13c51d6dc9219b0df1761d6b5f58ff5b616211b079b9 F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 F tool/mksqlite3c-noext.tcl 4f7cfef5152b0c91920355cbfc1d608a4ad242cb819f1aea07f6d0274f584a7f -F tool/mksqlite3c.tcl 00c4c0382eb000153182da2bee2547ca05554eeeed10177efe5894c54e4e6d4d +F tool/mksqlite3c.tcl bf9b40811aba68f73f2a8848fad9b1fb09fd54ab5b77e5227f18eea87ab60d92 F tool/mksqlite3h.tcl 1f5e4a1dbbbc43c83cc6e74fe32c6c620502240b66c7c0f33a51378e78fc4edf F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b F tool/mkvsix.tcl b9e0777a213c23156b6542842c238479e496ebf5 @@ -1864,27 +1882,27 @@ F tool/offsets.c 8ed2b344d33f06e71366a9b93ccedaa38c096cc1dbd4c3c26ad08c611528584 F tool/omittest.tcl 3d222272b1d840b4e3d67bff0cb743ce3f633faddadb3702b2056b726775db8f F tool/opcodesum.tcl 740ed206ba8c5040018988129abbf3089a0ccf4a F tool/pagesig.c ff0ca355fd3c2398e933da5e22439bbff89b803b -F tool/replace.tcl 60f91e8dd06ab81f74d213ecbd9c9945f32ac048 +F tool/replace.tcl 937c931ad560688e85bdd6258bdc754371bb1e2732e1fb28ef441e44c9228fce F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5 F tool/run-speed-test.sh f95d19fd669b68c4c38b6b475242841d47c66076 -F tool/showdb.c 7cc12c6deeddfe40ba5d948b408730696d8365988da05fcb6b6a90ea4965e2b4 +F tool/showdb.c 72239e95e1d05a2941c6a1d86b4d857812be4dadd71f24e381db572f350fc172 F tool/showjournal.c 5bad7ae8784a43d2b270d953060423b8bd480818 F tool/showlocks.c 9cc5e66d4ebbf2d194f39db2527ece92077e86ae627ddd233ee48e16e8142564 F tool/showshm.c a0ab6ec32dd1f11218ca2a4018f8fb875b59414801ab8ceed8b2e69b7b45a809 F tool/showstat4.c 0682ebea7abf4d3657f53c4a243f2e7eab48eab344ed36a94bb75dcd19a5c2a1 -F tool/showwal.c ad9d768f96ca6199ad3a8c9562d679680bd032dd01204ea3e5ea6fb931d81847 +F tool/showwal.c 0253c187ae16fdae9cde89e63e1dfcd3bb35e5416d066415f99e2f8cac6ab03d F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe -F tool/spaceanal.tcl a95036b36622e25cffd65a55b22d6af53dfbbff0de02d45dd0059bb3c9978609 -F tool/speed-check.sh 8ba7c7c0dba37e664679974f5954f2282275271a5b92f890756e282df0bfc458 +F tool/spaceanal.tcl 1b5be34c6223cb1af06da2a10fb77863eb869b1962d055820b0a11cf2336ab45 +F tool/speed-check.sh ff74a68bb95a0341275f4d3c9a7d8a3800bd278aceecf1913295a1f0175bc3e6 F tool/speedtest.tcl 06c76698485ccf597b9e7dbb1ac70706eb873355 F tool/speedtest16.c ecb6542862151c3e6509bbc00509b234562ae81e F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 7ce07da76b5e745783e703a834417d725b7d45fd F tool/split-sqlite3c.tcl 3efcd4240b738f6bb2b5af0aea7e1e0ef9bc1c61654f645076cec883030b710c -F tool/sqldiff.c 21226ef092ec1e543b237c5d3d2d32d344a60f2437eadfea04f65b348fbd00e4 -F tool/sqlite3_analyzer.c.in 7eeaae8b0d7577662acaabbb11107af0659d1b41bc1dfdd4d91422de27127968 +F tool/sqldiff.c 9c639de9fa541a947ea9776435c84adf00f43945e262556e15219ef09f0d912c +F tool/sqlite3_analyzer.c.in f88615bf33098945e0a42f17733f472083d150b58bdaaa5555a7129d0a51621c F tool/sqltclsh.c.in 1bcc2e9da58fadf17b0bf6a50e68c1159e602ce057210b655d50bad5aaaef898 F tool/sqltclsh.tcl 862f4cf1418df5e1315b5db3b5ebe88969e2a784525af5fbf9596592f14ed848 F tool/srcck1.c 371de5363b70154012955544f86fdee8f6e5326f @@ -1918,10 +1936,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 7bd55eee1ac63cf6d5699ce85bc5a29bf51afdf7a80bce44937fa833947a40f4 -R 6b8a0a7cf847af9edb1fb9387491b821 +P e1871201e73c1d970f0434d3c7190da2c1c49ded3a359640d959ec0c0450b8ed +R 6d4acf62ee33d6425f8616c1e2a2b241 +T +bgcolor * #d0c0ff T +sym-release * -T +sym-version-3.36.0 * +T +sym-version-3.37.2 * U drh -Z 05ee2bbc3eef4148ab2800c954a168c4 +Z bc8f65914f35757c2569ece42ec5d728 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index ef5b50a9..8927d8b4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5c9a6c06871cb9fe42814af9c039eb6da5427a6ec28f187af7ebfb62eafa66e5 +872ba256cbf61d9290b571c0e6d82a20c224ca3ad82971edc46b29818d5d17a0 diff --git a/src/alter.c b/src/alter.c index f998b893..bb43edbe 100644 --- a/src/alter.c +++ b/src/alter.c @@ -60,7 +60,7 @@ static void renameTestSchema( pParse->colNamesSet = 1; sqlite3NestedParse(pParse, "SELECT 1 " - "FROM \"%w\"." DFLT_SCHEMA_TABLE " " + "FROM \"%w\"." LEGACY_SCHEMA_TABLE " " "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" " AND sql NOT LIKE 'create virtual%%'" " AND sqlite_rename_test(%Q, sql, type, name, %d, %Q, %d)=NULL ", @@ -71,7 +71,7 @@ static void renameTestSchema( if( bTemp==0 ){ sqlite3NestedParse(pParse, "SELECT 1 " - "FROM temp." DFLT_SCHEMA_TABLE " " + "FROM temp." LEGACY_SCHEMA_TABLE " " "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" " AND sql NOT LIKE 'create virtual%%'" " AND sqlite_rename_test(%Q, sql, type, name, 1, %Q, %d)=NULL ", @@ -89,14 +89,14 @@ static void renameTestSchema( */ static void renameFixQuotes(Parse *pParse, const char *zDb, int bTemp){ sqlite3NestedParse(pParse, - "UPDATE \"%w\"." DFLT_SCHEMA_TABLE + "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET sql = sqlite_rename_quotefix(%Q, sql)" "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" " AND sql NOT LIKE 'create virtual%%'" , zDb, zDb ); if( bTemp==0 ){ sqlite3NestedParse(pParse, - "UPDATE temp." DFLT_SCHEMA_TABLE + "UPDATE temp." LEGACY_SCHEMA_TABLE " SET sql = sqlite_rename_quotefix('temp', sql)" "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" " AND sql NOT LIKE 'create virtual%%'" @@ -135,9 +135,7 @@ void sqlite3AlterRenameTable( const char *zTabName; /* Original name of the table */ Vdbe *v; VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */ - u32 savedDbFlags; /* Saved value of db->mDbFlags */ - savedDbFlags = db->mDbFlags; if( NEVER(db->mallocFailed) ) goto exit_rename_table; assert( pSrc->nSrc==1 ); assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); @@ -146,7 +144,6 @@ void sqlite3AlterRenameTable( if( !pTab ) goto exit_rename_table; iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); zDb = db->aDb[iDb].zDbSName; - db->mDbFlags |= DBFLAG_PreferBuiltin; /* Get a NULL terminated version of the new table name. */ zName = sqlite3NameFromToken(db, pName); @@ -175,7 +172,7 @@ void sqlite3AlterRenameTable( } #ifndef SQLITE_OMIT_VIEW - if( pTab->pSelect ){ + if( IsView(pTab) ){ sqlite3ErrorMsg(pParse, "view %s may not be altered", pTab->zName); goto exit_rename_table; } @@ -217,7 +214,7 @@ void sqlite3AlterRenameTable( /* Rewrite all CREATE TABLE, INDEX, TRIGGER or VIEW statements in ** the schema to use the new table name. */ sqlite3NestedParse(pParse, - "UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET " + "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, %d) " "WHERE (type!='index' OR tbl_name=%Q COLLATE nocase)" "AND name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" @@ -227,7 +224,7 @@ void sqlite3AlterRenameTable( /* Update the tbl_name and name columns of the sqlite_schema table ** as required. */ sqlite3NestedParse(pParse, - "UPDATE %Q." DFLT_SCHEMA_TABLE " SET " + "UPDATE %Q." LEGACY_SCHEMA_TABLE " SET " "tbl_name = %Q, " "name = CASE " "WHEN type='table' THEN %Q " @@ -287,7 +284,6 @@ void sqlite3AlterRenameTable( exit_rename_table: sqlite3SrcListDelete(db, pSrc); sqlite3DbFree(db, zName); - db->mDbFlags = savedDbFlags; } /* @@ -337,7 +333,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ zDb = db->aDb[iDb].zDbSName; zTab = &pNew->zName[16]; /* Skip the "sqlite_altertab_" prefix on the name */ pCol = &pNew->aCol[pNew->nCol-1]; - pDflt = pCol->pDflt; + pDflt = sqlite3ColumnExpr(pNew, pCol); pTab = sqlite3FindTable(db, zTab, zDb); assert( pTab ); @@ -371,7 +367,8 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ if( pDflt && pDflt->pLeft->op==TK_NULL ){ pDflt = 0; } - if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){ + assert( IsOrdinaryTable(pNew) ); + if( (db->flags&SQLITE_ForeignKeys) && pNew->u.tab.pFKey && pDflt ){ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, "Cannot add a REFERENCES column with non-NULL default value"); } @@ -408,31 +405,30 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n); if( zCol ){ char *zEnd = &zCol[pColDef->n-1]; - u32 savedDbFlags = db->mDbFlags; while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){ *zEnd-- = '\0'; } - db->mDbFlags |= DBFLAG_PreferBuiltin; /* substr() operations on characters, but addColOffset is in bytes. So we ** have to use printf() to translate between these units: */ + assert( IsOrdinaryTable(pTab) ); + assert( IsOrdinaryTable(pNew) ); sqlite3NestedParse(pParse, - "UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET " + "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " "sql = printf('%%.%ds, ',sql) || %Q" " || substr(sql,1+length(printf('%%.%ds',sql))) " "WHERE type = 'table' AND name = %Q", - zDb, pNew->addColOffset, zCol, pNew->addColOffset, + zDb, pNew->u.tab.addColOffset, zCol, pNew->u.tab.addColOffset, zTab ); sqlite3DbFree(db, zCol); - db->mDbFlags = savedDbFlags; } - /* Make sure the schema version is at least 3. But do not upgrade - ** from less than 3 to 4, as that will corrupt any preexisting DESC - ** index. - */ v = sqlite3GetVdbe(pParse); if( v ){ + /* Make sure the schema version is at least 3. But do not upgrade + ** from less than 3 to 4, as that will corrupt any preexisting DESC + ** index. + */ r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT); sqlite3VdbeUsesBtree(v, iDb); @@ -441,10 +437,25 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, 3); sqlite3ReleaseTempReg(pParse, r1); - } - /* Reload the table definition */ - renameReloadSchema(pParse, iDb, INITFLAG_AlterRename); + /* Reload the table definition */ + renameReloadSchema(pParse, iDb, INITFLAG_AlterAdd); + + /* Verify that constraints are still satisfied */ + if( pNew->pCheck!=0 + || (pCol->notNull && (pCol->colFlags & COLFLAG_GENERATED)!=0) + ){ + sqlite3NestedParse(pParse, + "SELECT CASE WHEN quick_check GLOB 'CHECK*'" + " THEN raise(ABORT,'CHECK constraint failed')" + " ELSE raise(ABORT,'NOT NULL constraint failed')" + " END" + " FROM pragma_quick_check(\"%w\",\"%w\")" + " WHERE quick_check GLOB 'CHECK*' OR quick_check GLOB 'NULL*'", + zTab, zDb + ); + } + } } /* @@ -485,7 +496,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ #endif /* Make sure this is not an attempt to ALTER a view. */ - if( pTab->pSelect ){ + if( IsView(pTab) ){ sqlite3ErrorMsg(pParse, "Cannot add a column to a view"); goto exit_begin_add_column; } @@ -494,7 +505,8 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ } sqlite3MayAbort(pParse); - assert( pTab->addColOffset>0 ); + assert( IsOrdinaryTable(pTab) ); + assert( pTab->u.tab.addColOffset>0 ); iDb = sqlite3SchemaToIndex(db, pTab->pSchema); /* Put a copy of the Table struct in Parse.pNewTable for the @@ -521,13 +533,13 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol); for(i=0; inCol; i++){ Column *pCol = &pNew->aCol[i]; - pCol->zName = sqlite3DbStrDup(db, pCol->zName); - pCol->hName = sqlite3StrIHash(pCol->zName); - pCol->zColl = 0; - pCol->pDflt = 0; + pCol->zCnName = sqlite3DbStrDup(db, pCol->zCnName); + pCol->hName = sqlite3StrIHash(pCol->zCnName); } + assert( IsOrdinaryTable(pNew) ); + pNew->u.tab.pDfltList = sqlite3ExprListDup(db, pTab->u.tab.pDfltList, 0); pNew->pSchema = db->aDb[iDb].pSchema; - pNew->addColOffset = pTab->addColOffset; + pNew->u.tab.addColOffset = pTab->u.tab.addColOffset; pNew->nTabRef = 1; exit_begin_add_column: @@ -547,7 +559,7 @@ exit_begin_add_column: static int isRealTable(Parse *pParse, Table *pTab, int bDrop){ const char *zType = 0; #ifndef SQLITE_OMIT_VIEW - if( pTab->pSelect ){ + if( IsView(pTab) ){ zType = "view"; } #endif @@ -614,7 +626,7 @@ void sqlite3AlterRenameColumn( zOld = sqlite3NameFromToken(db, pOld); if( !zOld ) goto exit_rename_column; for(iCol=0; iColnCol; iCol++){ - if( 0==sqlite3StrICmp(pTab->aCol[iCol].zName, zOld) ) break; + if( 0==sqlite3StrICmp(pTab->aCol[iCol].zCnName, zOld) ) break; } if( iCol==pTab->nCol ){ sqlite3ErrorMsg(pParse, "no such column: \"%s\"", zOld); @@ -635,18 +647,17 @@ void sqlite3AlterRenameColumn( assert( pNew->n>0 ); bQuote = sqlite3Isquote(pNew->z[0]); sqlite3NestedParse(pParse, - "UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET " + "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, %d) " "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X' " - " AND (type != 'index' OR tbl_name = %Q)" - " AND sql NOT LIKE 'create virtual%%'", + " AND (type != 'index' OR tbl_name = %Q)", zDb, zDb, pTab->zName, iCol, zNew, bQuote, iSchema==1, pTab->zName ); sqlite3NestedParse(pParse, - "UPDATE temp." DFLT_SCHEMA_TABLE " SET " + "UPDATE temp." LEGACY_SCHEMA_TABLE " SET " "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, 1) " "WHERE type IN ('trigger', 'view')", zDb, pTab->zName, iCol, zNew, bQuote @@ -681,7 +692,7 @@ void sqlite3AlterRenameColumn( ** the parse tree. */ struct RenameToken { - void *p; /* Parse tree element created by token t */ + const void *p; /* Parse tree element created by token t */ Token t; /* The token that created parse tree element p */ RenameToken *pNext; /* Next is a list of all RenameToken objects */ }; @@ -723,9 +734,9 @@ struct RenameCtx { ** Technically, as x no longer points into a valid object or to the byte ** following a valid object, it may not be used in comparison operations. */ -static void renameTokenCheckAll(Parse *pParse, void *pPtr){ +static void renameTokenCheckAll(Parse *pParse, const void *pPtr){ if( pParse->nErr==0 && pParse->db->mallocFailed==0 ){ - RenameToken *p; + const RenameToken *p; u8 i = 0; for(p=pParse->pRename; p; p=p->pNext){ if( p->p ){ @@ -751,7 +762,11 @@ static void renameTokenCheckAll(Parse *pParse, void *pPtr){ ** with tail recursion in tokenExpr() routine, for a small performance ** improvement. */ -void *sqlite3RenameTokenMap(Parse *pParse, void *pPtr, Token *pToken){ +const void *sqlite3RenameTokenMap( + Parse *pParse, + const void *pPtr, + const Token *pToken +){ RenameToken *pNew; assert( pPtr || pParse->db->mallocFailed ); renameTokenCheckAll(pParse, pPtr); @@ -773,7 +788,7 @@ void *sqlite3RenameTokenMap(Parse *pParse, void *pPtr, Token *pToken){ ** with parse tree element pFrom. This function remaps the associated token ** to parse tree element pTo. */ -void sqlite3RenameTokenRemap(Parse *pParse, void *pTo, void *pFrom){ +void sqlite3RenameTokenRemap(Parse *pParse, const void *pTo, const void *pFrom){ RenameToken *p; renameTokenCheckAll(pParse, pTo); for(p=pParse->pRename; p; p=p->pNext){ @@ -789,7 +804,10 @@ void sqlite3RenameTokenRemap(Parse *pParse, void *pTo, void *pFrom){ */ static int renameUnmapExprCb(Walker *pWalker, Expr *pExpr){ Parse *pParse = pWalker->pParse; - sqlite3RenameTokenRemap(pParse, 0, (void*)pExpr); + sqlite3RenameTokenRemap(pParse, 0, (const void*)pExpr); + if( ExprUseYTab(pExpr) ){ + sqlite3RenameTokenRemap(pParse, 0, (const void*)&pExpr->y.pTab); + } return WRC_Continue; } @@ -819,6 +837,7 @@ static void renameWalkWith(Walker *pWalker, Select *pSelect){ memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; if( pCopy ) sqlite3SelectPrep(sNC.pParse, p, &sNC); + if( sNC.pParse->db->mallocFailed ) return; sqlite3WalkSelect(pWalker, p); sqlite3RenameExprlistUnmap(pParse, pWith->a[i].pCols); } @@ -833,12 +852,12 @@ static void renameWalkWith(Walker *pWalker, Select *pSelect){ */ static void unmapColumnIdlistNames( Parse *pParse, - IdList *pIdList + const IdList *pIdList ){ if( pIdList ){ int ii; for(ii=0; iinId; ii++){ - sqlite3RenameTokenRemap(pParse, 0, (void*)pIdList->a[ii].zName); + sqlite3RenameTokenRemap(pParse, 0, (const void*)pIdList->a[ii].zName); } } } @@ -850,9 +869,9 @@ static int renameUnmapSelectCb(Walker *pWalker, Select *p){ Parse *pParse = pWalker->pParse; int i; if( pParse->nErr ) return WRC_Abort; + testcase( p->selFlags & SF_View ); + testcase( p->selFlags & SF_CopyCte ); if( p->selFlags & (SF_View|SF_CopyCte) ){ - testcase( p->selFlags & SF_View ); - testcase( p->selFlags & SF_CopyCte ); return WRC_Prune; } if( ALWAYS(p->pEList) ){ @@ -867,7 +886,7 @@ static int renameUnmapSelectCb(Walker *pWalker, Select *p){ SrcList *pSrc = p->pSrc; for(i=0; inSrc; i++){ sqlite3RenameTokenRemap(pParse, 0, (void*)pSrc->a[i].zName); - if( sqlite3WalkExpr(pWalker, pSrc->a[i].pOn) ) return WRC_Abort; + sqlite3WalkExpr(pWalker, pSrc->a[i].pOn); unmapColumnIdlistNames(pParse, pSrc->a[i].pUsing); } } @@ -935,7 +954,7 @@ static void renameTokenFree(sqlite3 *db, RenameToken *pToken){ static RenameToken *renameTokenFind( Parse *pParse, struct RenameCtx *pCtx, - void *pPtr + const void *pPtr ){ RenameToken **pp; if( NEVER(pPtr==0) ){ @@ -988,7 +1007,8 @@ static int renameColumnExprCb(Walker *pWalker, Expr *pExpr){ ){ renameTokenFind(pWalker->pParse, p, (void*)pExpr); }else if( pExpr->op==TK_COLUMN - && pExpr->iColumn==p->iCol + && pExpr->iColumn==p->iCol + && ALWAYS(ExprUseYTab(pExpr)) && p->pTab==pExpr->y.pTab ){ renameTokenFind(pWalker->pParse, p, (void*)pExpr); @@ -1054,18 +1074,18 @@ static void renameColumnParseError( static void renameColumnElistNames( Parse *pParse, RenameCtx *pCtx, - ExprList *pEList, + const ExprList *pEList, const char *zOld ){ if( pEList ){ int i; for(i=0; inExpr; i++){ - char *zName = pEList->a[i].zEName; + const char *zName = pEList->a[i].zEName; if( ALWAYS(pEList->a[i].eEName==ENAME_NAME) && ALWAYS(zName!=0) && 0==sqlite3_stricmp(zName, zOld) ){ - renameTokenFind(pParse, pCtx, (void*)zName); + renameTokenFind(pParse, pCtx, (const void*)zName); } } } @@ -1079,15 +1099,15 @@ static void renameColumnElistNames( static void renameColumnIdlistNames( Parse *pParse, RenameCtx *pCtx, - IdList *pIdList, + const IdList *pIdList, const char *zOld ){ if( pIdList ){ int i; for(i=0; inId; i++){ - char *zName = pIdList->a[i].zName; + const char *zName = pIdList->a[i].zName; if( 0==sqlite3_stricmp(zName, zOld) ){ - renameTokenFind(pParse, pCtx, (void*)zName); + renameTokenFind(pParse, pCtx, (const void*)zName); } } } @@ -1313,6 +1333,9 @@ static int renameResolveTrigger(Parse *pParse){ } } } + if( rc==SQLITE_OK && db->mallocFailed ){ + rc = SQLITE_NOMEM; + } sNC.pSrcList = pSrc; if( rc==SQLITE_OK && pStep->pWhere ){ rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere); @@ -1460,7 +1483,7 @@ static void renameColumnFunc( sqlite3BtreeLeaveAll(db); return; } - zOld = pTab->aCol[iCol].zName; + zOld = pTab->aCol[iCol].zCnName; memset(&sCtx, 0, sizeof(sCtx)); sCtx.iCol = ((iCol==pTab->iPKey) ? -1 : iCol); @@ -1479,8 +1502,8 @@ static void renameColumnFunc( sCtx.pTab = pTab; if( rc!=SQLITE_OK ) goto renameColumnFunc_done; if( sParse.pNewTable ){ - Select *pSelect = sParse.pNewTable->pSelect; - if( pSelect ){ + if( IsView(sParse.pNewTable) ){ + Select *pSelect = sParse.pNewTable->u.view.pSelect; pSelect->selFlags &= ~SF_View; sParse.rc = SQLITE_OK; sqlite3SelectPrep(&sParse, pSelect, 0); @@ -1489,16 +1512,15 @@ static void renameColumnFunc( sqlite3WalkSelect(&sWalker, pSelect); } if( rc!=SQLITE_OK ) goto renameColumnFunc_done; - }else{ + }else if( IsOrdinaryTable(sParse.pNewTable) ){ /* A regular table */ int bFKOnly = sqlite3_stricmp(zTable, sParse.pNewTable->zName); FKey *pFKey; - assert( sParse.pNewTable->pSelect==0 ); sCtx.pTab = sParse.pNewTable; if( bFKOnly==0 ){ if( iColnCol ){ renameTokenFind( - &sParse, &sCtx, (void*)sParse.pNewTable->aCol[iCol].zName + &sParse, &sCtx, (void*)sParse.pNewTable->aCol[iCol].zCnName ); } if( sCtx.iCol<0 ){ @@ -1513,12 +1535,15 @@ static void renameColumnFunc( } #ifndef SQLITE_OMIT_GENERATED_COLUMNS for(i=0; inCol; i++){ - sqlite3WalkExpr(&sWalker, sParse.pNewTable->aCol[i].pDflt); + Expr *pExpr = sqlite3ColumnExpr(sParse.pNewTable, + &sParse.pNewTable->aCol[i]); + sqlite3WalkExpr(&sWalker, pExpr); } #endif } - for(pFKey=sParse.pNewTable->pFKey; pFKey; pFKey=pFKey->pNextFrom){ + assert( IsOrdinaryTable(sParse.pNewTable) ); + for(pFKey=sParse.pNewTable->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){ for(i=0; inCol; i++){ if( bFKOnly==0 && pFKey->aCol[i].iFrom==iCol ){ renameTokenFind(&sParse, &sCtx, (void*)&pFKey->aCol[i]); @@ -1589,7 +1614,10 @@ renameColumnFunc_done: */ static int renameTableExprCb(Walker *pWalker, Expr *pExpr){ RenameCtx *p = pWalker->u.pRename; - if( pExpr->op==TK_COLUMN && p->pTab==pExpr->y.pTab ){ + if( pExpr->op==TK_COLUMN + && ALWAYS(ExprUseYTab(pExpr)) + && p->pTab==pExpr->y.pTab + ){ renameTokenFind(pWalker->pParse, p, (void*)&pExpr->y.pTab); } return WRC_Continue; @@ -1684,28 +1712,31 @@ static void renameTableFunc( if( sParse.pNewTable ){ Table *pTab = sParse.pNewTable; - if( pTab->pSelect ){ + if( IsView(pTab) ){ if( isLegacy==0 ){ - Select *pSelect = pTab->pSelect; + Select *pSelect = pTab->u.view.pSelect; NameContext sNC; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = &sParse; assert( pSelect->selFlags & SF_View ); pSelect->selFlags &= ~SF_View; - sqlite3SelectPrep(&sParse, pTab->pSelect, &sNC); + sqlite3SelectPrep(&sParse, pTab->u.view.pSelect, &sNC); if( sParse.nErr ){ rc = sParse.rc; }else{ - sqlite3WalkSelect(&sWalker, pTab->pSelect); + sqlite3WalkSelect(&sWalker, pTab->u.view.pSelect); } } }else{ /* Modify any FK definitions to point to the new table. */ #ifndef SQLITE_OMIT_FOREIGN_KEY - if( isLegacy==0 || (db->flags & SQLITE_ForeignKeys) ){ + if( (isLegacy==0 || (db->flags & SQLITE_ForeignKeys)) + && !IsVirtual(pTab) + ){ FKey *pFKey; - for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){ + assert( IsOrdinaryTable(pTab) ); + for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){ if( sqlite3_stricmp(pFKey->zTo, zOld)==0 ){ renameTokenFind(&sParse, &sCtx, (void*)pFKey->zTo); } @@ -1782,7 +1813,7 @@ static void renameTableFunc( static int renameQuotefixExprCb(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_STRING && (pExpr->flags & EP_DblQuoted) ){ - renameTokenFind(pWalker->pParse, pWalker->u.pRename, (void*)pExpr); + renameTokenFind(pWalker->pParse, pWalker->u.pRename, (const void*)pExpr); } return WRC_Continue; } @@ -1845,8 +1876,8 @@ static void renameQuotefixFunc( sWalker.u.pRename = &sCtx; if( sParse.pNewTable ){ - Select *pSelect = sParse.pNewTable->pSelect; - if( pSelect ){ + if( IsView(sParse.pNewTable) ){ + Select *pSelect = sParse.pNewTable->u.view.pSelect; pSelect->selFlags &= ~SF_View; sParse.rc = SQLITE_OK; sqlite3SelectPrep(&sParse, pSelect, 0); @@ -1859,7 +1890,9 @@ static void renameQuotefixFunc( sqlite3WalkExprList(&sWalker, sParse.pNewTable->pCheck); #ifndef SQLITE_OMIT_GENERATED_COLUMNS for(i=0; inCol; i++){ - sqlite3WalkExpr(&sWalker, sParse.pNewTable->aCol[i].pDflt); + sqlite3WalkExpr(&sWalker, + sqlite3ColumnExpr(sParse.pNewTable, + &sParse.pNewTable->aCol[i])); } #endif /* SQLITE_OMIT_GENERATED_COLUMNS */ } @@ -1942,11 +1975,11 @@ static void renameTableTest( rc = renameParseSql(&sParse, zDb, db, zInput, bTemp); db->flags |= (flags & (SQLITE_DqsDML|SQLITE_DqsDDL)); if( rc==SQLITE_OK ){ - if( isLegacy==0 && sParse.pNewTable && sParse.pNewTable->pSelect ){ + if( isLegacy==0 && sParse.pNewTable && IsView(sParse.pNewTable) ){ NameContext sNC; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = &sParse; - sqlite3SelectPrep(&sParse, sParse.pNewTable->pSelect, &sNC); + sqlite3SelectPrep(&sParse, sParse.pNewTable->u.view.pSelect, &sNC); if( sParse.nErr ) rc = sParse.rc; } @@ -2017,13 +2050,14 @@ static void dropColumnFunc( goto drop_column_done; } - pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol].zName); + pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol].zCnName); if( iColnCol-1 ){ RenameToken *pEnd; - pEnd = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol+1].zName); + pEnd = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol+1].zCnName); zEnd = (const char*)pEnd->t.z; }else{ - zEnd = (const char*)&zSql[pTab->addColOffset]; + assert( IsOrdinaryTable(pTab) ); + zEnd = (const char*)&zSql[pTab->u.tab.addColOffset]; while( ALWAYS(pCol->t.z[0]!=0) && pCol->t.z[0]!=',' ) pCol->t.z--; } @@ -2049,7 +2083,7 @@ drop_column_done: ** statement. Argument pSrc contains the possibly qualified name of the ** table being edited, and token pName the name of the column to drop. */ -void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, Token *pName){ +void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, const Token *pName){ sqlite3 *db = pParse->db; /* Database handle */ Table *pTab; /* Table to modify */ int iDb; /* Index of db containing pTab in aDb[] */ @@ -2104,7 +2138,7 @@ void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, Token *pName){ renameTestSchema(pParse, zDb, iDb==1, "", 0); renameFixQuotes(pParse, zDb, iDb==1); sqlite3NestedParse(pParse, - "UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET " + "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " "sql = sqlite_drop_column(%d, sql, %d) " "WHERE (type=='table' AND tbl_name=%Q COLLATE nocase)" , zDb, iDb, iCol, pTab->zName @@ -2159,6 +2193,12 @@ void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, Token *pName){ nField++; } } + if( nField==0 ){ + /* dbsqlfuzz 5f09e7bcc78b4954d06bf9f2400d7715f48d1fef */ + pParse->nMem++; + sqlite3VdbeAddOp2(v, OP_Null, 0, reg+1); + nField = 1; + } sqlite3VdbeAddOp3(v, OP_MakeRecord, reg+1, nField, regRec); if( pPk ){ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iCur, regRec, reg+1, pPk->nKeyCol); diff --git a/src/analyze.c b/src/analyze.c index dc77220a..5bbd34f9 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -433,7 +433,6 @@ static void statInit( + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample); } #endif - db = sqlite3_context_db_handle(context); p = sqlite3DbMallocZero(db, n); if( p==0 ){ sqlite3_result_error_nomem(context); @@ -852,28 +851,19 @@ static void statGet( ** ** I = (K+D-1)/D */ - char *z; - int i; - - char *zRet = sqlite3MallocZero( (p->nKeyCol+1)*25 ); - if( zRet==0 ){ - sqlite3_result_error_nomem(context); - return; - } + sqlite3_str sStat; /* Text of the constructed "stat" line */ + int i; /* Loop counter */ - sqlite3_snprintf(24, zRet, "%llu", + sqlite3StrAccumInit(&sStat, 0, 0, 0, (p->nKeyCol+1)*100); + sqlite3_str_appendf(&sStat, "%llu", p->nSkipAhead ? (u64)p->nEst : (u64)p->nRow); - z = zRet + sqlite3Strlen30(zRet); for(i=0; inKeyCol; i++){ u64 nDistinct = p->current.anDLt[i] + 1; u64 iVal = (p->nRow + nDistinct - 1) / nDistinct; - sqlite3_snprintf(24, z, " %llu", iVal); - z += sqlite3Strlen30(z); + sqlite3_str_appendf(&sStat, " %llu", iVal); assert( p->current.anEq[i] ); } - assert( z[0]=='\0' && z>zRet ); - - sqlite3_result_text(context, zRet, -1, sqlite3_free); + sqlite3ResultStrAccum(context, &sStat); } #ifdef SQLITE_ENABLE_STAT4 else if( eCall==STAT_GET_ROWID ){ @@ -892,6 +882,8 @@ static void statGet( } }else{ tRowcnt *aCnt = 0; + sqlite3_str sStat; + int i; assert( p->iGetnSample ); switch( eCall ){ @@ -903,23 +895,12 @@ static void statGet( break; } } - - { - char *zRet = sqlite3MallocZero(p->nCol * 25); - if( zRet==0 ){ - sqlite3_result_error_nomem(context); - }else{ - int i; - char *z = zRet; - for(i=0; inCol; i++){ - sqlite3_snprintf(24, z, "%llu ", (u64)aCnt[i]); - z += sqlite3Strlen30(z); - } - assert( z[0]=='\0' && z>zRet ); - z[-1] = '\0'; - sqlite3_result_text(context, zRet, -1, sqlite3_free); - } + sqlite3StrAccumInit(&sStat, 0, 0, 0, p->nCol*100); + for(i=0; inCol; i++){ + sqlite3_str_appendf(&sStat, "%llu ", (u64)aCnt[i]); } + if( sStat.nChar ) sStat.nChar--; + sqlite3ResultStrAccum(context, &sStat); } #endif /* SQLITE_ENABLE_STAT4 */ #ifndef SQLITE_DEBUG @@ -968,7 +949,7 @@ static void analyzeVdbeCommentIndexWithColumnName( }else if( i==XN_EXPR ){ VdbeComment((v,"%s.expr(%d)",pIdx->zName, k)); }else{ - VdbeComment((v,"%s.%s", pIdx->zName, pIdx->pTable->aCol[i].zName)); + VdbeComment((v,"%s.%s", pIdx->zName, pIdx->pTable->aCol[i].zCnName)); } } #else @@ -1015,7 +996,7 @@ static void analyzeOneTable( if( v==0 || NEVER(pTab==0) ){ return; } - if( pTab->tnum==0 ){ + if( !IsOrdinaryTable(pTab) ){ /* Do not gather statistics on views or virtual tables */ return; } @@ -1840,9 +1821,12 @@ static int loadStatTbl( */ static int loadStat4(sqlite3 *db, const char *zDb){ int rc = SQLITE_OK; /* Result codes from subroutines */ + const Table *pStat4; assert( db->lookaside.bDisable ); - if( sqlite3FindTable(db, "sqlite_stat4", zDb) ){ + if( (pStat4 = sqlite3FindTable(db, "sqlite_stat4", zDb))!=0 + && IsOrdinaryTable(pStat4) + ){ rc = loadStatTbl(db, "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx", "SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4", @@ -1879,6 +1863,7 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ char *zSql; int rc = SQLITE_OK; Schema *pSchema = db->aDb[iDb].pSchema; + const Table *pStat1; assert( iDb>=0 && iDbnDb ); assert( db->aDb[iDb].pBt!=0 ); @@ -1901,7 +1886,9 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ /* Load new statistics out of the sqlite_stat1 table */ sInfo.db = db; sInfo.zDatabase = db->aDb[iDb].zDbSName; - if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)!=0 ){ + if( (pStat1 = sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)) + && IsOrdinaryTable(pStat1) + ){ zSql = sqlite3MPrintf(db, "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase); if( zSql==0 ){ diff --git a/src/attach.c b/src/attach.c index 2fc84e5b..2123278c 100644 --- a/src/attach.c +++ b/src/attach.c @@ -346,9 +346,9 @@ static void codeAttach( sName.pParse = pParse; if( - SQLITE_OK!=(rc = resolveAttachExpr(&sName, pFilename)) || - SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) || - SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey)) + SQLITE_OK!=resolveAttachExpr(&sName, pFilename) || + SQLITE_OK!=resolveAttachExpr(&sName, pDbname) || + SQLITE_OK!=resolveAttachExpr(&sName, pKey) ){ goto attach_end; } @@ -357,6 +357,7 @@ static void codeAttach( if( pAuthArg ){ char *zAuthArg; if( pAuthArg->op==TK_STRING ){ + assert( !ExprHasProperty(pAuthArg, EP_IntValue) ); zAuthArg = pAuthArg->u.zToken; }else{ zAuthArg = 0; diff --git a/src/auth.c b/src/auth.c index 33420f58..3a4f73a2 100644 --- a/src/auth.c +++ b/src/auth.c @@ -175,10 +175,10 @@ void sqlite3AuthRead( if( iCol>=0 ){ assert( iColnCol ); - zCol = pTab->aCol[iCol].zName; + zCol = pTab->aCol[iCol].zCnName; }else if( pTab->iPKey>=0 ){ assert( pTab->iPKeynCol ); - zCol = pTab->aCol[pTab->iPKey].zName; + zCol = pTab->aCol[pTab->iPKey].zCnName; }else{ zCol = "ROWID"; } diff --git a/src/bitvec.c b/src/bitvec.c index bd4a0942..9393428d 100644 --- a/src/bitvec.c +++ b/src/bitvec.c @@ -353,7 +353,7 @@ int sqlite3BitvecBuiltinTest(int sz, int *aOp){ sqlite3BitvecClear(0, 1, pTmpSpace); /* Run the program */ - pc = 0; + pc = i = 0; while( (op = aOp[pc])!=0 ){ switch( op ){ case 1: diff --git a/src/btree.c b/src/btree.c index d1e84d0a..fe2d1b10 100644 --- a/src/btree.c +++ b/src/btree.c @@ -827,15 +827,13 @@ static int btreeMoveto( sqlite3VdbeRecordUnpack(pKeyInfo, (int)nKey, pKey, pIdxKey); if( pIdxKey->nField==0 || pIdxKey->nField>pKeyInfo->nAllField ){ rc = SQLITE_CORRUPT_BKPT; - goto moveto_done; + }else{ + rc = sqlite3BtreeIndexMoveto(pCur, pIdxKey, pRes); } + sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey); }else{ pIdxKey = 0; - } - rc = sqlite3BtreeMovetoUnpacked(pCur, pIdxKey, nKey, bias, pRes); -moveto_done: - if( pIdxKey ){ - sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey); + rc = sqlite3BtreeTableMoveto(pCur, nKey, bias, pRes); } return rc; } @@ -1248,7 +1246,7 @@ static void btreeParseCellPtr( pInfo->nPayload = nPayload; pInfo->pPayload = pIter; testcase( nPayload==pPage->maxLocal ); - testcase( nPayload==pPage->maxLocal+1 ); + testcase( nPayload==(u32)pPage->maxLocal+1 ); if( nPayload<=pPage->maxLocal ){ /* This is the (easy) common case where the entire payload fits ** on the local page. No overflow is required. @@ -1285,7 +1283,7 @@ static void btreeParseCellPtrIndex( pInfo->nPayload = nPayload; pInfo->pPayload = pIter; testcase( nPayload==pPage->maxLocal ); - testcase( nPayload==pPage->maxLocal+1 ); + testcase( nPayload==(u32)pPage->maxLocal+1 ); if( nPayload<=pPage->maxLocal ){ /* This is the (easy) common case where the entire payload fits ** on the local page. No overflow is required. @@ -1348,7 +1346,7 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){ while( (*pIter++)&0x80 && pItermaxLocal ); - testcase( nSize==pPage->maxLocal+1 ); + testcase( nSize==(u32)pPage->maxLocal+1 ); if( nSize<=pPage->maxLocal ){ nSize += (u32)(pIter - pCell); if( nSize<4 ) nSize = 4; @@ -1356,7 +1354,7 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){ int minLocal = pPage->minLocal; nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4); testcase( nSize==pPage->maxLocal ); - testcase( nSize==pPage->maxLocal+1 ); + testcase( nSize==(u32)pPage->maxLocal+1 ); if( nSize>pPage->maxLocal ){ nSize = minLocal; } @@ -1490,7 +1488,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage); memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz)); sz += sz2; - }else if( iFree+sz>usableSize ){ + }else if( NEVER(iFree+sz>usableSize) ){ return SQLITE_CORRUPT_PAGE(pPage); } @@ -1684,7 +1682,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ int g2; assert( pSpace+nByte<=data+pPage->pBt->usableSize ); *pIdx = g2 = (int)(pSpace-data); - if( NEVER(g2<=gap) ){ + if( g2<=gap ){ return SQLITE_CORRUPT_PAGE(pPage); }else{ return SQLITE_OK; @@ -3097,7 +3095,6 @@ static int lockBtree(BtShared *pBt){ MemPage *pPage1; /* Page 1 of the database file */ u32 nPage; /* Number of pages in the database */ u32 nPageFile = 0; /* Number of pages in the database file */ - u32 nPageHeader; /* Number of pages in the database according to hdr */ assert( sqlite3_mutex_held(pBt->mutex) ); assert( pBt->pPage1==0 ); @@ -3109,7 +3106,7 @@ static int lockBtree(BtShared *pBt){ /* Do some checking to help insure the file we opened really is ** a valid database file. */ - nPage = nPageHeader = get4byte(28+(u8*)pPage1->aData); + nPage = get4byte(28+(u8*)pPage1->aData); sqlite3PagerPagecount(pBt->pPager, (int*)&nPageFile); if( nPage==0 || memcmp(24+(u8*)pPage1->aData, 92+(u8*)pPage1->aData,4)!=0 ){ nPage = nPageFile; @@ -3144,7 +3141,7 @@ static int lockBtree(BtShared *pBt){ goto page1_init_failed; } - /* If the write version is set to 2, this database should be accessed + /* If the read version is set to 2, this database should be accessed ** in WAL mode. If the log is not already open, open it now. Then ** return SQLITE_OK and return without populating BtShared.pPage1. ** The caller detects this and calls this function again. This is @@ -3942,16 +3939,18 @@ int sqlite3BtreeIncrVacuum(Btree *p){ /* ** This routine is called prior to sqlite3PagerCommit when a transaction ** is committed for an auto-vacuum database. -** -** If SQLITE_OK is returned, then *pnTrunc is set to the number of pages -** the database file should be truncated to during the commit process. -** i.e. the database has been reorganized so that only the first *pnTrunc -** pages are in use. */ -static int autoVacuumCommit(BtShared *pBt){ +static int autoVacuumCommit(Btree *p){ int rc = SQLITE_OK; - Pager *pPager = pBt->pPager; - VVA_ONLY( int nRef = sqlite3PagerRefcount(pPager); ) + Pager *pPager; + BtShared *pBt; + sqlite3 *db; + VVA_ONLY( int nRef ); + + assert( p!=0 ); + pBt = p->pBt; + pPager = pBt->pPager; + VVA_ONLY( nRef = sqlite3PagerRefcount(pPager); ) assert( sqlite3_mutex_held(pBt->mutex) ); invalidateAllOverflowCache(pBt); @@ -3959,6 +3958,7 @@ static int autoVacuumCommit(BtShared *pBt){ if( !pBt->incrVacuum ){ Pgno nFin; /* Number of pages in database after autovacuuming */ Pgno nFree; /* Number of pages on the freelist initially */ + Pgno nVac; /* Number of pages to vacuum */ Pgno iFree; /* The next page to be freed */ Pgno nOrig; /* Database size before freeing */ @@ -3972,18 +3972,42 @@ static int autoVacuumCommit(BtShared *pBt){ } nFree = get4byte(&pBt->pPage1->aData[36]); - nFin = finalDbSize(pBt, nOrig, nFree); + db = p->db; + if( db->xAutovacPages ){ + int iDb; + for(iDb=0; ALWAYS(iDbnDb); iDb++){ + if( db->aDb[iDb].pBt==p ) break; + } + nVac = db->xAutovacPages( + db->pAutovacPagesArg, + db->aDb[iDb].zDbSName, + nOrig, + nFree, + pBt->pageSize + ); + if( nVac>nFree ){ + nVac = nFree; + } + if( nVac==0 ){ + return SQLITE_OK; + } + }else{ + nVac = nFree; + } + nFin = finalDbSize(pBt, nOrig, nVac); if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT; if( nFinnFin && rc==SQLITE_OK; iFree--){ - rc = incrVacuumStep(pBt, nFin, iFree, 1); + rc = incrVacuumStep(pBt, nFin, iFree, nVac==nFree); } if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); - put4byte(&pBt->pPage1->aData[32], 0); - put4byte(&pBt->pPage1->aData[36], 0); + if( nVac==nFree ){ + put4byte(&pBt->pPage1->aData[32], 0); + put4byte(&pBt->pPage1->aData[36], 0); + } put4byte(&pBt->pPage1->aData[28], nFin); pBt->bDoTruncate = 1; pBt->nPage = nFin; @@ -4034,7 +4058,7 @@ int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zSuperJrnl){ sqlite3BtreeEnter(p); #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ - rc = autoVacuumCommit(pBt); + rc = autoVacuumCommit(p); if( rc!=SQLITE_OK ){ sqlite3BtreeLeave(p); return rc; @@ -4221,7 +4245,7 @@ static void btreeSetNPage(BtShared *pBt, MemPage *pPage1){ int nPage = get4byte(&pPage1->aData[28]); testcase( nPage==0 ); if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage); - testcase( pBt->nPage!=nPage ); + testcase( pBt->nPage!=(u32)nPage ); pBt->nPage = nPage; } @@ -4839,7 +4863,9 @@ static int accessPayload( assert( pPage ); assert( eOp==0 || eOp==1 ); assert( pCur->eState==CURSOR_VALID ); - assert( pCur->ixnCell ); + if( pCur->ix>=pPage->nCell ){ + return SQLITE_CORRUPT_PAGE(pPage); + } assert( cursorHoldsMutex(pCur) ); getCellInfo(pCur); @@ -5026,7 +5052,6 @@ int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage>=0 && pCur->pPage ); - assert( pCur->ixpPage->nCell ); return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0); } @@ -5088,7 +5113,7 @@ static const void *fetchPayload( assert( pCur->eState==CURSOR_VALID ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( cursorOwnsBtShared(pCur) ); - assert( pCur->ixpPage->nCell ); + assert( pCur->ixpPage->nCell || CORRUPT_DB ); assert( pCur->info.nSize>0 ); assert( pCur->info.pPayload>pCur->pPage->aData || CORRUPT_DB ); assert( pCur->info.pPayloadpPage->aDataEnd ||CORRUPT_DB); @@ -5421,12 +5446,8 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ return rc; } -/* Move the cursor so that it points to an entry near the key -** specified by pIdxKey or intKey. Return a success code. -** -** For INTKEY tables, the intKey parameter is used. pIdxKey -** must be NULL. For index tables, pIdxKey is used and intKey -** is ignored. +/* Move the cursor so that it points to an entry in a table (a.k.a INTKEY) +** table near the key intKey. Return a success code. ** ** If an exact match is not found, then the cursor is always ** left pointing at a leaf page which would hold the entry if it @@ -5439,39 +5460,32 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ ** *pRes is as follows: ** ** *pRes<0 The cursor is left pointing at an entry that -** is smaller than intKey/pIdxKey or if the table is empty +** is smaller than intKey or if the table is empty ** and the cursor is therefore left point to nothing. ** ** *pRes==0 The cursor is left pointing at an entry that -** exactly matches intKey/pIdxKey. +** exactly matches intKey. ** ** *pRes>0 The cursor is left pointing at an entry that -** is larger than intKey/pIdxKey. -** -** For index tables, the pIdxKey->eqSeen field is set to 1 if there -** exists an entry in the table that exactly matches pIdxKey. +** is larger than intKey. */ -int sqlite3BtreeMovetoUnpacked( +int sqlite3BtreeTableMoveto( BtCursor *pCur, /* The cursor to be moved */ - UnpackedRecord *pIdxKey, /* Unpacked index key */ i64 intKey, /* The table key */ int biasRight, /* If true, bias the search to the high end */ int *pRes /* Write search results here */ ){ int rc; - RecordCompare xRecordCompare; assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( pRes ); - assert( (pIdxKey==0)==(pCur->pKeyInfo==0) ); - assert( pCur->eState!=CURSOR_VALID || (pIdxKey==0)==(pCur->curIntKey!=0) ); + assert( pCur->pKeyInfo==0 ); + assert( pCur->eState!=CURSOR_VALID || pCur->curIntKey!=0 ); /* If the cursor is already positioned at the point we are trying ** to move to, then just return without doing any work */ - if( pIdxKey==0 - && pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 - ){ + if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 ){ if( pCur->info.nKey==intKey ){ *pRes = 0; return SQLITE_OK; @@ -5493,9 +5507,7 @@ int sqlite3BtreeMovetoUnpacked( if( pCur->info.nKey==intKey ){ return SQLITE_OK; } - }else if( rc==SQLITE_DONE ){ - rc = SQLITE_OK; - }else{ + }else if( rc!=SQLITE_DONE ){ return rc; } } @@ -5506,17 +5518,6 @@ int sqlite3BtreeMovetoUnpacked( pCur->pBtree->nSeek++; /* Performance measurement during testing */ #endif - if( pIdxKey ){ - xRecordCompare = sqlite3VdbeFindCompare(pIdxKey); - pIdxKey->errCode = 0; - assert( pIdxKey->default_rc==1 - || pIdxKey->default_rc==0 - || pIdxKey->default_rc==-1 - ); - }else{ - xRecordCompare = 0; /* All keys are integers */ - } - rc = moveToRoot(pCur); if( rc ){ if( rc==SQLITE_EMPTY ){ @@ -5531,7 +5532,8 @@ int sqlite3BtreeMovetoUnpacked( assert( pCur->eState==CURSOR_VALID ); assert( pCur->pPage->nCell > 0 ); assert( pCur->iPage==0 || pCur->apPage[0]->intKey==pCur->curIntKey ); - assert( pCur->curIntKey || pIdxKey ); + assert( pCur->curIntKey ); + for(;;){ int lwr, upr, idx, c; Pgno chldPg; @@ -5545,133 +5547,238 @@ int sqlite3BtreeMovetoUnpacked( ** be the right kind (index or table) of b-tree page. Otherwise ** a moveToChild() or moveToRoot() call would have detected corruption. */ assert( pPage->nCell>0 ); - assert( pPage->intKey==(pIdxKey==0) ); + assert( pPage->intKey ); lwr = 0; upr = pPage->nCell-1; assert( biasRight==0 || biasRight==1 ); idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */ pCur->ix = (u16)idx; - if( xRecordCompare==0 ){ - for(;;){ - i64 nCellKey; - pCell = findCellPastPtr(pPage, idx); - if( pPage->intKeyLeaf ){ - while( 0x80 <= *(pCell++) ){ - if( pCell>=pPage->aDataEnd ){ - return SQLITE_CORRUPT_PAGE(pPage); - } + for(;;){ + i64 nCellKey; + pCell = findCellPastPtr(pPage, idx); + if( pPage->intKeyLeaf ){ + while( 0x80 <= *(pCell++) ){ + if( pCell>=pPage->aDataEnd ){ + return SQLITE_CORRUPT_PAGE(pPage); } } - getVarint(pCell, (u64*)&nCellKey); - if( nCellKeyupr ){ c = -1; break; } - }else if( nCellKey>intKey ){ - upr = idx-1; - if( lwr>upr ){ c = +1; break; } + } + getVarint(pCell, (u64*)&nCellKey); + if( nCellKeyupr ){ c = -1; break; } + }else if( nCellKey>intKey ){ + upr = idx-1; + if( lwr>upr ){ c = +1; break; } + }else{ + assert( nCellKey==intKey ); + pCur->ix = (u16)idx; + if( !pPage->leaf ){ + lwr = idx; + goto moveto_table_next_layer; }else{ - assert( nCellKey==intKey ); - pCur->ix = (u16)idx; - if( !pPage->leaf ){ - lwr = idx; - goto moveto_next_layer; - }else{ - pCur->curFlags |= BTCF_ValidNKey; - pCur->info.nKey = nCellKey; - pCur->info.nSize = 0; - *pRes = 0; - return SQLITE_OK; - } + pCur->curFlags |= BTCF_ValidNKey; + pCur->info.nKey = nCellKey; + pCur->info.nSize = 0; + *pRes = 0; + return SQLITE_OK; } - assert( lwr+upr>=0 ); - idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2; */ } + assert( lwr+upr>=0 ); + idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2; */ + } + assert( lwr==upr+1 || !pPage->leaf ); + assert( pPage->isInit ); + if( pPage->leaf ){ + assert( pCur->ixpPage->nCell ); + pCur->ix = (u16)idx; + *pRes = c; + rc = SQLITE_OK; + goto moveto_table_finish; + } +moveto_table_next_layer: + if( lwr>=pPage->nCell ){ + chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]); }else{ - for(;;){ - int nCell; /* Size of the pCell cell in bytes */ - pCell = findCellPastPtr(pPage, idx); - - /* The maximum supported page-size is 65536 bytes. This means that - ** the maximum number of record bytes stored on an index B-Tree - ** page is less than 16384 bytes and may be stored as a 2-byte - ** varint. This information is used to attempt to avoid parsing - ** the entire cell by checking for the cases where the record is - ** stored entirely within the b-tree page by inspecting the first - ** 2 bytes of the cell. - */ - nCell = pCell[0]; - if( nCell<=pPage->max1bytePayload ){ - /* This branch runs if the record-size field of the cell is a - ** single byte varint and the record fits entirely on the main - ** b-tree page. */ - testcase( pCell+nCell+1==pPage->aDataEnd ); - c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey); - }else if( !(pCell[1] & 0x80) - && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal - ){ - /* The record-size field is a 2 byte varint and the record - ** fits entirely on the main b-tree page. */ - testcase( pCell+nCell+2==pPage->aDataEnd ); - c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey); - }else{ - /* The record flows over onto one or more overflow pages. In - ** this case the whole cell needs to be parsed, a buffer allocated - ** and accessPayload() used to retrieve the record into the - ** buffer before VdbeRecordCompare() can be called. - ** - ** If the record is corrupt, the xRecordCompare routine may read - ** up to two varints past the end of the buffer. An extra 18 - ** bytes of padding is allocated at the end of the buffer in - ** case this happens. */ - void *pCellKey; - u8 * const pCellBody = pCell - pPage->childPtrSize; - const int nOverrun = 18; /* Size of the overrun padding */ - pPage->xParseCell(pPage, pCellBody, &pCur->info); - nCell = (int)pCur->info.nKey; - testcase( nCell<0 ); /* True if key size is 2^32 or more */ - testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */ - testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */ - testcase( nCell==2 ); /* Minimum legal index key size */ - if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){ - rc = SQLITE_CORRUPT_PAGE(pPage); - goto moveto_finish; - } - pCellKey = sqlite3Malloc( nCell+nOverrun ); - if( pCellKey==0 ){ - rc = SQLITE_NOMEM_BKPT; - goto moveto_finish; - } - pCur->ix = (u16)idx; - rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0); - memset(((u8*)pCellKey)+nCell,0,nOverrun); /* Fix uninit warnings */ - pCur->curFlags &= ~BTCF_ValidOvfl; - if( rc ){ - sqlite3_free(pCellKey); - goto moveto_finish; - } - c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey); - sqlite3_free(pCellKey); + chldPg = get4byte(findCell(pPage, lwr)); + } + pCur->ix = (u16)lwr; + rc = moveToChild(pCur, chldPg); + if( rc ) break; + } +moveto_table_finish: + pCur->info.nSize = 0; + assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); + return rc; +} + +/* Move the cursor so that it points to an entry in an index table +** near the key pIdxKey. Return a success code. +** +** If an exact match is not found, then the cursor is always +** left pointing at a leaf page which would hold the entry if it +** were present. The cursor might point to an entry that comes +** before or after the key. +** +** An integer is written into *pRes which is the result of +** comparing the key with the entry to which the cursor is +** pointing. The meaning of the integer written into +** *pRes is as follows: +** +** *pRes<0 The cursor is left pointing at an entry that +** is smaller than pIdxKey or if the table is empty +** and the cursor is therefore left point to nothing. +** +** *pRes==0 The cursor is left pointing at an entry that +** exactly matches pIdxKey. +** +** *pRes>0 The cursor is left pointing at an entry that +** is larger than pIdxKey. +** +** The pIdxKey->eqSeen field is set to 1 if there +** exists an entry in the table that exactly matches pIdxKey. +*/ +int sqlite3BtreeIndexMoveto( + BtCursor *pCur, /* The cursor to be moved */ + UnpackedRecord *pIdxKey, /* Unpacked index key */ + int *pRes /* Write search results here */ +){ + int rc; + RecordCompare xRecordCompare; + + assert( cursorOwnsBtShared(pCur) ); + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); + assert( pRes ); + assert( pCur->pKeyInfo!=0 ); + +#ifdef SQLITE_DEBUG + pCur->pBtree->nSeek++; /* Performance measurement during testing */ +#endif + + xRecordCompare = sqlite3VdbeFindCompare(pIdxKey); + pIdxKey->errCode = 0; + assert( pIdxKey->default_rc==1 + || pIdxKey->default_rc==0 + || pIdxKey->default_rc==-1 + ); + + rc = moveToRoot(pCur); + if( rc ){ + if( rc==SQLITE_EMPTY ){ + assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); + *pRes = -1; + return SQLITE_OK; + } + return rc; + } + assert( pCur->pPage ); + assert( pCur->pPage->isInit ); + assert( pCur->eState==CURSOR_VALID ); + assert( pCur->pPage->nCell > 0 ); + assert( pCur->iPage==0 || pCur->apPage[0]->intKey==pCur->curIntKey ); + assert( pCur->curIntKey || pIdxKey ); + for(;;){ + int lwr, upr, idx, c; + Pgno chldPg; + MemPage *pPage = pCur->pPage; + u8 *pCell; /* Pointer to current cell in pPage */ + + /* pPage->nCell must be greater than zero. If this is the root-page + ** the cursor would have been INVALID above and this for(;;) loop + ** not run. If this is not the root-page, then the moveToChild() routine + ** would have already detected db corruption. Similarly, pPage must + ** be the right kind (index or table) of b-tree page. Otherwise + ** a moveToChild() or moveToRoot() call would have detected corruption. */ + assert( pPage->nCell>0 ); + assert( pPage->intKey==(pIdxKey==0) ); + lwr = 0; + upr = pPage->nCell-1; + idx = upr>>1; /* idx = (lwr+upr)/2; */ + pCur->ix = (u16)idx; + for(;;){ + int nCell; /* Size of the pCell cell in bytes */ + pCell = findCellPastPtr(pPage, idx); + + /* The maximum supported page-size is 65536 bytes. This means that + ** the maximum number of record bytes stored on an index B-Tree + ** page is less than 16384 bytes and may be stored as a 2-byte + ** varint. This information is used to attempt to avoid parsing + ** the entire cell by checking for the cases where the record is + ** stored entirely within the b-tree page by inspecting the first + ** 2 bytes of the cell. + */ + nCell = pCell[0]; + if( nCell<=pPage->max1bytePayload ){ + /* This branch runs if the record-size field of the cell is a + ** single byte varint and the record fits entirely on the main + ** b-tree page. */ + testcase( pCell+nCell+1==pPage->aDataEnd ); + c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey); + }else if( !(pCell[1] & 0x80) + && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal + ){ + /* The record-size field is a 2 byte varint and the record + ** fits entirely on the main b-tree page. */ + testcase( pCell+nCell+2==pPage->aDataEnd ); + c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey); + }else{ + /* The record flows over onto one or more overflow pages. In + ** this case the whole cell needs to be parsed, a buffer allocated + ** and accessPayload() used to retrieve the record into the + ** buffer before VdbeRecordCompare() can be called. + ** + ** If the record is corrupt, the xRecordCompare routine may read + ** up to two varints past the end of the buffer. An extra 18 + ** bytes of padding is allocated at the end of the buffer in + ** case this happens. */ + void *pCellKey; + u8 * const pCellBody = pCell - pPage->childPtrSize; + const int nOverrun = 18; /* Size of the overrun padding */ + pPage->xParseCell(pPage, pCellBody, &pCur->info); + nCell = (int)pCur->info.nKey; + testcase( nCell<0 ); /* True if key size is 2^32 or more */ + testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */ + testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */ + testcase( nCell==2 ); /* Minimum legal index key size */ + if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){ + rc = SQLITE_CORRUPT_PAGE(pPage); + goto moveto_index_finish; } - assert( - (pIdxKey->errCode!=SQLITE_CORRUPT || c==0) - && (pIdxKey->errCode!=SQLITE_NOMEM || pCur->pBtree->db->mallocFailed) - ); - if( c<0 ){ - lwr = idx+1; - }else if( c>0 ){ - upr = idx-1; - }else{ - assert( c==0 ); - *pRes = 0; - rc = SQLITE_OK; - pCur->ix = (u16)idx; - if( pIdxKey->errCode ) rc = SQLITE_CORRUPT_BKPT; - goto moveto_finish; + pCellKey = sqlite3Malloc( nCell+nOverrun ); + if( pCellKey==0 ){ + rc = SQLITE_NOMEM_BKPT; + goto moveto_index_finish; } - if( lwr>upr ) break; - assert( lwr+upr>=0 ); - idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2 */ + pCur->ix = (u16)idx; + rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0); + memset(((u8*)pCellKey)+nCell,0,nOverrun); /* Fix uninit warnings */ + pCur->curFlags &= ~BTCF_ValidOvfl; + if( rc ){ + sqlite3_free(pCellKey); + goto moveto_index_finish; + } + c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey); + sqlite3_free(pCellKey); + } + assert( + (pIdxKey->errCode!=SQLITE_CORRUPT || c==0) + && (pIdxKey->errCode!=SQLITE_NOMEM || pCur->pBtree->db->mallocFailed) + ); + if( c<0 ){ + lwr = idx+1; + }else if( c>0 ){ + upr = idx-1; + }else{ + assert( c==0 ); + *pRes = 0; + rc = SQLITE_OK; + pCur->ix = (u16)idx; + if( pIdxKey->errCode ) rc = SQLITE_CORRUPT_BKPT; + goto moveto_index_finish; } + if( lwr>upr ) break; + assert( lwr+upr>=0 ); + idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2 */ } assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) ); assert( pPage->isInit ); @@ -5680,9 +5787,8 @@ int sqlite3BtreeMovetoUnpacked( pCur->ix = (u16)idx; *pRes = c; rc = SQLITE_OK; - goto moveto_finish; + goto moveto_index_finish; } -moveto_next_layer: if( lwr>=pPage->nCell ){ chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]); }else{ @@ -5692,7 +5798,7 @@ moveto_next_layer: rc = moveToChild(pCur, chldPg); if( rc ) break; } -moveto_finish: +moveto_index_finish: pCur->info.nSize = 0; assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); return rc; @@ -5793,16 +5899,6 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){ return SQLITE_CORRUPT_BKPT; } - /* If the database file is corrupt, it is possible for the value of idx - ** to be invalid here. This can only occur if a second cursor modifies - ** the page while cursor pCur is holding a reference to it. Which can - ** only happen if the database is corrupt in such a way as to link the - ** page into more than one b-tree structure. - ** - ** Update 2019-12-23: appears to long longer be possible after the - ** addition of anotherValidCursor() condition on balance_deeper(). */ - harmless( idx>pPage->nCell ); - if( idx>=pPage->nCell ){ if( !pPage->leaf ){ rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8])); @@ -6290,7 +6386,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){ assert( CORRUPT_DB || iPage>1 ); assert( !pMemPage || pMemPage->pgno==iPage ); - if( iPage<2 || iPage>pBt->nPage ){ + if( NEVER(iPage<2) || iPage>pBt->nPage ){ return SQLITE_CORRUPT_BKPT; } if( pMemPage ){ @@ -6714,16 +6810,18 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ int hdr; /* Beginning of the header. 0 most pages. 100 page 1 */ if( *pRC ) return; - assert( idx>=0 && idxnCell ); + assert( idx>=0 ); + assert( idxnCell ); assert( CORRUPT_DB || sz==cellSize(pPage, idx) ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( pPage->nFree>=0 ); data = pPage->aData; ptr = &pPage->aCellIdx[2*idx]; + assert( pPage->pBt->usableSize > (int)(ptr-data) ); pc = get2byte(ptr); hdr = pPage->hdrOffset; - testcase( pc==get2byte(&data[hdr+5]) ); + testcase( pc==(u32)get2byte(&data[hdr+5]) ); testcase( pc+sz==pPage->pBt->usableSize ); if( pc+sz > pPage->pBt->usableSize ){ *pRC = SQLITE_CORRUPT_BKPT; @@ -7015,7 +7113,7 @@ static int rebuildPage( assert( i(u32)usableSize) ){ j = 0; } + if( j>(u32)usableSize ){ j = 0; } memcpy(&pTmp[j], &aData[j], usableSize - j); for(k=0; pCArray->ixNx[k]<=i && ALWAYS(kpPg->aDataEnd ) goto editpage_fail; /* Add cells to the start of the page */ if( iNewpBt; assert( sqlite3_mutex_held(pBt->mutex) ); assert( sqlite3PagerIswriteable(pParent->pDbPage) ); @@ -7676,6 +7774,7 @@ static int balance_nonroot( goto balance_cleanup; } } + nMaxCells += apOld[i]->nCell + ArraySize(pParent->apOvfl); if( (i--)==0 ) break; if( pParent->nOverflow && i+nxDiv==pParent->aiOvfl[0] ){ @@ -7717,7 +7816,6 @@ static int balance_nonroot( /* Make nMaxCells a multiple of 4 in order to preserve 8-byte ** alignment */ - nMaxCells = nOld*(MX_CELL(pBt) + ArraySize(pParent->apOvfl)); nMaxCells = (nMaxCells + 3)&~3; /* @@ -8000,7 +8098,9 @@ static int balance_nonroot( apOld[i] = 0; rc = sqlite3PagerWrite(pNew->pDbPage); nNew++; - if( sqlite3PagerPageRefcount(pNew->pDbPage)!=1+(i==(iParentIdx-nxDiv)) ){ + if( sqlite3PagerPageRefcount(pNew->pDbPage)!=1+(i==(iParentIdx-nxDiv)) + && rc==SQLITE_OK + ){ rc = SQLITE_CORRUPT_BKPT; } if( rc ) goto balance_cleanup; @@ -8420,7 +8520,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){ ** Return SQLITE_CORRUPT if any cursor other than pCur is currently valid ** on the same B-tree as pCur. ** -** This can if a database is corrupt with two or more SQL tables +** This can occur if a database is corrupt with two or more SQL tables ** pointing to the same b-tree. If an insert occurs on one SQL table ** and causes a BEFORE TRIGGER to do a secondary insert on the other SQL ** table linked to the same b-tree. If the secondary insert causes a @@ -8649,7 +8749,7 @@ static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){ do{ rc = btreeGetPage(pBt, ovflPgno, &pPage, 0); if( rc ) return rc; - if( sqlite3PagerPageRefcount(pPage->pDbPage)!=1 ){ + if( sqlite3PagerPageRefcount(pPage->pDbPage)!=1 || pPage->isInit ){ rc = SQLITE_CORRUPT_BKPT; }else{ if( iOffset+ovflPageSize<(u32)nTotal ){ @@ -8798,7 +8898,8 @@ int sqlite3BtreeInsert( ** to an adjacent cell. Move the cursor so that it is pointing either ** to the cell to be overwritten or an adjacent cell. */ - rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, flags!=0, &loc); + rc = sqlite3BtreeTableMoveto(pCur, pX->nKey, + (flags & BTREE_APPEND)!=0, &loc); if( rc ) return rc; } }else{ @@ -8821,13 +8922,11 @@ int sqlite3BtreeInsert( r.aMem = pX->aMem; r.nField = pX->nMem; r.default_rc = 0; - r.errCode = 0; - r.r1 = 0; - r.r2 = 0; r.eqSeen = 0; - rc = sqlite3BtreeMovetoUnpacked(pCur, &r, 0, flags!=0, &loc); + rc = sqlite3BtreeIndexMoveto(pCur, &r, &loc); }else{ - rc = btreeMoveto(pCur, pX->pKey, pX->nKey, flags!=0, &loc); + rc = btreeMoveto(pCur, pX->pKey, pX->nKey, + (flags & BTREE_APPEND)!=0, &loc); } if( rc ) return rc; } @@ -8890,7 +8989,10 @@ int sqlite3BtreeInsert( idx = pCur->ix; if( loc==0 ){ CellInfo info; - assert( idxnCell ); + assert( idx>=0 ); + if( idx>=pPage->nCell ){ + return SQLITE_CORRUPT_BKPT; + } rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ){ goto end_insert; @@ -9072,7 +9174,7 @@ int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){ } }while( rc==SQLITE_OK && nOut>0 ); - if( rc==SQLITE_OK && nRem>0 ){ + if( rc==SQLITE_OK && nRem>0 && ALWAYS(pPgnoOut) ){ Pgno pgnoNew; MemPage *pNew = 0; rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0); @@ -9145,7 +9247,12 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ iCellIdx = pCur->ix; pPage = pCur->pPage; pCell = findCell(pPage, iCellIdx); - if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ) return SQLITE_CORRUPT; + if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ){ + return SQLITE_CORRUPT_BKPT; + } + if( pPage->nCell<=iCellIdx ){ + return SQLITE_CORRUPT_BKPT; + } /* If the bPreserve flag is set to true, then the cursor position must ** be preserved following this delete operation. If the current delete @@ -9461,7 +9568,7 @@ static int clearDatabasePage( BtShared *pBt, /* The BTree that contains the table */ Pgno pgno, /* Page number to clear */ int freePageFlag, /* Deallocate page if true */ - int *pnChange /* Add number of Cells freed to this counter */ + i64 *pnChange /* Add number of Cells freed to this counter */ ){ MemPage *pPage; int rc; @@ -9476,11 +9583,12 @@ static int clearDatabasePage( } rc = getAndInitPage(pBt, pgno, &pPage, 0, 0); if( rc ) return rc; - if( pPage->bBusy ){ + if( (pBt->openFlags & BTREE_SINGLE)==0 + && sqlite3PagerPageRefcount(pPage->pDbPage)!=1 + ){ rc = SQLITE_CORRUPT_BKPT; goto cleardatabasepage_out; } - pPage->bBusy = 1; hdr = pPage->hdrOffset; for(i=0; inCell; i++){ pCell = findCell(pPage, i); @@ -9494,6 +9602,7 @@ static int clearDatabasePage( if( !pPage->leaf ){ rc = clearDatabasePage(pBt, get4byte(&pPage->aData[hdr+8]), 1, pnChange); if( rc ) goto cleardatabasepage_out; + if( pPage->intKey ) pnChange = 0; } if( pnChange ){ testcase( !pPage->intKey ); @@ -9506,7 +9615,6 @@ static int clearDatabasePage( } cleardatabasepage_out: - pPage->bBusy = 0; releasePage(pPage); return rc; } @@ -9523,7 +9631,7 @@ cleardatabasepage_out: ** If pnChange is not NULL, then the integer value pointed to by pnChange ** is incremented by the number of entries in the table. */ -int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){ +int sqlite3BtreeClearTable(Btree *p, int iTable, i64 *pnChange){ int rc; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); @@ -9585,10 +9693,10 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){ return SQLITE_CORRUPT_BKPT; } - rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0); - if( rc ) return rc; rc = sqlite3BtreeClearTable(p, iTable, 0); - if( rc ){ + if( rc ) return rc; + rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0); + if( NEVER(rc) ){ releasePage(pPage); return rc; } diff --git a/src/btree.h b/src/btree.h index b7afecc4..f80ba4a9 100644 --- a/src/btree.h +++ b/src/btree.h @@ -123,7 +123,7 @@ int sqlite3BtreeIncrVacuum(Btree *); #define BTREE_BLOBKEY 2 /* Table has keys only - no data */ int sqlite3BtreeDropTable(Btree*, int, int*); -int sqlite3BtreeClearTable(Btree*, int, int*); +int sqlite3BtreeClearTable(Btree*, int, i64*); int sqlite3BtreeClearTableOfCursor(BtCursor*); int sqlite3BtreeTripAllCursors(Btree*, int, int); @@ -247,13 +247,17 @@ void sqlite3BtreeCursorHint(BtCursor*, int, ...); #endif int sqlite3BtreeCloseCursor(BtCursor*); -int sqlite3BtreeMovetoUnpacked( +int sqlite3BtreeTableMoveto( BtCursor*, - UnpackedRecord *pUnKey, i64 intKey, int bias, int *pRes ); +int sqlite3BtreeIndexMoveto( + BtCursor*, + UnpackedRecord *pUnKey, + int *pRes +); int sqlite3BtreeCursorHasMoved(BtCursor*); int sqlite3BtreeCursorRestore(BtCursor*, int*); int sqlite3BtreeDelete(BtCursor*, u8 flags); diff --git a/src/btreeInt.h b/src/btreeInt.h index 37c07fe9..1076fd8f 100644 --- a/src/btreeInt.h +++ b/src/btreeInt.h @@ -272,7 +272,6 @@ typedef struct CellInfo CellInfo; */ struct MemPage { u8 isInit; /* True if previously initialized. MUST BE FIRST! */ - u8 bBusy; /* Prevent endless loops on corrupt database files */ u8 intKey; /* True if table b-trees. False for index b-trees */ u8 intKeyLeaf; /* True if the leaf of an intKey table */ Pgno pgno; /* Page number for this page */ diff --git a/src/build.c b/src/build.c index 5bf5680d..d53ff3b6 100644 --- a/src/build.c +++ b/src/build.c @@ -170,17 +170,21 @@ void sqlite3FinishCoding(Parse *pParse){ int i; int reg; - addrRewind = - sqlite3VdbeAddOp1(v, OP_Rewind, pReturning->iRetCur); - VdbeCoverage(v); - reg = pReturning->iRetReg; - for(i=0; inRetCol; i++){ - sqlite3VdbeAddOp3(v, OP_Column, pReturning->iRetCur, i, reg+i); + if( pReturning->nRetCol==0 ){ + assert( CORRUPT_DB ); + }else{ + addrRewind = + sqlite3VdbeAddOp1(v, OP_Rewind, pReturning->iRetCur); + VdbeCoverage(v); + reg = pReturning->iRetReg; + for(i=0; inRetCol; i++){ + sqlite3VdbeAddOp3(v, OP_Column, pReturning->iRetCur, i, reg+i); + } + sqlite3VdbeAddOp2(v, OP_ResultRow, reg, i); + sqlite3VdbeAddOp2(v, OP_Next, pReturning->iRetCur, addrRewind+1); + VdbeCoverage(v); + sqlite3VdbeJumpHere(v, addrRewind); } - sqlite3VdbeAddOp2(v, OP_ResultRow, reg, i); - sqlite3VdbeAddOp2(v, OP_Next, pReturning->iRetCur, addrRewind+1); - VdbeCoverage(v); - sqlite3VdbeJumpHere(v, addrRewind); } sqlite3VdbeAddOp0(v, OP_Halt); @@ -261,7 +265,11 @@ void sqlite3FinishCoding(Parse *pParse){ if( pParse->bReturning ){ Returning *pRet = pParse->u1.pReturning; - sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol); + if( pRet->nRetCol==0 ){ + assert( CORRUPT_DB ); + }else{ + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol); + } } /* Finally, jump back to the beginning of the executable code. */ @@ -285,20 +293,22 @@ void sqlite3FinishCoding(Parse *pParse){ /* ** Run the parser and code generator recursively in order to generate ** code for the SQL statement given onto the end of the pParse context -** currently under construction. When the parser is run recursively -** this way, the final OP_Halt is not appended and other initialization -** and finalization steps are omitted because those are handling by the -** outermost parser. +** currently under construction. Notes: +** +** * The final OP_Halt is not appended and other initialization +** and finalization steps are omitted because those are handling by the +** outermost parser. ** -** Not everything is nestable. This facility is designed to permit -** INSERT, UPDATE, and DELETE operations against the schema table. Use -** care if you decide to try to use this routine for some other purposes. +** * Built-in SQL functions always take precedence over application-defined +** SQL functions. In other words, it is not possible to override a +** built-in function. */ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ va_list ap; char *zSql; char *zErrMsg = 0; sqlite3 *db = pParse->db; + u32 savedDbFlags = db->mDbFlags; char saveBuf[PARSE_TAIL_SZ]; if( pParse->nErr ) return; @@ -317,7 +327,9 @@ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ pParse->nested++; memcpy(saveBuf, PARSE_TAIL(pParse), PARSE_TAIL_SZ); memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ); + db->mDbFlags |= DBFLAG_PreferBuiltin; sqlite3RunParser(pParse, zSql, &zErrMsg); + db->mDbFlags = savedDbFlags; sqlite3DbFree(db, zErrMsg); sqlite3DbFree(db, zSql); memcpy(PARSE_TAIL(pParse), saveBuf, PARSE_TAIL_SZ); @@ -375,17 +387,17 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){ p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName); if( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){ if( i==1 ){ - if( sqlite3StrICmp(zName+7, &ALT_TEMP_SCHEMA_TABLE[7])==0 - || sqlite3StrICmp(zName+7, &ALT_SCHEMA_TABLE[7])==0 - || sqlite3StrICmp(zName+7, &DFLT_SCHEMA_TABLE[7])==0 + if( sqlite3StrICmp(zName+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0 + || sqlite3StrICmp(zName+7, &PREFERRED_SCHEMA_TABLE[7])==0 + || sqlite3StrICmp(zName+7, &LEGACY_SCHEMA_TABLE[7])==0 ){ p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, - DFLT_TEMP_SCHEMA_TABLE); + LEGACY_TEMP_SCHEMA_TABLE); } }else{ - if( sqlite3StrICmp(zName+7, &ALT_SCHEMA_TABLE[7])==0 ){ + if( sqlite3StrICmp(zName+7, &PREFERRED_SCHEMA_TABLE[7])==0 ){ p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, - DFLT_SCHEMA_TABLE); + LEGACY_SCHEMA_TABLE); } } } @@ -403,11 +415,11 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){ if( p ) break; } if( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){ - if( sqlite3StrICmp(zName+7, &ALT_SCHEMA_TABLE[7])==0 ){ - p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, DFLT_SCHEMA_TABLE); - }else if( sqlite3StrICmp(zName+7, &ALT_TEMP_SCHEMA_TABLE[7])==0 ){ + if( sqlite3StrICmp(zName+7, &PREFERRED_SCHEMA_TABLE[7])==0 ){ + p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, LEGACY_SCHEMA_TABLE); + }else if( sqlite3StrICmp(zName+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0 ){ p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, - DFLT_TEMP_SCHEMA_TABLE); + LEGACY_TEMP_SCHEMA_TABLE); } } } @@ -453,6 +465,7 @@ Table *sqlite3LocateTable( pMod = sqlite3PragmaVtabRegister(db, zName); } if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){ + testcase( pMod->pEpoTab==0 ); return pMod->pEpoTab; } } @@ -503,6 +516,22 @@ Table *sqlite3LocateTableItem( } /* +** Return the preferred table name for system tables. Translate legacy +** names into the new preferred names, as appropriate. +*/ +const char *sqlite3PreferredTableName(const char *zName){ + if( sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){ + if( sqlite3StrICmp(zName+7, &LEGACY_SCHEMA_TABLE[7])==0 ){ + return PREFERRED_SCHEMA_TABLE; + } + if( sqlite3StrICmp(zName+7, &LEGACY_TEMP_SCHEMA_TABLE[7])==0 ){ + return PREFERRED_TEMP_SCHEMA_TABLE; + } + } + return zName; +} + +/* ** Locate the in-memory structure that describes ** a particular index given the name of that index ** and the name of the database that contains the index. @@ -667,6 +696,84 @@ void sqlite3CommitInternalChanges(sqlite3 *db){ } /* +** Set the expression associated with a column. This is usually +** the DEFAULT value, but might also be the expression that computes +** the value for a generated column. +*/ +void sqlite3ColumnSetExpr( + Parse *pParse, /* Parsing context */ + Table *pTab, /* The table containing the column */ + Column *pCol, /* The column to receive the new DEFAULT expression */ + Expr *pExpr /* The new default expression */ +){ + ExprList *pList; + assert( IsOrdinaryTable(pTab) ); + pList = pTab->u.tab.pDfltList; + if( pCol->iDflt==0 + || NEVER(pList==0) + || NEVER(pList->nExpriDflt) + ){ + pCol->iDflt = pList==0 ? 1 : pList->nExpr+1; + pTab->u.tab.pDfltList = sqlite3ExprListAppend(pParse, pList, pExpr); + }else{ + sqlite3ExprDelete(pParse->db, pList->a[pCol->iDflt-1].pExpr); + pList->a[pCol->iDflt-1].pExpr = pExpr; + } +} + +/* +** Return the expression associated with a column. The expression might be +** the DEFAULT clause or the AS clause of a generated column. +** Return NULL if the column has no associated expression. +*/ +Expr *sqlite3ColumnExpr(Table *pTab, Column *pCol){ + if( pCol->iDflt==0 ) return 0; + if( NEVER(!IsOrdinaryTable(pTab)) ) return 0; + if( NEVER(pTab->u.tab.pDfltList==0) ) return 0; + if( NEVER(pTab->u.tab.pDfltList->nExpriDflt) ) return 0; + return pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr; +} + +/* +** Set the collating sequence name for a column. +*/ +void sqlite3ColumnSetColl( + sqlite3 *db, + Column *pCol, + const char *zColl +){ + i64 nColl; + i64 n; + char *zNew; + assert( zColl!=0 ); + n = sqlite3Strlen30(pCol->zCnName) + 1; + if( pCol->colFlags & COLFLAG_HASTYPE ){ + n += sqlite3Strlen30(pCol->zCnName+n) + 1; + } + nColl = sqlite3Strlen30(zColl) + 1; + zNew = sqlite3DbRealloc(db, pCol->zCnName, nColl+n); + if( zNew ){ + pCol->zCnName = zNew; + memcpy(pCol->zCnName + n, zColl, nColl); + pCol->colFlags |= COLFLAG_HASCOLL; + } +} + +/* +** Return the collating squence name for a column +*/ +const char *sqlite3ColumnColl(Column *pCol){ + const char *z; + if( (pCol->colFlags & COLFLAG_HASCOLL)==0 ) return 0; + z = pCol->zCnName; + while( *z ){ z++; } + if( pCol->colFlags & COLFLAG_HASTYPE ){ + do{ z++; }while( *z ); + } + return z+1; +} + +/* ** Delete memory allocated for the column names of a table or view (the ** Table.aCol[] array). */ @@ -676,12 +783,20 @@ void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){ assert( pTable!=0 ); if( (pCol = pTable->aCol)!=0 ){ for(i=0; inCol; i++, pCol++){ - assert( pCol->zName==0 || pCol->hName==sqlite3StrIHash(pCol->zName) ); - sqlite3DbFree(db, pCol->zName); - sqlite3ExprDelete(db, pCol->pDflt); - sqlite3DbFree(db, pCol->zColl); + assert( pCol->zCnName==0 || pCol->hName==sqlite3StrIHash(pCol->zCnName) ); + sqlite3DbFree(db, pCol->zCnName); } sqlite3DbFree(db, pTable->aCol); + if( IsOrdinaryTable(pTable) ){ + sqlite3ExprListDelete(db, pTable->u.tab.pDfltList); + } + if( db==0 || db->pnBytesFreed==0 ){ + pTable->aCol = 0; + pTable->nCol = 0; + if( IsOrdinaryTable(pTable) ){ + pTable->u.tab.pDfltList = 0; + } + } } } @@ -733,19 +848,25 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){ sqlite3FreeIndex(db, pIndex); } - /* Delete any foreign keys attached to this table. */ - sqlite3FkDelete(db, pTable); + if( IsOrdinaryTable(pTable) ){ + sqlite3FkDelete(db, pTable); + } +#ifndef SQLITE_OMIT_VIRTUAL_TABLE + else if( IsVirtual(pTable) ){ + sqlite3VtabClear(db, pTable); + } +#endif + else{ + assert( IsView(pTable) ); + sqlite3SelectDelete(db, pTable->u.view.pSelect); + } /* Delete the Table structure itself. */ sqlite3DeleteColumnNames(db, pTable); sqlite3DbFree(db, pTable->zName); sqlite3DbFree(db, pTable->zColAff); - sqlite3SelectDelete(db, pTable->pSelect); sqlite3ExprListDelete(db, pTable->pCheck); -#ifndef SQLITE_OMIT_VIRTUALTABLE - sqlite3VtabClear(db, pTable); -#endif sqlite3DbFree(db, pTable); /* Verify that no lookaside memory was used by schema tables */ @@ -791,10 +912,10 @@ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){ ** are not \000 terminated and are not persistent. The returned string ** is \000 terminated and is persistent. */ -char *sqlite3NameFromToken(sqlite3 *db, Token *pName){ +char *sqlite3NameFromToken(sqlite3 *db, const Token *pName){ char *zName; if( pName ){ - zName = sqlite3DbStrNDup(db, (char*)pName->z, pName->n); + zName = sqlite3DbStrNDup(db, (const char*)pName->z, pName->n); sqlite3Dequote(zName); }else{ zName = 0; @@ -808,7 +929,7 @@ char *sqlite3NameFromToken(sqlite3 *db, Token *pName){ */ void sqlite3OpenSchemaTable(Parse *p, int iDb){ Vdbe *v = sqlite3GetVdbe(p); - sqlite3TableLock(p, iDb, SCHEMA_ROOT, 1, DFLT_SCHEMA_TABLE); + sqlite3TableLock(p, iDb, SCHEMA_ROOT, 1, LEGACY_SCHEMA_TABLE); sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, SCHEMA_ROOT, iDb, 5); if( p->nTab==0 ){ p->nTab = 1; @@ -1271,6 +1392,7 @@ void sqlite3StartTable( /* If an error occurs, we jump here */ begin_table_error: + pParse->checkSchema = 1; sqlite3DbFree(db, zName); return; } @@ -1280,7 +1402,7 @@ begin_table_error: */ #if SQLITE_ENABLE_HIDDEN_COLUMNS void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){ - if( sqlite3_strnicmp(pCol->zName, "__hidden__", 10)==0 ){ + if( sqlite3_strnicmp(pCol->zCnName, "__hidden__", 10)==0 ){ pCol->colFlags |= COLFLAG_HIDDEN; if( pTab ) pTab->tabFlags |= TF_HasHidden; }else if( pTab && pCol!=pTab->aCol && (pCol[-1].colFlags & COLFLAG_HIDDEN) ){ @@ -1371,7 +1493,7 @@ void sqlite3AddReturning(Parse *pParse, ExprList *pList){ ** first to get things going. Then this routine is called for each ** column. */ -void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){ +void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){ Table *p; int i; char *z; @@ -1379,55 +1501,96 @@ void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){ Column *pCol; sqlite3 *db = pParse->db; u8 hName; + Column *aNew; + u8 eType = COLTYPE_CUSTOM; + u8 szEst = 1; + char affinity = SQLITE_AFF_BLOB; if( (p = pParse->pNewTable)==0 ) return; if( p->nCol+1>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName); return; } - z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2); + if( !IN_RENAME_OBJECT ) sqlite3DequoteToken(&sName); + + /* Because keywords GENERATE ALWAYS can be converted into indentifiers + ** by the parser, we can sometimes end up with a typename that ends + ** with "generated always". Check for this case and omit the surplus + ** text. */ + if( sType.n>=16 + && sqlite3_strnicmp(sType.z+(sType.n-6),"always",6)==0 + ){ + sType.n -= 6; + while( ALWAYS(sType.n>0) && sqlite3Isspace(sType.z[sType.n-1]) ) sType.n--; + if( sType.n>=9 + && sqlite3_strnicmp(sType.z+(sType.n-9),"generated",9)==0 + ){ + sType.n -= 9; + while( sType.n>0 && sqlite3Isspace(sType.z[sType.n-1]) ) sType.n--; + } + } + + /* Check for standard typenames. For standard typenames we will + ** set the Column.eType field rather than storing the typename after + ** the column name, in order to save space. */ + if( sType.n>=3 ){ + sqlite3DequoteToken(&sType); + for(i=0; i0) ); if( z==0 ) return; - if( IN_RENAME_OBJECT ) sqlite3RenameTokenMap(pParse, (void*)z, pName); - memcpy(z, pName->z, pName->n); - z[pName->n] = 0; + if( IN_RENAME_OBJECT ) sqlite3RenameTokenMap(pParse, (void*)z, &sName); + memcpy(z, sName.z, sName.n); + z[sName.n] = 0; sqlite3Dequote(z); hName = sqlite3StrIHash(z); for(i=0; inCol; i++){ - if( p->aCol[i].hName==hName && sqlite3StrICmp(z, p->aCol[i].zName)==0 ){ + if( p->aCol[i].hName==hName && sqlite3StrICmp(z, p->aCol[i].zCnName)==0 ){ sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); sqlite3DbFree(db, z); return; } } - if( (p->nCol & 0x7)==0 ){ - Column *aNew; - aNew = sqlite3DbRealloc(db,p->aCol,(p->nCol+8)*sizeof(p->aCol[0])); - if( aNew==0 ){ - sqlite3DbFree(db, z); - return; - } - p->aCol = aNew; + aNew = sqlite3DbRealloc(db,p->aCol,((i64)p->nCol+1)*sizeof(p->aCol[0])); + if( aNew==0 ){ + sqlite3DbFree(db, z); + return; } + p->aCol = aNew; pCol = &p->aCol[p->nCol]; memset(pCol, 0, sizeof(p->aCol[0])); - pCol->zName = z; + pCol->zCnName = z; pCol->hName = hName; sqlite3ColumnPropertiesFromName(p, pCol); - if( pType->n==0 ){ + if( sType.n==0 ){ /* If there is no type specified, columns have the default affinity ** 'BLOB' with a default size of 4 bytes. */ - pCol->affinity = SQLITE_AFF_BLOB; - pCol->szEst = 1; + pCol->affinity = affinity; + pCol->eCType = eType; + pCol->szEst = szEst; #ifdef SQLITE_ENABLE_SORTER_REFERENCES - if( 4>=sqlite3GlobalConfig.szSorterRef ){ - pCol->colFlags |= COLFLAG_SORTERREF; + if( affinity==SQLITE_AFF_BLOB ){ + if( 4>=sqlite3GlobalConfig.szSorterRef ){ + pCol->colFlags |= COLFLAG_SORTERREF; + } } #endif }else{ zType = z + sqlite3Strlen30(z) + 1; - memcpy(zType, pType->z, pType->n); - zType[pType->n] = 0; + memcpy(zType, sType.z, sType.n); + zType[sType.n] = 0; sqlite3Dequote(zType); pCol->affinity = sqlite3AffinityType(zType, pCol); pCol->colFlags |= COLFLAG_HASTYPE; @@ -1582,7 +1745,7 @@ void sqlite3AddDefaultValue( pCol = &(p->aCol[p->nCol-1]); if( !sqlite3ExprIsConstantOrFunction(pExpr, isInit) ){ sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant", - pCol->zName); + pCol->zCnName); #ifndef SQLITE_OMIT_GENERATED_COLUMNS }else if( pCol->colFlags & COLFLAG_GENERATED ){ testcase( pCol->colFlags & COLFLAG_VIRTUAL ); @@ -1593,15 +1756,15 @@ void sqlite3AddDefaultValue( /* A copy of pExpr is used instead of the original, as pExpr contains ** tokens that point to volatile memory. */ - Expr x; - sqlite3ExprDelete(db, pCol->pDflt); + Expr x, *pDfltExpr; memset(&x, 0, sizeof(x)); x.op = TK_SPAN; x.u.zToken = sqlite3DbSpanDup(db, zStart, zEnd); x.pLeft = pExpr; x.flags = EP_Skip; - pCol->pDflt = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE); + pDfltExpr = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE); sqlite3DbFree(db, x.u.zToken); + sqlite3ColumnSetExpr(pParse, p, pCol, pDfltExpr); } } if( IN_RENAME_OBJECT ){ @@ -1697,9 +1860,11 @@ void sqlite3AddPrimaryKey( assert( pCExpr!=0 ); sqlite3StringToId(pCExpr); if( pCExpr->op==TK_ID ){ - const char *zCName = pCExpr->u.zToken; + const char *zCName; + assert( !ExprHasProperty(pCExpr, EP_IntValue) ); + zCName = pCExpr->u.zToken; for(iCol=0; iColnCol; iCol++){ - if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){ + if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zCnName)==0 ){ pCol = &pTab->aCol[iCol]; makeColumnPartOfPrimaryKey(pParse, pCol); break; @@ -1710,7 +1875,7 @@ void sqlite3AddPrimaryKey( } if( nTerm==1 && pCol - && sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0 + && pCol->eCType==COLTYPE_INTEGER && sortOrder!=SQLITE_SO_DESC ){ if( IN_RENAME_OBJECT && pList ){ @@ -1790,8 +1955,7 @@ void sqlite3AddCollateType(Parse *pParse, Token *pToken){ if( sqlite3LocateCollSeq(pParse, zColl) ){ Index *pIdx; - sqlite3DbFree(db, p->aCol[i].zColl); - p->aCol[i].zColl = zColl; + sqlite3ColumnSetColl(db, &p->aCol[i], zColl); /* If the column is declared as " PRIMARY KEY COLLATE ", ** then an index may have been created on this column before the @@ -1800,12 +1964,11 @@ void sqlite3AddCollateType(Parse *pParse, Token *pToken){ for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pIdx->nKeyCol==1 ); if( pIdx->aiColumn[0]==i ){ - pIdx->azColl[0] = p->aCol[i].zColl; + pIdx->azColl[0] = sqlite3ColumnColl(&p->aCol[i]); } } - }else{ - sqlite3DbFree(db, zColl); } + sqlite3DbFree(db, zColl); } /* Change the most recently parsed column to be a GENERATED ALWAYS AS @@ -1825,7 +1988,7 @@ void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){ sqlite3ErrorMsg(pParse, "virtual tables cannot use computed columns"); goto generated_done; } - if( pCol->pDflt ) goto generated_error; + if( pCol->iDflt>0 ) goto generated_error; if( pType ){ if( pType->n==7 && sqlite3StrNICmp("virtual",pType->z,7)==0 ){ /* no-op */ @@ -1843,13 +2006,13 @@ void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){ if( pCol->colFlags & COLFLAG_PRIMKEY ){ makeColumnPartOfPrimaryKey(pParse, pCol); /* For the error message */ } - pCol->pDflt = pExpr; + sqlite3ColumnSetExpr(pParse, pTab, pCol, pExpr); pExpr = 0; goto generated_done; generated_error: sqlite3ErrorMsg(pParse, "error in generated column \"%s\"", - pCol->zName); + pCol->zCnName); generated_done: sqlite3ExprDelete(pParse->db, pExpr); #else @@ -1951,7 +2114,7 @@ static char *createTableStmt(sqlite3 *db, Table *p){ Column *pCol; n = 0; for(pCol = p->aCol, i=0; inCol; i++, pCol++){ - n += identLength(pCol->zName) + 5; + n += identLength(pCol->zCnName) + 5; } n += identLength(p->zName); if( n<50 ){ @@ -1987,7 +2150,7 @@ static char *createTableStmt(sqlite3 *db, Table *p){ sqlite3_snprintf(n-k, &zStmt[k], zSep); k += sqlite3Strlen30(&zStmt[k]); zSep = zSep2; - identPut(zStmt, &k, pCol->zName); + identPut(zStmt, &k, pCol->zCnName); assert( pCol->affinity-SQLITE_AFF_BLOB >= 0 ); assert( pCol->affinity-SQLITE_AFF_BLOB < ArraySize(azType) ); testcase( pCol->affinity==SQLITE_AFF_BLOB ); @@ -2071,7 +2234,6 @@ static void estimateIndexWidth(Index *pIdx){ */ static int hasColumn(const i16 *aiCol, int nCol, int x){ while( nCol-- > 0 ){ - assert( aiCol[0]>=0 ); if( x==*(aiCol++) ){ return 1; } @@ -2184,7 +2346,9 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ */ if( !db->init.imposterTable ){ for(i=0; inCol; i++){ - if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 ){ + if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 + && (pTab->aCol[i].notNull==OE_None) + ){ pTab->aCol[i].notNull = OE_Abort; } } @@ -2206,7 +2370,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ if( pTab->iPKey>=0 ){ ExprList *pList; Token ipkToken; - sqlite3TokenInit(&ipkToken, pTab->aCol[pTab->iPKey].zName); + sqlite3TokenInit(&ipkToken, pTab->aCol[pTab->iPKey].zCnName); pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0)); if( pList==0 ){ @@ -2336,7 +2500,7 @@ int sqlite3IsShadowTableOf(sqlite3 *db, Table *pTab, const char *zName){ nName = sqlite3Strlen30(pTab->zName); if( sqlite3_strnicmp(zName, pTab->zName, nName)!=0 ) return 0; if( zName[nName]!='_' ) return 0; - pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->azModuleArg[0]); + pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->u.vtab.azArg[0]); if( pMod==0 ) return 0; if( pMod->pModule->iVersion<3 ) return 0; if( pMod->pModule->xShadowName==0 ) return 0; @@ -2346,6 +2510,41 @@ int sqlite3IsShadowTableOf(sqlite3 *db, Table *pTab, const char *zName){ #ifndef SQLITE_OMIT_VIRTUALTABLE /* +** Table pTab is a virtual table. If it the virtual table implementation +** exists and has an xShadowName method, then loop over all other ordinary +** tables within the same schema looking for shadow tables of pTab, and mark +** any shadow tables seen using the TF_Shadow flag. +*/ +void sqlite3MarkAllShadowTablesOf(sqlite3 *db, Table *pTab){ + int nName; /* Length of pTab->zName */ + Module *pMod; /* Module for the virtual table */ + HashElem *k; /* For looping through the symbol table */ + + assert( IsVirtual(pTab) ); + pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->u.vtab.azArg[0]); + if( pMod==0 ) return; + if( NEVER(pMod->pModule==0) ) return; + if( pMod->pModule->iVersion<3 ) return; + if( pMod->pModule->xShadowName==0 ) return; + assert( pTab->zName!=0 ); + nName = sqlite3Strlen30(pTab->zName); + for(k=sqliteHashFirst(&pTab->pSchema->tblHash); k; k=sqliteHashNext(k)){ + Table *pOther = sqliteHashData(k); + assert( pOther->zName!=0 ); + if( !IsOrdinaryTable(pOther) ) continue; + if( pOther->tabFlags & TF_Shadow ) continue; + if( sqlite3StrNICmp(pOther->zName, pTab->zName, nName)==0 + && pOther->zName[nName]=='_' + && pMod->pModule->xShadowName(pOther->zName+nName+1) + ){ + pOther->tabFlags |= TF_Shadow; + } + } +} +#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* ** Return true if zName is a shadow table name in the current database ** connection. ** @@ -2417,7 +2616,7 @@ void sqlite3EndTable( Parse *pParse, /* Parse context */ Token *pCons, /* The ',' token after the last column defn. */ Token *pEnd, /* The ')' before options in the CREATE TABLE */ - u8 tabOpts, /* Extra table options. Usually 0. */ + u32 tabOpts, /* Extra table options. Usually 0. */ Select *pSelect /* Select from a "CREATE ... AS SELECT" */ ){ Table *p; /* The new table */ @@ -2445,7 +2644,7 @@ void sqlite3EndTable( ** table itself. So mark it read-only. */ if( db->init.busy ){ - if( pSelect ){ + if( pSelect || (!IsOrdinaryTable(p) && db->init.newTnum) ){ sqlite3ErrorMsg(pParse, ""); return; } @@ -2453,6 +2652,44 @@ void sqlite3EndTable( if( p->tnum==1 ) p->tabFlags |= TF_Readonly; } + /* Special processing for tables that include the STRICT keyword: + ** + ** * Do not allow custom column datatypes. Every column must have + ** a datatype that is one of INT, INTEGER, REAL, TEXT, or BLOB. + ** + ** * If a PRIMARY KEY is defined, other than the INTEGER PRIMARY KEY, + ** then all columns of the PRIMARY KEY must have a NOT NULL + ** constraint. + */ + if( tabOpts & TF_Strict ){ + int ii; + p->tabFlags |= TF_Strict; + for(ii=0; iinCol; ii++){ + Column *pCol = &p->aCol[ii]; + if( pCol->eCType==COLTYPE_CUSTOM ){ + if( pCol->colFlags & COLFLAG_HASTYPE ){ + sqlite3ErrorMsg(pParse, + "unknown datatype for %s.%s: \"%s\"", + p->zName, pCol->zCnName, sqlite3ColumnType(pCol, "") + ); + }else{ + sqlite3ErrorMsg(pParse, "missing datatype for %s.%s", + p->zName, pCol->zCnName); + } + return; + }else if( pCol->eCType==COLTYPE_ANY ){ + pCol->affinity = SQLITE_AFF_BLOB; + } + if( (pCol->colFlags & COLFLAG_PRIMKEY)!=0 + && p->iPKey!=ii + && pCol->notNull == OE_None + ){ + pCol->notNull = OE_Abort; + p->tabFlags |= TF_HasNotNull; + } + } + } + assert( (p->tabFlags & TF_HasPrimaryKey)==0 || p->iPKey>=0 || sqlite3PrimaryKeyIndex(p)!=0 ); assert( (p->tabFlags & TF_HasPrimaryKey)!=0 @@ -2497,7 +2734,7 @@ void sqlite3EndTable( for(ii=0; iinCol; ii++){ u32 colFlags = p->aCol[ii].colFlags; if( (colFlags & COLFLAG_GENERATED)!=0 ){ - Expr *pX = p->aCol[ii].pDflt; + Expr *pX = sqlite3ColumnExpr(p, &p->aCol[ii]); testcase( colFlags & COLFLAG_VIRTUAL ); testcase( colFlags & COLFLAG_STORED ); if( sqlite3ResolveSelfReference(pParse, p, NC_GenCol, pX, 0) ){ @@ -2507,8 +2744,8 @@ void sqlite3EndTable( ** tree that have been allocated from lookaside memory, which is ** illegal in a schema and will lead to errors or heap corruption ** when the database connection closes. */ - sqlite3ExprDelete(db, pX); - p->aCol[ii].pDflt = sqlite3ExprAlloc(db, TK_NULL, 0, 0); + sqlite3ColumnSetExpr(pParse, p, &p->aCol[ii], + sqlite3ExprAlloc(db, TK_NULL, 0, 0)); } }else{ nNG++; @@ -2548,7 +2785,7 @@ void sqlite3EndTable( /* ** Initialize zType for the new view or table. */ - if( p->pSelect==0 ){ + if( IsOrdinaryTable(p) ){ /* A regular table */ zType = "table"; zType2 = "TABLE"; @@ -2634,7 +2871,7 @@ void sqlite3EndTable( ** the information we've collected. */ sqlite3NestedParse(pParse, - "UPDATE %Q." DFLT_SCHEMA_TABLE + "UPDATE %Q." LEGACY_SCHEMA_TABLE " SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q" " WHERE rowid=#%d", db->aDb[iDb].zDbSName, @@ -2698,12 +2935,12 @@ void sqlite3EndTable( } #ifndef SQLITE_OMIT_ALTERTABLE - if( !pSelect && !p->pSelect ){ + if( !pSelect && IsOrdinaryTable(p) ){ assert( pCons && pEnd ); if( pCons->z==0 ){ pCons = pEnd; } - p->addColOffset = 13 + (int)(pCons->z - pParse->sNameToken.z); + p->u.tab.addColOffset = 13 + (int)(pCons->z - pParse->sNameToken.z); } #endif } @@ -2760,12 +2997,13 @@ void sqlite3CreateView( */ pSelect->selFlags |= SF_View; if( IN_RENAME_OBJECT ){ - p->pSelect = pSelect; + p->u.view.pSelect = pSelect; pSelect = 0; }else{ - p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); + p->u.view.pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); } p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE); + p->eTabType = TABTYP_VIEW; if( db->mallocFailed ) goto create_view_fail; /* Locate the end of the CREATE VIEW statement. Make sEnd point to @@ -2819,13 +3057,12 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ assert( pTable ); #ifndef SQLITE_OMIT_VIRTUALTABLE - db->nSchemaLock++; - rc = sqlite3VtabCallConnect(pParse, pTable); - db->nSchemaLock--; - if( rc ){ - return 1; + if( IsVirtual(pTable) ){ + db->nSchemaLock++; + rc = sqlite3VtabCallConnect(pParse, pTable); + db->nSchemaLock--; + return rc; } - if( IsVirtual(pTable) ) return 0; #endif #ifndef SQLITE_OMIT_VIEW @@ -2862,8 +3099,8 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ ** to be permanent. So the computation is done on a copy of the SELECT ** statement that defines the view. */ - assert( pTable->pSelect ); - pSel = sqlite3SelectDup(db, pTable->pSelect, 0); + assert( IsView(pTable) ); + pSel = sqlite3SelectDup(db, pTable->u.view.pSelect, 0); if( pSel ){ u8 eParseMode = pParse->eParseMode; pParse->eParseMode = PARSE_MODE_NORMAL; @@ -2922,8 +3159,6 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ pTable->pSchema->schemaFlags |= DB_UnresetViews; if( db->mallocFailed ){ sqlite3DeleteColumnNames(db, pTable); - pTable->aCol = 0; - pTable->nCol = 0; } #endif /* SQLITE_OMIT_VIEW */ return nErr; @@ -2940,10 +3175,8 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){ if( !DbHasProperty(db, idx, DB_UnresetViews) ) return; for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){ Table *pTab = sqliteHashData(i); - if( pTab->pSelect ){ + if( IsView(pTab) ){ sqlite3DeleteColumnNames(db, pTab); - pTab->aCol = 0; - pTab->nCol = 0; } } DbClearProperty(db, idx, DB_UnresetViews); @@ -3017,7 +3250,7 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){ ** token for additional information. */ sqlite3NestedParse(pParse, - "UPDATE %Q." DFLT_SCHEMA_TABLE + "UPDATE %Q." LEGACY_SCHEMA_TABLE " SET rootpage=%d WHERE #%d AND rootpage=#%d", pParse->db->aDb[iDb].zDbSName, iTable, r1, r1); #endif @@ -3152,7 +3385,7 @@ void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){ ** database. */ sqlite3NestedParse(pParse, - "DELETE FROM %Q." DFLT_SCHEMA_TABLE + "DELETE FROM %Q." LEGACY_SCHEMA_TABLE " WHERE tbl_name=%Q and type!='trigger'", pDb->zDbSName, pTab->zName); if( !isView && !IsVirtual(pTab) ){ @@ -3180,6 +3413,7 @@ int sqlite3ReadOnlyShadowTables(sqlite3 *db){ if( (db->flags & SQLITE_Defensive)!=0 && db->pVtabCtx==0 && db->nVdbeExec==0 + && !sqlite3VtabInSync(db) ){ return 1; } @@ -3199,6 +3433,9 @@ static int tableMayNotBeDropped(sqlite3 *db, Table *pTab){ if( (pTab->tabFlags & TF_Shadow)!=0 && sqlite3ReadOnlyShadowTables(db) ){ return 1; } + if( pTab->tabFlags & TF_Eponymous ){ + return 1; + } return 0; } @@ -3283,11 +3520,11 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ /* Ensure DROP TABLE is not used on a view, and DROP VIEW is not used ** on a table. */ - if( isView && pTab->pSelect==0 ){ + if( isView && !IsView(pTab) ){ sqlite3ErrorMsg(pParse, "use DROP TABLE to delete table %s", pTab->zName); goto exit_drop_table; } - if( !isView && pTab->pSelect ){ + if( !isView && IsView(pTab) ){ sqlite3ErrorMsg(pParse, "use DROP VIEW to delete view %s", pTab->zName); goto exit_drop_table; } @@ -3338,7 +3575,7 @@ void sqlite3CreateForeignKey( FKey *pFKey = 0; FKey *pNextTo; Table *p = pParse->pNewTable; - int nByte; + i64 nByte; int i; int nCol; char *z; @@ -3351,7 +3588,7 @@ void sqlite3CreateForeignKey( if( pToCol && pToCol->nExpr!=1 ){ sqlite3ErrorMsg(pParse, "foreign key on %s" " should reference only one column of table %T", - p->aCol[iCol].zName, pTo); + p->aCol[iCol].zCnName, pTo); goto fk_end; } nCol = 1; @@ -3374,7 +3611,8 @@ void sqlite3CreateForeignKey( goto fk_end; } pFKey->pFrom = p; - pFKey->pNextFrom = p->pFKey; + assert( IsOrdinaryTable(p) ); + pFKey->pNextFrom = p->u.tab.pFKey; z = (char*)&pFKey->aCol[nCol]; pFKey->zTo = z; if( IN_RENAME_OBJECT ){ @@ -3391,7 +3629,7 @@ void sqlite3CreateForeignKey( for(i=0; inCol; j++){ - if( sqlite3StrICmp(p->aCol[j].zName, pFromCol->a[i].zEName)==0 ){ + if( sqlite3StrICmp(p->aCol[j].zCnName, pFromCol->a[i].zEName)==0 ){ pFKey->aCol[i].iFrom = j; break; } @@ -3439,7 +3677,8 @@ void sqlite3CreateForeignKey( /* Link the foreign key to the table as the last step. */ - p->pFKey = pFKey; + assert( IsOrdinaryTable(p) ); + p->u.tab.pFKey = pFKey; pFKey = 0; fk_end: @@ -3460,7 +3699,9 @@ void sqlite3DeferForeignKey(Parse *pParse, int isDeferred){ #ifndef SQLITE_OMIT_FOREIGN_KEY Table *pTab; FKey *pFKey; - if( (pTab = pParse->pNewTable)==0 || (pFKey = pTab->pFKey)==0 ) return; + if( (pTab = pParse->pNewTable)==0 ) return; + if( NEVER(!IsOrdinaryTable(pTab)) ) return; + if( (pFKey = pTab->u.tab.pFKey)==0 ) return; assert( isDeferred==0 || isDeferred==1 ); /* EV: R-30323-21917 */ pFKey->isDeferred = (u8)isDeferred; #endif @@ -3752,7 +3993,7 @@ void sqlite3CreateIndex( goto exit_create_index; } #ifndef SQLITE_OMIT_VIEW - if( pTab->pSelect ){ + if( IsView(pTab) ){ sqlite3ErrorMsg(pParse, "views may not be indexed"); goto exit_create_index; } @@ -3843,7 +4084,7 @@ void sqlite3CreateIndex( Token prevCol; Column *pCol = &pTab->aCol[pTab->nCol-1]; pCol->colFlags |= COLFLAG_UNIQUE; - sqlite3TokenInit(&prevCol, pCol->zName); + sqlite3TokenInit(&prevCol, pCol->zCnName); pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &prevCol, 0)); if( pList==0 ) goto exit_create_index; @@ -3861,6 +4102,7 @@ void sqlite3CreateIndex( Expr *pExpr = pList->a[i].pExpr; assert( pExpr!=0 ); if( pExpr->op==TK_COLLATE ){ + assert( !ExprHasProperty(pExpr, EP_IntValue) ); nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken)); } } @@ -3956,6 +4198,7 @@ void sqlite3CreateIndex( zColl = 0; if( pListItem->pExpr->op==TK_COLLATE ){ int nColl; + assert( !ExprHasProperty(pListItem->pExpr, EP_IntValue) ); zColl = pListItem->pExpr->u.zToken; nColl = sqlite3Strlen30(zColl) + 1; assert( nExtra>=nColl ); @@ -3964,7 +4207,7 @@ void sqlite3CreateIndex( zExtra += nColl; nExtra -= nColl; }else if( j>=0 ){ - zColl = pTab->aCol[j].zColl; + zColl = sqlite3ColumnColl(&pTab->aCol[j]); } if( !zColl ) zColl = sqlite3StrBINARY; if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){ @@ -4162,7 +4405,7 @@ void sqlite3CreateIndex( /* Add an entry in sqlite_schema for this index */ sqlite3NestedParse(pParse, - "INSERT INTO %Q." DFLT_SCHEMA_TABLE " VALUES('index',%Q,%Q,#%d,%Q);", + "INSERT INTO %Q." LEGACY_SCHEMA_TABLE " VALUES('index',%Q,%Q,#%d,%Q);", db->aDb[iDb].zDbSName, pIndex->zName, pTab->zName, @@ -4204,7 +4447,7 @@ exit_create_index: ** The list was already ordered when this routine was entered, so at this ** point at most a single index (the newly added index) will be out of ** order. So we have to reorder at most one index. */ - Index **ppFrom = &pTab->pIndex; + Index **ppFrom; Index *pThis; for(ppFrom=&pTab->pIndex; (pThis = *ppFrom)!=0; ppFrom=&pThis->pNext){ Index *pNext; @@ -4348,7 +4591,7 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){ if( v ){ sqlite3BeginWriteOperation(pParse, 1, iDb); sqlite3NestedParse(pParse, - "DELETE FROM %Q." DFLT_SCHEMA_TABLE " WHERE name=%Q AND type='index'", + "DELETE FROM %Q." LEGACY_SCHEMA_TABLE " WHERE name=%Q AND type='index'", db->aDb[iDb].zDbSName, pIndex->zName ); sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName); @@ -4744,6 +4987,7 @@ void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){ }else{ pItem->u1.zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy); pItem->fg.isIndexedBy = 1; + assert( pItem->fg.isCte==0 ); /* No collision on union u2 */ } } } @@ -5056,7 +5300,7 @@ void sqlite3UniqueConstraint( for(j=0; jnKeyCol; j++){ char *zCol; assert( pIdx->aiColumn[j]>=0 ); - zCol = pTab->aCol[pIdx->aiColumn[j]].zName; + zCol = pTab->aCol[pIdx->aiColumn[j]].zCnName; if( j ) sqlite3_str_append(&errMsg, ", ", 2); sqlite3_str_appendall(&errMsg, pTab->zName); sqlite3_str_append(&errMsg, ".", 1); @@ -5083,7 +5327,7 @@ void sqlite3RowidConstraint( int rc; if( pTab->iPKey>=0 ){ zMsg = sqlite3MPrintf(pParse->db, "%s.%s", pTab->zName, - pTab->aCol[pTab->iPKey].zName); + pTab->aCol[pTab->iPKey].zCnName); rc = SQLITE_CONSTRAINT_PRIMARYKEY; }else{ zMsg = sqlite3MPrintf(pParse->db, "%s.rowid", pTab->zName); diff --git a/src/callback.c b/src/callback.c index 421cef28..936c374a 100644 --- a/src/callback.c +++ b/src/callback.c @@ -337,6 +337,7 @@ FuncDef *sqlite3FunctionSearch( ){ FuncDef *p; for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){ + assert( p->funcFlags & SQLITE_FUNC_BUILTIN ); if( sqlite3StrICmp(p->zName, zFunc)==0 ){ return p; } @@ -358,6 +359,7 @@ void sqlite3InsertBuiltinFuncs( int nName = sqlite3Strlen30(zName); int h = SQLITE_FUNC_HASH(zName[0], nName); assert( zName[0]>='a' && zName[0]<='z' ); + assert( aDef[i].funcFlags & SQLITE_FUNC_BUILTIN ); pOther = sqlite3FunctionSearch(h, zName); if( pOther ){ assert( pOther!=&aDef[i] && pOther->pNext!=&aDef[i] ); diff --git a/src/ctime.c b/src/ctime.c index fa69216c..de68ea7f 100644 --- a/src/ctime.c +++ b/src/ctime.c @@ -13,7 +13,6 @@ ** This file implements routines used to report what compile-time options ** SQLite was built with. */ - #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS /* IMP: R-16824-07538 */ /* @@ -35,6 +34,7 @@ ** comma. e.g. (-DSQLITE_DEFAULT_LOOKASIDE="100,100") */ #define CTIMEOPT_VAL2_(opt1,opt2) #opt1 "," #opt2 #define CTIMEOPT_VAL2(opt) CTIMEOPT_VAL2_(opt) +#include "sqliteInt.h" /* ** An array of names of all compile-time options. This array should @@ -49,13 +49,13 @@ static const char * const sqlite3azCompileOpt[] = { /* ** BEGIN CODE GENERATED BY tool/mkctime.tcl */ -#if SQLITE_32BIT_ROWID +#ifdef SQLITE_32BIT_ROWID "32BIT_ROWID", #endif -#if SQLITE_4_BYTE_ALIGNED_MALLOC +#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC "4_BYTE_ALIGNED_MALLOC", #endif -#if SQLITE_64BIT_STATS +#ifdef SQLITE_64BIT_STATS "64BIT_STATS", #endif #ifdef SQLITE_ALLOW_COVERING_INDEX_SCAN @@ -63,19 +63,22 @@ static const char * const sqlite3azCompileOpt[] = { "ALLOW_COVERING_INDEX_SCAN=" CTIMEOPT_VAL(SQLITE_ALLOW_COVERING_INDEX_SCAN), # endif #endif -#if SQLITE_ALLOW_URI_AUTHORITY +#ifdef SQLITE_ALLOW_URI_AUTHORITY "ALLOW_URI_AUTHORITY", #endif +#ifdef SQLITE_ATOMIC_INTRINSICS + "ATOMIC_INTRINSICS=" CTIMEOPT_VAL(SQLITE_ATOMIC_INTRINSICS), +#endif #ifdef SQLITE_BITMASK_TYPE "BITMASK_TYPE=" CTIMEOPT_VAL(SQLITE_BITMASK_TYPE), #endif -#if SQLITE_BUG_COMPATIBLE_20160819 +#ifdef SQLITE_BUG_COMPATIBLE_20160819 "BUG_COMPATIBLE_20160819", #endif -#if SQLITE_CASE_SENSITIVE_LIKE +#ifdef SQLITE_CASE_SENSITIVE_LIKE "CASE_SENSITIVE_LIKE", #endif -#if SQLITE_CHECK_PAGES +#ifdef SQLITE_CHECK_PAGES "CHECK_PAGES", #endif #if defined(__clang__) && defined(__clang_major__) @@ -87,22 +90,22 @@ static const char * const sqlite3azCompileOpt[] = { #elif defined(__GNUC__) && defined(__VERSION__) "COMPILER=gcc-" __VERSION__, #endif -#if SQLITE_COVERAGE_TEST +#ifdef SQLITE_COVERAGE_TEST "COVERAGE_TEST", #endif -#if SQLITE_DEBUG +#ifdef SQLITE_DEBUG "DEBUG", #endif -#if SQLITE_DEFAULT_AUTOMATIC_INDEX +#ifdef SQLITE_DEFAULT_AUTOMATIC_INDEX "DEFAULT_AUTOMATIC_INDEX", #endif -#if SQLITE_DEFAULT_AUTOVACUUM +#ifdef SQLITE_DEFAULT_AUTOVACUUM "DEFAULT_AUTOVACUUM", #endif #ifdef SQLITE_DEFAULT_CACHE_SIZE "DEFAULT_CACHE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_CACHE_SIZE), #endif -#if SQLITE_DEFAULT_CKPTFULLFSYNC +#ifdef SQLITE_DEFAULT_CKPTFULLFSYNC "DEFAULT_CKPTFULLFSYNC", #endif #ifdef SQLITE_DEFAULT_FILE_FORMAT @@ -111,7 +114,7 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_DEFAULT_FILE_PERMISSIONS "DEFAULT_FILE_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_PERMISSIONS), #endif -#if SQLITE_DEFAULT_FOREIGN_KEYS +#ifdef SQLITE_DEFAULT_FOREIGN_KEYS "DEFAULT_FOREIGN_KEYS", #endif #ifdef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT @@ -140,7 +143,7 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS "DEFAULT_PROXYDIR_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_PROXYDIR_PERMISSIONS), #endif -#if SQLITE_DEFAULT_RECURSIVE_TRIGGERS +#ifdef SQLITE_DEFAULT_RECURSIVE_TRIGGERS "DEFAULT_RECURSIVE_TRIGGERS", #endif #ifdef SQLITE_DEFAULT_ROWEST @@ -161,196 +164,196 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_DEFAULT_WORKER_THREADS "DEFAULT_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WORKER_THREADS), #endif -#if SQLITE_DIRECT_OVERFLOW_READ +#ifdef SQLITE_DIRECT_OVERFLOW_READ "DIRECT_OVERFLOW_READ", #endif -#if SQLITE_DISABLE_DIRSYNC +#ifdef SQLITE_DISABLE_DIRSYNC "DISABLE_DIRSYNC", #endif -#if SQLITE_DISABLE_FTS3_UNICODE +#ifdef SQLITE_DISABLE_FTS3_UNICODE "DISABLE_FTS3_UNICODE", #endif -#if SQLITE_DISABLE_FTS4_DEFERRED +#ifdef SQLITE_DISABLE_FTS4_DEFERRED "DISABLE_FTS4_DEFERRED", #endif -#if SQLITE_DISABLE_INTRINSIC +#ifdef SQLITE_DISABLE_INTRINSIC "DISABLE_INTRINSIC", #endif -#if SQLITE_DISABLE_LFS +#ifdef SQLITE_DISABLE_LFS "DISABLE_LFS", #endif -#if SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS +#ifdef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS "DISABLE_PAGECACHE_OVERFLOW_STATS", #endif -#if SQLITE_DISABLE_SKIPAHEAD_DISTINCT +#ifdef SQLITE_DISABLE_SKIPAHEAD_DISTINCT "DISABLE_SKIPAHEAD_DISTINCT", #endif #ifdef SQLITE_ENABLE_8_3_NAMES "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES), #endif -#if SQLITE_ENABLE_API_ARMOR +#ifdef SQLITE_ENABLE_API_ARMOR "ENABLE_API_ARMOR", #endif -#if SQLITE_ENABLE_ATOMIC_WRITE +#ifdef SQLITE_ENABLE_ATOMIC_WRITE "ENABLE_ATOMIC_WRITE", #endif -#if SQLITE_ENABLE_BATCH_ATOMIC_WRITE +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE "ENABLE_BATCH_ATOMIC_WRITE", #endif -#if SQLITE_ENABLE_BYTECODE_VTAB +#ifdef SQLITE_ENABLE_BYTECODE_VTAB "ENABLE_BYTECODE_VTAB", #endif #ifdef SQLITE_ENABLE_CEROD "ENABLE_CEROD=" CTIMEOPT_VAL(SQLITE_ENABLE_CEROD), #endif -#if SQLITE_ENABLE_COLUMN_METADATA +#ifdef SQLITE_ENABLE_COLUMN_METADATA "ENABLE_COLUMN_METADATA", #endif -#if SQLITE_ENABLE_COLUMN_USED_MASK +#ifdef SQLITE_ENABLE_COLUMN_USED_MASK "ENABLE_COLUMN_USED_MASK", #endif -#if SQLITE_ENABLE_COSTMULT +#ifdef SQLITE_ENABLE_COSTMULT "ENABLE_COSTMULT", #endif -#if SQLITE_ENABLE_CURSOR_HINTS +#ifdef SQLITE_ENABLE_CURSOR_HINTS "ENABLE_CURSOR_HINTS", #endif -#if SQLITE_ENABLE_DBPAGE_VTAB +#ifdef SQLITE_ENABLE_DBPAGE_VTAB "ENABLE_DBPAGE_VTAB", #endif -#if SQLITE_ENABLE_DBSTAT_VTAB +#ifdef SQLITE_ENABLE_DBSTAT_VTAB "ENABLE_DBSTAT_VTAB", #endif -#if SQLITE_ENABLE_EXPENSIVE_ASSERT +#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT "ENABLE_EXPENSIVE_ASSERT", #endif -#if SQLITE_ENABLE_EXPLAIN_COMMENTS +#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS "ENABLE_EXPLAIN_COMMENTS", #endif -#if SQLITE_ENABLE_FTS3 +#ifdef SQLITE_ENABLE_FTS3 "ENABLE_FTS3", #endif -#if SQLITE_ENABLE_FTS3_PARENTHESIS +#ifdef SQLITE_ENABLE_FTS3_PARENTHESIS "ENABLE_FTS3_PARENTHESIS", #endif -#if SQLITE_ENABLE_FTS3_TOKENIZER +#ifdef SQLITE_ENABLE_FTS3_TOKENIZER "ENABLE_FTS3_TOKENIZER", #endif -#if SQLITE_ENABLE_FTS4 +#ifdef SQLITE_ENABLE_FTS4 "ENABLE_FTS4", #endif -#if SQLITE_ENABLE_FTS5 +#ifdef SQLITE_ENABLE_FTS5 "ENABLE_FTS5", #endif -#if SQLITE_ENABLE_GEOPOLY +#ifdef SQLITE_ENABLE_GEOPOLY "ENABLE_GEOPOLY", #endif -#if SQLITE_ENABLE_HIDDEN_COLUMNS +#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS "ENABLE_HIDDEN_COLUMNS", #endif -#if SQLITE_ENABLE_ICU +#ifdef SQLITE_ENABLE_ICU "ENABLE_ICU", #endif -#if SQLITE_ENABLE_IOTRACE +#ifdef SQLITE_ENABLE_IOTRACE "ENABLE_IOTRACE", #endif -#if SQLITE_ENABLE_JSON1 +#ifdef SQLITE_ENABLE_JSON1 "ENABLE_JSON1", #endif -#if SQLITE_ENABLE_LOAD_EXTENSION +#ifdef SQLITE_ENABLE_LOAD_EXTENSION "ENABLE_LOAD_EXTENSION", #endif #ifdef SQLITE_ENABLE_LOCKING_STYLE "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE), #endif -#if SQLITE_ENABLE_MATH_FUNCTIONS +#ifdef SQLITE_ENABLE_MATH_FUNCTIONS "ENABLE_MATH_FUNCTIONS", #endif -#if SQLITE_ENABLE_MEMORY_MANAGEMENT +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT "ENABLE_MEMORY_MANAGEMENT", #endif -#if SQLITE_ENABLE_MEMSYS3 +#ifdef SQLITE_ENABLE_MEMSYS3 "ENABLE_MEMSYS3", #endif -#if SQLITE_ENABLE_MEMSYS5 +#ifdef SQLITE_ENABLE_MEMSYS5 "ENABLE_MEMSYS5", #endif -#if SQLITE_ENABLE_MULTIPLEX +#ifdef SQLITE_ENABLE_MULTIPLEX "ENABLE_MULTIPLEX", #endif -#if SQLITE_ENABLE_NORMALIZE +#ifdef SQLITE_ENABLE_NORMALIZE "ENABLE_NORMALIZE", #endif -#if SQLITE_ENABLE_NULL_TRIM +#ifdef SQLITE_ENABLE_NULL_TRIM "ENABLE_NULL_TRIM", #endif -#if SQLITE_ENABLE_OFFSET_SQL_FUNC +#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC "ENABLE_OFFSET_SQL_FUNC", #endif -#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK +#ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK "ENABLE_OVERSIZE_CELL_CHECK", #endif -#if SQLITE_ENABLE_PREUPDATE_HOOK +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK "ENABLE_PREUPDATE_HOOK", #endif -#if SQLITE_ENABLE_QPSG +#ifdef SQLITE_ENABLE_QPSG "ENABLE_QPSG", #endif -#if SQLITE_ENABLE_RBU +#ifdef SQLITE_ENABLE_RBU "ENABLE_RBU", #endif -#if SQLITE_ENABLE_RTREE +#ifdef SQLITE_ENABLE_RTREE "ENABLE_RTREE", #endif -#if SQLITE_ENABLE_SELECTTRACE +#ifdef SQLITE_ENABLE_SELECTTRACE "ENABLE_SELECTTRACE", #endif -#if SQLITE_ENABLE_SESSION +#ifdef SQLITE_ENABLE_SESSION "ENABLE_SESSION", #endif -#if SQLITE_ENABLE_SNAPSHOT +#ifdef SQLITE_ENABLE_SNAPSHOT "ENABLE_SNAPSHOT", #endif -#if SQLITE_ENABLE_SORTER_REFERENCES +#ifdef SQLITE_ENABLE_SORTER_REFERENCES "ENABLE_SORTER_REFERENCES", #endif -#if SQLITE_ENABLE_SQLLOG +#ifdef SQLITE_ENABLE_SQLLOG "ENABLE_SQLLOG", #endif -#if SQLITE_ENABLE_STAT4 +#ifdef SQLITE_ENABLE_STAT4 "ENABLE_STAT4", #endif -#if SQLITE_ENABLE_STMTVTAB +#ifdef SQLITE_ENABLE_STMTVTAB "ENABLE_STMTVTAB", #endif -#if SQLITE_ENABLE_STMT_SCANSTATUS +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS "ENABLE_STMT_SCANSTATUS", #endif -#if SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION +#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION "ENABLE_UNKNOWN_SQL_FUNCTION", #endif -#if SQLITE_ENABLE_UNLOCK_NOTIFY +#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY "ENABLE_UNLOCK_NOTIFY", #endif -#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT +#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT "ENABLE_UPDATE_DELETE_LIMIT", #endif -#if SQLITE_ENABLE_URI_00_ERROR +#ifdef SQLITE_ENABLE_URI_00_ERROR "ENABLE_URI_00_ERROR", #endif -#if SQLITE_ENABLE_VFSTRACE +#ifdef SQLITE_ENABLE_VFSTRACE "ENABLE_VFSTRACE", #endif -#if SQLITE_ENABLE_WHERETRACE +#ifdef SQLITE_ENABLE_WHERETRACE "ENABLE_WHERETRACE", #endif -#if SQLITE_ENABLE_ZIPVFS +#ifdef SQLITE_ENABLE_ZIPVFS "ENABLE_ZIPVFS", #endif -#if SQLITE_EXPLAIN_ESTIMATED_ROWS +#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS "EXPLAIN_ESTIMATED_ROWS", #endif -#if SQLITE_EXTRA_IFNULLROW +#ifdef SQLITE_EXTRA_IFNULLROW "EXTRA_IFNULLROW", #endif #ifdef SQLITE_EXTRA_INIT @@ -362,10 +365,10 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_FTS3_MAX_EXPR_DEPTH "FTS3_MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_FTS3_MAX_EXPR_DEPTH), #endif -#if SQLITE_FTS5_ENABLE_TEST_MI +#ifdef SQLITE_FTS5_ENABLE_TEST_MI "FTS5_ENABLE_TEST_MI", #endif -#if SQLITE_FTS5_NO_WITHOUT_ROWID +#ifdef SQLITE_FTS5_NO_WITHOUT_ROWID "FTS5_NO_WITHOUT_ROWID", #endif #if HAVE_ISNAN || SQLITE_HAVE_ISNAN @@ -376,28 +379,28 @@ static const char * const sqlite3azCompileOpt[] = { "HOMEGROWN_RECURSIVE_MUTEX=" CTIMEOPT_VAL(SQLITE_HOMEGROWN_RECURSIVE_MUTEX), # endif #endif -#if SQLITE_IGNORE_AFP_LOCK_ERRORS +#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS "IGNORE_AFP_LOCK_ERRORS", #endif -#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS +#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS "IGNORE_FLOCK_LOCK_ERRORS", #endif -#if SQLITE_INLINE_MEMCPY +#ifdef SQLITE_INLINE_MEMCPY "INLINE_MEMCPY", #endif -#if SQLITE_INT64_TYPE +#ifdef SQLITE_INT64_TYPE "INT64_TYPE", #endif #ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX "INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX), #endif -#if SQLITE_LIKE_DOESNT_MATCH_BLOBS +#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS "LIKE_DOESNT_MATCH_BLOBS", #endif -#if SQLITE_LOCK_TRACE +#ifdef SQLITE_LOCK_TRACE "LOCK_TRACE", #endif -#if SQLITE_LOG_CACHE_SPILL +#ifdef SQLITE_LOG_CACHE_SPILL "LOG_CACHE_SPILL", #endif #ifdef SQLITE_MALLOC_SOFT_LIMIT @@ -460,190 +463,187 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_MAX_WORKER_THREADS "MAX_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_MAX_WORKER_THREADS), #endif -#if SQLITE_MEMDEBUG +#ifdef SQLITE_MEMDEBUG "MEMDEBUG", #endif -#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT +#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT "MIXED_ENDIAN_64BIT_FLOAT", #endif -#if SQLITE_MMAP_READWRITE +#ifdef SQLITE_MMAP_READWRITE "MMAP_READWRITE", #endif -#if SQLITE_MUTEX_NOOP +#ifdef SQLITE_MUTEX_NOOP "MUTEX_NOOP", #endif -#if SQLITE_MUTEX_OMIT +#ifdef SQLITE_MUTEX_OMIT "MUTEX_OMIT", #endif -#if SQLITE_MUTEX_PTHREADS +#ifdef SQLITE_MUTEX_PTHREADS "MUTEX_PTHREADS", #endif -#if SQLITE_MUTEX_W32 +#ifdef SQLITE_MUTEX_W32 "MUTEX_W32", #endif -#if SQLITE_NEED_ERR_NAME +#ifdef SQLITE_NEED_ERR_NAME "NEED_ERR_NAME", #endif -#if SQLITE_NOINLINE - "NOINLINE", -#endif -#if SQLITE_NO_SYNC +#ifdef SQLITE_NO_SYNC "NO_SYNC", #endif -#if SQLITE_OMIT_ALTERTABLE +#ifdef SQLITE_OMIT_ALTERTABLE "OMIT_ALTERTABLE", #endif -#if SQLITE_OMIT_ANALYZE +#ifdef SQLITE_OMIT_ANALYZE "OMIT_ANALYZE", #endif -#if SQLITE_OMIT_ATTACH +#ifdef SQLITE_OMIT_ATTACH "OMIT_ATTACH", #endif -#if SQLITE_OMIT_AUTHORIZATION +#ifdef SQLITE_OMIT_AUTHORIZATION "OMIT_AUTHORIZATION", #endif -#if SQLITE_OMIT_AUTOINCREMENT +#ifdef SQLITE_OMIT_AUTOINCREMENT "OMIT_AUTOINCREMENT", #endif -#if SQLITE_OMIT_AUTOINIT +#ifdef SQLITE_OMIT_AUTOINIT "OMIT_AUTOINIT", #endif -#if SQLITE_OMIT_AUTOMATIC_INDEX +#ifdef SQLITE_OMIT_AUTOMATIC_INDEX "OMIT_AUTOMATIC_INDEX", #endif -#if SQLITE_OMIT_AUTORESET +#ifdef SQLITE_OMIT_AUTORESET "OMIT_AUTORESET", #endif -#if SQLITE_OMIT_AUTOVACUUM +#ifdef SQLITE_OMIT_AUTOVACUUM "OMIT_AUTOVACUUM", #endif -#if SQLITE_OMIT_BETWEEN_OPTIMIZATION +#ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION "OMIT_BETWEEN_OPTIMIZATION", #endif -#if SQLITE_OMIT_BLOB_LITERAL +#ifdef SQLITE_OMIT_BLOB_LITERAL "OMIT_BLOB_LITERAL", #endif -#if SQLITE_OMIT_CAST +#ifdef SQLITE_OMIT_CAST "OMIT_CAST", #endif -#if SQLITE_OMIT_CHECK +#ifdef SQLITE_OMIT_CHECK "OMIT_CHECK", #endif -#if SQLITE_OMIT_COMPLETE +#ifdef SQLITE_OMIT_COMPLETE "OMIT_COMPLETE", #endif -#if SQLITE_OMIT_COMPOUND_SELECT +#ifdef SQLITE_OMIT_COMPOUND_SELECT "OMIT_COMPOUND_SELECT", #endif -#if SQLITE_OMIT_CONFLICT_CLAUSE +#ifdef SQLITE_OMIT_CONFLICT_CLAUSE "OMIT_CONFLICT_CLAUSE", #endif -#if SQLITE_OMIT_CTE +#ifdef SQLITE_OMIT_CTE "OMIT_CTE", #endif #if defined(SQLITE_OMIT_DATETIME_FUNCS) || defined(SQLITE_OMIT_FLOATING_POINT) "OMIT_DATETIME_FUNCS", #endif -#if SQLITE_OMIT_DECLTYPE +#ifdef SQLITE_OMIT_DECLTYPE "OMIT_DECLTYPE", #endif -#if SQLITE_OMIT_DEPRECATED +#ifdef SQLITE_OMIT_DEPRECATED "OMIT_DEPRECATED", #endif -#if SQLITE_OMIT_DESERIALIZE +#ifdef SQLITE_OMIT_DESERIALIZE "OMIT_DESERIALIZE", #endif -#if SQLITE_OMIT_DISKIO +#ifdef SQLITE_OMIT_DISKIO "OMIT_DISKIO", #endif -#if SQLITE_OMIT_EXPLAIN +#ifdef SQLITE_OMIT_EXPLAIN "OMIT_EXPLAIN", #endif -#if SQLITE_OMIT_FLAG_PRAGMAS +#ifdef SQLITE_OMIT_FLAG_PRAGMAS "OMIT_FLAG_PRAGMAS", #endif -#if SQLITE_OMIT_FLOATING_POINT +#ifdef SQLITE_OMIT_FLOATING_POINT "OMIT_FLOATING_POINT", #endif -#if SQLITE_OMIT_FOREIGN_KEY +#ifdef SQLITE_OMIT_FOREIGN_KEY "OMIT_FOREIGN_KEY", #endif -#if SQLITE_OMIT_GET_TABLE +#ifdef SQLITE_OMIT_GET_TABLE "OMIT_GET_TABLE", #endif -#if SQLITE_OMIT_HEX_INTEGER +#ifdef SQLITE_OMIT_HEX_INTEGER "OMIT_HEX_INTEGER", #endif -#if SQLITE_OMIT_INCRBLOB +#ifdef SQLITE_OMIT_INCRBLOB "OMIT_INCRBLOB", #endif -#if SQLITE_OMIT_INTEGRITY_CHECK +#ifdef SQLITE_OMIT_INTEGRITY_CHECK "OMIT_INTEGRITY_CHECK", #endif -#if SQLITE_OMIT_INTROSPECTION_PRAGMAS +#ifdef SQLITE_OMIT_INTROSPECTION_PRAGMAS "OMIT_INTROSPECTION_PRAGMAS", #endif -#if SQLITE_OMIT_LIKE_OPTIMIZATION +#ifdef SQLITE_OMIT_LIKE_OPTIMIZATION "OMIT_LIKE_OPTIMIZATION", #endif -#if SQLITE_OMIT_LOAD_EXTENSION +#ifdef SQLITE_OMIT_LOAD_EXTENSION "OMIT_LOAD_EXTENSION", #endif -#if SQLITE_OMIT_LOCALTIME +#ifdef SQLITE_OMIT_LOCALTIME "OMIT_LOCALTIME", #endif -#if SQLITE_OMIT_LOOKASIDE +#ifdef SQLITE_OMIT_LOOKASIDE "OMIT_LOOKASIDE", #endif -#if SQLITE_OMIT_MEMORYDB +#ifdef SQLITE_OMIT_MEMORYDB "OMIT_MEMORYDB", #endif -#if SQLITE_OMIT_OR_OPTIMIZATION +#ifdef SQLITE_OMIT_OR_OPTIMIZATION "OMIT_OR_OPTIMIZATION", #endif -#if SQLITE_OMIT_PAGER_PRAGMAS +#ifdef SQLITE_OMIT_PAGER_PRAGMAS "OMIT_PAGER_PRAGMAS", #endif -#if SQLITE_OMIT_PARSER_TRACE +#ifdef SQLITE_OMIT_PARSER_TRACE "OMIT_PARSER_TRACE", #endif -#if SQLITE_OMIT_POPEN +#ifdef SQLITE_OMIT_POPEN "OMIT_POPEN", #endif -#if SQLITE_OMIT_PRAGMA +#ifdef SQLITE_OMIT_PRAGMA "OMIT_PRAGMA", #endif -#if SQLITE_OMIT_PROGRESS_CALLBACK +#ifdef SQLITE_OMIT_PROGRESS_CALLBACK "OMIT_PROGRESS_CALLBACK", #endif -#if SQLITE_OMIT_QUICKBALANCE +#ifdef SQLITE_OMIT_QUICKBALANCE "OMIT_QUICKBALANCE", #endif -#if SQLITE_OMIT_REINDEX +#ifdef SQLITE_OMIT_REINDEX "OMIT_REINDEX", #endif -#if SQLITE_OMIT_SCHEMA_PRAGMAS +#ifdef SQLITE_OMIT_SCHEMA_PRAGMAS "OMIT_SCHEMA_PRAGMAS", #endif -#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS +#ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS "OMIT_SCHEMA_VERSION_PRAGMAS", #endif -#if SQLITE_OMIT_SHARED_CACHE +#ifdef SQLITE_OMIT_SHARED_CACHE "OMIT_SHARED_CACHE", #endif -#if SQLITE_OMIT_SHUTDOWN_DIRECTORIES +#ifdef SQLITE_OMIT_SHUTDOWN_DIRECTORIES "OMIT_SHUTDOWN_DIRECTORIES", #endif -#if SQLITE_OMIT_SUBQUERY +#ifdef SQLITE_OMIT_SUBQUERY "OMIT_SUBQUERY", #endif -#if SQLITE_OMIT_TCL_VARIABLE +#ifdef SQLITE_OMIT_TCL_VARIABLE "OMIT_TCL_VARIABLE", #endif -#if SQLITE_OMIT_TEMPDB +#ifdef SQLITE_OMIT_TEMPDB "OMIT_TEMPDB", #endif -#if SQLITE_OMIT_TEST_CONTROL +#ifdef SQLITE_OMIT_TEST_CONTROL "OMIT_TEST_CONTROL", #endif #ifdef SQLITE_OMIT_TRACE @@ -651,37 +651,37 @@ static const char * const sqlite3azCompileOpt[] = { "OMIT_TRACE=" CTIMEOPT_VAL(SQLITE_OMIT_TRACE), # endif #endif -#if SQLITE_OMIT_TRIGGER +#ifdef SQLITE_OMIT_TRIGGER "OMIT_TRIGGER", #endif -#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION +#ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION "OMIT_TRUNCATE_OPTIMIZATION", #endif -#if SQLITE_OMIT_UTF16 +#ifdef SQLITE_OMIT_UTF16 "OMIT_UTF16", #endif -#if SQLITE_OMIT_VACUUM +#ifdef SQLITE_OMIT_VACUUM "OMIT_VACUUM", #endif -#if SQLITE_OMIT_VIEW +#ifdef SQLITE_OMIT_VIEW "OMIT_VIEW", #endif -#if SQLITE_OMIT_VIRTUALTABLE +#ifdef SQLITE_OMIT_VIRTUALTABLE "OMIT_VIRTUALTABLE", #endif -#if SQLITE_OMIT_WAL +#ifdef SQLITE_OMIT_WAL "OMIT_WAL", #endif -#if SQLITE_OMIT_WSD +#ifdef SQLITE_OMIT_WSD "OMIT_WSD", #endif -#if SQLITE_OMIT_XFER_OPT +#ifdef SQLITE_OMIT_XFER_OPT "OMIT_XFER_OPT", #endif -#if SQLITE_PCACHE_SEPARATE_HEADER +#ifdef SQLITE_PCACHE_SEPARATE_HEADER "PCACHE_SEPARATE_HEADER", #endif -#if SQLITE_PERFORMANCE_TRACE +#ifdef SQLITE_PERFORMANCE_TRACE "PERFORMANCE_TRACE", #endif #ifdef SQLITE_POWERSAFE_OVERWRITE @@ -689,28 +689,28 @@ static const char * const sqlite3azCompileOpt[] = { "POWERSAFE_OVERWRITE=" CTIMEOPT_VAL(SQLITE_POWERSAFE_OVERWRITE), # endif #endif -#if SQLITE_PREFER_PROXY_LOCKING +#ifdef SQLITE_PREFER_PROXY_LOCKING "PREFER_PROXY_LOCKING", #endif -#if SQLITE_PROXY_DEBUG +#ifdef SQLITE_PROXY_DEBUG "PROXY_DEBUG", #endif -#if SQLITE_REVERSE_UNORDERED_SELECTS +#ifdef SQLITE_REVERSE_UNORDERED_SELECTS "REVERSE_UNORDERED_SELECTS", #endif -#if SQLITE_RTREE_INT_ONLY +#ifdef SQLITE_RTREE_INT_ONLY "RTREE_INT_ONLY", #endif -#if SQLITE_SECURE_DELETE +#ifdef SQLITE_SECURE_DELETE "SECURE_DELETE", #endif -#if SQLITE_SMALL_STACK +#ifdef SQLITE_SMALL_STACK "SMALL_STACK", #endif #ifdef SQLITE_SORTER_PMASZ "SORTER_PMASZ=" CTIMEOPT_VAL(SQLITE_SORTER_PMASZ), #endif -#if SQLITE_SOUNDEX +#ifdef SQLITE_SOUNDEX "SOUNDEX", #endif #ifdef SQLITE_STAT4_SAMPLES @@ -719,7 +719,7 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_STMTJRNL_SPILL "STMTJRNL_SPILL=" CTIMEOPT_VAL(SQLITE_STMTJRNL_SPILL), #endif -#if SQLITE_SUBSTR_COMPATIBILITY +#ifdef SQLITE_SUBSTR_COMPATIBILITY "SUBSTR_COMPATIBILITY", #endif #if (!defined(SQLITE_WIN32_MALLOC) \ @@ -728,13 +728,13 @@ static const char * const sqlite3azCompileOpt[] = { ) || defined(SQLITE_SYSTEM_MALLOC) "SYSTEM_MALLOC", #endif -#if SQLITE_TCL +#ifdef SQLITE_TCL "TCL", #endif #ifdef SQLITE_TEMP_STORE "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE), #endif -#if SQLITE_TEST +#ifdef SQLITE_TEST "TEST", #endif #if defined(SQLITE_THREADSAFE) @@ -744,31 +744,31 @@ static const char * const sqlite3azCompileOpt[] = { #else "THREADSAFE=1", #endif -#if SQLITE_UNLINK_AFTER_CLOSE +#ifdef SQLITE_UNLINK_AFTER_CLOSE "UNLINK_AFTER_CLOSE", #endif -#if SQLITE_UNTESTABLE +#ifdef SQLITE_UNTESTABLE "UNTESTABLE", #endif -#if SQLITE_USER_AUTHENTICATION +#ifdef SQLITE_USER_AUTHENTICATION "USER_AUTHENTICATION", #endif -#if SQLITE_USE_ALLOCA +#ifdef SQLITE_USE_ALLOCA "USE_ALLOCA", #endif -#if SQLITE_USE_FCNTL_TRACE +#ifdef SQLITE_USE_FCNTL_TRACE "USE_FCNTL_TRACE", #endif -#if SQLITE_USE_URI +#ifdef SQLITE_USE_URI "USE_URI", #endif -#if SQLITE_VDBE_COVERAGE +#ifdef SQLITE_VDBE_COVERAGE "VDBE_COVERAGE", #endif -#if SQLITE_WIN32_MALLOC +#ifdef SQLITE_WIN32_MALLOC "WIN32_MALLOC", #endif -#if SQLITE_ZERO_MALLOC +#ifdef SQLITE_ZERO_MALLOC "ZERO_MALLOC", #endif /* diff --git a/src/date.c b/src/date.c index f88f544e..20a0a5d1 100644 --- a/src/date.c +++ b/src/date.c @@ -1009,131 +1009,100 @@ static void strftimeFunc( sqlite3_value **argv ){ DateTime x; - u64 n; size_t i,j; - char *z; sqlite3 *db; const char *zFmt; - char zBuf[100]; + sqlite3_str sRes; + + if( argc==0 ) return; zFmt = (const char*)sqlite3_value_text(argv[0]); if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return; db = sqlite3_context_db_handle(context); - for(i=0, n=1; zFmt[i]; i++, n++){ - if( zFmt[i]=='%' ){ - switch( zFmt[i+1] ){ - case 'd': - case 'H': - case 'm': - case 'M': - case 'S': - case 'W': - n++; - /* fall thru */ - case 'w': - case '%': - break; - case 'f': - n += 8; - break; - case 'j': - n += 3; - break; - case 'Y': - n += 8; - break; - case 's': - case 'J': - n += 50; - break; - default: - return; /* ERROR. return a NULL */ - } - i++; - } - } - testcase( n==sizeof(zBuf)-1 ); - testcase( n==sizeof(zBuf) ); - testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH]+1 ); - testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ); - if( n(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ){ - sqlite3_result_error_toobig(context); - return; - }else{ - z = sqlite3DbMallocRawNN(db, (int)n); - if( z==0 ){ - sqlite3_result_error_nomem(context); - return; - } - } + sqlite3StrAccumInit(&sRes, 0, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); + computeJD(&x); computeYMD_HMS(&x); for(i=j=0; zFmt[i]; i++){ - if( zFmt[i]!='%' ){ - z[j++] = zFmt[i]; - }else{ - i++; - switch( zFmt[i] ){ - case 'd': sqlite3_snprintf(3, &z[j],"%02d",x.D); j+=2; break; - case 'f': { - double s = x.s; - if( s>59.999 ) s = 59.999; - sqlite3_snprintf(7, &z[j],"%06.3f", s); - j += sqlite3Strlen30(&z[j]); - break; - } - case 'H': sqlite3_snprintf(3, &z[j],"%02d",x.h); j+=2; break; - case 'W': /* Fall thru */ - case 'j': { - int nDay; /* Number of days since 1st day of year */ - DateTime y = x; - y.validJD = 0; - y.M = 1; - y.D = 1; - computeJD(&y); - nDay = (int)((x.iJD-y.iJD+43200000)/86400000); - if( zFmt[i]=='W' ){ - int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */ - wd = (int)(((x.iJD+43200000)/86400000)%7); - sqlite3_snprintf(3, &z[j],"%02d",(nDay+7-wd)/7); - j += 2; - }else{ - sqlite3_snprintf(4, &z[j],"%03d",nDay+1); - j += 3; - } - break; - } - case 'J': { - sqlite3_snprintf(20, &z[j],"%.16g",x.iJD/86400000.0); - j+=sqlite3Strlen30(&z[j]); - break; - } - case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break; - case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break; - case 's': { - i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000); - sqlite3Int64ToText(iS, &z[j]); - j += sqlite3Strlen30(&z[j]); - break; - } - case 'S': sqlite3_snprintf(3,&z[j],"%02d",(int)x.s); j+=2; break; - case 'w': { - z[j++] = (char)(((x.iJD+129600000)/86400000) % 7) + '0'; - break; - } - case 'Y': { - sqlite3_snprintf(5,&z[j],"%04d",x.Y); j+=sqlite3Strlen30(&z[j]); - break; + if( zFmt[i]!='%' ) continue; + if( j59.999 ) s = 59.999; + sqlite3_str_appendf(&sRes, "%06.3f", s); + break; + } + case 'H': { + sqlite3_str_appendf(&sRes, "%02d", x.h); + break; + } + case 'W': /* Fall thru */ + case 'j': { + int nDay; /* Number of days since 1st day of year */ + DateTime y = x; + y.validJD = 0; + y.M = 1; + y.D = 1; + computeJD(&y); + nDay = (int)((x.iJD-y.iJD+43200000)/86400000); + if( zFmt[i]=='W' ){ + int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */ + wd = (int)(((x.iJD+43200000)/86400000)%7); + sqlite3_str_appendf(&sRes,"%02d",(nDay+7-wd)/7); + }else{ + sqlite3_str_appendf(&sRes,"%03d",nDay+1); } - default: z[j++] = '%'; break; + break; + } + case 'J': { + sqlite3_str_appendf(&sRes,"%.16g",x.iJD/86400000.0); + break; + } + case 'm': { + sqlite3_str_appendf(&sRes,"%02d",x.M); + break; + } + case 'M': { + sqlite3_str_appendf(&sRes,"%02d",x.m); + break; + } + case 's': { + i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000); + sqlite3_str_appendf(&sRes,"%lld",iS); + break; + } + case 'S': { + sqlite3_str_appendf(&sRes,"%02d",(int)x.s); + break; + } + case 'w': { + sqlite3_str_appendchar(&sRes, 1, + (char)(((x.iJD+129600000)/86400000) % 7) + '0'); + break; + } + case 'Y': { + sqlite3_str_appendf(&sRes,"%04d",x.Y); + break; + } + case '%': { + sqlite3_str_appendchar(&sRes, 1, '%'); + break; + } + default: { + sqlite3_str_reset(&sRes); + return; } } } - z[j] = 0; - sqlite3_result_text(context, z, -1, - z==zBuf ? SQLITE_TRANSIENT : SQLITE_DYNAMIC); + if( jaPg; statClearCells(p); - sqlite3PagerUnref(p->pPg); sqlite3_free(p->zPath); memset(p, 0, sizeof(StatPage)); + p->aPg = aPg; } static void statResetCsr(StatCursor *pCsr){ int i; - sqlite3_reset(pCsr->pStmt); + /* In some circumstances, specifically if an OOM has occurred, the call + ** to sqlite3_reset() may cause the pager to be reset (emptied). It is + ** important that statClearPage() is called to free any page refs before + ** this happens. dbsqlfuzz 9ed3e4e3816219d3509d711636c38542bf3f40b1. */ for(i=0; iaPage); i++){ statClearPage(&pCsr->aPage[i]); + sqlite3_free(pCsr->aPage[i].aPg); + pCsr->aPage[i].aPg = 0; } + sqlite3_reset(pCsr->pStmt); pCsr->iPage = 0; sqlite3_free(pCsr->zPath); pCsr->zPath = 0; @@ -382,7 +397,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){ int isLeaf; int szPage; - u8 *aData = sqlite3PagerGetData(p->pPg); + u8 *aData = p->aPg; u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0]; p->flags = aHdr[0]; @@ -453,7 +468,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){ if( nPayload>(u32)nLocal ){ int j; int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4); - if( iOff+nLocal>nUsable || nPayload>0x7fffffff ){ + if( iOff+nLocal+4>nUsable || nPayload>0x7fffffff ){ goto statPageIsCorrupt; } pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4); @@ -513,6 +528,38 @@ static void statSizeAndOffset(StatCursor *pCsr){ } /* +** Load a copy of the page data for page iPg into the buffer belonging +** to page object pPg. Allocate the buffer if necessary. Return SQLITE_OK +** if successful, or an SQLite error code otherwise. +*/ +static int statGetPage( + Btree *pBt, /* Load page from this b-tree */ + u32 iPg, /* Page number to load */ + StatPage *pPg /* Load page into this object */ +){ + int pgsz = sqlite3BtreeGetPageSize(pBt); + DbPage *pDbPage = 0; + int rc; + + if( pPg->aPg==0 ){ + pPg->aPg = (u8*)sqlite3_malloc(pgsz + DBSTAT_PAGE_PADDING_BYTES); + if( pPg->aPg==0 ){ + return SQLITE_NOMEM_BKPT; + } + memset(&pPg->aPg[pgsz], 0, DBSTAT_PAGE_PADDING_BYTES); + } + + rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPg, &pDbPage, 0); + if( rc==SQLITE_OK ){ + const u8 *a = sqlite3PagerGetData(pDbPage); + memcpy(pPg->aPg, a, pgsz); + sqlite3PagerUnref(pDbPage); + } + + return rc; +} + +/* ** Move a DBSTAT cursor to the next entry. Normally, the next ** entry will be the next page, but in aggregated mode (pCsr->isAgg!=0), ** the next entry is the next btree. @@ -530,7 +577,7 @@ static int statNext(sqlite3_vtab_cursor *pCursor){ pCsr->zPath = 0; statNextRestart: - if( pCsr->aPage[0].pPg==0 ){ + if( pCsr->iPage<0 ){ /* Start measuring space on the next btree */ statResetCounts(pCsr); rc = sqlite3_step(pCsr->pStmt); @@ -542,7 +589,7 @@ statNextRestart: pCsr->isEof = 1; return sqlite3_reset(pCsr->pStmt); } - rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg, 0); + rc = statGetPage(pBt, iRoot, &pCsr->aPage[0]); pCsr->aPage[0].iPgno = iRoot; pCsr->aPage[0].iCell = 0; if( !pCsr->isAgg ){ @@ -593,9 +640,8 @@ statNextRestart: if( !p->iRightChildPg || p->iCell>p->nCell ){ statClearPage(p); - if( pCsr->iPage>0 ){ - pCsr->iPage--; - }else if( pCsr->isAgg ){ + pCsr->iPage--; + if( pCsr->isAgg && pCsr->iPage<0 ){ /* label-statNext-done: When computing aggregate space usage over ** an entire btree, this is the exit point from this function */ return SQLITE_OK; @@ -614,7 +660,7 @@ statNextRestart: }else{ p[1].iPgno = p->aCell[p->iCell].iChildPg; } - rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg, 0); + rc = statGetPage(pBt, p[1].iPgno, &p[1]); pCsr->nPage++; p[1].iCell = 0; if( !pCsr->isAgg ){ @@ -744,6 +790,7 @@ static int statFilter( } if( rc==SQLITE_OK ){ + pCsr->iPage = -1; rc = statNext(pCursor); } return rc; diff --git a/src/delete.c b/src/delete.c index dd074bb3..e2b283ea 100644 --- a/src/delete.c +++ b/src/delete.c @@ -84,7 +84,7 @@ int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){ return 1; } #ifndef SQLITE_OMIT_VIEW - if( !viewOk && pTab->pSelect ){ + if( !viewOk && IsView(pTab) ){ sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName); return 1; } @@ -188,13 +188,13 @@ Expr *sqlite3LimitWhere( }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); if( pPk->nKeyCol==1 ){ - const char *zName = pTab->aCol[pPk->aiColumn[0]].zName; + const char *zName = pTab->aCol[pPk->aiColumn[0]].zCnName; pLhs = sqlite3Expr(db, TK_ID, zName); pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, zName)); }else{ int i; for(i=0; inKeyCol; i++){ - Expr *p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zName); + Expr *p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zCnName); pEList = sqlite3ExprListAppend(pParse, pEList, p); } pLhs = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); @@ -210,6 +210,7 @@ Expr *sqlite3LimitWhere( pSelectSrc = sqlite3SrcListDup(db, pSrc, 0); pSrc->a[0].pTab = pTab; if( pSrc->a[0].fg.isIndexedBy ){ + assert( pSrc->a[0].fg.isCte==0 ); pSrc->a[0].u2.pIBIndex = 0; pSrc->a[0].fg.isIndexedBy = 0; sqlite3DbFree(db, pSrc->a[0].u1.zIndexedBy); @@ -301,7 +302,7 @@ void sqlite3DeleteFrom( */ #ifndef SQLITE_OMIT_TRIGGER pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); - isView = pTab->pSelect!=0; + isView = IsView(pTab); #else # define pTrigger 0 # define isView 0 @@ -551,7 +552,7 @@ void sqlite3DeleteFrom( if( eOnePass!=ONEPASS_OFF ){ assert( nKey==nPk ); /* OP_Found will use an unpacked key */ if( !IsVirtual(pTab) && aToOpen[iDataCur-iTabCur] ){ - assert( pPk!=0 || pTab->pSelect!=0 ); + assert( pPk!=0 || IsView(pTab) ); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey); VdbeCoverage(v); } @@ -785,7 +786,7 @@ void sqlite3GenerateRowDelete( ** the update-hook is not invoked for rows removed by REPLACE, but the ** pre-update-hook is. */ - if( pTab->pSelect==0 ){ + if( !IsView(pTab) ){ u8 p5 = 0; sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek); sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0)); diff --git a/src/expr.c b/src/expr.c index b751f51a..a51d37a7 100644 --- a/src/expr.c +++ b/src/expr.c @@ -21,9 +21,9 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piToFree); /* ** Return the affinity character for a single column of a table. */ -char sqlite3TableColumnAffinity(Table *pTab, int iCol){ - assert( iColnCol ); - return iCol>=0 ? pTab->aCol[iCol].affinity : SQLITE_AFF_INTEGER; +char sqlite3TableColumnAffinity(const Table *pTab, int iCol){ + if( iCol<0 || NEVER(iCol>=pTab->nCol) ) return SQLITE_AFF_INTEGER; + return pTab->aCol[iCol].affinity; } /* @@ -53,11 +53,14 @@ char sqlite3ExprAffinity(const Expr *pExpr){ } op = pExpr->op; if( op==TK_REGISTER ) op = pExpr->op2; - if( (op==TK_COLUMN || op==TK_AGG_COLUMN) && pExpr->y.pTab ){ - return sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); + if( op==TK_COLUMN || op==TK_AGG_COLUMN ){ + assert( ExprUseYTab(pExpr) ); + if( pExpr->y.pTab ){ + return sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); + } } if( op==TK_SELECT ){ - assert( pExpr->flags&EP_xIsSelect ); + assert( ExprUseXSelect(pExpr) ); assert( pExpr->x.pSelect!=0 ); assert( pExpr->x.pSelect->pEList!=0 ); assert( pExpr->x.pSelect->pEList->a[0].pExpr!=0 ); @@ -70,12 +73,15 @@ char sqlite3ExprAffinity(const Expr *pExpr){ } #endif if( op==TK_SELECT_COLUMN ){ - assert( pExpr->pLeft->flags&EP_xIsSelect ); + assert( pExpr->pLeft!=0 && ExprUseXSelect(pExpr->pLeft) ); + assert( pExpr->iColumn < pExpr->iTable ); + assert( pExpr->iTable==pExpr->pLeft->x.pSelect->pEList->nExpr ); return sqlite3ExprAffinity( pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr ); } if( op==TK_VECTOR ){ + assert( ExprUseXList(pExpr) ); return sqlite3ExprAffinity(pExpr->x.pList->a[0].pExpr); } return pExpr->affExpr; @@ -90,7 +96,7 @@ char sqlite3ExprAffinity(const Expr *pExpr){ ** and the pExpr parameter is returned unchanged. */ Expr *sqlite3ExprAddCollateToken( - Parse *pParse, /* Parsing context */ + const Parse *pParse, /* Parsing context */ Expr *pExpr, /* Add the "COLLATE" clause to this expression */ const Token *pCollName, /* Name of collating sequence */ int dequote /* True to dequote pCollName */ @@ -105,7 +111,11 @@ Expr *sqlite3ExprAddCollateToken( } return pExpr; } -Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){ +Expr *sqlite3ExprAddCollateString( + const Parse *pParse, /* Parsing context */ + Expr *pExpr, /* Add the "COLLATE" clause to this expression */ + const char *zC /* The collating sequence name */ +){ Token s; assert( zC!=0 ); sqlite3TokenInit(&s, (char*)zC); @@ -131,7 +141,7 @@ Expr *sqlite3ExprSkipCollate(Expr *pExpr){ Expr *sqlite3ExprSkipCollateAndLikely(Expr *pExpr){ while( pExpr && ExprHasProperty(pExpr, EP_Skip|EP_Unlikely) ){ if( ExprHasProperty(pExpr, EP_Unlikely) ){ - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + assert( ExprUseXList(pExpr) ); assert( pExpr->x.pList->nExpr>0 ); assert( pExpr->op==TK_FUNCTION ); pExpr = pExpr->x.pList->a[0].pExpr; @@ -164,27 +174,30 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){ while( p ){ int op = p->op; if( op==TK_REGISTER ) op = p->op2; - if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_TRIGGER) - && p->y.pTab!=0 - ){ - /* op==TK_REGISTER && p->y.pTab!=0 happens when pExpr was originally - ** a TK_COLUMN but was previously evaluated and cached in a register */ - int j = p->iColumn; - if( j>=0 ){ - const char *zColl = p->y.pTab->aCol[j].zColl; - pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0); + if( op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_TRIGGER ){ + assert( ExprUseYTab(p) ); + if( p->y.pTab!=0 ){ + /* op==TK_REGISTER && p->y.pTab!=0 happens when pExpr was originally + ** a TK_COLUMN but was previously evaluated and cached in a register */ + int j = p->iColumn; + if( j>=0 ){ + const char *zColl = sqlite3ColumnColl(&p->y.pTab->aCol[j]); + pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0); + } + break; } - break; } if( op==TK_CAST || op==TK_UPLUS ){ p = p->pLeft; continue; } if( op==TK_VECTOR ){ + assert( ExprUseXList(p) ); p = p->x.pList->a[0].pExpr; continue; } if( op==TK_COLLATE ){ + assert( !ExprHasProperty(p, EP_IntValue) ); pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken); break; } @@ -194,11 +207,9 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){ }else{ Expr *pNext = p->pRight; /* The Expr.x union is never used at the same time as Expr.pRight */ + assert( ExprUseXList(p) ); assert( p->x.pList==0 || p->pRight==0 ); - if( p->x.pList!=0 - && !db->mallocFailed - && ALWAYS(!ExprHasProperty(p, EP_xIsSelect)) - ){ + if( p->x.pList!=0 && !db->mallocFailed ){ int i; for(i=0; ALWAYS(ix.pList->nExpr); i++){ if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){ @@ -281,7 +292,7 @@ static char comparisonAffinity(const Expr *pExpr){ aff = sqlite3ExprAffinity(pExpr->pLeft); if( pExpr->pRight ){ aff = sqlite3CompareAffinity(pExpr->pRight, aff); - }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + }else if( ExprUseXSelect(pExpr) ){ aff = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr, aff); }else if( aff==0 ){ aff = SQLITE_AFF_BLOB; @@ -407,7 +418,7 @@ static int codeCompare( ** But a TK_SELECT might be either a vector or a scalar. It is only ** considered a vector if it has two or more result columns. */ -int sqlite3ExprIsVector(Expr *pExpr){ +int sqlite3ExprIsVector(const Expr *pExpr){ return sqlite3ExprVectorSize(pExpr)>1; } @@ -417,12 +428,14 @@ int sqlite3ExprIsVector(Expr *pExpr){ ** is a sub-select, return the number of columns in the sub-select. For ** any other type of expression, return 1. */ -int sqlite3ExprVectorSize(Expr *pExpr){ +int sqlite3ExprVectorSize(const Expr *pExpr){ u8 op = pExpr->op; if( op==TK_REGISTER ) op = pExpr->op2; if( op==TK_VECTOR ){ + assert( ExprUseXList(pExpr) ); return pExpr->x.pList->nExpr; }else if( op==TK_SELECT ){ + assert( ExprUseXSelect(pExpr) ); return pExpr->x.pSelect->pEList->nExpr; }else{ return 1; @@ -449,8 +462,10 @@ Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){ if( sqlite3ExprIsVector(pVector) ){ assert( pVector->op2==0 || pVector->op==TK_REGISTER ); if( pVector->op==TK_SELECT || pVector->op2==TK_SELECT ){ + assert( ExprUseXSelect(pVector) ); return pVector->x.pSelect->pEList->a[i].pExpr; }else{ + assert( ExprUseXList(pVector) ); return pVector->x.pList->a[i].pExpr; } } @@ -481,11 +496,12 @@ Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){ Expr *sqlite3ExprForVectorField( Parse *pParse, /* Parsing context */ Expr *pVector, /* The vector. List of expressions or a sub-SELECT */ - int iField /* Which column of the vector to return */ + int iField, /* Which column of the vector to return */ + int nField /* Total number of columns in the vector */ ){ Expr *pRet; if( pVector->op==TK_SELECT ){ - assert( pVector->flags & EP_xIsSelect ); + assert( ExprUseXSelect(pVector) ); /* The TK_SELECT_COLUMN Expr node: ** ** pLeft: pVector containing TK_SELECT. Not deleted. @@ -504,14 +520,23 @@ Expr *sqlite3ExprForVectorField( */ pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, 0, 0); if( pRet ){ + pRet->iTable = nField; pRet->iColumn = iField; pRet->pLeft = pVector; } - assert( pRet==0 || pRet->iTable==0 ); }else{ - if( pVector->op==TK_VECTOR ) pVector = pVector->x.pList->a[iField].pExpr; + if( pVector->op==TK_VECTOR ){ + Expr **ppVector; + assert( ExprUseXList(pVector) ); + ppVector = &pVector->x.pList->a[iField].pExpr; + pVector = *ppVector; + if( IN_RENAME_OBJECT ){ + /* This must be a vector UPDATE inside a trigger */ + *ppVector = 0; + return pVector; + } + } pRet = sqlite3ExprDup(pParse->db, pVector, 0); - sqlite3RenameTokenRemap(pParse, pRet, pVector); } return pRet; } @@ -567,10 +592,12 @@ static int exprVectorRegister( return pVector->iTable+iField; } if( op==TK_SELECT ){ + assert( ExprUseXSelect(pVector) ); *ppExpr = pVector->x.pSelect->pEList->a[iField].pExpr; return regSelect+iField; } if( op==TK_VECTOR ){ + assert( ExprUseXList(pVector) ); *ppExpr = pVector->x.pList->a[iField].pExpr; return sqlite3ExprCodeTemp(pParse, *ppExpr, pRegFree); } @@ -704,14 +731,14 @@ int sqlite3ExprCheckHeight(Parse *pParse, int nHeight){ ** to by pnHeight, the second parameter, then set *pnHeight to that ** value. */ -static void heightOfExpr(Expr *p, int *pnHeight){ +static void heightOfExpr(const Expr *p, int *pnHeight){ if( p ){ if( p->nHeight>*pnHeight ){ *pnHeight = p->nHeight; } } } -static void heightOfExprList(ExprList *p, int *pnHeight){ +static void heightOfExprList(const ExprList *p, int *pnHeight){ if( p ){ int i; for(i=0; inExpr; i++){ @@ -719,8 +746,8 @@ static void heightOfExprList(ExprList *p, int *pnHeight){ } } } -static void heightOfSelect(Select *pSelect, int *pnHeight){ - Select *p; +static void heightOfSelect(const Select *pSelect, int *pnHeight){ + const Select *p; for(p=pSelect; p; p=p->pPrior){ heightOfExpr(p->pWhere, pnHeight); heightOfExpr(p->pHaving, pnHeight); @@ -745,7 +772,7 @@ static void exprSetHeight(Expr *p){ int nHeight = 0; heightOfExpr(p->pLeft, &nHeight); heightOfExpr(p->pRight, &nHeight); - if( ExprHasProperty(p, EP_xIsSelect) ){ + if( ExprUseXSelect(p) ){ heightOfSelect(p->x.pSelect, &nHeight); }else if( p->x.pList ){ heightOfExprList(p->x.pList, &nHeight); @@ -772,7 +799,7 @@ void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){ ** Return the maximum height of any expression tree referenced ** by the select statement passed as an argument. */ -int sqlite3SelectExprHeight(Select *p){ +int sqlite3SelectExprHeight(const Select *p){ int nHeight = 0; heightOfSelect(p, &nHeight); return nHeight; @@ -784,7 +811,7 @@ int sqlite3SelectExprHeight(Select *p){ */ void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){ if( pParse->nErr ) return; - if( p && p->x.pList && !ExprHasProperty(p, EP_xIsSelect) ){ + if( p && ExprUseXList(p) && p->x.pList ){ p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList); } } @@ -942,6 +969,63 @@ void sqlite3PExprAddSelect(Parse *pParse, Expr *pExpr, Select *pSelect){ } } +/* +** Expression list pEList is a list of vector values. This function +** converts the contents of pEList to a VALUES(...) Select statement +** returning 1 row for each element of the list. For example, the +** expression list: +** +** ( (1,2), (3,4) (5,6) ) +** +** is translated to the equivalent of: +** +** VALUES(1,2), (3,4), (5,6) +** +** Each of the vector values in pEList must contain exactly nElem terms. +** If a list element that is not a vector or does not contain nElem terms, +** an error message is left in pParse. +** +** This is used as part of processing IN(...) expressions with a list +** of vectors on the RHS. e.g. "... IN ((1,2), (3,4), (5,6))". +*/ +Select *sqlite3ExprListToValues(Parse *pParse, int nElem, ExprList *pEList){ + int ii; + Select *pRet = 0; + assert( nElem>1 ); + for(ii=0; iinExpr; ii++){ + Select *pSel; + Expr *pExpr = pEList->a[ii].pExpr; + int nExprElem; + if( pExpr->op==TK_VECTOR ){ + assert( ExprUseXList(pExpr) ); + nExprElem = pExpr->x.pList->nExpr; + }else{ + nExprElem = 1; + } + if( nExprElem!=nElem ){ + sqlite3ErrorMsg(pParse, "IN(...) element has %d term%s - expected %d", + nExprElem, nExprElem>1?"s":"", nElem + ); + break; + } + assert( ExprUseXList(pExpr) ); + pSel = sqlite3SelectNew(pParse, pExpr->x.pList, 0, 0, 0, 0, 0, SF_Values,0); + pExpr->x.pList = 0; + if( pSel ){ + if( pRet ){ + pSel->op = TK_ALL; + pSel->pPrior = pRet; + } + pRet = pSel; + } + } + + if( pRet && pRet->pPrior ){ + pRet->selFlags |= SF_MultiValue; + } + sqlite3ExprListDelete(pParse->db, pEList); + return pRet; +} /* ** Join two expressions using an AND operator. If either expression is @@ -975,7 +1059,7 @@ Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){ Expr *sqlite3ExprFunction( Parse *pParse, /* Parsing context */ ExprList *pList, /* Argument list */ - Token *pToken, /* Name of the function */ + const Token *pToken, /* Name of the function */ int eDistinct /* SF_Distinct or SF_ALL or 0 */ ){ Expr *pNew; @@ -986,12 +1070,15 @@ Expr *sqlite3ExprFunction( sqlite3ExprListDelete(db, pList); /* Avoid memory leak when malloc fails */ return 0; } - if( pList && pList->nExpr > pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){ + if( pList + && pList->nExpr > pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] + && !pParse->nested + ){ sqlite3ErrorMsg(pParse, "too many arguments on function %T", pToken); } pNew->x.pList = pList; ExprSetProperty(pNew, EP_HasFunc); - assert( !ExprHasProperty(pNew, EP_xIsSelect) ); + assert( ExprUseXList(pNew) ); sqlite3ExprSetHeightAndFlags(pParse, pNew); if( eDistinct==SF_Distinct ) ExprSetProperty(pNew, EP_Distinct); return pNew; @@ -1010,8 +1097,8 @@ Expr *sqlite3ExprFunction( */ void sqlite3ExprFunctionUsable( Parse *pParse, /* Parsing and code generating context */ - Expr *pExpr, /* The function invocation */ - FuncDef *pDef /* The function being invoked */ + const Expr *pExpr, /* The function invocation */ + const FuncDef *pDef /* The function being invoked */ ){ assert( !IN_RENAME_OBJECT ); assert( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 ); @@ -1117,27 +1204,26 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n){ */ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){ assert( p!=0 ); - /* Sanity check: Assert that the IntValue is non-negative if it exists */ - assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 ); - - assert( !ExprHasProperty(p, EP_WinFunc) || p->y.pWin!=0 || db->mallocFailed ); - assert( p->op!=TK_FUNCTION || ExprHasProperty(p, EP_TokenOnly|EP_Reduced) - || p->y.pWin==0 || ExprHasProperty(p, EP_WinFunc) ); + assert( !ExprUseUValue(p) || p->u.iValue>=0 ); + assert( !ExprUseYWin(p) || !ExprUseYSub(p) ); + assert( !ExprUseYWin(p) || p->y.pWin!=0 || db->mallocFailed ); + assert( p->op!=TK_FUNCTION || !ExprUseYSub(p) ); #ifdef SQLITE_DEBUG if( ExprHasProperty(p, EP_Leaf) && !ExprHasProperty(p, EP_TokenOnly) ){ assert( p->pLeft==0 ); assert( p->pRight==0 ); - assert( p->x.pSelect==0 ); + assert( !ExprUseXSelect(p) || p->x.pSelect==0 ); + assert( !ExprUseXList(p) || p->x.pList==0 ); } #endif if( !ExprHasProperty(p, (EP_TokenOnly|EP_Leaf)) ){ /* The Expr.x union is never used at the same time as Expr.pRight */ - assert( p->x.pList==0 || p->pRight==0 ); + assert( (ExprUseXList(p) && p->x.pList==0) || p->pRight==0 ); if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft); if( p->pRight ){ assert( !ExprHasProperty(p, EP_WinFunc) ); sqlite3ExprDeleteNN(db, p->pRight); - }else if( ExprHasProperty(p, EP_xIsSelect) ){ + }else if( ExprUseXSelect(p) ){ assert( !ExprHasProperty(p, EP_WinFunc) ); sqlite3SelectDelete(db, p->x.pSelect); }else{ @@ -1149,7 +1235,10 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){ #endif } } - if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken); + if( ExprHasProperty(p, EP_MemToken) ){ + assert( !ExprHasProperty(p, EP_IntValue) ); + sqlite3DbFree(db, p->u.zToken); + } if( !ExprHasProperty(p, EP_Static) ){ sqlite3DbFreeNN(db, p); } @@ -1191,7 +1280,7 @@ void sqlite3ExprUnmapAndDelete(Parse *pParse, Expr *p){ ** passed as the first argument. This is always one of EXPR_FULLSIZE, ** EXPR_REDUCEDSIZE or EXPR_TOKENONLYSIZE. */ -static int exprStructSize(Expr *p){ +static int exprStructSize(const Expr *p){ if( ExprHasProperty(p, EP_TokenOnly) ) return EXPR_TOKENONLYSIZE; if( ExprHasProperty(p, EP_Reduced) ) return EXPR_REDUCEDSIZE; return EXPR_FULLSIZE; @@ -1231,7 +1320,7 @@ static int exprStructSize(Expr *p){ ** of dupedExprStructSize() contain multiple assert() statements that attempt ** to enforce this constraint. */ -static int dupedExprStructSize(Expr *p, int flags){ +static int dupedExprStructSize(const Expr *p, int flags){ int nSize; assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */ assert( EXPR_FULLSIZE<=0xfff ); @@ -1262,7 +1351,7 @@ static int dupedExprStructSize(Expr *p, int flags){ ** of the Expr structure and a copy of the Expr.u.zToken string (if that ** string is defined.) */ -static int dupedExprNodeSize(Expr *p, int flags){ +static int dupedExprNodeSize(const Expr *p, int flags){ int nByte = dupedExprStructSize(p, flags) & 0xfff; if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){ nByte += sqlite3Strlen30NN(p->u.zToken)+1; @@ -1283,7 +1372,7 @@ static int dupedExprNodeSize(Expr *p, int flags){ ** and Expr.pRight variables (but not for any structures pointed to or ** descended from the Expr.x.pList or Expr.x.pSelect variables). */ -static int dupedExprSize(Expr *p, int flags){ +static int dupedExprSize(const Expr *p, int flags){ int nByte = 0; if( p ){ nByte = dupedExprNodeSize(p, flags); @@ -1302,7 +1391,7 @@ static int dupedExprSize(Expr *p, int flags){ ** if any. Before returning, *pzBuffer is set to the first byte past the ** portion of the buffer copied into by this function. */ -static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ +static Expr *exprDup(sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer){ Expr *pNew; /* Value to return */ u8 *zAlloc; /* Memory space from which to build Expr object */ u32 staticFlag; /* EP_Static if space not obtained from malloc */ @@ -1365,7 +1454,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_Leaf)) ){ /* Fill in the pNew->x.pSelect or pNew->x.pList member. */ - if( ExprHasProperty(p, EP_xIsSelect) ){ + if( ExprUseXSelect(p) ){ pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, dupFlags); }else{ pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, dupFlags); @@ -1394,7 +1483,6 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){ if( pNew->op==TK_SELECT_COLUMN ){ pNew->pLeft = p->pLeft; - assert( p->iColumn==0 || p->pRight==0 ); assert( p->pRight==0 || p->pRight==p->pLeft || ExprHasProperty(p->pLeft, EP_Subquery) ); }else{ @@ -1484,15 +1572,17 @@ static void gatherSelectWindows(Select *p){ ** truncated version of the usual Expr structure that will be stored as ** part of the in-memory representation of the database schema. */ -Expr *sqlite3ExprDup(sqlite3 *db, Expr *p, int flags){ +Expr *sqlite3ExprDup(sqlite3 *db, const Expr *p, int flags){ assert( flags==0 || flags==EXPRDUP_REDUCE ); return p ? exprDup(db, p, flags, 0) : 0; } -ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){ +ExprList *sqlite3ExprListDup(sqlite3 *db, const ExprList *p, int flags){ ExprList *pNew; - struct ExprList_item *pItem, *pOldItem; + struct ExprList_item *pItem; + const struct ExprList_item *pOldItem; int i; - Expr *pPriorSelectCol = 0; + Expr *pPriorSelectColOld = 0; + Expr *pPriorSelectColNew = 0; assert( db!=0 ); if( p==0 ) return 0; pNew = sqlite3DbMallocRawNN(db, sqlite3DbMallocSize(db, p)); @@ -1509,17 +1599,17 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){ && pOldExpr->op==TK_SELECT_COLUMN && (pNewExpr = pItem->pExpr)!=0 ){ - assert( pNewExpr->iColumn==0 || i>0 ); - if( pNewExpr->iColumn==0 ){ - assert( pOldExpr->pLeft==pOldExpr->pRight - || ExprHasProperty(pOldExpr->pLeft, EP_Subquery) ); - pPriorSelectCol = pNewExpr->pLeft = pNewExpr->pRight; + if( pNewExpr->pRight ){ + pPriorSelectColOld = pOldExpr->pRight; + pPriorSelectColNew = pNewExpr->pRight; + pNewExpr->pLeft = pNewExpr->pRight; }else{ - assert( i>0 ); - assert( pItem[-1].pExpr!=0 ); - assert( pNewExpr->iColumn==pItem[-1].pExpr->iColumn+1 ); - assert( pPriorSelectCol==pItem[-1].pExpr->pLeft ); - pNewExpr->pLeft = pPriorSelectCol; + if( pOldExpr->pLeft!=pPriorSelectColOld ){ + pPriorSelectColOld = pOldExpr->pLeft; + pPriorSelectColNew = sqlite3ExprDup(db, pPriorSelectColOld, flags); + pNewExpr->pRight = pPriorSelectColNew; + } + pNewExpr->pLeft = pPriorSelectColNew; } } pItem->zEName = sqlite3DbStrDup(db, pOldItem->zEName); @@ -1541,7 +1631,7 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){ */ #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) \ || !defined(SQLITE_OMIT_SUBQUERY) -SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){ +SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){ SrcList *pNew; int i; int nByte; @@ -1553,7 +1643,7 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){ pNew->nSrc = pNew->nAlloc = p->nSrc; for(i=0; inSrc; i++){ SrcItem *pNewItem = &pNew->a[i]; - SrcItem *pOldItem = &p->a[i]; + const SrcItem *pOldItem = &p->a[i]; Table *pTab; pNewItem->pSchema = pOldItem->pSchema; pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase); @@ -1585,7 +1675,7 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){ } return pNew; } -IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){ +IdList *sqlite3IdListDup(sqlite3 *db, const IdList *p){ IdList *pNew; int i; assert( db!=0 ); @@ -1609,11 +1699,11 @@ IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){ } return pNew; } -Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){ +Select *sqlite3SelectDup(sqlite3 *db, const Select *pDup, int flags){ Select *pRet = 0; Select *pNext = 0; Select **pp = &pRet; - Select *p; + const Select *p; assert( db!=0 ); for(p=pDup; p; p=p->pPrior){ @@ -1658,7 +1748,7 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){ return pRet; } #else -Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){ +Select *sqlite3SelectDup(sqlite3 *db, const Select *p, int flags){ assert( p==0 ); return 0; } @@ -1778,11 +1868,9 @@ ExprList *sqlite3ExprListAppendVector( } for(i=0; inId; i++){ - Expr *pSubExpr = sqlite3ExprForVectorField(pParse, pExpr, i); + Expr *pSubExpr = sqlite3ExprForVectorField(pParse, pExpr, i, pColumns->nId); assert( pSubExpr!=0 || db->mallocFailed ); - assert( pSubExpr==0 || pSubExpr->iTable==0 ); if( pSubExpr==0 ) continue; - pSubExpr->iTable = pColumns->nId; pList = sqlite3ExprListAppend(pParse, pList, pSubExpr); if( pList ){ assert( pList->nExpr==iFirst+i+1 ); @@ -1856,7 +1944,7 @@ void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder, int eNulls){ void sqlite3ExprListSetName( Parse *pParse, /* Parsing context */ ExprList *pList, /* List to which to add the span. */ - Token *pName, /* Name to be added */ + const Token *pName, /* Name to be added */ int dequote /* True to cause the name to be dequoted */ ){ assert( pList!=0 || pParse->db->mallocFailed!=0 ); @@ -1874,7 +1962,7 @@ void sqlite3ExprListSetName( ** to the token-map. */ sqlite3Dequote(pItem->zEName); if( IN_RENAME_OBJECT ){ - sqlite3RenameTokenMap(pParse, (void*)pItem->zEName, pName); + sqlite3RenameTokenMap(pParse, (const void*)pItem->zEName, pName); } } } @@ -1993,7 +2081,7 @@ u32 sqlite3IsTrueOrFalse(const char *zIn){ int sqlite3ExprIdToTrueFalse(Expr *pExpr){ u32 v; assert( pExpr->op==TK_ID || pExpr->op==TK_STRING ); - if( !ExprHasProperty(pExpr, EP_Quoted) + if( !ExprHasProperty(pExpr, EP_Quoted|EP_IntValue) && (v = sqlite3IsTrueOrFalse(pExpr->u.zToken))!=0 ){ pExpr->op = TK_TRUEFALSE; @@ -2010,6 +2098,7 @@ int sqlite3ExprIdToTrueFalse(Expr *pExpr){ int sqlite3ExprTruthValue(const Expr *pExpr){ pExpr = sqlite3ExprSkipCollate((Expr*)pExpr); assert( pExpr->op==TK_TRUEFALSE ); + assert( !ExprHasProperty(pExpr, EP_IntValue) ); assert( sqlite3StrICmp(pExpr->u.zToken,"true")==0 || sqlite3StrICmp(pExpr->u.zToken,"false")==0 ); return pExpr->u.zToken[4]==0; @@ -2214,7 +2303,7 @@ static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){ } /* Check if pExpr is a sub-select. If so, consider it variable. */ - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( ExprUseXSelect(pExpr) ){ pWalker->eCode = 0; return WRC_Abort; } @@ -2302,7 +2391,7 @@ int sqlite3ExprContainsSubquery(Expr *p){ ** in *pValue. If the expression is not an integer or if it is too big ** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged. */ -int sqlite3ExprIsInteger(Expr *p, int *pValue){ +int sqlite3ExprIsInteger(const Expr *p, int *pValue){ int rc = 0; if( NEVER(p==0) ) return 0; /* Used to only happen following on OOM */ @@ -2321,9 +2410,9 @@ int sqlite3ExprIsInteger(Expr *p, int *pValue){ break; } case TK_UMINUS: { - int v; + int v = 0; if( sqlite3ExprIsInteger(p->pLeft, &v) ){ - assert( v!=(-2147483647-1) ); + assert( ((unsigned int)v)!=0x80000000 ); *pValue = -v; rc = 1; } @@ -2364,10 +2453,11 @@ int sqlite3ExprCanBeNull(const Expr *p){ case TK_BLOB: return 0; case TK_COLUMN: + assert( ExprUseYTab(p) ); return ExprHasProperty(p, EP_CanBeNull) || p->y.pTab==0 || /* Reference to column of index on expression */ (p->iColumn>=0 - && ALWAYS(p->y.pTab->aCol!=0) /* Defense against OOM problems */ + && p->y.pTab->aCol!=0 /* Possible due to prior error */ && p->y.pTab->aCol[p->iColumn].notNull==0); default: return 1; @@ -2435,13 +2525,13 @@ int sqlite3IsRowid(const char *z){ ** table, then return NULL. */ #ifndef SQLITE_OMIT_SUBQUERY -static Select *isCandidateForInOpt(Expr *pX){ +static Select *isCandidateForInOpt(const Expr *pX){ Select *p; SrcList *pSrc; ExprList *pEList; Table *pTab; int i; - if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0; /* Not a subquery */ + if( !ExprUseXSelect(pX) ) return 0; /* Not a subquery */ if( ExprHasProperty(pX, EP_VarSelect) ) return 0; /* Correlated subq */ p = pX->x.pSelect; if( p->pPrior ) return 0; /* Not a compound SELECT */ @@ -2459,7 +2549,7 @@ static Select *isCandidateForInOpt(Expr *pX){ if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */ pTab = pSrc->a[0].pTab; assert( pTab!=0 ); - assert( pTab->pSelect==0 ); /* FROM clause is not a view */ + assert( !IsView(pTab) ); /* FROM clause is not a view */ if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */ pEList = p->pEList; assert( pEList!=0 ); @@ -2612,7 +2702,7 @@ int sqlite3FindInIndex( ** or not NULL is actually possible (it may not be, for example, due ** to NOT NULL constraints in the schema). If no NULL values are possible, ** set prRhsHasNull to 0 before continuing. */ - if( prRhsHasNull && (pX->flags & EP_xIsSelect) ){ + if( prRhsHasNull && ExprUseXSelect(pX) ){ int i; ExprList *pEList = pX->x.pSelect->pEList; for(i=0; inExpr; i++){ @@ -2713,7 +2803,8 @@ int sqlite3FindInIndex( CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs); int j; - assert( pReq!=0 || pRhs->iColumn==XN_ROWID || pParse->nErr ); + assert( pReq!=0 || pRhs->iColumn==XN_ROWID + || pParse->nErr || db->mallocFailed ); for(j=0; jaiColumn[j]!=pRhs->iColumn ) continue; assert( pIdx->azColl[j] ); @@ -2768,7 +2859,7 @@ int sqlite3FindInIndex( */ if( eType==0 && (inFlags & IN_INDEX_NOOP_OK) - && !ExprHasProperty(pX, EP_xIsSelect) + && ExprUseXList(pX) && (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2) ){ eType = IN_INDEX_NOOP; @@ -2813,10 +2904,10 @@ int sqlite3FindInIndex( ** It is the responsibility of the caller to ensure that the returned ** string is eventually freed using sqlite3DbFree(). */ -static char *exprINAffinity(Parse *pParse, Expr *pExpr){ +static char *exprINAffinity(Parse *pParse, const Expr *pExpr){ Expr *pLeft = pExpr->pLeft; int nVal = sqlite3ExprVectorSize(pLeft); - Select *pSelect = (pExpr->flags & EP_xIsSelect) ? pExpr->x.pSelect : 0; + Select *pSelect = ExprUseXSelect(pExpr) ? pExpr->x.pSelect : 0; char *zRet; assert( pExpr->op==TK_IN ); @@ -2866,7 +2957,7 @@ void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){ */ void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){ #ifndef SQLITE_OMIT_SUBQUERY - if( pExpr->flags & EP_xIsSelect ){ + if( ExprUseXSelect(pExpr) ){ sqlite3SubselectError(pParse, pExpr->x.pSelect->pEList->nExpr, 1); }else #endif @@ -2930,10 +3021,11 @@ void sqlite3CodeRhsOfIN( */ if( ExprHasProperty(pExpr, EP_Subrtn) ){ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( ExprUseXSelect(pExpr) ){ ExplainQueryPlan((pParse, 0, "REUSE LIST SUBQUERY %d", pExpr->x.pSelect->selId)); } + assert( ExprUseYSub(pExpr) ); sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn, pExpr->y.sub.iAddr); sqlite3VdbeAddOp2(v, OP_OpenDup, iTab, pExpr->iTable); @@ -2942,6 +3034,7 @@ void sqlite3CodeRhsOfIN( } /* Begin coding the subroutine */ + assert( !ExprUseYWin(pExpr) ); ExprSetProperty(pExpr, EP_Subrtn); assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); pExpr->y.sub.regReturn = ++pParse->nMem; @@ -2962,7 +3055,7 @@ void sqlite3CodeRhsOfIN( pExpr->iTable = iTab; addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, nVal); #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( ExprUseXSelect(pExpr) ){ VdbeComment((v, "Result of SELECT %u", pExpr->x.pSelect->selId)); }else{ VdbeComment((v, "RHS of IN operator")); @@ -2970,7 +3063,7 @@ void sqlite3CodeRhsOfIN( #endif pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, nVal, 1); - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( ExprUseXSelect(pExpr) ){ /* Case 1: expr IN (SELECT ...) ** ** Generate code to write the results of the select into the temporary @@ -3068,6 +3161,7 @@ void sqlite3CodeRhsOfIN( if( addrOnce ){ sqlite3VdbeJumpHere(v, addrOnce); /* Subroutine return */ + assert( ExprUseYSub(pExpr) ); sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn); sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1); sqlite3ClearTempRegCache(pParse); @@ -3104,19 +3198,22 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ testcase( pExpr->op==TK_EXISTS ); testcase( pExpr->op==TK_SELECT ); assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT ); - assert( ExprHasProperty(pExpr, EP_xIsSelect) ); + assert( ExprUseXSelect(pExpr) ); pSel = pExpr->x.pSelect; /* If this routine has already been coded, then invoke it as a ** subroutine. */ if( ExprHasProperty(pExpr, EP_Subrtn) ){ ExplainQueryPlan((pParse, 0, "REUSE SUBQUERY %d", pSel->selId)); + assert( ExprUseYSub(pExpr) ); sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn, pExpr->y.sub.iAddr); return pExpr->iTable; } /* Begin coding the subroutine */ + assert( !ExprUseYWin(pExpr) ); + assert( !ExprHasProperty(pExpr, EP_Reduced|EP_TokenOnly) ); ExprSetProperty(pExpr, EP_Subrtn); pExpr->y.sub.regReturn = ++pParse->nMem; pExpr->y.sub.iAddr = @@ -3196,6 +3293,7 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ } /* Subroutine return */ + assert( ExprUseYSub(pExpr) ); sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn); sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1); sqlite3ClearTempRegCache(pParse); @@ -3212,7 +3310,7 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ */ int sqlite3ExprCheckIN(Parse *pParse, Expr *pIn){ int nVector = sqlite3ExprVectorSize(pIn->pLeft); - if( (pIn->flags & EP_xIsSelect)!=0 && !pParse->db->mallocFailed ){ + if( ExprUseXSelect(pIn) && !pParse->db->mallocFailed ){ if( nVector!=pIn->x.pSelect->pEList->nExpr ){ sqlite3SubselectError(pParse, pIn->x.pSelect->pEList->nExpr, nVector); return 1; @@ -3346,13 +3444,15 @@ static void sqlite3ExprCodeIN( ** This is step (1) in the in-operator.md optimized algorithm. */ if( eType==IN_INDEX_NOOP ){ - ExprList *pList = pExpr->x.pList; - CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); + ExprList *pList; + CollSeq *pColl; int labelOk = sqlite3VdbeMakeLabel(pParse); int r2, regToFree; int regCkNull = 0; int ii; - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + assert( ExprUseXList(pExpr) ); + pList = pExpr->x.pList; + pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); if( destIfNull!=destIfFalse ){ regCkNull = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_BitAnd, rLhs, rLhs, regCkNull); @@ -3589,9 +3689,10 @@ void sqlite3ExprCodeLoadIndexColumn( ** and store the result in register regOut */ void sqlite3ExprCodeGeneratedColumn( - Parse *pParse, - Column *pCol, - int regOut + Parse *pParse, /* Parsing context */ + Table *pTab, /* Table containing the generated column */ + Column *pCol, /* The generated column */ + int regOut /* Put the result in this register */ ){ int iAddr; Vdbe *v = pParse->pVdbe; @@ -3602,7 +3703,7 @@ void sqlite3ExprCodeGeneratedColumn( }else{ iAddr = 0; } - sqlite3ExprCodeCopy(pParse, pCol->pDflt, regOut); + sqlite3ExprCodeCopy(pParse, sqlite3ColumnExpr(pTab,pCol), regOut); if( pCol->affinity>=SQLITE_AFF_TEXT ){ sqlite3VdbeAddOp4(v, OP_Affinity, regOut, 1, 0, &pCol->affinity, 1); } @@ -3638,12 +3739,13 @@ void sqlite3ExprCodeGetColumnOfTable( }else if( (pCol = &pTab->aCol[iCol])->colFlags & COLFLAG_VIRTUAL ){ Parse *pParse = sqlite3VdbeParser(v); if( pCol->colFlags & COLFLAG_BUSY ){ - sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pCol->zName); + sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", + pCol->zCnName); }else{ int savedSelfTab = pParse->iSelfTab; pCol->colFlags |= COLFLAG_BUSY; pParse->iSelfTab = iTabCur+1; - sqlite3ExprCodeGeneratedColumn(pParse, pCol, regOut); + sqlite3ExprCodeGeneratedColumn(pParse, pTab, pCol, regOut); pParse->iSelfTab = savedSelfTab; pCol->colFlags &= ~COLFLAG_BUSY; } @@ -3736,6 +3838,7 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){ int i; iResult = pParse->nMem+1; pParse->nMem += nResult; + assert( ExprUseXList(p) ); for(i=0; ix.pList->a[i].pExpr, i+iResult); } @@ -3810,6 +3913,7 @@ static int exprCodeInlineFunction( ** Test-only SQL functions that are only usable if enabled ** via SQLITE_TESTCTRL_INTERNAL_FUNCTIONS */ +#if !defined(SQLITE_UNTESTABLE) case INLINEFUNC_expr_compare: { /* Compare two expressions using sqlite3ExprCompare() */ assert( nFarg==2 ); @@ -3843,7 +3947,6 @@ static int exprCodeInlineFunction( break; } -#ifdef SQLITE_DEBUG case INLINEFUNC_affinity: { /* The AFFINITY() function evaluates to a string that describes ** the type affinity of the argument. This is used for testing of @@ -3857,7 +3960,7 @@ static int exprCodeInlineFunction( (aff<=SQLITE_AFF_NONE) ? "none" : azAff[aff-SQLITE_AFF_BLOB]); break; } -#endif +#endif /* !defined(SQLITE_UNTESTABLE) */ } return target; } @@ -3911,7 +4014,8 @@ expr_code_doover: if( pCol->iColumn<0 ){ VdbeComment((v,"%s.rowid",pTab->zName)); }else{ - VdbeComment((v,"%s.%s",pTab->zName,pTab->aCol[pCol->iColumn].zName)); + VdbeComment((v,"%s.%s", + pTab->zName, pTab->aCol[pCol->iColumn].zCnName)); if( pTab->aCol[pCol->iColumn].affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, target); } @@ -3933,6 +4037,7 @@ expr_code_doover: */ int aff; iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target); + assert( ExprUseYTab(pExpr) ); if( pExpr->y.pTab ){ aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); }else{ @@ -3956,9 +4061,11 @@ expr_code_doover: ** immediately prior to the first column. */ Column *pCol; - Table *pTab = pExpr->y.pTab; + Table *pTab; int iSrc; int iCol = pExpr->iColumn; + assert( ExprUseYTab(pExpr) ); + pTab = pExpr->y.pTab; assert( pTab!=0 ); assert( iCol>=XN_ROWID ); assert( iColnCol ); @@ -3972,12 +4079,12 @@ expr_code_doover: if( pCol->colFlags & COLFLAG_GENERATED ){ if( pCol->colFlags & COLFLAG_BUSY ){ sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", - pCol->zName); + pCol->zCnName); return 0; } pCol->colFlags |= COLFLAG_BUSY; if( pCol->colFlags & COLFLAG_NOTAVAIL ){ - sqlite3ExprCodeGeneratedColumn(pParse, pCol, iSrc); + sqlite3ExprCodeGeneratedColumn(pParse, pTab, pCol, iSrc); } pCol->colFlags &= ~(COLFLAG_BUSY|COLFLAG_NOTAVAIL); return iSrc; @@ -3996,6 +4103,7 @@ expr_code_doover: iTab = pParse->iSelfTab - 1; } } + assert( ExprUseYTab(pExpr) ); iReg = sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab, pExpr->iColumn, iTab, target, pExpr->op2); @@ -4073,6 +4181,7 @@ expr_code_doover: sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target); inReg = target; } + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3VdbeAddOp2(v, OP_Cast, target, sqlite3AffinityType(pExpr->u.zToken, 0)); return inReg; @@ -4240,8 +4349,8 @@ expr_code_doover: ** multiple times if we know they always give the same result */ return sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1); } - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); assert( !ExprHasProperty(pExpr, EP_TokenOnly) ); + assert( ExprUseXList(pExpr) ); pFarg = pExpr->x.pList; nFarg = pFarg ? pFarg->nExpr : 0; assert( !ExprHasProperty(pExpr, EP_IntValue) ); @@ -4330,7 +4439,7 @@ expr_code_doover: sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ); } #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC - if( pDef->funcFlags & SQLITE_FUNC_OFFSET ){ + if( (pDef->funcFlags & SQLITE_FUNC_OFFSET)!=0 && ALWAYS(pFarg!=0) ){ Expr *pArg = pFarg->a[0].pExpr; if( pArg->op==TK_COLUMN ){ sqlite3VdbeAddOp3(v, OP_Offset, pArg->iTable, pArg->iColumn, target); @@ -4360,7 +4469,10 @@ expr_code_doover: testcase( op==TK_SELECT ); if( pParse->db->mallocFailed ){ return 0; - }else if( op==TK_SELECT && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1 ){ + }else if( op==TK_SELECT + && ALWAYS( ExprUseXSelect(pExpr) ) + && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1 + ){ sqlite3SubselectError(pParse, nCol, 1); }else{ return sqlite3CodeSubselect(pParse, pExpr); @@ -4372,11 +4484,9 @@ expr_code_doover: if( pExpr->pLeft->iTable==0 ){ pExpr->pLeft->iTable = sqlite3CodeSubselect(pParse, pExpr->pLeft); } - assert( pExpr->iTable==0 || pExpr->pLeft->op==TK_SELECT - || pExpr->pLeft->op==TK_ERROR ); - if( pExpr->iTable!=0 - && pExpr->iTable!=(n = sqlite3ExprVectorSize(pExpr->pLeft)) - ){ + assert( pExpr->pLeft->op==TK_SELECT || pExpr->pLeft->op==TK_ERROR ); + n = sqlite3ExprVectorSize(pExpr->pLeft); + if( pExpr->iTable!=n ){ sqlite3ErrorMsg(pParse, "%d columns assigned %d values", pExpr->iTable, n); } @@ -4444,9 +4554,14 @@ expr_code_doover: ** p1==1 -> old.a p1==4 -> new.a ** p1==2 -> old.b p1==5 -> new.b */ - Table *pTab = pExpr->y.pTab; - int iCol = pExpr->iColumn; - int p1 = pExpr->iTable * (pTab->nCol+1) + 1 + Table *pTab; + int iCol; + int p1; + + assert( ExprUseYTab(pExpr) ); + pTab = pExpr->y.pTab; + iCol = pExpr->iColumn; + p1 = pExpr->iTable * (pTab->nCol+1) + 1 + sqlite3TableColumnToStorage(pTab, iCol); assert( pExpr->iTable==0 || pExpr->iTable==1 ); @@ -4457,7 +4572,7 @@ expr_code_doover: sqlite3VdbeAddOp2(v, OP_Param, p1, target); VdbeComment((v, "r[%d]=%s.%s", target, (pExpr->iTable ? "new" : "old"), - (pExpr->iColumn<0 ? "rowid" : pExpr->y.pTab->aCol[iCol].zName) + (pExpr->iColumn<0 ? "rowid" : pExpr->y.pTab->aCol[iCol].zCnName) )); #ifndef SQLITE_OMIT_FLOATING_POINT @@ -4534,7 +4649,7 @@ expr_code_doover: Expr *pDel = 0; sqlite3 *db = pParse->db; - assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList ); + assert( ExprUseXList(pExpr) && pExpr->x.pList!=0 ); assert(pExpr->x.pList->nExpr > 0); pEList = pExpr->x.pList; aListelem = pEList->a; @@ -4731,7 +4846,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ inReg = sqlite3ExprCodeTarget(pParse, pExpr, target); if( inReg!=target ){ u8 op; - if( ExprHasProperty(pExpr,EP_Subquery) ){ + if( ALWAYS(pExpr) && ExprHasProperty(pExpr,EP_Subquery) ){ op = OP_Copy; }else{ op = OP_SCopy; @@ -4879,7 +4994,7 @@ static void exprCodeBetween( memset(&compRight, 0, sizeof(Expr)); memset(&exprAnd, 0, sizeof(Expr)); - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + assert( ExprUseXList(pExpr) ); pDel = sqlite3ExprDup(db, pExpr->pLeft, 0); if( db->mallocFailed==0 ){ exprAnd.op = TK_AND; @@ -5269,7 +5384,11 @@ void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,int jumpIfNull){ ** Otherwise, if the values are not the same or if pExpr is not a simple ** SQL value, zero is returned. */ -static int exprCompareVariable(Parse *pParse, Expr *pVar, Expr *pExpr){ +static int exprCompareVariable( + const Parse *pParse, + const Expr *pVar, + const Expr *pExpr +){ int res = 0; int iVar; sqlite3_value *pL, *pR = 0; @@ -5321,7 +5440,12 @@ static int exprCompareVariable(Parse *pParse, Expr *pVar, Expr *pExpr){ ** Argument pParse should normally be NULL. If it is not NULL and pA or ** pB causes a return value of 2. */ -int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){ +int sqlite3ExprCompare( + const Parse *pParse, + const Expr *pA, + const Expr *pB, + int iTab +){ u32 combinedFlags; if( pA==0 || pB==0 ){ return pB==pA ? 0 : 2; @@ -5345,7 +5469,9 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){ } return 2; } - if( pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && pA->u.zToken ){ + assert( !ExprHasProperty(pA, EP_IntValue) ); + assert( !ExprHasProperty(pB, EP_IntValue) ); + if( pA->u.zToken ){ if( pA->op==TK_FUNCTION || pA->op==TK_AGG_FUNCTION ){ if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; #ifndef SQLITE_OMIT_WINDOWFUNC @@ -5363,7 +5489,12 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){ return 0; }else if( pA->op==TK_COLLATE ){ if( sqlite3_stricmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; - }else if( ALWAYS(pB->u.zToken!=0) && strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ + }else + if( pB->u.zToken!=0 + && pA->op!=TK_COLUMN + && pA->op!=TK_AGG_COLUMN + && strcmp(pA->u.zToken,pB->u.zToken)!=0 + ){ return 2; } } @@ -5405,7 +5536,7 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){ ** Two NULL pointers are considered to be the same. But a NULL pointer ** always differs from a non-NULL pointer. */ -int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){ +int sqlite3ExprListCompare(const ExprList *pA, const ExprList *pB, int iTab){ int i; if( pA==0 && pB==0 ) return 0; if( pA==0 || pB==0 ) return 1; @@ -5424,7 +5555,7 @@ int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){ ** Like sqlite3ExprCompare() except COLLATE operators at the top-level ** are ignored. */ -int sqlite3ExprCompareSkip(Expr *pA, Expr *pB, int iTab){ +int sqlite3ExprCompareSkip(Expr *pA,Expr *pB, int iTab){ return sqlite3ExprCompare(0, sqlite3ExprSkipCollateAndLikely(pA), sqlite3ExprSkipCollateAndLikely(pB), @@ -5438,9 +5569,9 @@ int sqlite3ExprCompareSkip(Expr *pA, Expr *pB, int iTab){ ** non-NULL if pNN is not NULL */ static int exprImpliesNotNull( - Parse *pParse, /* Parsing context */ - Expr *p, /* The expression to be checked */ - Expr *pNN, /* The expression that is NOT NULL */ + const Parse *pParse,/* Parsing context */ + const Expr *p, /* The expression to be checked */ + const Expr *pNN, /* The expression that is NOT NULL */ int iTab, /* Table being evaluated */ int seenNot /* Return true only if p can be any non-NULL value */ ){ @@ -5452,12 +5583,13 @@ static int exprImpliesNotNull( switch( p->op ){ case TK_IN: { if( seenNot && ExprHasProperty(p, EP_xIsSelect) ) return 0; - assert( ExprHasProperty(p,EP_xIsSelect) - || (p->x.pList!=0 && p->x.pList->nExpr>0) ); + assert( ExprUseXSelect(p) || (p->x.pList!=0 && p->x.pList->nExpr>0) ); return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1); } case TK_BETWEEN: { - ExprList *pList = p->x.pList; + ExprList *pList; + assert( ExprUseXList(p) ); + pList = p->x.pList; assert( pList!=0 ); assert( pList->nExpr==2 ); if( seenNot ) return 0; @@ -5533,7 +5665,12 @@ static int exprImpliesNotNull( ** improvement. Returning false might cause a performance reduction, but ** it will always give the correct answer and is hence always safe. */ -int sqlite3ExprImpliesExpr(Parse *pParse, Expr *pE1, Expr *pE2, int iTab){ +int sqlite3ExprImpliesExpr( + const Parse *pParse, + const Expr *pE1, + const Expr *pE2, + int iTab +){ if( sqlite3ExprCompare(pParse, pE1, pE2, iTab)==0 ){ return 1; } @@ -5629,10 +5766,14 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_GE ); /* The y.pTab=0 assignment in wherecode.c always happens after the ** impliesNotNullRow() test */ - if( (pLeft->op==TK_COLUMN && ALWAYS(pLeft->y.pTab!=0) - && IsVirtual(pLeft->y.pTab)) - || (pRight->op==TK_COLUMN && ALWAYS(pRight->y.pTab!=0) - && IsVirtual(pRight->y.pTab)) + assert( pLeft->op!=TK_COLUMN || ExprUseYTab(pLeft) ); + assert( pRight->op!=TK_COLUMN || ExprUseYTab(pRight) ); + if( (pLeft->op==TK_COLUMN + && pLeft->y.pTab!=0 + && IsVirtual(pLeft->y.pTab)) + || (pRight->op==TK_COLUMN + && pRight->y.pTab!=0 + && IsVirtual(pRight->y.pTab)) ){ return WRC_Prune; } @@ -5741,88 +5882,125 @@ int sqlite3ExprCoveredByIndex( } -/* -** An instance of the following structure is used by the tree walker -** to count references to table columns in the arguments of an -** aggregate function, in order to implement the -** sqlite3FunctionThisSrc() routine. -*/ -struct SrcCount { - SrcList *pSrc; /* One particular FROM clause in a nested query */ - int iSrcInner; /* Smallest cursor number in this context */ - int nThis; /* Number of references to columns in pSrcList */ - int nOther; /* Number of references to columns in other FROM clauses */ +/* Structure used to pass information throught the Walker in order to +** implement sqlite3ReferencesSrcList(). +*/ +struct RefSrcList { + sqlite3 *db; /* Database connection used for sqlite3DbRealloc() */ + SrcList *pRef; /* Looking for references to these tables */ + i64 nExclude; /* Number of tables to exclude from the search */ + int *aiExclude; /* Cursor IDs for tables to exclude from the search */ }; /* -** xSelect callback for sqlite3FunctionUsesThisSrc(). If this is the first -** SELECT with a FROM clause encountered during this iteration, set -** SrcCount.iSrcInner to the cursor number of the leftmost object in -** the FROM cause. +** Walker SELECT callbacks for sqlite3ReferencesSrcList(). +** +** When entering a new subquery on the pExpr argument, add all FROM clause +** entries for that subquery to the exclude list. +** +** When leaving the subquery, remove those entries from the exclude list. */ -static int selectSrcCount(Walker *pWalker, Select *pSel){ - struct SrcCount *p = pWalker->u.pSrcCount; - if( p->iSrcInner==0x7FFFFFFF && ALWAYS(pSel->pSrc) && pSel->pSrc->nSrc ){ - pWalker->u.pSrcCount->iSrcInner = pSel->pSrc->a[0].iCursor; +static int selectRefEnter(Walker *pWalker, Select *pSelect){ + struct RefSrcList *p = pWalker->u.pRefSrcList; + SrcList *pSrc = pSelect->pSrc; + i64 i, j; + int *piNew; + if( pSrc->nSrc==0 ) return WRC_Continue; + j = p->nExclude; + p->nExclude += pSrc->nSrc; + piNew = sqlite3DbRealloc(p->db, p->aiExclude, p->nExclude*sizeof(int)); + if( piNew==0 ){ + p->nExclude = 0; + return WRC_Abort; + }else{ + p->aiExclude = piNew; + } + for(i=0; inSrc; i++, j++){ + p->aiExclude[j] = pSrc->a[i].iCursor; } return WRC_Continue; } +static void selectRefLeave(Walker *pWalker, Select *pSelect){ + struct RefSrcList *p = pWalker->u.pRefSrcList; + SrcList *pSrc = pSelect->pSrc; + if( p->nExclude ){ + assert( p->nExclude>=pSrc->nSrc ); + p->nExclude -= pSrc->nSrc; + } +} -/* -** Count the number of references to columns. +/* This is the Walker EXPR callback for sqlite3ReferencesSrcList(). +** +** Set the 0x01 bit of pWalker->eCode if there is a reference to any +** of the tables shown in RefSrcList.pRef. +** +** Set the 0x02 bit of pWalker->eCode if there is a reference to a +** table is in neither RefSrcList.pRef nor RefSrcList.aiExclude. */ -static int exprSrcCount(Walker *pWalker, Expr *pExpr){ - /* There was once a NEVER() on the second term on the grounds that - ** sqlite3FunctionUsesThisSrc() was always called before - ** sqlite3ExprAnalyzeAggregates() and so the TK_COLUMNs have not yet - ** been converted into TK_AGG_COLUMN. But this is no longer true due - ** to window functions - sqlite3WindowRewrite() may now indirectly call - ** FunctionUsesThisSrc() when creating a new sub-select. */ - if( pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN ){ +static int exprRefToSrcList(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_COLUMN + || pExpr->op==TK_AGG_COLUMN + ){ int i; - struct SrcCount *p = pWalker->u.pSrcCount; - SrcList *pSrc = p->pSrc; + struct RefSrcList *p = pWalker->u.pRefSrcList; + SrcList *pSrc = p->pRef; int nSrc = pSrc ? pSrc->nSrc : 0; for(i=0; iiTable==pSrc->a[i].iCursor ) break; + if( pExpr->iTable==pSrc->a[i].iCursor ){ + pWalker->eCode |= 1; + return WRC_Continue; + } } - if( inThis++; - }else if( pExpr->iTableiSrcInner ){ - /* In a well-formed parse tree (no name resolution errors), - ** TK_COLUMN nodes with smaller Expr.iTable values are in an - ** outer context. Those are the only ones to count as "other" */ - p->nOther++; + for(i=0; inExclude && p->aiExclude[i]!=pExpr->iTable; i++){} + if( i>=p->nExclude ){ + pWalker->eCode |= 2; } } return WRC_Continue; } /* -** Determine if any of the arguments to the pExpr Function reference -** pSrcList. Return true if they do. Also return true if the function -** has no arguments or has only constant arguments. Return false if pExpr -** references columns but not columns of tables found in pSrcList. +** Check to see if pExpr references any tables in pSrcList. +** Possible return values: +** +** 1 pExpr does references a table in pSrcList. +** +** 0 pExpr references some table that is not defined in either +** pSrcList or in subqueries of pExpr itself. +** +** -1 pExpr only references no tables at all, or it only +** references tables defined in subqueries of pExpr itself. +** +** As currently used, pExpr is always an aggregate function call. That +** fact is exploited for efficiency. */ -int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){ +int sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr, SrcList *pSrcList){ Walker w; - struct SrcCount cnt; - assert( pExpr->op==TK_AGG_FUNCTION ); + struct RefSrcList x; memset(&w, 0, sizeof(w)); - w.xExprCallback = exprSrcCount; - w.xSelectCallback = selectSrcCount; - w.u.pSrcCount = &cnt; - cnt.pSrc = pSrcList; - cnt.iSrcInner = (pSrcList&&pSrcList->nSrc)?pSrcList->a[0].iCursor:0x7FFFFFFF; - cnt.nThis = 0; - cnt.nOther = 0; + memset(&x, 0, sizeof(x)); + w.xExprCallback = exprRefToSrcList; + w.xSelectCallback = selectRefEnter; + w.xSelectCallback2 = selectRefLeave; + w.u.pRefSrcList = &x; + x.db = pParse->db; + x.pRef = pSrcList; + assert( pExpr->op==TK_AGG_FUNCTION ); + assert( ExprUseXList(pExpr) ); sqlite3WalkExprList(&w, pExpr->x.pList); #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(pExpr, EP_WinFunc) ){ sqlite3WalkExpr(&w, pExpr->y.pWin->pFilter); } #endif - return cnt.nThis>0 || cnt.nOther==0; + sqlite3DbFree(pParse->db, x.aiExclude); + if( w.eCode & 0x01 ){ + return 1; + }else if( w.eCode ){ + return 0; + }else{ + return -1; + } } /* @@ -5957,6 +6135,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ && (k = addAggInfoColumn(pParse->db, pAggInfo))>=0 ){ pCol = &pAggInfo->aCol[k]; + assert( ExprUseYTab(pExpr) ); pCol->pTab = pExpr->y.pTab; pCol->iTable = pExpr->iTable; pCol->iColumn = pExpr->iColumn; @@ -6020,7 +6199,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ pItem = &pAggInfo->aFunc[i]; pItem->pFExpr = pExpr; pItem->iMem = ++pParse->nMem; - assert( !ExprHasProperty(pExpr, EP_IntValue) ); + assert( ExprUseUToken(pExpr) ); pItem->pFunc = sqlite3FindFunction(pParse->db, pExpr->u.zToken, pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0); diff --git a/src/fkey.c b/src/fkey.c index 9f622f40..6ee35bf3 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -215,7 +215,9 @@ int sqlite3FkLocateIndex( */ if( pParent->iPKey>=0 ){ if( !zKey ) return 0; - if( !sqlite3StrICmp(pParent->aCol[pParent->iPKey].zName, zKey) ) return 0; + if( !sqlite3StrICmp(pParent->aCol[pParent->iPKey].zCnName, zKey) ){ + return 0; + } } }else if( paiCol ){ assert( nCol>1 ); @@ -257,11 +259,11 @@ int sqlite3FkLocateIndex( /* If the index uses a collation sequence that is different from ** the default collation sequence for the column, this index is ** unusable. Bail out early in this case. */ - zDfltColl = pParent->aCol[iCol].zColl; + zDfltColl = sqlite3ColumnColl(&pParent->aCol[iCol]); if( !zDfltColl ) zDfltColl = sqlite3StrBINARY; if( sqlite3StrICmp(pIdx->azColl[i], zDfltColl) ) break; - zIdxCol = pParent->aCol[iCol].zName; + zIdxCol = pParent->aCol[iCol].zCnName; for(j=0; jaCol[j].zCol, zIdxCol)==0 ){ if( aiCol ) aiCol[i] = pFKey->aCol[j].iFrom; @@ -485,7 +487,7 @@ static Expr *exprTableRegister( pCol = &pTab->aCol[iCol]; pExpr->iTable = regBase + sqlite3TableColumnToStorage(pTab,iCol) + 1; pExpr->affExpr = pCol->affinity; - zColl = pCol->zColl; + zColl = sqlite3ColumnColl(pCol); if( zColl==0 ) zColl = db->pDfltColl->zName; pExpr = sqlite3ExprAddCollateString(pParse, pExpr, zColl); }else{ @@ -508,6 +510,7 @@ static Expr *exprTableColumn( ){ Expr *pExpr = sqlite3Expr(db, TK_COLUMN, 0); if( pExpr ){ + assert( ExprUseYTab(pExpr) ); pExpr->y.pTab = pTab; pExpr->iTable = iCursor; pExpr->iColumn = iCol; @@ -594,7 +597,7 @@ static void fkScanChildren( pLeft = exprTableRegister(pParse, pTab, regData, iCol); iCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom; assert( iCol>=0 ); - zCol = pFKey->pFrom->aCol[iCol].zName; + zCol = pFKey->pFrom->aCol[iCol].zCnName; pRight = sqlite3Expr(db, TK_ID, zCol); pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight); pWhere = sqlite3ExprAnd(pParse, pWhere, pEq); @@ -629,7 +632,7 @@ static void fkScanChildren( i16 iCol = pIdx->aiColumn[i]; assert( iCol>=0 ); pLeft = exprTableRegister(pParse, pTab, regData, iCol); - pRight = sqlite3Expr(db, TK_ID, pTab->aCol[iCol].zName); + pRight = sqlite3Expr(db, TK_ID, pTab->aCol[iCol].zCnName); pEq = sqlite3PExpr(pParse, TK_IS, pLeft, pRight); pAll = sqlite3ExprAnd(pParse, pAll, pEq); } @@ -700,6 +703,25 @@ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){ } /* +** Clear the apTrigger[] cache of CASCADE triggers for all foreign keys +** in a particular database. This needs to happen when the schema +** changes. +*/ +void sqlite3FkClearTriggerCache(sqlite3 *db, int iDb){ + HashElem *k; + Hash *pHash = &db->aDb[iDb].pSchema->tblHash; + for(k=sqliteHashFirst(pHash); k; k=sqliteHashNext(k)){ + Table *pTab = sqliteHashData(k); + FKey *pFKey; + if( !IsOrdinaryTable(pTab) ) continue; + for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){ + fkTriggerDelete(db, pFKey->apTrigger[0]); pFKey->apTrigger[0] = 0; + fkTriggerDelete(db, pFKey->apTrigger[1]); pFKey->apTrigger[1] = 0; + } + } +} + +/* ** This function is called to generate code that runs when table pTab is ** being dropped from the database. The SrcList passed as the second argument ** to this function contains a single entry guaranteed to resolve to @@ -718,12 +740,12 @@ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){ */ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){ sqlite3 *db = pParse->db; - if( (db->flags&SQLITE_ForeignKeys) && !IsVirtual(pTab) ){ + if( (db->flags&SQLITE_ForeignKeys) && IsOrdinaryTable(pTab) ){ int iSkip = 0; Vdbe *v = sqlite3GetVdbe(pParse); assert( v ); /* VDBE has already been allocated */ - assert( pTab->pSelect==0 ); /* Not a view */ + assert( IsOrdinaryTable(pTab) ); if( sqlite3FkReferences(pTab)==0 ){ /* Search for a deferred foreign key constraint for which this table ** is the child table. If one cannot be found, return without @@ -731,7 +753,7 @@ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){ ** the entire DELETE if there are no outstanding deferred constraints ** when this statement is run. */ FKey *p; - for(p=pTab->pFKey; p; p=p->pNextFrom){ + for(p=pTab->u.tab.pFKey; p; p=p->pNextFrom){ if( p->isDeferred || (db->flags & SQLITE_DeferFKs) ) break; } if( !p ) return; @@ -820,7 +842,7 @@ static int fkParentIsModified( if( aChange[iKey]>=0 || (iKey==pTab->iPKey && bChngRowid) ){ Column *pCol = &pTab->aCol[iKey]; if( zKey ){ - if( 0==sqlite3StrICmp(pCol->zName, zKey) ) return 1; + if( 0==sqlite3StrICmp(pCol->zCnName, zKey) ) return 1; }else if( pCol->colFlags & COLFLAG_PRIMKEY ){ return 1; } @@ -887,13 +909,14 @@ void sqlite3FkCheck( /* If foreign-keys are disabled, this function is a no-op. */ if( (db->flags&SQLITE_ForeignKeys)==0 ) return; + if( !IsOrdinaryTable(pTab) ) return; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); zDb = db->aDb[iDb].zDbSName; /* Loop through all the foreign key constraints for which pTab is the ** child table (the table that the foreign key definition is part of). */ - for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){ + for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){ Table *pTo; /* Parent table of foreign key pFKey */ Index *pIdx = 0; /* Index on key columns in pTo */ int *aiFree = 0; @@ -960,7 +983,7 @@ void sqlite3FkCheck( ** values read from the parent table are NULL. */ if( db->xAuth ){ int rcauth; - char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zName; + char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zCnName; rcauth = sqlite3AuthReadCol(pParse, pTo->zName, zCol, iDb); bIgnore = (rcauth==SQLITE_IGNORE); } @@ -1075,10 +1098,10 @@ u32 sqlite3FkOldmask( Table *pTab /* Table being modified */ ){ u32 mask = 0; - if( pParse->db->flags&SQLITE_ForeignKeys ){ + if( pParse->db->flags&SQLITE_ForeignKeys && IsOrdinaryTable(pTab) ){ FKey *p; int i; - for(p=pTab->pFKey; p; p=p->pNextFrom){ + for(p=pTab->u.tab.pFKey; p; p=p->pNextFrom){ for(i=0; inCol; i++) mask |= COLUMN_MASK(p->aCol[i].iFrom); } for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ @@ -1128,19 +1151,19 @@ int sqlite3FkRequired( ){ int eRet = 1; /* Value to return if bHaveFK is true */ int bHaveFK = 0; /* If FK processing is required */ - if( pParse->db->flags&SQLITE_ForeignKeys ){ + if( pParse->db->flags&SQLITE_ForeignKeys && IsOrdinaryTable(pTab) ){ if( !aChange ){ /* A DELETE operation. Foreign key processing is required if the ** table in question is either the child or parent table for any ** foreign key constraint. */ - bHaveFK = (sqlite3FkReferences(pTab) || pTab->pFKey); + bHaveFK = (sqlite3FkReferences(pTab) || pTab->u.tab.pFKey); }else{ /* This is an UPDATE. Foreign key processing is only required if the ** operation modifies one or more child or parent key columns. */ FKey *p; /* Check if any child key columns are being modified. */ - for(p=pTab->pFKey; p; p=p->pNextFrom){ + for(p=pTab->u.tab.pFKey; p; p=p->pNextFrom){ if( fkChildIsModified(pTab, p, aChange, chngRowid) ){ if( 0==sqlite3_stricmp(pTab->zName, p->zTo) ) eRet = 2; bHaveFK = 1; @@ -1233,8 +1256,8 @@ static Trigger *fkActionTrigger( assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKeynCol) ); assert( pIdx==0 || pIdx->aiColumn[i]>=0 ); sqlite3TokenInit(&tToCol, - pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName); - sqlite3TokenInit(&tFromCol, pFKey->pFrom->aCol[iFromCol].zName); + pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zCnName); + sqlite3TokenInit(&tFromCol, pFKey->pFrom->aCol[iFromCol].zCnName); /* Create the expression "OLD.zToCol = zFromCol". It is important ** that the "OLD.zToCol" term is on the LHS of the = operator, so @@ -1279,7 +1302,7 @@ static Trigger *fkActionTrigger( testcase( pCol->colFlags & COLFLAG_STORED ); pDflt = 0; }else{ - pDflt = pCol->pDflt; + pDflt = sqlite3ColumnExpr(pFKey->pFrom, pCol); } if( pDflt ){ pNew = sqlite3ExprDup(db, pDflt, 0); @@ -1416,9 +1439,9 @@ void sqlite3FkDelete(sqlite3 *db, Table *pTab){ FKey *pFKey; /* Iterator variable */ FKey *pNext; /* Copy of pFKey->pNextFrom */ - assert( db==0 || IsVirtual(pTab) - || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) ); - for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){ + assert( IsOrdinaryTable(pTab) ); + for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pNext){ + assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) ); /* Remove the FK from the fkeyHash hash table. */ if( !db || db->pnBytesFreed==0 ){ diff --git a/src/func.c b/src/func.c index dc19ec72..6a2903d3 100644 --- a/src/func.c +++ b/src/func.c @@ -571,9 +571,9 @@ static void last_insert_rowid( /* ** Implementation of the changes() SQL function. ** -** IMP: R-62073-11209 The changes() SQL function is a wrapper -** around the sqlite3_changes() C/C++ function and hence follows the same -** rules for counting changes. +** IMP: R-32760-32347 The changes() SQL function is a wrapper +** around the sqlite3_changes64() C/C++ function and hence follows the +** same rules for counting changes. */ static void changes( sqlite3_context *context, @@ -582,12 +582,12 @@ static void changes( ){ sqlite3 *db = sqlite3_context_db_handle(context); UNUSED_PARAMETER2(NotUsed, NotUsed2); - sqlite3_result_int(context, sqlite3_changes(db)); + sqlite3_result_int64(context, sqlite3_changes64(db)); } /* ** Implementation of the total_changes() SQL function. The return value is -** the same as the sqlite3_total_changes() API function. +** the same as the sqlite3_total_changes64() API function. */ static void total_changes( sqlite3_context *context, @@ -596,9 +596,9 @@ static void total_changes( ){ sqlite3 *db = sqlite3_context_db_handle(context); UNUSED_PARAMETER2(NotUsed, NotUsed2); - /* IMP: R-52756-41993 This function is a wrapper around the - ** sqlite3_total_changes() C/C++ interface. */ - sqlite3_result_int(context, sqlite3_total_changes(db)); + /* IMP: R-11217-42568 This function is a wrapper around the + ** sqlite3_total_changes64() C/C++ interface. */ + sqlite3_result_int64(context, sqlite3_total_changes64(db)); } /* @@ -1715,97 +1715,167 @@ static void minMaxFinalize(sqlite3_context *context){ /* ** group_concat(EXPR, ?SEPARATOR?) +** +** The SEPARATOR goes before the EXPR string. This is tragic. The +** groupConcatInverse() implementation would have been easier if the +** SEPARATOR were appended after EXPR. And the order is undocumented, +** so we could change it, in theory. But the old behavior has been +** around for so long that we dare not, for fear of breaking something. */ +typedef struct { + StrAccum str; /* The accumulated concatenation */ +#ifndef SQLITE_OMIT_WINDOWFUNC + int nAccum; /* Number of strings presently concatenated */ + int nFirstSepLength; /* Used to detect separator length change */ + /* If pnSepLengths!=0, refs an array of inter-string separator lengths, + ** stored as actually incorporated into presently accumulated result. + ** (Hence, its slots in use number nAccum-1 between method calls.) + ** If pnSepLengths==0, nFirstSepLength is the length used throughout. + */ + int *pnSepLengths; +#endif +} GroupConcatCtx; + static void groupConcatStep( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zVal; - StrAccum *pAccum; + GroupConcatCtx *pGCC; const char *zSep; int nVal, nSep; assert( argc==1 || argc==2 ); if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; - pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum)); - - if( pAccum ){ + pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC)); + if( pGCC ){ sqlite3 *db = sqlite3_context_db_handle(context); - int firstTerm = pAccum->mxAlloc==0; - pAccum->mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH]; - if( !firstTerm ){ - if( argc==2 ){ - zSep = (char*)sqlite3_value_text(argv[1]); - nSep = sqlite3_value_bytes(argv[1]); - }else{ - zSep = ","; - nSep = 1; + int firstTerm = pGCC->str.mxAlloc==0; + pGCC->str.mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH]; + if( argc==1 ){ + if( !firstTerm ){ + sqlite3_str_appendchar(&pGCC->str, 1, ','); + } +#ifndef SQLITE_OMIT_WINDOWFUNC + else{ + pGCC->nFirstSepLength = 1; + } +#endif + }else if( !firstTerm ){ + zSep = (char*)sqlite3_value_text(argv[1]); + nSep = sqlite3_value_bytes(argv[1]); + if( zSep ){ + sqlite3_str_append(&pGCC->str, zSep, nSep); + } +#ifndef SQLITE_OMIT_WINDOWFUNC + else{ + nSep = 0; + } + if( nSep != pGCC->nFirstSepLength || pGCC->pnSepLengths != 0 ){ + int *pnsl = pGCC->pnSepLengths; + if( pnsl == 0 ){ + /* First separator length variation seen, start tracking them. */ + pnsl = (int*)sqlite3_malloc64((pGCC->nAccum+1) * sizeof(int)); + if( pnsl!=0 ){ + int i = 0, nA = pGCC->nAccum-1; + while( inFirstSepLength; + } + }else{ + pnsl = (int*)sqlite3_realloc64(pnsl, pGCC->nAccum * sizeof(int)); + } + if( pnsl!=0 ){ + if( ALWAYS(pGCC->nAccum>0) ){ + pnsl[pGCC->nAccum-1] = nSep; + } + pGCC->pnSepLengths = pnsl; + }else{ + sqlite3StrAccumSetError(&pGCC->str, SQLITE_NOMEM); + } } - if( zSep ) sqlite3_str_append(pAccum, zSep, nSep); +#endif } +#ifndef SQLITE_OMIT_WINDOWFUNC + else{ + pGCC->nFirstSepLength = sqlite3_value_bytes(argv[1]); + } + pGCC->nAccum += 1; +#endif zVal = (char*)sqlite3_value_text(argv[0]); nVal = sqlite3_value_bytes(argv[0]); - if( zVal ) sqlite3_str_append(pAccum, zVal, nVal); + if( zVal ) sqlite3_str_append(&pGCC->str, zVal, nVal); } } + #ifndef SQLITE_OMIT_WINDOWFUNC static void groupConcatInverse( sqlite3_context *context, int argc, sqlite3_value **argv ){ - int n; - StrAccum *pAccum; + GroupConcatCtx *pGCC; assert( argc==1 || argc==2 ); + (void)argc; /* Suppress unused parameter warning */ if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; - pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum)); - /* pAccum is always non-NULL since groupConcatStep() will have always + pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC)); + /* pGCC is always non-NULL since groupConcatStep() will have always ** run frist to initialize it */ - if( ALWAYS(pAccum) ){ - n = sqlite3_value_bytes(argv[0]); - if( argc==2 ){ - n += sqlite3_value_bytes(argv[1]); + if( ALWAYS(pGCC) ){ + int nVS; + /* Must call sqlite3_value_text() to convert the argument into text prior + ** to invoking sqlite3_value_bytes(), in case the text encoding is UTF16 */ + (void)sqlite3_value_text(argv[0]); + nVS = sqlite3_value_bytes(argv[0]); + pGCC->nAccum -= 1; + if( pGCC->pnSepLengths!=0 ){ + assert(pGCC->nAccum >= 0); + if( pGCC->nAccum>0 ){ + nVS += *pGCC->pnSepLengths; + memmove(pGCC->pnSepLengths, pGCC->pnSepLengths+1, + (pGCC->nAccum-1)*sizeof(int)); + } }else{ - n++; + /* If removing single accumulated string, harmlessly over-do. */ + nVS += pGCC->nFirstSepLength; } - if( n>=(int)pAccum->nChar ){ - pAccum->nChar = 0; + if( nVS>=(int)pGCC->str.nChar ){ + pGCC->str.nChar = 0; }else{ - pAccum->nChar -= n; - memmove(pAccum->zText, &pAccum->zText[n], pAccum->nChar); + pGCC->str.nChar -= nVS; + memmove(pGCC->str.zText, &pGCC->str.zText[nVS], pGCC->str.nChar); + } + if( pGCC->str.nChar==0 ){ + pGCC->str.mxAlloc = 0; + sqlite3_free(pGCC->pnSepLengths); + pGCC->pnSepLengths = 0; } - if( pAccum->nChar==0 ) pAccum->mxAlloc = 0; } } #else # define groupConcatInverse 0 #endif /* SQLITE_OMIT_WINDOWFUNC */ static void groupConcatFinalize(sqlite3_context *context){ - StrAccum *pAccum; - pAccum = sqlite3_aggregate_context(context, 0); - if( pAccum ){ - if( pAccum->accError==SQLITE_TOOBIG ){ - sqlite3_result_error_toobig(context); - }else if( pAccum->accError==SQLITE_NOMEM ){ - sqlite3_result_error_nomem(context); - }else{ - sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), -1, - sqlite3_free); - } + GroupConcatCtx *pGCC + = (GroupConcatCtx*)sqlite3_aggregate_context(context, 0); + if( pGCC ){ + sqlite3ResultStrAccum(context, &pGCC->str); +#ifndef SQLITE_OMIT_WINDOWFUNC + sqlite3_free(pGCC->pnSepLengths); +#endif } } #ifndef SQLITE_OMIT_WINDOWFUNC static void groupConcatValue(sqlite3_context *context){ - sqlite3_str *pAccum; - pAccum = (sqlite3_str*)sqlite3_aggregate_context(context, 0); - if( pAccum ){ + GroupConcatCtx *pGCC + = (GroupConcatCtx*)sqlite3_aggregate_context(context, 0); + if( pGCC ){ + StrAccum *pAccum = &pGCC->str; if( pAccum->accError==SQLITE_TOOBIG ){ sqlite3_result_error_toobig(context); }else if( pAccum->accError==SQLITE_NOMEM ){ sqlite3_result_error_nomem(context); }else{ const char *zText = sqlite3_str_value(pAccum); - sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT); + sqlite3_result_text(context, zText, pAccum->nChar, SQLITE_TRANSIENT); } } } @@ -1869,11 +1939,12 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){ int nExpr; assert( pExpr!=0 ); assert( pExpr->op==TK_FUNCTION ); + assert( ExprUseXList(pExpr) ); if( !pExpr->x.pList ){ return 0; } - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); nExpr = pExpr->x.pList->nExpr; + assert( !ExprHasProperty(pExpr, EP_IntValue) ); pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0); #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION if( pDef==0 ) return 0; @@ -1897,6 +1968,7 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){ Expr *pEscape = pExpr->x.pList->a[2].pExpr; char *zEscape; if( pEscape->op!=TK_STRING ) return 0; + assert( !ExprHasProperty(pEscape, EP_IntValue) ); zEscape = pEscape->u.zToken; if( zEscape[0]==0 || zEscape[1]!=0 ) return 0; if( zEscape[0]==aWc[0] ) return 0; @@ -2123,12 +2195,12 @@ void sqlite3RegisterBuiltinFunctions(void){ */ static FuncDef aBuiltinFunc[] = { /***** Functions only available with SQLITE_TESTCTRL_INTERNAL_FUNCTIONS *****/ +#if !defined(SQLITE_UNTESTABLE) TEST_FUNC(implies_nonnull_row, 2, INLINEFUNC_implies_nonnull_row, 0), TEST_FUNC(expr_compare, 2, INLINEFUNC_expr_compare, 0), TEST_FUNC(expr_implies_expr, 2, INLINEFUNC_expr_implies_expr, 0), -#ifdef SQLITE_DEBUG - TEST_FUNC(affinity, 1, INLINEFUNC_affinity, 0), -#endif + TEST_FUNC(affinity, 1, INLINEFUNC_affinity, 0), +#endif /* !defined(SQLITE_UNTESTABLE) */ /***** Regular functions *****/ #ifdef SQLITE_SOUNDEX FUNCTION(soundex, 1, 0, 0, soundexFunc ), @@ -2160,11 +2232,11 @@ void sqlite3RegisterBuiltinFunctions(void){ FUNCTION(min, -1, 0, 1, minmaxFunc ), FUNCTION(min, 0, 0, 1, 0 ), WAGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize, minMaxValue, 0, - SQLITE_FUNC_MINMAX ), + SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ), FUNCTION(max, -1, 1, 1, minmaxFunc ), FUNCTION(max, 0, 1, 1, 0 ), WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0, - SQLITE_FUNC_MINMAX ), + SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ), FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF), FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH), FUNCTION(instr, 2, 0, 0, instrFunc ), @@ -2200,9 +2272,10 @@ void sqlite3RegisterBuiltinFunctions(void){ WAGGREGATE(total, 1,0,0, sumStep,totalFinalize,totalFinalize,sumInverse, 0), WAGGREGATE(avg, 1,0,0, sumStep, avgFinalize, avgFinalize, sumInverse, 0), WAGGREGATE(count, 0,0,0, countStep, - countFinalize, countFinalize, countInverse, SQLITE_FUNC_COUNT ), + countFinalize, countFinalize, countInverse, + SQLITE_FUNC_COUNT|SQLITE_FUNC_ANYORDER ), WAGGREGATE(count, 1,0,0, countStep, - countFinalize, countFinalize, countInverse, 0 ), + countFinalize, countFinalize, countInverse, SQLITE_FUNC_ANYORDER ), WAGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize, groupConcatValue, groupConcatInverse, 0), WAGGREGATE(group_concat, 2, 0, 0, groupConcatStep, @@ -2277,6 +2350,7 @@ void sqlite3RegisterBuiltinFunctions(void){ for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash){ int n = sqlite3Strlen30(p->zName); int h = p->zName[0] + n; + assert( p->funcFlags & SQLITE_FUNC_BUILTIN ); printf(" %s(%d)", p->zName, h); } printf("\n"); diff --git a/src/global.c b/src/global.c index 4648c26d..34b7d958 100644 --- a/src/global.c +++ b/src/global.c @@ -298,6 +298,18 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = { */ FuncDefHash sqlite3BuiltinFunctions; +#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) +/* +** Counter used for coverage testing. Does not come into play for +** release builds. +** +** Access to this global variable is not mutex protected. This might +** result in TSAN warnings. But as the variable does not exist in +** release builds, that should not be a concern. +*/ +unsigned int sqlite3CoverageCounter; +#endif /* SQLITE_COVERAGE_TEST || SQLITE_DEBUG */ + #ifdef VDBE_PROFILE /* ** The following performance counter can be used in place of @@ -347,3 +359,45 @@ const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER; ** Name of the default collating sequence */ const char sqlite3StrBINARY[] = "BINARY"; + +/* +** Standard typenames. These names must match the COLTYPE_* definitions. +** Adjust the SQLITE_N_STDTYPE value if adding or removing entries. +** +** sqlite3StdType[] The actual names of the datatypes. +** +** sqlite3StdTypeLen[] The length (in bytes) of each entry +** in sqlite3StdType[]. +** +** sqlite3StdTypeAffinity[] The affinity associated with each entry +** in sqlite3StdType[]. +** +** sqlite3StdTypeMap[] The type value (as returned from +** sqlite3_column_type() or sqlite3_value_type()) +** for each entry in sqlite3StdType[]. +*/ +const unsigned char sqlite3StdTypeLen[] = { 3, 4, 3, 7, 4, 4 }; +const char sqlite3StdTypeAffinity[] = { + SQLITE_AFF_NUMERIC, + SQLITE_AFF_BLOB, + SQLITE_AFF_INTEGER, + SQLITE_AFF_INTEGER, + SQLITE_AFF_REAL, + SQLITE_AFF_TEXT +}; +const char sqlite3StdTypeMap[] = { + 0, + SQLITE_BLOB, + SQLITE_INTEGER, + SQLITE_INTEGER, + SQLITE_FLOAT, + SQLITE_TEXT +}; +const char *sqlite3StdType[] = { + "ANY", + "BLOB", + "INT", + "INTEGER", + "REAL", + "TEXT" +}; diff --git a/src/hash.h b/src/hash.h index 951cc06c..3f491e45 100644 --- a/src/hash.h +++ b/src/hash.h @@ -91,6 +91,6 @@ void sqlite3HashClear(Hash*); /* ** Number of entries in a hash table */ -/* #define sqliteHashCount(H) ((H)->count) // NOT USED */ +#define sqliteHashCount(H) ((H)->count) #endif /* SQLITE_HASH_H */ diff --git a/src/insert.c b/src/insert.c index 1ed0b431..7fc9a897 100644 --- a/src/insert.c +++ b/src/insert.c @@ -43,7 +43,7 @@ void sqlite3OpenTable( }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); assert( pPk!=0 ); - assert( pPk->tnum==pTab->tnum ); + assert( pPk->tnum==pTab->tnum || CORRUPT_DB ); sqlite3VdbeAddOp3(v, opcode, iCur, pPk->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pPk); VdbeComment((v, "%s", pTab->zName)); @@ -110,28 +110,68 @@ const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){ } /* +** Make changes to the evolving bytecode to do affinity transformations +** of values that are about to be gathered into a row for table pTab. +** +** For ordinary (legacy, non-strict) tables: +** ----------------------------------------- +** ** Compute the affinity string for table pTab, if it has not already been ** computed. As an optimization, omit trailing SQLITE_AFF_BLOB affinities. ** -** If the affinity exists (if it is no entirely SQLITE_AFF_BLOB values) and -** if iReg>0 then code an OP_Affinity opcode that will set the affinities -** for register iReg and following. Or if affinities exists and iReg==0, +** If the affinity string is empty (because it was all SQLITE_AFF_BLOB entries +** which were then optimized out) then this routine becomes a no-op. +** +** Otherwise if iReg>0 then code an OP_Affinity opcode that will set the +** affinities for register iReg and following. Or if iReg==0, ** then just set the P4 operand of the previous opcode (which should be ** an OP_MakeRecord) to the affinity string. ** ** A column affinity string has one character per column: ** -** Character Column affinity -** ------------------------------ -** 'A' BLOB -** 'B' TEXT -** 'C' NUMERIC -** 'D' INTEGER -** 'E' REAL +** Character Column affinity +** --------- --------------- +** 'A' BLOB +** 'B' TEXT +** 'C' NUMERIC +** 'D' INTEGER +** 'E' REAL +** +** For STRICT tables: +** ------------------ +** +** Generate an appropropriate OP_TypeCheck opcode that will verify the +** datatypes against the column definitions in pTab. If iReg==0, that +** means an OP_MakeRecord opcode has already been generated and should be +** the last opcode generated. The new OP_TypeCheck needs to be inserted +** before the OP_MakeRecord. The new OP_TypeCheck should use the same +** register set as the OP_MakeRecord. If iReg>0 then register iReg is +** the first of a series of registers that will form the new record. +** Apply the type checking to that array of registers. */ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ int i, j; - char *zColAff = pTab->zColAff; + char *zColAff; + if( pTab->tabFlags & TF_Strict ){ + if( iReg==0 ){ + /* Move the previous opcode (which should be OP_MakeRecord) forward + ** by one slot and insert a new OP_TypeCheck where the current + ** OP_MakeRecord is found */ + VdbeOp *pPrev; + sqlite3VdbeAppendP4(v, pTab, P4_TABLE); + pPrev = sqlite3VdbeGetOp(v, -1); + assert( pPrev!=0 ); + assert( pPrev->opcode==OP_MakeRecord || sqlite3VdbeDb(v)->mallocFailed ); + pPrev->opcode = OP_TypeCheck; + sqlite3VdbeAddOp3(v, OP_MakeRecord, pPrev->p1, pPrev->p2, pPrev->p3); + }else{ + /* Insert an isolated OP_Typecheck */ + sqlite3VdbeAddOp2(v, OP_TypeCheck, iReg, pTab->nNVCol); + sqlite3VdbeAppendP4(v, pTab, P4_TABLE); + } + return; + } + zColAff = pTab->zColAff; if( zColAff==0 ){ sqlite3 *db = sqlite3VdbeDb(v); zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1); @@ -157,6 +197,8 @@ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ if( iReg ){ sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i); }else{ + assert( sqlite3VdbeGetOp(v, -1)->opcode==OP_MakeRecord + || sqlite3VdbeDb(v)->mallocFailed ); sqlite3VdbeChangeP4(v, -1, zColAff, i); } } @@ -240,24 +282,30 @@ void sqlite3ComputeGeneratedColumns( ** that appropriate affinity has been applied to the regular columns */ sqlite3TableAffinity(pParse->pVdbe, pTab, iRegStore); - if( (pTab->tabFlags & TF_HasStored)!=0 - && (pOp = sqlite3VdbeGetOp(pParse->pVdbe,-1))->opcode==OP_Affinity - ){ - /* Change the OP_Affinity argument to '@' (NONE) for all stored - ** columns. '@' is the no-op affinity and those columns have not - ** yet been computed. */ - int ii, jj; - char *zP4 = pOp->p4.z; - assert( zP4!=0 ); - assert( pOp->p4type==P4_DYNAMIC ); - for(ii=jj=0; zP4[jj]; ii++){ - if( pTab->aCol[ii].colFlags & COLFLAG_VIRTUAL ){ - continue; - } - if( pTab->aCol[ii].colFlags & COLFLAG_STORED ){ - zP4[jj] = SQLITE_AFF_NONE; + if( (pTab->tabFlags & TF_HasStored)!=0 ){ + pOp = sqlite3VdbeGetOp(pParse->pVdbe,-1); + if( pOp->opcode==OP_Affinity ){ + /* Change the OP_Affinity argument to '@' (NONE) for all stored + ** columns. '@' is the no-op affinity and those columns have not + ** yet been computed. */ + int ii, jj; + char *zP4 = pOp->p4.z; + assert( zP4!=0 ); + assert( pOp->p4type==P4_DYNAMIC ); + for(ii=jj=0; zP4[jj]; ii++){ + if( pTab->aCol[ii].colFlags & COLFLAG_VIRTUAL ){ + continue; + } + if( pTab->aCol[ii].colFlags & COLFLAG_STORED ){ + zP4[jj] = SQLITE_AFF_NONE; + } + jj++; } - jj++; + }else if( pOp->opcode==OP_TypeCheck ){ + /* If an OP_TypeCheck was generated because the table is STRICT, + ** then set the P3 operand to indicate that generated columns should + ** not be checked */ + pOp->p3 = 1; } } @@ -293,7 +341,7 @@ void sqlite3ComputeGeneratedColumns( int x; pCol->colFlags |= COLFLAG_BUSY; w.eCode = 0; - sqlite3WalkExpr(&w, pCol->pDflt); + sqlite3WalkExpr(&w, sqlite3ColumnExpr(pTab, pCol)); pCol->colFlags &= ~COLFLAG_BUSY; if( w.eCode & COLFLAG_NOTAVAIL ){ pRedo = pCol; @@ -302,13 +350,13 @@ void sqlite3ComputeGeneratedColumns( eProgress = 1; assert( pCol->colFlags & COLFLAG_GENERATED ); x = sqlite3TableColumnToStorage(pTab, i) + iRegStore; - sqlite3ExprCodeGeneratedColumn(pParse, pCol, x); + sqlite3ExprCodeGeneratedColumn(pParse, pTab, pCol, x); pCol->colFlags &= ~COLFLAG_NOTAVAIL; } } }while( pRedo && eProgress ); if( pRedo ){ - sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pRedo->zName); + sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pRedo->zCnName); } pParse->iSelfTab = 0; } @@ -703,7 +751,7 @@ void sqlite3Insert( */ #ifndef SQLITE_OMIT_TRIGGER pTrigger = sqlite3TriggersExist(pParse, pTab, TK_INSERT, 0, &tmask); - isView = pTab->pSelect!=0; + isView = IsView(pTab); #else # define pTrigger 0 # define tmask 0 @@ -794,7 +842,7 @@ void sqlite3Insert( } for(i=0; inId; i++){ for(j=0; jnCol; j++){ - if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){ + if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zCnName)==0 ){ pColumn->a[i].idx = j; if( i!=j ) bIdListInOrder = 0; if( j==pTab->iPKey ){ @@ -804,7 +852,7 @@ void sqlite3Insert( if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){ sqlite3ErrorMsg(pParse, "cannot INSERT into generated column \"%s\"", - pTab->aCol[j].zName); + pTab->aCol[j].zCnName); goto insert_cleanup; } #endif @@ -989,7 +1037,7 @@ void sqlite3Insert( pTab->zName); goto insert_cleanup; } - if( pTab->pSelect ){ + if( IsView(pTab) ){ sqlite3ErrorMsg(pParse, "cannot UPSERT a view"); goto insert_cleanup; } @@ -1088,7 +1136,9 @@ void sqlite3Insert( }else if( pColumn==0 ){ /* Hidden columns that are not explicitly named in the INSERT ** get there default value */ - sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore); + sqlite3ExprCodeFactorable(pParse, + sqlite3ColumnExpr(pTab, &pTab->aCol[i]), + iRegStore); continue; } } @@ -1097,13 +1147,17 @@ void sqlite3Insert( if( j>=pColumn->nId ){ /* A column not named in the insert column list gets its ** default value */ - sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore); + sqlite3ExprCodeFactorable(pParse, + sqlite3ColumnExpr(pTab, &pTab->aCol[i]), + iRegStore); continue; } k = j; }else if( nColumn==0 ){ /* This is INSERT INTO ... DEFAULT VALUES. Load the default value. */ - sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore); + sqlite3ExprCodeFactorable(pParse, + sqlite3ColumnExpr(pTab, &pTab->aCol[i]), + iRegStore); continue; }else{ k = i - nHidden; @@ -1618,7 +1672,7 @@ void sqlite3GenerateConstraintChecks( db = pParse->db; v = pParse->pVdbe; assert( v!=0 ); - assert( pTab->pSelect==0 ); /* This table is not a VIEW */ + assert( !IsView(pTab) ); /* This table is not a VIEW */ nCol = pTab->nCol; /* pPk is the PRIMARY KEY index for WITHOUT ROWID tables and NULL for @@ -1669,7 +1723,7 @@ void sqlite3GenerateConstraintChecks( } if( onError==OE_Replace ){ if( b2ndPass /* REPLACE becomes ABORT on the 2nd pass */ - || pCol->pDflt==0 /* REPLACE is ABORT if no DEFAULT value */ + || pCol->iDflt==0 /* REPLACE is ABORT if no DEFAULT value */ ){ testcase( pCol->colFlags & COLFLAG_VIRTUAL ); testcase( pCol->colFlags & COLFLAG_STORED ); @@ -1691,7 +1745,8 @@ void sqlite3GenerateConstraintChecks( VdbeCoverage(v); assert( (pCol->colFlags & COLFLAG_GENERATED)==0 ); nSeenReplace++; - sqlite3ExprCodeCopy(pParse, pCol->pDflt, iReg); + sqlite3ExprCodeCopy(pParse, + sqlite3ColumnExpr(pTab, pCol), iReg); sqlite3VdbeJumpHere(v, addr1); break; } @@ -1701,7 +1756,7 @@ void sqlite3GenerateConstraintChecks( case OE_Rollback: case OE_Fail: { char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName, - pCol->zName); + pCol->zCnName); sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError, iReg); sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC); @@ -1954,6 +2009,7 @@ void sqlite3GenerateConstraintChecks( if( onError==OE_Replace /* IPK rule is REPLACE */ && onError!=overrideError /* Rules for other constraints are different */ && pTab->pIndex /* There exist other constraints */ + && !upsertIpkDelay /* IPK check already deferred by UPSERT */ ){ ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1; VdbeComment((v, "defer IPK REPLACE until last")); @@ -2119,7 +2175,7 @@ void sqlite3GenerateConstraintChecks( testcase( sqlite3TableColumnToStorage(pTab, iField)!=iField ); x = sqlite3TableColumnToStorage(pTab, iField) + regNewData + 1; sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i); - VdbeComment((v, "%s", pTab->aCol[iField].zName)); + VdbeComment((v, "%s", pTab->aCol[iField].zCnName)); } } sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]); @@ -2170,7 +2226,8 @@ void sqlite3GenerateConstraintChecks( ** ** This is not possible for ENABLE_PREUPDATE_HOOK builds, as the row ** must be explicitly deleted in order to ensure any pre-update hook - ** is invoked. */ + ** is invoked. */ + assert( IsOrdinaryTable(pTab) ); #ifndef SQLITE_ENABLE_PREUPDATE_HOOK if( (ix==0 && pIdx->pNext==0) /* Condition 3 */ && pPk==pIdx /* Condition 2 */ @@ -2178,7 +2235,7 @@ void sqlite3GenerateConstraintChecks( && ( 0==(db->flags&SQLITE_RecTriggers) || /* Condition 4 */ 0==sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0)) && ( 0==(db->flags&SQLITE_ForeignKeys) || /* Condition 5 */ - (0==pTab->pFKey && 0==sqlite3FkReferences(pTab))) + (0==pTab->u.tab.pFKey && 0==sqlite3FkReferences(pTab))) ){ sqlite3VdbeResolveLabel(v, addrUniqueOk); continue; @@ -2213,7 +2270,7 @@ void sqlite3GenerateConstraintChecks( x = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]); sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i); VdbeComment((v, "%s.%s", pTab->zName, - pTab->aCol[pPk->aiColumn[i]].zName)); + pTab->aCol[pPk->aiColumn[i]].zCnName)); } } if( isUpdate ){ @@ -2277,7 +2334,8 @@ void sqlite3GenerateConstraintChecks( assert( onError==OE_Replace ); nConflictCk = sqlite3VdbeCurrentAddr(v) - addrConflictCk; - assert( nConflictCk>0 ); + assert( nConflictCk>0 || db->mallocFailed ); + testcase( nConflictCk<=0 ); testcase( nConflictCk>1 ); if( regTrigCnt ){ sqlite3MultiWrite(pParse); @@ -2360,6 +2418,7 @@ void sqlite3GenerateConstraintChecks( if( ipkTop ){ sqlite3VdbeGoto(v, ipkTop); VdbeComment((v, "Do IPK REPLACE")); + assert( ipkBottom>0 ); sqlite3VdbeJumpHere(v, ipkBottom); } @@ -2412,7 +2471,7 @@ void sqlite3SetMakeRecordP5(Vdbe *v, Table *pTab){ if( pTab->pSchema->file_format<2 ) return; for(i=pTab->nCol-1; i>0; i--){ - if( pTab->aCol[i].pDflt!=0 ) break; + if( pTab->aCol[i].iDflt!=0 ) break; if( pTab->aCol[i].colFlags & COLFLAG_PRIMKEY ) break; } sqlite3VdbeChangeP5(v, i+1); @@ -2477,7 +2536,7 @@ void sqlite3CompleteInsertion( v = pParse->pVdbe; assert( v!=0 ); - assert( pTab->pSelect==0 ); /* This table is not a VIEW */ + assert( !IsView(pTab) ); /* This table is not a VIEW */ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ /* All REPLACE indexes are at the end of the list */ assert( pIdx->onError!=OE_Replace @@ -2490,7 +2549,6 @@ void sqlite3CompleteInsertion( } pik_flags = (useSeekResult ? OPFLAG_USESEEKRESULT : 0); if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){ - assert( pParse->nested==0 ); pik_flags |= OPFLAG_NCHANGE; pik_flags |= (update_flags & OPFLAG_SAVEPOSITION); if( update_flags==0 ){ @@ -2563,8 +2621,9 @@ int sqlite3OpenTableAndIndices( assert( op==OP_OpenWrite || p5==0 ); if( IsVirtual(pTab) ){ /* This routine is a no-op for virtual tables. Leave the output - ** variables *piDataCur and *piIdxCur uninitialized so that valgrind - ** can detect if they are used by mistake in the caller. */ + ** variables *piDataCur and *piIdxCur set to illegal cursor numbers + ** for improved error detection. */ + *piDataCur = *piIdxCur = -999; return 0; } iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); @@ -2779,13 +2838,8 @@ static int xferOptimization( if( HasRowid(pDest)!=HasRowid(pSrc) ){ return 0; /* source and destination must both be WITHOUT ROWID or not */ } -#ifndef SQLITE_OMIT_VIRTUALTABLE - if( IsVirtual(pSrc) ){ - return 0; /* tab2 must not be a virtual table */ - } -#endif - if( pSrc->pSelect ){ - return 0; /* tab2 may not be a view */ + if( !IsOrdinaryTable(pSrc) ){ + return 0; /* tab2 may not be a view or virtual table */ } if( pDest->nCol!=pSrc->nCol ){ return 0; /* Number of columns must be the same in tab1 and tab2 */ @@ -2793,6 +2847,9 @@ static int xferOptimization( if( pDest->iPKey!=pSrc->iPKey ){ return 0; /* Both tables must have the same INTEGER PRIMARY KEY */ } + if( (pDest->tabFlags & TF_Strict)!=0 && (pSrc->tabFlags & TF_Strict)==0 ){ + return 0; /* Cannot feed from a non-strict into a strict table */ + } for(i=0; inCol; i++){ Column *pDestCol = &pDest->aCol[i]; Column *pSrcCol = &pSrc->aCol[i]; @@ -2829,7 +2886,9 @@ static int xferOptimization( ** This requirement could be relaxed for VIRTUAL columns, I suppose. */ if( (pDestCol->colFlags & COLFLAG_GENERATED)!=0 ){ - if( sqlite3ExprCompare(0, pSrcCol->pDflt, pDestCol->pDflt, -1)!=0 ){ + if( sqlite3ExprCompare(0, + sqlite3ColumnExpr(pSrc, pSrcCol), + sqlite3ColumnExpr(pDest, pDestCol), -1)!=0 ){ testcase( pDestCol->colFlags & COLFLAG_VIRTUAL ); testcase( pDestCol->colFlags & COLFLAG_STORED ); return 0; /* Different generator expressions */ @@ -2839,7 +2898,8 @@ static int xferOptimization( if( pDestCol->affinity!=pSrcCol->affinity ){ return 0; /* Affinity must be the same on all columns */ } - if( sqlite3_stricmp(pDestCol->zColl, pSrcCol->zColl)!=0 ){ + if( sqlite3_stricmp(sqlite3ColumnColl(pDestCol), + sqlite3ColumnColl(pSrcCol))!=0 ){ return 0; /* Collating sequence must be the same on all columns */ } if( pDestCol->notNull && !pSrcCol->notNull ){ @@ -2847,11 +2907,15 @@ static int xferOptimization( } /* Default values for second and subsequent columns need to match. */ if( (pDestCol->colFlags & COLFLAG_GENERATED)==0 && i>0 ){ - assert( pDestCol->pDflt==0 || pDestCol->pDflt->op==TK_SPAN ); - assert( pSrcCol->pDflt==0 || pSrcCol->pDflt->op==TK_SPAN ); - if( (pDestCol->pDflt==0)!=(pSrcCol->pDflt==0) - || (pDestCol->pDflt && strcmp(pDestCol->pDflt->u.zToken, - pSrcCol->pDflt->u.zToken)!=0) + Expr *pDestExpr = sqlite3ColumnExpr(pDest, pDestCol); + Expr *pSrcExpr = sqlite3ColumnExpr(pSrc, pSrcCol); + assert( pDestExpr==0 || pDestExpr->op==TK_SPAN ); + assert( pDestExpr==0 || !ExprHasProperty(pDestExpr, EP_IntValue) ); + assert( pSrcExpr==0 || pSrcExpr->op==TK_SPAN ); + assert( pSrcExpr==0 || !ExprHasProperty(pSrcExpr, EP_IntValue) ); + if( (pDestExpr==0)!=(pSrcExpr==0) + || (pDestExpr!=0 && strcmp(pDestExpr->u.zToken, + pSrcExpr->u.zToken)!=0) ){ return 0; /* Default values must be the same for all columns */ } @@ -2888,7 +2952,8 @@ static int xferOptimization( ** the extra complication to make this rule less restrictive is probably ** not worth the effort. Ticket [6284df89debdfa61db8073e062908af0c9b6118e] */ - if( (db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){ + assert( IsOrdinaryTable(pDest) ); + if( (db->flags & SQLITE_ForeignKeys)!=0 && pDest->u.tab.pFKey!=0 ){ return 0; } #endif diff --git a/src/loadext.c b/src/loadext.c index aeea837c..4edefec0 100644 --- a/src/loadext.c +++ b/src/loadext.c @@ -480,6 +480,11 @@ static const sqlite3_api_routines sqlite3Apis = { sqlite3_database_file_object, /* Version 3.34.0 and later */ sqlite3_txn_state, + /* Version 3.36.1 and later */ + sqlite3_changes64, + sqlite3_total_changes64, + /* Version 3.37.0 and later */ + sqlite3_autovacuum_pages, }; /* True if x is the directory separator character diff --git a/src/main.c b/src/main.c index a04a6bc0..804719f1 100644 --- a/src/main.c +++ b/src/main.c @@ -1086,7 +1086,7 @@ void sqlite3_set_last_insert_rowid(sqlite3 *db, sqlite3_int64 iRowid){ /* ** Return the number of changes in the most recent call to sqlite3_exec(). */ -int sqlite3_changes(sqlite3 *db){ +sqlite3_int64 sqlite3_changes64(sqlite3 *db){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; @@ -1095,11 +1095,14 @@ int sqlite3_changes(sqlite3 *db){ #endif return db->nChange; } +int sqlite3_changes(sqlite3 *db){ + return (int)sqlite3_changes64(db); +} /* ** Return the number of changes since the database handle was opened. */ -int sqlite3_total_changes(sqlite3 *db){ +sqlite3_int64 sqlite3_total_changes64(sqlite3 *db){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; @@ -1108,6 +1111,9 @@ int sqlite3_total_changes(sqlite3 *db){ #endif return db->nTotalChange; } +int sqlite3_total_changes(sqlite3 *db){ + return (int)sqlite3_total_changes64(db); +} /* ** Close all open savepoints. This function only manipulates fields of the @@ -1132,7 +1138,9 @@ void sqlite3CloseSavepoints(sqlite3 *db){ ** with SQLITE_ANY as the encoding. */ static void functionDestroy(sqlite3 *db, FuncDef *p){ - FuncDestructor *pDestructor = p->u.pDestructor; + FuncDestructor *pDestructor; + assert( (p->funcFlags & SQLITE_FUNC_BUILTIN)==0 ); + pDestructor = p->u.pDestructor; if( pDestructor ){ pDestructor->nRef--; if( pDestructor->nRef==0 ){ @@ -1236,7 +1244,7 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){ /* Convert the connection into a zombie and then close it. */ - db->magic = SQLITE_MAGIC_ZOMBIE; + db->eOpenState = SQLITE_STATE_ZOMBIE; sqlite3LeaveMutexAndCloseZombie(db); return SQLITE_OK; } @@ -1300,7 +1308,7 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ ** or if the connection has not yet been closed by sqlite3_close_v2(), ** then just leave the mutex and return. */ - if( db->magic!=SQLITE_MAGIC_ZOMBIE || connectionIsBusy(db) ){ + if( db->eOpenState!=SQLITE_STATE_ZOMBIE || connectionIsBusy(db) ){ sqlite3_mutex_leave(db->mutex); return; } @@ -1386,7 +1394,7 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ sqlite3_free(db->auth.zAuthPW); #endif - db->magic = SQLITE_MAGIC_ERROR; + db->eOpenState = SQLITE_STATE_ERROR; /* The temp-database schema is allocated differently from the other schema ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()). @@ -1395,8 +1403,11 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ ** structure? */ sqlite3DbFree(db, db->aDb[1].pSchema); + if( db->xAutovacDestr ){ + db->xAutovacDestr(db->pAutovacPagesArg); + } sqlite3_mutex_leave(db->mutex); - db->magic = SQLITE_MAGIC_CLOSED; + db->eOpenState = SQLITE_STATE_CLOSED; sqlite3_mutex_free(db->mutex); assert( sqlite3LookasideUsed(db,0)==0 ); if( db->lookaside.bMalloced ){ @@ -1449,7 +1460,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){ /* Any deferred constraint violations have now been resolved. */ db->nDeferredCons = 0; db->nDeferredImmCons = 0; - db->flags &= ~(u64)SQLITE_DeferFKs; + db->flags &= ~(u64)(SQLITE_DeferFKs|SQLITE_CorruptRdOnly); /* If one has been configured, invoke the rollback-hook callback */ if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){ @@ -1784,7 +1795,7 @@ int sqlite3_busy_timeout(sqlite3 *db, int ms){ */ void sqlite3_interrupt(sqlite3 *db){ #ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) && (db==0 || db->magic!=SQLITE_MAGIC_ZOMBIE) ){ + if( !sqlite3SafetyCheckOk(db) && (db==0 || db->eOpenState!=SQLITE_STATE_ZOMBIE) ){ (void)SQLITE_MISUSE_BKPT; return; } @@ -1813,7 +1824,6 @@ int sqlite3CreateFunc( FuncDestructor *pDestructor ){ FuncDef *p; - int nName; int extraFlags; assert( sqlite3_mutex_held(db->mutex) ); @@ -1823,7 +1833,7 @@ int sqlite3CreateFunc( || ((xFinal==0)!=(xStep==0)) /* Both or neither of xFinal and xStep */ || ((xValue==0)!=(xInverse==0)) /* Both or neither of xValue, xInverse */ || (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) - || (255<(nName = sqlite3Strlen30( zFunctionName))) + || (255nRef==0 ){ - assert( rc!=SQLITE_OK ); + assert( rc!=SQLITE_OK || (xStep==0 && xFinal==0) ); xDestroy(p); sqlite3_free(pArg); } @@ -2286,6 +2307,34 @@ void *sqlite3_preupdate_hook( } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ +/* +** Register a function to be invoked prior to each autovacuum that +** determines the number of pages to vacuum. +*/ +int sqlite3_autovacuum_pages( + sqlite3 *db, /* Attach the hook to this database */ + unsigned int (*xCallback)(void*,const char*,u32,u32,u32), + void *pArg, /* Argument to the function */ + void (*xDestructor)(void*) /* Destructor for pArg */ +){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + if( xDestructor ) xDestructor(pArg); + return SQLITE_MISUSE_BKPT; + } +#endif + sqlite3_mutex_enter(db->mutex); + if( db->xAutovacDestr ){ + db->xAutovacDestr(db->pAutovacPagesArg); + } + db->xAutovacPages = xCallback; + db->pAutovacPagesArg = pArg; + db->xAutovacDestr = xDestructor; + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; +} + + #ifndef SQLITE_OMIT_WAL /* ** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint(). @@ -2808,6 +2857,8 @@ int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ if( newLimit>=0 ){ /* IMP: R-52476-28732 */ if( newLimit>aHardLimit[limitId] ){ newLimit = aHardLimit[limitId]; /* IMP: R-51463-25634 */ + }else if( newLimit<1 && limitId==SQLITE_LIMIT_LENGTH ){ + newLimit = 1; } db->aLimit[limitId] = newLimit; } @@ -3079,7 +3130,7 @@ int sqlite3ParseUri( */ static const char *uriParameter(const char *zFilename, const char *zParam){ zFilename += sqlite3Strlen30(zFilename) + 1; - while( zFilename[0] ){ + while( ALWAYS(zFilename!=0) && zFilename[0] ){ int x = strcmp(zFilename, zParam); zFilename += sqlite3Strlen30(zFilename) + 1; if( x==0 ) return zFilename; @@ -3139,8 +3190,8 @@ static int openDatabase( ** dealt with in the previous code block. Besides these, the only ** valid input flags for sqlite3_open_v2() are SQLITE_OPEN_READONLY, ** SQLITE_OPEN_READWRITE, SQLITE_OPEN_CREATE, SQLITE_OPEN_SHAREDCACHE, - ** SQLITE_OPEN_PRIVATECACHE, and some reserved bits. Silently mask - ** off all other flags. + ** SQLITE_OPEN_PRIVATECACHE, SQLITE_OPEN_EXRESCODE, and some reserved + ** bits. Silently mask off all other flags. */ flags &= ~( SQLITE_OPEN_DELETEONCLOSE | SQLITE_OPEN_EXCLUSIVE | @@ -3175,9 +3226,9 @@ static int openDatabase( } } sqlite3_mutex_enter(db->mutex); - db->errMask = 0xff; + db->errMask = (flags & SQLITE_OPEN_EXRESCODE)!=0 ? 0xffffffff : 0xff; db->nDb = 2; - db->magic = SQLITE_MAGIC_BUSY; + db->eOpenState = SQLITE_STATE_BUSY; db->aDb = db->aDbStatic; db->lookaside.bDisable = 1; db->lookaside.sz = 0; @@ -3189,7 +3240,15 @@ static int openDatabase( db->nextAutovac = -1; db->szMmap = sqlite3GlobalConfig.szMmap; db->nextPagesize = 0; + db->init.azInit = sqlite3StdType; /* Any array of string ptrs will do */ +#ifdef SQLITE_ENABLE_SORTER_MMAP + /* Beginning with version 3.37.0, using the VFS xFetch() API to memory-map + ** the temporary files used to do external sorts (see code in vdbesort.c) + ** is disabled. It can still be used either by defining + ** SQLITE_ENABLE_SORTER_MMAP at compile time or by using the + ** SQLITE_TESTCTRL_SORTER_MMAP test-control at runtime. */ db->nMaxSorterMmap = 0x7FFFFFFF; +#endif db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger | SQLITE_EnableView @@ -3337,7 +3396,7 @@ static int openDatabase( db->aDb[1].zDbSName = "temp"; db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF; - db->magic = SQLITE_MAGIC_OPEN; + db->eOpenState = SQLITE_STATE_OPEN; if( db->mallocFailed ){ goto opendb_out; } @@ -3399,12 +3458,12 @@ opendb_out: sqlite3_mutex_leave(db->mutex); } rc = sqlite3_errcode(db); - assert( db!=0 || rc==SQLITE_NOMEM ); - if( rc==SQLITE_NOMEM ){ + assert( db!=0 || (rc&0xff)==SQLITE_NOMEM ); + if( (rc&0xff)==SQLITE_NOMEM ){ sqlite3_close(db); db = 0; }else if( rc!=SQLITE_OK ){ - db->magic = SQLITE_MAGIC_SICK; + db->eOpenState = SQLITE_STATE_SICK; } *ppDb = db; #ifdef SQLITE_ENABLE_SQLLOG @@ -3415,7 +3474,7 @@ opendb_out: } #endif sqlite3_free_filename(zOpen); - return rc & 0xff; + return rc; } @@ -3715,7 +3774,7 @@ int sqlite3_table_column_metadata( /* Locate the table in question */ pTab = sqlite3FindTable(db, zTableName, zDbName); - if( !pTab || pTab->pSelect ){ + if( !pTab || IsView(pTab) ){ pTab = 0; goto error_out; } @@ -3726,7 +3785,7 @@ int sqlite3_table_column_metadata( }else{ for(iCol=0; iColnCol; iCol++){ pCol = &pTab->aCol[iCol]; - if( 0==sqlite3StrICmp(pCol->zName, zColumnName) ){ + if( 0==sqlite3StrICmp(pCol->zCnName, zColumnName) ){ break; } } @@ -3753,7 +3812,7 @@ int sqlite3_table_column_metadata( */ if( pCol ){ zDataType = sqlite3ColumnType(pCol,0); - zCollSeq = pCol->zColl; + zCollSeq = sqlite3ColumnColl(pCol); notnull = pCol->notNull!=0; primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0; autoinc = pTab->iPKey==iCol && (pTab->tabFlags & TF_Autoincrement)!=0; @@ -4203,12 +4262,16 @@ int sqlite3_test_control(int op, ...){ */ case SQLITE_TESTCTRL_IMPOSTER: { sqlite3 *db = va_arg(ap, sqlite3*); + int iDb; sqlite3_mutex_enter(db->mutex); - db->init.iDb = sqlite3FindDbName(db, va_arg(ap,const char*)); - db->init.busy = db->init.imposterTable = va_arg(ap,int); - db->init.newTnum = va_arg(ap,int); - if( db->init.busy==0 && db->init.newTnum>0 ){ - sqlite3ResetAllSchemasOfConnection(db); + iDb = sqlite3FindDbName(db, va_arg(ap,const char*)); + if( iDb>=0 ){ + db->init.iDb = iDb; + db->init.busy = db->init.imposterTable = va_arg(ap,int); + db->init.newTnum = va_arg(ap,int); + if( db->init.busy==0 && db->init.newTnum>0 ){ + sqlite3ResetAllSchemasOfConnection(db); + } } sqlite3_mutex_leave(db->mutex); break; @@ -4420,7 +4483,7 @@ const char *sqlite3_uri_key(const char *zFilename, int N){ if( zFilename==0 || N<0 ) return 0; zFilename = databaseName(zFilename); zFilename += sqlite3Strlen30(zFilename) + 1; - while( zFilename[0] && (N--)>0 ){ + while( ALWAYS(zFilename) && zFilename[0] && (N--)>0 ){ zFilename += sqlite3Strlen30(zFilename) + 1; zFilename += sqlite3Strlen30(zFilename) + 1; } @@ -4463,12 +4526,14 @@ sqlite3_int64 sqlite3_uri_int64( ** corruption. */ const char *sqlite3_filename_database(const char *zFilename){ + if( zFilename==0 ) return 0; return databaseName(zFilename); } const char *sqlite3_filename_journal(const char *zFilename){ + if( zFilename==0 ) return 0; zFilename = databaseName(zFilename); zFilename += sqlite3Strlen30(zFilename) + 1; - while( zFilename[0] ){ + while( ALWAYS(zFilename) && zFilename[0] ){ zFilename += sqlite3Strlen30(zFilename) + 1; zFilename += sqlite3Strlen30(zFilename) + 1; } @@ -4479,7 +4544,7 @@ const char *sqlite3_filename_wal(const char *zFilename){ return 0; #else zFilename = sqlite3_filename_journal(zFilename); - zFilename += sqlite3Strlen30(zFilename) + 1; + if( zFilename ) zFilename += sqlite3Strlen30(zFilename) + 1; return zFilename; #endif } diff --git a/src/malloc.c b/src/malloc.c index b8a88f12..932cecc2 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -316,7 +316,7 @@ void *sqlite3_malloc64(sqlite3_uint64 n){ ** TRUE if p is a lookaside memory allocation from db */ #ifndef SQLITE_OMIT_LOOKASIDE -static int isLookaside(sqlite3 *db, void *p){ +static int isLookaside(sqlite3 *db, const void *p){ return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pEnd); } #else @@ -327,18 +327,18 @@ static int isLookaside(sqlite3 *db, void *p){ ** Return the size of a memory allocation previously obtained from ** sqlite3Malloc() or sqlite3_malloc(). */ -int sqlite3MallocSize(void *p){ +int sqlite3MallocSize(const void *p){ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); - return sqlite3GlobalConfig.m.xSize(p); + return sqlite3GlobalConfig.m.xSize((void*)p); } -static int lookasideMallocSize(sqlite3 *db, void *p){ +static int lookasideMallocSize(sqlite3 *db, const void *p){ #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE return plookaside.pMiddle ? db->lookaside.szTrue : LOOKASIDE_SMALL; #else return db->lookaside.szTrue; #endif } -int sqlite3DbMallocSize(sqlite3 *db, void *p){ +int sqlite3DbMallocSize(sqlite3 *db, const void *p){ assert( p!=0 ); #ifdef SQLITE_DEBUG if( db==0 || !isLookaside(db,p) ){ @@ -365,7 +365,7 @@ int sqlite3DbMallocSize(sqlite3 *db, void *p){ } } } - return sqlite3GlobalConfig.m.xSize(p); + return sqlite3GlobalConfig.m.xSize((void*)p); } sqlite3_uint64 sqlite3_msize(void *p){ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); diff --git a/src/mem2.c b/src/mem2.c index ac031508..04d6298d 100644 --- a/src/mem2.c +++ b/src/mem2.c @@ -149,7 +149,7 @@ static void adjustStats(int iSize, int increment){ ** This routine checks the guards at either end of the allocation and ** if they are incorrect it asserts. */ -static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){ +static struct MemBlockHdr *sqlite3MemsysGetHeader(const void *pAllocation){ struct MemBlockHdr *p; int *pInt; u8 *pU8; @@ -396,7 +396,7 @@ void sqlite3MemdebugSetType(void *p, u8 eType){ ** ** assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); */ -int sqlite3MemdebugHasType(void *p, u8 eType){ +int sqlite3MemdebugHasType(const void *p, u8 eType){ int rc = 1; if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){ struct MemBlockHdr *pHdr; @@ -418,7 +418,7 @@ int sqlite3MemdebugHasType(void *p, u8 eType){ ** ** assert( sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); */ -int sqlite3MemdebugNoType(void *p, u8 eType){ +int sqlite3MemdebugNoType(const void *p, u8 eType){ int rc = 1; if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){ struct MemBlockHdr *pHdr; diff --git a/src/memdb.c b/src/memdb.c index 4e5751f9..31b2324b 100644 --- a/src/memdb.c +++ b/src/memdb.c @@ -272,7 +272,7 @@ static int memdbRead( */ static int memdbEnlarge(MemStore *p, sqlite3_int64 newSz){ unsigned char *pNew; - if( (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)==0 || p->nMmap>0 ){ + if( (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)==0 || NEVER(p->nMmap>0) ){ return SQLITE_FULL; } if( newSz>p->szMax ){ @@ -331,8 +331,9 @@ static int memdbTruncate(sqlite3_file *pFile, sqlite_int64 size){ MemStore *p = ((MemFile*)pFile)->pStore; int rc = SQLITE_OK; memdbEnter(p); - if( NEVER(size>p->sz) ){ - rc = SQLITE_FULL; + if( size>p->sz ){ + /* This can only happen with a corrupt wal mode db */ + rc = SQLITE_CORRUPT; }else{ p->sz = size; } @@ -471,7 +472,7 @@ static int memdbFetch( ){ MemStore *p = ((MemFile*)pFile)->pStore; memdbEnter(p); - if( iOfst+iAmt>p->sz ){ + if( iOfst+iAmt>p->sz || (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)!=0 ){ *pp = 0; }else{ p->nMmap++; @@ -505,10 +506,9 @@ static int memdbOpen( MemFile *pFile = (MemFile*)pFd; MemStore *p = 0; int szName; - if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){ - return ORIGVFS(pVfs)->xOpen(ORIGVFS(pVfs), zName, pFd, flags, pOutFlags); - } - memset(pFile, 0, sizeof(*p)); + UNUSED_PARAMETER(pVfs); + + memset(pFile, 0, sizeof(*pFile)); szName = sqlite3Strlen30(zName); if( szName>1 && zName[0]=='/' ){ int i; @@ -567,8 +567,9 @@ static int memdbOpen( p->szMax = sqlite3GlobalConfig.mxMemdbSize; } pFile->pStore = p; - assert( pOutFlags!=0 ); /* True because flags==SQLITE_OPEN_MAIN_DB */ - *pOutFlags = flags | SQLITE_OPEN_MEMORY; + if( pOutFlags!=0 ){ + *pOutFlags = flags | SQLITE_OPEN_MEMORY; + } pFd->pMethods = &memdb_io_methods; memdbLeave(p); return SQLITE_OK; @@ -809,10 +810,11 @@ int sqlite3_deserialize( sqlite3_mutex_enter(db->mutex); if( zSchema==0 ) zSchema = db->aDb[0].zDbSName; iDb = sqlite3FindDbName(db, zSchema); - if( iDb<0 ){ + testcase( iDb==1 ); + if( iDb<2 && iDb!=0 ){ rc = SQLITE_ERROR; goto end_deserialize; - } + } zSql = sqlite3_mprintf("ATTACH x AS %Q", zSchema); if( zSql==0 ){ rc = SQLITE_NOMEM; diff --git a/src/memjournal.c b/src/memjournal.c index 598d5cc0..63ef2ad7 100644 --- a/src/memjournal.c +++ b/src/memjournal.c @@ -265,7 +265,7 @@ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){ p->pFirst = 0; }else{ i64 iOff = p->nChunkSize; - for(pIter=p->pFirst; ALWAYS(pIter) && iOff<=size; pIter=pIter->pNext){ + for(pIter=p->pFirst; ALWAYS(pIter) && iOffpNext){ iOff += p->nChunkSize; } if( ALWAYS(pIter) ){ diff --git a/src/os.c b/src/os.c index f1798ff9..0c3c9d89 100644 --- a/src/os.c +++ b/src/os.c @@ -161,6 +161,7 @@ int sqlite3OsSectorSize(sqlite3_file *id){ return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE); } int sqlite3OsDeviceCharacteristics(sqlite3_file *id){ + if( NEVER(id->pMethods==0) ) return 0; return id->pMethods->xDeviceCharacteristics(id); } #ifndef SQLITE_OMIT_WAL @@ -315,12 +316,15 @@ int sqlite3OsOpenMalloc( rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, pOutFlags); if( rc!=SQLITE_OK ){ sqlite3_free(pFile); + *ppFile = 0; }else{ *ppFile = pFile; } }else{ + *ppFile = 0; rc = SQLITE_NOMEM_BKPT; } + assert( *ppFile!=0 || rc!=SQLITE_OK ); return rc; } void sqlite3OsCloseFree(sqlite3_file *pFile){ diff --git a/src/os_unix.c b/src/os_unix.c index d45fdaba..cd619f5c 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -3951,7 +3951,9 @@ static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){ /* Forward declaration */ static int unixGetTempname(int nBuf, char *zBuf); -static int unixFcntlExternalReader(unixFile*, int*); +#ifndef SQLITE_OMIT_WAL + static int unixFcntlExternalReader(unixFile*, int*); +#endif /* ** Information and control of an open file handle. @@ -4070,7 +4072,12 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ #endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */ case SQLITE_FCNTL_EXTERNAL_READER: { +#ifndef SQLITE_OMIT_WAL return unixFcntlExternalReader((unixFile*)id, (int*)pArg); +#else + *(int*)pArg = 0; + return SQLITE_OK; +#endif } } return SQLITE_NOTFOUND; @@ -5792,24 +5799,34 @@ static int fillInUnixFile( } /* +** Directories to consider for temp files. +*/ +static const char *azTempDirs[] = { + 0, + 0, + "/var/tmp", + "/usr/tmp", + "/tmp", + "." +}; + +/* +** Initialize first two members of azTempDirs[] array. +*/ +static void unixTempFileInit(void){ + azTempDirs[0] = getenv("SQLITE_TMPDIR"); + azTempDirs[1] = getenv("TMPDIR"); +} + +/* ** Return the name of a directory in which to put temporary files. ** If no suitable temporary file directory can be found, return NULL. */ static const char *unixTempFileDir(void){ - static const char *azDirs[] = { - 0, - 0, - "/var/tmp", - "/usr/tmp", - "/tmp", - "." - }; unsigned int i = 0; struct stat buf; const char *zDir = sqlite3_temp_directory; - if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR"); - if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR"); while(1){ if( zDir!=0 && osStat(zDir, &buf)==0 @@ -5818,8 +5835,8 @@ static const char *unixTempFileDir(void){ ){ return zDir; } - if( i>=sizeof(azDirs)/sizeof(azDirs[0]) ) break; - zDir = azDirs[i++]; + if( i>=sizeof(azTempDirs)/sizeof(azTempDirs[0]) ) break; + zDir = azTempDirs[i++]; } return 0; } @@ -6125,6 +6142,11 @@ static int unixOpen( } memset(p, 0, sizeof(unixFile)); +#ifdef SQLITE_ASSERT_NO_FILES + /* Applications that never read or write a persistent disk files */ + assert( zName==0 ); +#endif + if( eType==SQLITE_OPEN_MAIN_DB ){ UnixUnusedFd *pUnused; pUnused = findReusableFd(zName, flags); @@ -8086,6 +8108,9 @@ int sqlite3_os_init(void){ assert( UNIX_SHM_DMS==128 ); /* Byte offset of the deadman-switch */ #endif + /* Initialize temp file dir array. */ + unixTempFileInit(); + return SQLITE_OK; } diff --git a/src/pager.c b/src/pager.c index 12a78cde..a2fc10f2 100644 --- a/src/pager.c +++ b/src/pager.c @@ -630,6 +630,7 @@ struct Pager { u8 noLock; /* Do not lock (except in WAL mode) */ u8 readOnly; /* True for a read-only database */ u8 memDb; /* True to inhibit all file I/O */ + u8 memVfs; /* VFS-implemented memory database */ /************************************************************************** ** The following block contains those class members that change during @@ -679,8 +680,8 @@ struct Pager { i16 nReserve; /* Number of unused bytes at end of each page */ u32 vfsFlags; /* Flags for sqlite3_vfs.xOpen() */ u32 sectorSize; /* Assumed sector size during rollback */ - int pageSize; /* Number of bytes in a page */ Pgno mxPgno; /* Maximum allowed size of the database */ + i64 pageSize; /* Number of bytes in a page */ i64 journalSizeLimit; /* Size limit for persistent journal files */ char *zFilename; /* Name of the database file */ char *zJournal; /* Name of the journal file */ @@ -3024,6 +3025,7 @@ static int readDbPage(PgHdr *pPg){ */ static void pager_write_changecounter(PgHdr *pPg){ u32 change_counter; + if( NEVER(pPg==0) ) return; /* Increment the value just read and write it back to byte 24. */ change_counter = sqlite3Get4byte((u8*)pPg->pPager->dbFileVers)+1; @@ -3915,7 +3917,7 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){ #if defined(SQLITE_DEBUG) static void assertTruncateConstraintCb(PgHdr *pPg){ assert( pPg->flags&PGHDR_DIRTY ); - assert( !subjRequiresPage(pPg) || pPg->pgno<=pPg->pPager->dbSize ); + assert( pPg->pgno<=pPg->pPager->dbSize || !subjRequiresPage(pPg) ); } static void assertTruncateConstraint(Pager *pPager){ sqlite3PcacheIterateDirty(pPager->pPCache, assertTruncateConstraintCb); @@ -4858,6 +4860,7 @@ int sqlite3PagerOpen( pPager->zWal = 0; } #endif + (void)pPtr; /* Suppress warning about unused pPtr value */ if( nPathname ) sqlite3DbFree(0, zPathname); pPager->pVfs = pVfs; @@ -4870,7 +4873,7 @@ int sqlite3PagerOpen( rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout); assert( !memDb ); #ifndef SQLITE_OMIT_DESERIALIZE - memJM = (fout&SQLITE_OPEN_MEMORY)!=0; + pPager->memVfs = memJM = (fout&SQLITE_OPEN_MEMORY)!=0; #endif readOnly = (fout&SQLITE_OPEN_READONLY)!=0; @@ -5255,7 +5258,7 @@ int sqlite3PagerSharedLock(Pager *pPager){ ** may mean that the pager was in the error-state when this ** function was called and the journal file does not exist. */ - if( !isOpen(pPager->jfd) ){ + if( !isOpen(pPager->jfd) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){ sqlite3_vfs * const pVfs = pPager->pVfs; int bExists; /* True if journal file exists */ rc = sqlite3OsAccess( @@ -6737,8 +6740,8 @@ int sqlite3PagerRefcount(Pager *pPager){ ** used by the pager and its associated cache. */ int sqlite3PagerMemUsed(Pager *pPager){ - int perPageSize = pPager->pageSize + pPager->nExtra + sizeof(PgHdr) - + 5*sizeof(void*); + int perPageSize = pPager->pageSize + pPager->nExtra + + (int)(sizeof(PgHdr) + 5*sizeof(void*)); return perPageSize*sqlite3PcachePagecount(pPager->pPCache) + sqlite3MallocSize(pPager) + pPager->pageSize; @@ -6807,7 +6810,7 @@ void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){ ** Return true if this is an in-memory or temp-file backed pager. */ int sqlite3PagerIsMemdb(Pager *pPager){ - return pPager->tempFile; + return pPager->tempFile || pPager->memVfs; } /* @@ -6932,14 +6935,14 @@ int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){ } pPager->nSavepoint = nNew; - /* If this is a release of the outermost savepoint, truncate - ** the sub-journal to zero bytes in size. */ + /* Truncate the sub-journal so that it only includes the parts + ** that are still in use. */ if( op==SAVEPOINT_RELEASE ){ PagerSavepoint *pRel = &pPager->aSavepoint[nNew]; if( pRel->bTruncateOnRelease && isOpen(pPager->sjfd) ){ /* Only truncate if it is an in-memory sub-journal. */ if( sqlite3JournalIsInMemory(pPager->sjfd) ){ - i64 sz = (pPager->pageSize+4)*pRel->iSubRec; + i64 sz = (pPager->pageSize+4)*(i64)pRel->iSubRec; rc = sqlite3OsTruncate(pPager->sjfd, sz); assert( rc==SQLITE_OK ); } @@ -7127,7 +7130,7 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){ pPgOld = sqlite3PagerLookup(pPager, pgno); assert( !pPgOld || pPgOld->nRef==1 || CORRUPT_DB ); if( pPgOld ){ - if( pPgOld->nRef>1 ){ + if( NEVER(pPgOld->nRef>1) ){ sqlite3PagerUnrefNotNull(pPgOld); return SQLITE_CORRUPT_BKPT; } diff --git a/src/parse.y b/src/parse.y index 359b02bc..97a26c28 100644 --- a/src/parse.y +++ b/src/parse.y @@ -196,16 +196,19 @@ ifnotexists(A) ::= IF NOT EXISTS. {A = 1;} temp(A) ::= TEMP. {A = pParse->db->init.busy==0;} %endif SQLITE_OMIT_TEMPDB temp(A) ::= . {A = 0;} -create_table_args ::= LP columnlist conslist_opt(X) RP(E) table_options(F). { +create_table_args ::= LP columnlist conslist_opt(X) RP(E) table_option_set(F). { sqlite3EndTable(pParse,&X,&E,F,0); } create_table_args ::= AS select(S). { sqlite3EndTable(pParse,0,0,0,S); sqlite3SelectDelete(pParse->db, S); } -%type table_options {int} -table_options(A) ::= . {A = 0;} -table_options(A) ::= WITHOUT nm(X). { +%type table_option_set {u32} +%type table_option {u32} +table_option_set(A) ::= . {A = 0;} +table_option_set(A) ::= table_option(A). +table_option_set(A) ::= table_option_set(X) COMMA table_option(Y). {A = X|Y;} +table_option(A) ::= WITHOUT nm(X). { if( X.n==5 && sqlite3_strnicmp(X.z,"rowid",5)==0 ){ A = TF_WithoutRowid | TF_NoVisibleRowid; }else{ @@ -213,9 +216,17 @@ table_options(A) ::= WITHOUT nm(X). { sqlite3ErrorMsg(pParse, "unknown table option: %.*s", X.n, X.z); } } +table_option(A) ::= nm(X). { + if( X.n==6 && sqlite3_strnicmp(X.z,"strict",6)==0 ){ + A = TF_Strict; + }else{ + A = 0; + sqlite3ErrorMsg(pParse, "unknown table option: %.*s", X.n, X.z); + } +} columnlist ::= columnlist COMMA columnname carglist. columnlist ::= columnname carglist. -columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,&A,&Y);} +columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,A,Y);} // Declare some tokens early in order to influence their values, to // improve performance and reduce the executable size. The goal here is @@ -1028,9 +1039,9 @@ idlist(A) ::= nm(Y). ExprClearVVAProperties(p); p->iAgg = -1; p->pLeft = p->pRight = 0; - p->x.pList = 0; p->pAggInfo = 0; - p->y.pTab = 0; + memset(&p->x, 0, sizeof(p->x)); + memset(&p->y, 0, sizeof(p->y)); p->op2 = 0; p->iTable = 0; p->iColumn = 0; @@ -1254,20 +1265,28 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] { */ sqlite3ExprUnmapAndDelete(pParse, A); A = sqlite3Expr(pParse->db, TK_INTEGER, N ? "1" : "0"); - }else if( Y->nExpr==1 && sqlite3ExprIsConstant(Y->a[0].pExpr) ){ - Expr *pRHS = Y->a[0].pExpr; - Y->a[0].pExpr = 0; - sqlite3ExprListDelete(pParse->db, Y); - pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0); - A = sqlite3PExpr(pParse, TK_EQ, A, pRHS); - if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0); }else{ - A = sqlite3PExpr(pParse, TK_IN, A, 0); - if( A ){ - A->x.pList = Y; - sqlite3ExprSetHeightAndFlags(pParse, A); - }else{ + Expr *pRHS = Y->a[0].pExpr; + if( Y->nExpr==1 && sqlite3ExprIsConstant(pRHS) && A->op!=TK_VECTOR ){ + Y->a[0].pExpr = 0; sqlite3ExprListDelete(pParse->db, Y); + pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0); + A = sqlite3PExpr(pParse, TK_EQ, A, pRHS); + }else{ + A = sqlite3PExpr(pParse, TK_IN, A, 0); + if( A==0 ){ + sqlite3ExprListDelete(pParse->db, Y); + }else if( A->pLeft->op==TK_VECTOR ){ + int nExpr = A->pLeft->x.pList->nExpr; + Select *pSelectRHS = sqlite3ExprListToValues(pParse, nExpr, Y); + if( pSelectRHS ){ + parserDoubleLinkSelect(pParse, pSelectRHS); + sqlite3PExprAddSelect(pParse, A, pSelectRHS); + } + }else{ + A->x.pList = Y; + sqlite3ExprSetHeightAndFlags(pParse, A); + } } if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0); } @@ -1619,7 +1638,8 @@ cmd ::= ANALYZE nm(X) dbnm(Y). {sqlite3Analyze(pParse, &X, &Y);} %endif //////////////////////// ALTER TABLE table ... //////////////////////////////// -%ifndef SQLITE_OMIT_ALTERTABLE +%ifndef SQLITE_OMIT_ALTERTABLE +%ifndef SQLITE_OMIT_VIRTUALTABLE cmd ::= ALTER TABLE fullname(X) RENAME TO nm(Z). { sqlite3AlterRenameTable(pParse,X,&Z); } @@ -1643,7 +1663,8 @@ cmd ::= ALTER TABLE fullname(X) RENAME kwcolumn_opt nm(Y) TO nm(Z). { kwcolumn_opt ::= . kwcolumn_opt ::= COLUMNKW. -%endif SQLITE_OMIT_ALTERTABLE +%endif SQLITE_OMIT_VIRTUALTABLE +%endif SQLITE_OMIT_ALTERTABLE //////////////////////// CREATE VIRTUAL TABLE ... ///////////////////////////// %ifndef SQLITE_OMIT_VIRTUALTABLE diff --git a/src/pcache.c b/src/pcache.c index 36829be4..14d1e7cd 100644 --- a/src/pcache.c +++ b/src/pcache.c @@ -243,11 +243,14 @@ static int numberOfCachePages(PCache *p){ ** suggested cache size is set to N. */ return p->szCache; }else{ + i64 n; /* IMPLEMANTATION-OF: R-59858-46238 If the argument N is negative, then the ** number of cache pages is adjusted to be a number of pages that would ** use approximately abs(N*1024) bytes of memory based on the current ** page size. */ - return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); + n = ((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); + if( n>1000000000 ) n = 1000000000; + return (int)n; } } diff --git a/src/pcache1.c b/src/pcache1.c index 3eae6b63..a93b1468 100644 --- a/src/pcache1.c +++ b/src/pcache1.c @@ -817,12 +817,18 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){ */ static void pcache1Cachesize(sqlite3_pcache *p, int nMax){ PCache1 *pCache = (PCache1 *)p; + u32 n; + assert( nMax>=0 ); if( pCache->bPurgeable ){ PGroup *pGroup = pCache->pGroup; pcache1EnterMutex(pGroup); - pGroup->nMaxPage += (nMax - pCache->nMax); + n = (u32)nMax; + if( n > 0x7fff0000 - pGroup->nMaxPage + pCache->nMax ){ + n = 0x7fff0000 - pGroup->nMaxPage + pCache->nMax; + } + pGroup->nMaxPage += (n - pCache->nMax); pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; - pCache->nMax = nMax; + pCache->nMax = n; pCache->n90pct = pCache->nMax*9/10; pcache1EnforceMaxPage(pCache); pcache1LeaveMutex(pGroup); @@ -838,7 +844,7 @@ static void pcache1Shrink(sqlite3_pcache *p){ PCache1 *pCache = (PCache1*)p; if( pCache->bPurgeable ){ PGroup *pGroup = pCache->pGroup; - int savedMaxPage; + unsigned int savedMaxPage; pcache1EnterMutex(pGroup); savedMaxPage = pGroup->nMaxPage; pGroup->nMaxPage = 0; diff --git a/src/pragma.c b/src/pragma.c index 84f29c2f..ba84af75 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -467,7 +467,11 @@ void sqlite3Pragma( /* Locate the pragma in the lookup table */ pPragma = pragmaLocate(zLeft); - if( pPragma==0 ) goto pragma_out; + if( pPragma==0 ){ + /* IMP: R-43042-22504 No error messages are generated if an + ** unknown pragma is issued. */ + goto pragma_out; + } /* Make sure the database schema is loaded if the pragma requires that */ if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){ @@ -1117,6 +1121,14 @@ void sqlite3Pragma( }else{ db->flags &= ~mask; if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0; + if( (mask & SQLITE_WriteSchema)!=0 + && sqlite3_stricmp(zRight, "reset")==0 + ){ + /* IMP: R-60817-01178 If the argument is "RESET" then schema + ** writing is disabled (as with "PRAGMA writable_schema=OFF") and, + ** in addition, the schema is reloaded. */ + sqlite3ResetAllSchemasOfConnection(db); + } } /* Many of the flag-pragmas modify the code generated by the SQL @@ -1157,6 +1169,7 @@ void sqlite3Pragma( sqlite3ViewGetColumnNames(pParse, pTab); for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){ int isHidden = 0; + const Expr *pColExpr; if( pCol->colFlags & COLFLAG_NOINSERT ){ if( pPragma->iArg==0 ){ nHidden++; @@ -1177,13 +1190,16 @@ void sqlite3Pragma( }else{ for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){} } - assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN || isHidden>=2 ); + pColExpr = sqlite3ColumnExpr(pTab,pCol); + assert( pColExpr==0 || pColExpr->op==TK_SPAN || isHidden>=2 ); + assert( pColExpr==0 || !ExprHasProperty(pColExpr, EP_IntValue) + || isHidden>=2 ); sqlite3VdbeMultiLoad(v, 1, pPragma->iArg ? "issisii" : "issisi", i-nHidden, - pCol->zName, + pCol->zCnName, sqlite3ColumnType(pCol,""), pCol->notNull ? 1 : 0, - pCol->pDflt && isHidden<2 ? pCol->pDflt->u.zToken : 0, + (isHidden>=2 || pColExpr==0) ? 0 : pColExpr->u.zToken, k, isHidden); } @@ -1191,6 +1207,81 @@ void sqlite3Pragma( } break; + /* + ** PRAGMA table_list + ** + ** Return a single row for each table, virtual table, or view in the + ** entire schema. + ** + ** schema: Name of attached database hold this table + ** name: Name of the table itself + ** type: "table", "view", "virtual", "shadow" + ** ncol: Number of columns + ** wr: True for a WITHOUT ROWID table + ** strict: True for a STRICT table + */ + case PragTyp_TABLE_LIST: { + int ii; + pParse->nMem = 6; + sqlite3CodeVerifyNamedSchema(pParse, zDb); + for(ii=0; iinDb; ii++){ + HashElem *k; + Hash *pHash; + int initNCol; + if( zDb && sqlite3_stricmp(zDb, db->aDb[ii].zDbSName)!=0 ) continue; + + /* Ensure that the Table.nCol field is initialized for all views + ** and virtual tables. Each time we initialize a Table.nCol value + ** for a table, that can potentially disrupt the hash table, so restart + ** the initialization scan. + */ + pHash = &db->aDb[ii].pSchema->tblHash; + initNCol = sqliteHashCount(pHash); + while( initNCol-- ){ + for(k=sqliteHashFirst(pHash); 1; k=sqliteHashNext(k) ){ + Table *pTab; + if( k==0 ){ initNCol = 0; break; } + pTab = sqliteHashData(k); + if( pTab->nCol==0 ){ + char *zSql = sqlite3MPrintf(db, "SELECT*FROM\"%w\"", pTab->zName); + if( zSql ){ + sqlite3_stmt *pDummy = 0; + (void)sqlite3_prepare(db, zSql, -1, &pDummy, 0); + (void)sqlite3_finalize(pDummy); + sqlite3DbFree(db, zSql); + } + pHash = &db->aDb[ii].pSchema->tblHash; + break; + } + } + } + + for(k=sqliteHashFirst(pHash); k; k=sqliteHashNext(k) ){ + Table *pTab = sqliteHashData(k); + const char *zType; + if( zRight && sqlite3_stricmp(zRight, pTab->zName)!=0 ) continue; + if( IsView(pTab) ){ + zType = "view"; + }else if( IsVirtual(pTab) ){ + zType = "virtual"; + }else if( pTab->tabFlags & TF_Shadow ){ + zType = "shadow"; + }else{ + zType = "table"; + } + sqlite3VdbeMultiLoad(v, 1, "sssiii", + db->aDb[ii].zDbSName, + sqlite3PreferredTableName(pTab->zName), + zType, + pTab->nCol, + (pTab->tabFlags & TF_WithoutRowid)!=0, + (pTab->tabFlags & TF_Strict)!=0 + ); + } + } + } + break; + #ifdef SQLITE_DEBUG case PragTyp_STATS: { Index *pIdx; @@ -1200,7 +1291,7 @@ void sqlite3Pragma( for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){ Table *pTab = sqliteHashData(i); sqlite3VdbeMultiLoad(v, 1, "ssiii", - pTab->zName, + sqlite3PreferredTableName(pTab->zName), 0, pTab->szTabRow, pTab->nRowLogEst, @@ -1250,7 +1341,7 @@ void sqlite3Pragma( for(i=0; iaiColumn[i]; sqlite3VdbeMultiLoad(v, 1, "iisX", i, cnum, - cnum<0 ? 0 : pTab->aCol[cnum].zName); + cnum<0 ? 0 : pTab->aCol[cnum].zCnName); if( pPragma->iArg ){ sqlite3VdbeMultiLoad(v, 4, "isiX", pIdx->aSortOrder[i], @@ -1319,11 +1410,13 @@ void sqlite3Pragma( pParse->nMem = 6; for(i=0; iu.pHash ){ + assert( p->funcFlags & SQLITE_FUNC_BUILTIN ); pragmaFunclistLine(v, p, 1, showInternFunc); } } for(j=sqliteHashFirst(&db->aFunc); j; j=sqliteHashNext(j)){ p = (FuncDef*)sqliteHashData(j); + assert( (p->funcFlags & SQLITE_FUNC_BUILTIN)==0 ); pragmaFunclistLine(v, p, 0, showInternFunc); } } @@ -1357,8 +1450,8 @@ void sqlite3Pragma( FKey *pFK; Table *pTab; pTab = sqlite3FindTable(db, zRight, zDb); - if( pTab ){ - pFK = pTab->pFKey; + if( pTab && IsOrdinaryTable(pTab) ){ + pFK = pTab->u.tab.pFKey; if( pFK ){ int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); int i = 0; @@ -1371,7 +1464,7 @@ void sqlite3Pragma( i, j, pFK->zTo, - pTab->aCol[pFK->aCol[j].iFrom].zName, + pTab->aCol[pFK->aCol[j].iFrom].zCnName, pFK->aCol[j].zCol, actionName(pFK->aAction[1]), /* ON UPDATE */ actionName(pFK->aAction[0]), /* ON DELETE */ @@ -1417,7 +1510,7 @@ void sqlite3Pragma( pTab = (Table*)sqliteHashData(k); k = sqliteHashNext(k); } - if( pTab==0 || pTab->pFKey==0 ) continue; + if( pTab==0 || !IsOrdinaryTable(pTab) || pTab->u.tab.pFKey==0 ) continue; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); zDb = db->aDb[iDb].zDbSName; sqlite3CodeVerifySchema(pParse, iDb); @@ -1425,7 +1518,8 @@ void sqlite3Pragma( if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow; sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead); sqlite3VdbeLoadString(v, regResult, pTab->zName); - for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){ + assert( IsOrdinaryTable(pTab) ); + for(i=1, pFK=pTab->u.tab.pFKey; pFK; i++, pFK=pFK->pNextFrom){ pParent = sqlite3FindTable(db, pFK->zTo, zDb); if( pParent==0 ) continue; pIdx = 0; @@ -1447,7 +1541,8 @@ void sqlite3Pragma( if( pFK ) break; if( pParse->nTabnTab = i; addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, 0); VdbeCoverage(v); - for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){ + assert( IsOrdinaryTable(pTab) ); + for(i=1, pFK=pTab->u.tab.pFKey; pFK; i++, pFK=pFK->pNextFrom){ pParent = sqlite3FindTable(db, pFK->zTo, zDb); pIdx = 0; aiCols = 0; @@ -1461,6 +1556,7 @@ void sqlite3Pragma( ** regRow..regRow+n. If any of the child key values are NULL, this ** row cannot cause an FK violation. Jump directly to addrOk in ** this case. */ + if( regRow+pFK->nCol>pParse->nMem ) pParse->nMem = regRow+pFK->nCol; for(j=0; jnCol; j++){ int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom; sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j); @@ -1647,8 +1743,9 @@ void sqlite3Pragma( int loopTop; int iDataCur, iIdxCur; int r1 = -1; + int bStrict; - if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */ + if( !IsOrdinaryTable(pTab) ) continue; if( pObjTab && pObjTab!=pTab ) continue; pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0, @@ -1668,23 +1765,48 @@ void sqlite3Pragma( /* Sanity check on record header decoding */ sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nNVCol-1,3); sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); + VdbeComment((v, "(right-most column)")); } - /* Verify that all NOT NULL columns really are NOT NULL */ + /* Verify that all NOT NULL columns really are NOT NULL. At the + ** same time verify the type of the content of STRICT tables */ + bStrict = (pTab->tabFlags & TF_Strict)!=0; for(j=0; jnCol; j++){ char *zErr; - int jmp2; + Column *pCol = pTab->aCol + j; + int doError, jmp2; if( j==pTab->iPKey ) continue; - if( pTab->aCol[j].notNull==0 ) continue; + if( pCol->notNull==0 && !bStrict ) continue; + doError = bStrict ? sqlite3VdbeMakeLabel(pParse) : 0; sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3); if( sqlite3VdbeGetOp(v,-1)->opcode==OP_Column ){ sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); } - jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v); - zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName, - pTab->aCol[j].zName); - sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); - integrityCheckResultRow(v); - sqlite3VdbeJumpHere(v, jmp2); + if( pCol->notNull ){ + jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v); + zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName, + pCol->zCnName); + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); + if( bStrict && pCol->eCType!=COLTYPE_ANY ){ + sqlite3VdbeGoto(v, doError); + }else{ + integrityCheckResultRow(v); + } + sqlite3VdbeJumpHere(v, jmp2); + } + if( (pTab->tabFlags & TF_Strict)!=0 + && pCol->eCType!=COLTYPE_ANY + ){ + jmp2 = sqlite3VdbeAddOp3(v, OP_IsNullOrType, 3, 0, + sqlite3StdTypeMap[pCol->eCType-1]); + VdbeCoverage(v); + zErr = sqlite3MPrintf(db, "non-%s value in %s.%s", + sqlite3StdType[pCol->eCType-1], + pTab->zName, pTab->aCol[j].zCnName); + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); + sqlite3VdbeResolveLabel(v, doError); + integrityCheckResultRow(v); + sqlite3VdbeJumpHere(v, jmp2); + } } /* Verify CHECK constraints */ if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){ @@ -2218,12 +2340,12 @@ void sqlite3Pragma( case PragTyp_ANALYSIS_LIMIT: { sqlite3_int64 N; if( zRight - && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK + && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK /* IMP: R-40975-20399 */ && N>=0 ){ db->nAnalysisLimit = (int)(N&0x7fffffff); } - returnSingleInt(v, db->nAnalysisLimit); + returnSingleInt(v, db->nAnalysisLimit); /* IMP: R-57594-65522 */ break; } diff --git a/src/pragma.h b/src/pragma.h index be99befb..6eb05763 100644 --- a/src/pragma.h +++ b/src/pragma.h @@ -43,13 +43,14 @@ #define PragTyp_SOFT_HEAP_LIMIT 35 #define PragTyp_SYNCHRONOUS 36 #define PragTyp_TABLE_INFO 37 -#define PragTyp_TEMP_STORE 38 -#define PragTyp_TEMP_STORE_DIRECTORY 39 -#define PragTyp_THREADS 40 -#define PragTyp_WAL_AUTOCHECKPOINT 41 -#define PragTyp_WAL_CHECKPOINT 42 -#define PragTyp_LOCK_STATUS 43 -#define PragTyp_STATS 44 +#define PragTyp_TABLE_LIST 38 +#define PragTyp_TEMP_STORE 39 +#define PragTyp_TEMP_STORE_DIRECTORY 40 +#define PragTyp_THREADS 41 +#define PragTyp_WAL_AUTOCHECKPOINT 42 +#define PragTyp_WAL_CHECKPOINT 43 +#define PragTyp_LOCK_STATUS 44 +#define PragTyp_STATS 45 /* Property flags associated with various pragma. */ #define PragFlg_NeedSchema 0x01 /* Force schema load before running */ @@ -82,45 +83,51 @@ static const char *const pragCName[] = { /* 13 */ "pk", /* 14 */ "hidden", /* table_info reuses 8 */ - /* 15 */ "seqno", /* Used by: index_xinfo */ - /* 16 */ "cid", - /* 17 */ "name", - /* 18 */ "desc", - /* 19 */ "coll", - /* 20 */ "key", - /* 21 */ "name", /* Used by: function_list */ - /* 22 */ "builtin", - /* 23 */ "type", - /* 24 */ "enc", - /* 25 */ "narg", - /* 26 */ "flags", - /* 27 */ "tbl", /* Used by: stats */ - /* 28 */ "idx", - /* 29 */ "wdth", - /* 30 */ "hght", - /* 31 */ "flgs", - /* 32 */ "seq", /* Used by: index_list */ - /* 33 */ "name", - /* 34 */ "unique", - /* 35 */ "origin", - /* 36 */ "partial", - /* 37 */ "table", /* Used by: foreign_key_check */ - /* 38 */ "rowid", - /* 39 */ "parent", - /* 40 */ "fkid", - /* index_info reuses 15 */ - /* 41 */ "seq", /* Used by: database_list */ - /* 42 */ "name", - /* 43 */ "file", - /* 44 */ "busy", /* Used by: wal_checkpoint */ - /* 45 */ "log", - /* 46 */ "checkpointed", - /* collation_list reuses 32 */ - /* 47 */ "database", /* Used by: lock_status */ - /* 48 */ "status", - /* 49 */ "cache_size", /* Used by: default_cache_size */ + /* 15 */ "schema", /* Used by: table_list */ + /* 16 */ "name", + /* 17 */ "type", + /* 18 */ "ncol", + /* 19 */ "wr", + /* 20 */ "strict", + /* 21 */ "seqno", /* Used by: index_xinfo */ + /* 22 */ "cid", + /* 23 */ "name", + /* 24 */ "desc", + /* 25 */ "coll", + /* 26 */ "key", + /* 27 */ "name", /* Used by: function_list */ + /* 28 */ "builtin", + /* 29 */ "type", + /* 30 */ "enc", + /* 31 */ "narg", + /* 32 */ "flags", + /* 33 */ "tbl", /* Used by: stats */ + /* 34 */ "idx", + /* 35 */ "wdth", + /* 36 */ "hght", + /* 37 */ "flgs", + /* 38 */ "seq", /* Used by: index_list */ + /* 39 */ "name", + /* 40 */ "unique", + /* 41 */ "origin", + /* 42 */ "partial", + /* 43 */ "table", /* Used by: foreign_key_check */ + /* 44 */ "rowid", + /* 45 */ "parent", + /* 46 */ "fkid", + /* index_info reuses 21 */ + /* 47 */ "seq", /* Used by: database_list */ + /* 48 */ "name", + /* 49 */ "file", + /* 50 */ "busy", /* Used by: wal_checkpoint */ + /* 51 */ "log", + /* 52 */ "checkpointed", + /* collation_list reuses 38 */ + /* 53 */ "database", /* Used by: lock_status */ + /* 54 */ "status", + /* 55 */ "cache_size", /* Used by: default_cache_size */ /* module_list pragma_list reuses 9 */ - /* 50 */ "timeout", /* Used by: busy_timeout */ + /* 56 */ "timeout", /* Used by: busy_timeout */ }; /* Definitions of all built-in pragmas */ @@ -171,7 +178,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "busy_timeout", /* ePragTyp: */ PragTyp_BUSY_TIMEOUT, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 50, 1, + /* ColNames: */ 56, 1, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "cache_size", @@ -210,7 +217,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "collation_list", /* ePragTyp: */ PragTyp_COLLATION_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 32, 2, + /* ColNames: */ 38, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) @@ -245,14 +252,14 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "database_list", /* ePragTyp: */ PragTyp_DATABASE_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0, - /* ColNames: */ 41, 3, + /* ColNames: */ 47, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) {/* zName: */ "default_cache_size", /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, - /* ColNames: */ 49, 1, + /* ColNames: */ 55, 1, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -282,7 +289,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "foreign_key_check", /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 37, 4, + /* ColNames: */ 43, 4, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FOREIGN_KEY) @@ -325,7 +332,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "function_list", /* ePragTyp: */ PragTyp_FUNCTION_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 21, 6, + /* ColNames: */ 27, 6, /* iArg: */ 0 }, #endif #endif @@ -354,23 +361,23 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "index_info", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 15, 3, + /* ColNames: */ 21, 3, /* iArg: */ 0 }, {/* zName: */ "index_list", /* ePragTyp: */ PragTyp_INDEX_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 32, 5, + /* ColNames: */ 38, 5, /* iArg: */ 0 }, {/* zName: */ "index_xinfo", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 15, 6, + /* ColNames: */ 21, 6, /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_INTEGRITY_CHECK) {/* zName: */ "integrity_check", /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, - /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif @@ -404,7 +411,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "lock_status", /* ePragTyp: */ PragTyp_LOCK_STATUS, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 47, 2, + /* ColNames: */ 53, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) @@ -478,7 +485,7 @@ static const PragmaName aPragmaName[] = { #if !defined(SQLITE_OMIT_INTEGRITY_CHECK) {/* zName: */ "quick_check", /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, - /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif @@ -543,7 +550,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "stats", /* ePragTyp: */ PragTyp_STATS, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, - /* ColNames: */ 27, 5, + /* ColNames: */ 33, 5, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) @@ -559,6 +566,11 @@ static const PragmaName aPragmaName[] = { /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 8, 6, /* iArg: */ 0 }, + {/* zName: */ "table_list", + /* ePragTyp: */ PragTyp_TABLE_LIST, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1, + /* ColNames: */ 15, 6, + /* iArg: */ 0 }, {/* zName: */ "table_xinfo", /* ePragTyp: */ PragTyp_TABLE_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, @@ -634,7 +646,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "wal_checkpoint", /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, /* ePragFlg: */ PragFlg_NeedSchema, - /* ColNames: */ 44, 3, + /* ColNames: */ 50, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -645,4 +657,4 @@ static const PragmaName aPragmaName[] = { /* iArg: */ SQLITE_WriteSchema|SQLITE_NoSchemaError }, #endif }; -/* Number of pragmas: 67 on by default, 77 total. */ +/* Number of pragmas: 68 on by default, 78 total. */ diff --git a/src/prepare.c b/src/prepare.c index 6dcb3842..97541bea 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -29,10 +29,15 @@ static void corruptSchema( pData->rc = SQLITE_NOMEM_BKPT; }else if( pData->pzErrMsg[0]!=0 ){ /* A error message has already been generated. Do not overwrite it */ - }else if( pData->mInitFlags & (INITFLAG_AlterRename|INITFLAG_AlterDrop) ){ + }else if( pData->mInitFlags & (INITFLAG_AlterMask) ){ + static const char *azAlterType[] = { + "rename", + "drop column", + "add column" + }; *pData->pzErrMsg = sqlite3MPrintf(db, "error in %s %s after %s: %s", azObj[0], azObj[1], - (pData->mInitFlags & INITFLAG_AlterRename) ? "rename" : "drop column", + azAlterType[(pData->mInitFlags&INITFLAG_AlterMask)-1], zExtra ); pData->rc = SQLITE_ERROR; @@ -134,7 +139,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){ } } db->init.orphanTrigger = 0; - db->init.azInit = argv; + db->init.azInit = (const char**)argv; pStmt = 0; TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, 0); rc = db->errCode; @@ -153,6 +158,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){ } } } + db->init.azInit = sqlite3StdType; /* Any array of string ptrs will do */ sqlite3_finalize(pStmt); }else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){ corruptSchema(pData, argv, 0); @@ -741,7 +747,7 @@ static int sqlite3Prepare( sParse.checkSchema = 0; } if( sParse.rc!=SQLITE_OK && sParse.rc!=SQLITE_DONE ){ - if( sParse.checkSchema ){ + if( sParse.checkSchema && db->init.busy==0 ){ schemaIsValid(&sParse); } if( sParse.pVdbe ){ @@ -802,6 +808,7 @@ static int sqlite3LockAndPrepare( ** reset is considered a permanent error. */ rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail); assert( rc==SQLITE_OK || *ppStmt==0 ); + if( rc==SQLITE_OK || db->mallocFailed ) break; }while( rc==SQLITE_ERROR_RETRY || (rc==SQLITE_SCHEMA && (sqlite3ResetOneSchema(db,-1), cnt++)==0) ); sqlite3BtreeLeaveAll(db); diff --git a/src/printf.c b/src/printf.c index f663e1b1..e6351845 100644 --- a/src/printf.c +++ b/src/printf.c @@ -145,7 +145,7 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){ /* ** Set the StrAccum object to an error mode. */ -static void setStrAccumError(StrAccum *p, u8 eError){ +void sqlite3StrAccumSetError(StrAccum *p, u8 eError){ assert( eError==SQLITE_NOMEM || eError==SQLITE_TOOBIG ); p->accError = eError; if( p->mxAlloc ) sqlite3_str_reset(p); @@ -181,12 +181,12 @@ static char *printfTempBuf(sqlite3_str *pAccum, sqlite3_int64 n){ char *z; if( pAccum->accError ) return 0; if( n>pAccum->nAlloc && n>pAccum->mxAlloc ){ - setStrAccumError(pAccum, SQLITE_TOOBIG); + sqlite3StrAccumSetError(pAccum, SQLITE_TOOBIG); return 0; } z = sqlite3DbMallocRaw(pAccum->db, n); if( z==0 ){ - setStrAccumError(pAccum, SQLITE_NOMEM); + sqlite3StrAccumSetError(pAccum, SQLITE_NOMEM); } return z; } @@ -925,7 +925,7 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ return 0; } if( p->mxAlloc==0 ){ - setStrAccumError(p, SQLITE_TOOBIG); + sqlite3StrAccumSetError(p, SQLITE_TOOBIG); return p->nAlloc - p->nChar - 1; }else{ char *zOld = isMalloced(p) ? p->zText : 0; @@ -938,7 +938,7 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ } if( szNew > p->mxAlloc ){ sqlite3_str_reset(p); - setStrAccumError(p, SQLITE_TOOBIG); + sqlite3StrAccumSetError(p, SQLITE_TOOBIG); return 0; }else{ p->nAlloc = (int)szNew; @@ -956,7 +956,7 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ p->printfFlags |= SQLITE_PRINTF_MALLOCED; }else{ sqlite3_str_reset(p); - setStrAccumError(p, SQLITE_NOMEM); + sqlite3StrAccumSetError(p, SQLITE_NOMEM); return 0; } } @@ -1029,7 +1029,7 @@ static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){ memcpy(zText, p->zText, p->nChar+1); p->printfFlags |= SQLITE_PRINTF_MALLOCED; }else{ - setStrAccumError(p, SQLITE_NOMEM); + sqlite3StrAccumSetError(p, SQLITE_NOMEM); } p->zText = zText; return zText; @@ -1045,6 +1045,22 @@ char *sqlite3StrAccumFinish(StrAccum *p){ } /* +** Use the content of the StrAccum passed as the second argument +** as the result of an SQL function. +*/ +void sqlite3ResultStrAccum(sqlite3_context *pCtx, StrAccum *p){ + if( p->accError ){ + sqlite3_result_error_code(pCtx, p->accError); + sqlite3_str_reset(p); + }else if( isMalloced(p) ){ + sqlite3_result_text(pCtx, p->zText, p->nChar, SQLITE_DYNAMIC); + }else{ + sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC); + sqlite3_str_reset(p); + } +} + +/* ** This singleton is an sqlite3_str object that is returned if ** sqlite3_malloc() fails to provide space for a real one. This ** sqlite3_str object accepts no new text and always returns diff --git a/src/resolve.c b/src/resolve.c index 93e10b6e..27b260e0 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -87,6 +87,7 @@ static void resolveAlias( }else{ incrAggFunctionDepth(pDup, nSubquery); if( pExpr->op==TK_COLLATE ){ + assert( !ExprHasProperty(pExpr, EP_IntValue) ); pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken); } @@ -190,6 +191,7 @@ Bitmask sqlite3ExprColUsed(Expr *pExpr){ Table *pExTab; n = pExpr->iColumn; + assert( ExprUseYTab(pExpr) ); pExTab = pExpr->y.pTab; assert( pExTab!=0 ); if( (pExTab->tabFlags & TF_HasGenerated)!=0 @@ -303,7 +305,7 @@ static int lookupName( u8 hCol; pTab = pItem->pTab; assert( pTab!=0 && pTab->zName!=0 ); - assert( pTab->nCol>0 ); + assert( pTab->nCol>0 || pParse->nErr ); if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){ int hit = 0; pEList = pItem->pSelect->pEList; @@ -327,16 +329,16 @@ static int lookupName( if( sqlite3StrICmp(zTabName, zTab)!=0 ){ continue; } + assert( ExprUseYTab(pExpr) ); if( IN_RENAME_OBJECT && pItem->zAlias ){ sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->y.pTab); } } - if( 0==(cntTab++) ){ - pMatch = pItem; - } hCol = sqlite3StrIHash(zCol); for(j=0, pCol=pTab->aCol; jnCol; j++, pCol++){ - if( pCol->hName==hCol && sqlite3StrICmp(pCol->zName, zCol)==0 ){ + if( pCol->hName==hCol + && sqlite3StrICmp(pCol->zCnName, zCol)==0 + ){ /* If there has been exactly one prior match and this match ** is for the right-hand table of a NATURAL JOIN or is in a ** USING clause, then skip this match. @@ -352,9 +354,14 @@ static int lookupName( break; } } + if( 0==cnt && VisibleRowid(pTab) ){ + cntTab++; + pMatch = pItem; + } } if( pMatch ){ pExpr->iTable = pMatch->iCursor; + assert( ExprUseYTab(pExpr) ); pExpr->y.pTab = pMatch->pTab; /* RIGHT JOIN not (yet) supported */ assert( (pMatch->fg.jointype & JT_RIGHT)==0 ); @@ -409,7 +416,9 @@ static int lookupName( pSchema = pTab->pSchema; cntTab++; for(iCol=0, pCol=pTab->aCol; iColnCol; iCol++, pCol++){ - if( pCol->hName==hCol && sqlite3StrICmp(pCol->zName, zCol)==0 ){ + if( pCol->hName==hCol + && sqlite3StrICmp(pCol->zCnName, zCol)==0 + ){ if( iCol==pTab->iPKey ){ iCol = -1; } @@ -426,6 +435,7 @@ static int lookupName( #ifndef SQLITE_OMIT_UPSERT if( pExpr->iTable==EXCLUDED_TABLE_NUMBER ){ testcase( iCol==(-1) ); + assert( ExprUseYTab(pExpr) ); if( IN_RENAME_OBJECT ){ pExpr->iColumn = iCol; pExpr->y.pTab = pTab; @@ -438,6 +448,7 @@ static int lookupName( }else #endif /* SQLITE_OMIT_UPSERT */ { + assert( ExprUseYTab(pExpr) ); pExpr->y.pTab = pTab; if( pParse->bReturning ){ eNewExprOp = TK_REGISTER; @@ -474,7 +485,7 @@ static int lookupName( && pMatch && (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0 && sqlite3IsRowid(zCol) - && VisibleRowid(pMatch->pTab) + && ALWAYS(VisibleRowid(pMatch->pTab)) ){ cnt = 1; pExpr->iColumn = -1; @@ -512,8 +523,8 @@ static int lookupName( ){ Expr *pOrig; assert( pExpr->pLeft==0 && pExpr->pRight==0 ); - assert( pExpr->x.pList==0 ); - assert( pExpr->x.pSelect==0 ); + assert( ExprUseXList(pExpr)==0 || pExpr->x.pList==0 ); + assert( ExprUseXSelect(pExpr)==0 || pExpr->x.pSelect==0 ); pOrig = pEList->a[j].pExpr; if( (pNC->ncFlags&NC_AllowAgg)==0 && ExprHasProperty(pOrig, EP_Agg) ){ sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs); @@ -585,7 +596,7 @@ static int lookupName( sqlite3VdbeAddDblquoteStr(db, pParse->pVdbe, zCol); #endif pExpr->op = TK_STRING; - pExpr->y.pTab = 0; + memset(&pExpr->y, 0, sizeof(pExpr->y)); return WRC_Prune; } if( sqlite3ExprIdToTrueFalse(pExpr) ){ @@ -671,7 +682,9 @@ Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){ Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0); if( p ){ SrcItem *pItem = &pSrc->a[iSrc]; - Table *pTab = p->y.pTab = pItem->pTab; + Table *pTab; + assert( ExprUseYTab(p) ); + pTab = p->y.pTab = pItem->pTab; p->iTable = pItem->iCursor; if( p->y.pTab->iPKey==iCol ){ p->iColumn = -1; @@ -738,6 +751,7 @@ static void notValidImpl( static int exprProbability(Expr *p){ double r = -1.0; if( p->op!=TK_FLOAT ) return -1; + assert( !ExprHasProperty(p, EP_IntValue) ); sqlite3AtoF(p->u.zToken, &r, sqlite3Strlen30(p->u.zToken), SQLITE_UTF8); assert( r>=0.0 ); if( r>1.0 ) return -1; @@ -786,6 +800,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ assert( pSrcList && pSrcList->nSrc>=1 ); pItem = pSrcList->a; pExpr->op = TK_COLUMN; + assert( ExprUseYTab(pExpr) ); pExpr->y.pTab = pItem->pTab; pExpr->iTable = pItem->iCursor; pExpr->iColumn--; @@ -817,6 +832,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ } sqlite3WalkExpr(pWalker, pExpr->pLeft); if( 0==sqlite3ExprCanBeNull(pExpr->pLeft) && !IN_RENAME_OBJECT ){ + testcase( ExprHasProperty(pExpr, EP_FromJoin) ); + assert( !ExprHasProperty(pExpr, EP_IntValue) ); if( pExpr->op==TK_NOTNULL ){ pExpr->u.zToken = "true"; ExprSetProperty(pExpr, EP_IsTrue); @@ -852,6 +869,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_ID ){ zDb = 0; zTable = 0; + assert( !ExprHasProperty(pExpr, EP_IntValue) ); zColumn = pExpr->u.zToken; }else{ Expr *pLeft = pExpr->pLeft; @@ -864,12 +882,15 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ zDb = 0; }else{ assert( pRight->op==TK_DOT ); + assert( !ExprHasProperty(pRight, EP_IntValue) ); zDb = pLeft->u.zToken; pLeft = pRight->pLeft; pRight = pRight->pRight; } + assert( ExprUseUToken(pLeft) && ExprUseUToken(pRight) ); zTable = pLeft->u.zToken; zColumn = pRight->u.zToken; + assert( ExprUseYTab(pExpr) ); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, (void*)pExpr, (void*)pRight); sqlite3RenameTokenRemap(pParse, (void*)&pExpr->y.pTab, (void*)pLeft); @@ -894,7 +915,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ #ifndef SQLITE_OMIT_WINDOWFUNC Window *pWin = (IsWindowFunc(pExpr) ? pExpr->y.pWin : 0); #endif - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) ); zId = pExpr->u.zToken; nId = sqlite3Strlen30(zId); pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0); @@ -1058,7 +1079,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ #ifndef SQLITE_OMIT_WINDOWFUNC if( pWin ){ Select *pSel = pNC->pWinSelect; - assert( pWin==pExpr->y.pWin ); + assert( pWin==0 || (ExprUseYWin(pExpr) && pWin==pExpr->y.pWin) ); if( IN_RENAME_OBJECT==0 ){ sqlite3WindowUpdate(pParse, pSel ? pSel->pWinDefn : 0, pWin, pDef); if( pParse->db->mallocFailed ) break; @@ -1071,7 +1092,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ }else #endif /* SQLITE_OMIT_WINDOWFUNC */ { - NameContext *pNC2 = pNC; + NameContext *pNC2; /* For looping up thru outer contexts */ pExpr->op = TK_AGG_FUNCTION; pExpr->op2 = 0; #ifndef SQLITE_OMIT_WINDOWFUNC @@ -1079,16 +1100,22 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ sqlite3WalkExpr(pWalker, pExpr->y.pWin->pFilter); } #endif - while( pNC2 && !sqlite3FunctionUsesThisSrc(pExpr, pNC2->pSrcList) ){ + pNC2 = pNC; + while( pNC2 + && sqlite3ReferencesSrcList(pParse, pExpr, pNC2->pSrcList)==0 + ){ pExpr->op2++; pNC2 = pNC2->pNext; } assert( pDef!=0 || IN_RENAME_OBJECT ); if( pNC2 && pDef ){ assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg ); + assert( SQLITE_FUNC_ANYORDER==NC_OrderAgg ); testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 ); - pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX); - + testcase( (pDef->funcFlags & SQLITE_FUNC_ANYORDER)!=0 ); + pNC2->ncFlags |= NC_HasAgg + | ((pDef->funcFlags^SQLITE_FUNC_ANYORDER) + & (SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER)); } } pNC->ncFlags |= savedAllowFlags; @@ -1104,15 +1131,17 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ #endif case TK_IN: { testcase( pExpr->op==TK_IN ); - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( ExprUseXSelect(pExpr) ){ int nRef = pNC->nRef; testcase( pNC->ncFlags & NC_IsCheck ); testcase( pNC->ncFlags & NC_PartIdx ); testcase( pNC->ncFlags & NC_IdxExpr ); testcase( pNC->ncFlags & NC_GenCol ); - sqlite3ResolveNotValid(pParse, pNC, "subqueries", - NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol, pExpr); - sqlite3WalkSelect(pWalker, pExpr->x.pSelect); + if( pNC->ncFlags & NC_SelfRef ){ + notValidImpl(pParse, pNC, "subqueries", pExpr); + }else{ + sqlite3WalkSelect(pWalker, pExpr->x.pSelect); + } assert( pNC->nRef>=nRef ); if( nRef!=pNC->nRef ){ ExprSetProperty(pExpr, EP_VarSelect); @@ -1159,6 +1188,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ assert( pExpr->pLeft!=0 ); nLeft = sqlite3ExprVectorSize(pExpr->pLeft); if( pExpr->op==TK_BETWEEN ){ + assert( ExprUseXList(pExpr) ); nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[0].pExpr); if( nRight==nLeft ){ nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[1].pExpr); @@ -1207,7 +1237,9 @@ static int resolveAsName( UNUSED_PARAMETER(pParse); if( pE->op==TK_ID ){ - char *zCol = pE->u.zToken; + const char *zCol; + assert( !ExprHasProperty(pE, EP_IntValue) ); + zCol = pE->u.zToken; for(i=0; inExpr; i++){ if( pEList->a[i].eEName==ENAME_NAME && sqlite3_stricmp(pEList->a[i].zEName, zCol)==0 @@ -1631,7 +1663,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ p->pOrderBy = 0; } - /* Recursively resolve names in all subqueries + /* Recursively resolve names in all subqueries in the FROM clause */ for(i=0; ipSrc->nSrc; i++){ SrcItem *pItem = &p->pSrc->a[i]; @@ -1675,7 +1707,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ pGroupBy = p->pGroupBy; if( pGroupBy || (sNC.ncFlags & NC_HasAgg)!=0 ){ assert( NC_MinMaxAgg==SF_MinMaxAgg ); - p->selFlags |= SF_Aggregate | (sNC.ncFlags&NC_MinMaxAgg); + assert( NC_OrderAgg==SF_OrderByReqd ); + p->selFlags |= SF_Aggregate | (sNC.ncFlags&(NC_MinMaxAgg|NC_OrderAgg)); }else{ sNC.ncFlags &= ~NC_AllowAgg; } @@ -1858,8 +1891,8 @@ int sqlite3ResolveExprNames( Walker w; if( pExpr==0 ) return SQLITE_OK; - savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin); - pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin); + savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); + pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); w.pParse = pNC->pParse; w.xExprCallback = resolveExprStep; w.xSelectCallback = (pNC->ncFlags & NC_NoSelect) ? 0 : resolveSelectStep; @@ -1902,8 +1935,8 @@ int sqlite3ResolveExprListNames( w.xSelectCallback = resolveSelectStep; w.xSelectCallback2 = 0; w.u.pNC = pNC; - savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin); - pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin); + savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); + pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); for(i=0; inExpr; i++){ Expr *pExpr = pList->a[i].pExpr; if( pExpr==0 ) continue; @@ -1921,10 +1954,11 @@ int sqlite3ResolveExprListNames( assert( EP_Win==NC_HasWin ); testcase( pNC->ncFlags & NC_HasAgg ); testcase( pNC->ncFlags & NC_HasWin ); - if( pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin) ){ + if( pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg) ){ ExprSetProperty(pExpr, pNC->ncFlags & (NC_HasAgg|NC_HasWin) ); - savedHasAgg |= pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin); - pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin); + savedHasAgg |= pNC->ncFlags & + (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); + pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); } if( w.pParse->nErr>0 ) return WRC_Abort; } diff --git a/src/select.c b/src/select.c index 7d8fd593..7f15c2ac 100644 --- a/src/select.c +++ b/src/select.c @@ -271,7 +271,7 @@ int sqlite3ColumnIndex(Table *pTab, const char *zCol){ u8 h = sqlite3StrIHash(zCol); Column *pCol; for(pCol=pTab->aCol, i=0; inCol; pCol++, i++){ - if( pCol->hName==h && sqlite3StrICmp(pCol->zName, zCol)==0 ) return i; + if( pCol->hName==h && sqlite3StrICmp(pCol->zCnName, zCol)==0 ) return i; } return -1; } @@ -347,6 +347,9 @@ static void addWhereTerm( pE2 = sqlite3CreateColumnExpr(db, pSrc, iRight, iColRight); pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2); + assert( pE2!=0 || pEq==0 ); /* Due to db->mallocFailed test + ** in sqlite3DbMallocRawNN() called from + ** sqlite3PExpr(). */ if( pEq && isOuterJoin ){ ExprSetProperty(pEq, EP_FromJoin); assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) ); @@ -388,10 +391,13 @@ void sqlite3SetJoinExpr(Expr *p, int iTable){ assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); ExprSetVVAProperty(p, EP_NoReduce); p->iRightJoinTable = iTable; - if( p->op==TK_FUNCTION && p->x.pList ){ - int i; - for(i=0; ix.pList->nExpr; i++){ - sqlite3SetJoinExpr(p->x.pList->a[i].pExpr, iTable); + if( p->op==TK_FUNCTION ){ + assert( ExprUseXList(p) ); + if( p->x.pList ){ + int i; + for(i=0; ix.pList->nExpr; i++){ + sqlite3SetJoinExpr(p->x.pList->a[i].pExpr, iTable); + } } } sqlite3SetJoinExpr(p->pLeft, iTable); @@ -414,10 +420,13 @@ static void unsetJoinExpr(Expr *p, int iTable){ if( p->op==TK_COLUMN && p->iTable==iTable ){ ExprClearProperty(p, EP_CanBeNull); } - if( p->op==TK_FUNCTION && p->x.pList ){ - int i; - for(i=0; ix.pList->nExpr; i++){ - unsetJoinExpr(p->x.pList->a[i].pExpr, iTable); + if( p->op==TK_FUNCTION ){ + assert( ExprUseXList(p) ); + if( p->x.pList ){ + int i; + for(i=0; ix.pList->nExpr; i++){ + unsetJoinExpr(p->x.pList->a[i].pExpr, iTable); + } } } unsetJoinExpr(p->pLeft, iTable); @@ -470,7 +479,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ int iLeftCol; /* Matching column in the left table */ if( IsHiddenColumn(&pRightTab->aCol[j]) ) continue; - zName = pRightTab->aCol[j].zName; + zName = pRightTab->aCol[j].zCnName; if( tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol, 1) ){ addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, j, isOuter, &p->pWhere); @@ -873,7 +882,9 @@ static void fixDistinctOpenEph( int iVal, /* Value returned by codeDistinct() */ int iOpenEphAddr /* Address of OP_OpenEphemeral instruction for iTab */ ){ - if( eTnctType==WHERE_DISTINCT_UNIQUE || eTnctType==WHERE_DISTINCT_ORDERED ){ + if( pParse->nErr==0 + && (eTnctType==WHERE_DISTINCT_UNIQUE || eTnctType==WHERE_DISTINCT_ORDERED) + ){ Vdbe *v = pParse->pVdbe; sqlite3VdbeChangeToNoop(v, iOpenEphAddr); if( sqlite3VdbeGetOp(v, iOpenEphAddr+1)->opcode==OP_Explain ){ @@ -930,9 +941,13 @@ static void selectExprDefer( struct ExprList_item *pItem = &pEList->a[i]; if( pItem->u.x.iOrderByCol==0 ){ Expr *pExpr = pItem->pExpr; - Table *pTab = pExpr->y.pTab; - if( pExpr->op==TK_COLUMN && pExpr->iColumn>=0 && pTab && !IsVirtual(pTab) - && (pTab->aCol[pExpr->iColumn].colFlags & COLFLAG_SORTERREF) + Table *pTab; + if( pExpr->op==TK_COLUMN + && pExpr->iColumn>=0 + && ALWAYS( ExprUseYTab(pExpr) ) + && (pTab = pExpr->y.pTab)!=0 + && IsOrdinaryTable(pTab) + && (pTab->aCol[pExpr->iColumn].colFlags & COLFLAG_SORTERREF)!=0 ){ int j; for(j=0; jiTable = pExpr->iTable; + assert( ExprUseYTab(pNew) ); pNew->y.pTab = pExpr->y.pTab; pNew->iColumn = pPk ? pPk->aiColumn[k] : -1; pExtra = sqlite3ExprListAppend(pParse, pExtra, pNew); @@ -1801,7 +1817,7 @@ static const char *columnTypeImpl( break; } - assert( pTab && pExpr->y.pTab==pTab ); + assert( pTab && ExprUseYTab(pExpr) && pExpr->y.pTab==pTab ); if( pS ){ /* The "table" is actually a sub-select or a view in the FROM clause ** of the SELECT statement. Return the declaration type and origin @@ -1835,7 +1851,7 @@ static const char *columnTypeImpl( zType = "INTEGER"; zOrigCol = "rowid"; }else{ - zOrigCol = pTab->aCol[iCol].zName; + zOrigCol = pTab->aCol[iCol].zCnName; zType = sqlite3ColumnType(&pTab->aCol[iCol],0); } zOrigTab = pTab->zName; @@ -1861,9 +1877,11 @@ static const char *columnTypeImpl( ** statement. */ NameContext sNC; - Select *pS = pExpr->x.pSelect; - Expr *p = pS->pEList->a[0].pExpr; - assert( ExprHasProperty(pExpr, EP_xIsSelect) ); + Select *pS; + Expr *p; + assert( ExprUseXSelect(pExpr) ); + pS = pExpr->x.pSelect; + p = pS->pEList->a[0].pExpr; sNC.pSrcList = pS->pSrc; sNC.pNext = pNC; sNC.pParse = pNC->pParse; @@ -1992,7 +2010,8 @@ void sqlite3GenerateColumnNames( assert( p!=0 ); assert( p->op!=TK_AGG_COLUMN ); /* Agg processing has not run yet */ - assert( p->op!=TK_COLUMN || p->y.pTab!=0 ); /* Covering idx not yet coded */ + assert( p->op!=TK_COLUMN + || (ExprUseYTab(p) && p->y.pTab!=0) ); /* Covering idx not yet coded */ if( pEList->a[i].zEName && pEList->a[i].eEName==ENAME_NAME ){ /* An AS clause always takes first priority */ char *zName = pEList->a[i].zEName; @@ -2007,7 +2026,7 @@ void sqlite3GenerateColumnNames( if( iCol<0 ){ zCol = "rowid"; }else{ - zCol = pTab->aCol[iCol].zName; + zCol = pTab->aCol[iCol].zCnName; } if( fullName ){ char *zName = 0; @@ -2088,11 +2107,14 @@ int sqlite3ColumnsFromExprList( pColExpr = pColExpr->pRight; assert( pColExpr!=0 ); } - if( pColExpr->op==TK_COLUMN && (pTab = pColExpr->y.pTab)!=0 ){ + if( pColExpr->op==TK_COLUMN + && ALWAYS( ExprUseYTab(pColExpr) ) + && (pTab = pColExpr->y.pTab)!=0 + ){ /* For columns use the column name name */ int iCol = pColExpr->iColumn; if( iCol<0 ) iCol = pTab->iPKey; - zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid"; + zName = iCol>=0 ? pTab->aCol[iCol].zCnName : "rowid"; }else if( pColExpr->op==TK_ID ){ assert( !ExprHasProperty(pColExpr, EP_IntValue) ); zName = pColExpr->u.zToken; @@ -2120,7 +2142,7 @@ int sqlite3ColumnsFromExprList( zName = sqlite3MPrintf(db, "%.*z:%u", nName, zName, ++cnt); if( cnt>3 ) sqlite3_randomness(sizeof(cnt), &cnt); } - pCol->zName = zName; + pCol->zCnName = zName; pCol->hName = sqlite3StrIHash(zName); sqlite3ColumnPropertiesFromName(0, pCol); if( zName && sqlite3HashInsert(&ht, zName, pCol)==pCol ){ @@ -2130,7 +2152,7 @@ int sqlite3ColumnsFromExprList( sqlite3HashClear(&ht); if( db->mallocFailed ){ for(j=0; jpEList->a; for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){ const char *zType; - int n, m; + i64 n, m; pTab->tabFlags |= (pCol->colFlags & COLFLAG_NOINSERT); p = a[i].pExpr; zType = columnType(&sNC, p, 0, 0, 0); @@ -2182,17 +2204,21 @@ void sqlite3SelectAddColumnTypeAndCollation( pCol->affinity = sqlite3ExprAffinity(p); if( zType ){ m = sqlite3Strlen30(zType); - n = sqlite3Strlen30(pCol->zName); - pCol->zName = sqlite3DbReallocOrFree(db, pCol->zName, n+m+2); - if( pCol->zName ){ - memcpy(&pCol->zName[n+1], zType, m+1); + n = sqlite3Strlen30(pCol->zCnName); + pCol->zCnName = sqlite3DbReallocOrFree(db, pCol->zCnName, n+m+2); + if( pCol->zCnName ){ + memcpy(&pCol->zCnName[n+1], zType, m+1); pCol->colFlags |= COLFLAG_HASTYPE; + }else{ + testcase( pCol->colFlags & COLFLAG_HASTYPE ); + pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL); } } if( pCol->affinity<=SQLITE_AFF_NONE ) pCol->affinity = aff; pColl = sqlite3ExprCollSeq(pParse, p); - if( pColl && pCol->zColl==0 ){ - pCol->zColl = sqlite3DbStrDup(db, pColl->zName); + if( pColl ){ + assert( pTab->pIndex==0 ); + sqlite3ColumnSetColl(db, pCol, pColl->zName); } } pTab->szTabRow = 1; /* Any non-zero value works */ @@ -2356,7 +2382,7 @@ static CollSeq *multiSelectCollSeq(Parse *pParse, Select *p, int iCol){ */ static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){ ExprList *pOrderBy = p->pOrderBy; - int nOrderBy = p->pOrderBy->nExpr; + int nOrderBy = ALWAYS(pOrderBy!=0) ? pOrderBy->nExpr : 0; sqlite3 *db = pParse->db; KeyInfo *pRet = sqlite3KeyInfoAlloc(db, nOrderBy+nExtra, 1); if( pRet ){ @@ -2428,7 +2454,7 @@ static void generateWithRecursiveQuery( SrcList *pSrc = p->pSrc; /* The FROM clause of the recursive query */ int nCol = p->pEList->nExpr; /* Number of columns in the recursive table */ Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */ - Select *pSetup = p->pPrior; /* The setup query */ + Select *pSetup; /* The setup query */ Select *pFirstRec; /* Left-most recursive term */ int addrTop; /* Top of the loop */ int addrCont, addrBreak; /* CONTINUE and BREAK addresses */ @@ -2512,7 +2538,6 @@ static void generateWithRecursiveQuery( ** iDistinct table. pFirstRec is left pointing to the left-most ** recursive term of the CTE. */ - pFirstRec = p; for(pFirstRec=p; ALWAYS(pFirstRec!=0); pFirstRec=pFirstRec->pPrior){ if( pFirstRec->selFlags & SF_Aggregate ){ sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported"); @@ -2978,6 +3003,7 @@ static int multiSelect( int nCol; /* Number of columns in result set */ assert( p->pNext==0 ); + assert( p->pEList!=0 ); nCol = p->pEList->nExpr; pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1); if( !pKeyInfo ){ @@ -3012,7 +3038,11 @@ static int multiSelect( multi_select_end: pDest->iSdst = dest.iSdst; pDest->nSdst = dest.nSdst; - sqlite3SelectDelete(db, pDelete); + if( pDelete ){ + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3SelectDelete, + pDelete); + } return rc; } #endif /* SQLITE_OMIT_COMPOUND_SELECT */ @@ -3325,6 +3355,7 @@ static int multiSelectOrderBy( for(i=1; db->mallocFailed==0 && i<=p->pEList->nExpr; i++){ struct ExprList_item *pItem; for(j=0, pItem=pOrderBy->a; ju.x.iOrderByCol>0 ); if( pItem->u.x.iOrderByCol==i ) break; } @@ -3351,6 +3382,7 @@ static int multiSelectOrderBy( struct ExprList_item *pItem; aPermute[0] = nOrderBy; for(i=1, pItem=pOrderBy->a; i<=nOrderBy; i++, pItem++){ + assert( pItem!=0 ); assert( pItem->u.x.iOrderByCol>0 ); assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr ); aPermute[i] = pItem->u.x.iOrderByCol - 1; @@ -3663,7 +3695,7 @@ static Expr *substExpr( } pExpr->pLeft = substExpr(pSubst, pExpr->pLeft); pExpr->pRight = substExpr(pSubst, pExpr->pRight); - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( ExprUseXSelect(pExpr) ){ substSelect(pSubst, pExpr->x.pSelect, 1); }else{ substExprList(pSubst, pExpr->x.pList); @@ -3754,10 +3786,10 @@ static void recomputeColumnsUsed( ** new cursor number assigned, set an entry in the aCsrMap[] array ** to map the old cursor number to the new: ** -** aCsrMap[iOld] = iNew; +** aCsrMap[iOld+1] = iNew; ** ** The array is guaranteed by the caller to be large enough for all -** existing cursor numbers in pSrc. +** existing cursor numbers in pSrc. aCsrMap[0] is the array size. ** ** If pSrc contains any sub-selects, call this routine recursively ** on the FROM clause of each such sub-select, with iExcept set to -1. @@ -3773,10 +3805,11 @@ static void srclistRenumberCursors( for(i=0, pItem=pSrc->a; inSrc; i++, pItem++){ if( i!=iExcept ){ Select *p; - if( !pItem->fg.isRecursive || aCsrMap[pItem->iCursor]==0 ){ - aCsrMap[pItem->iCursor] = pParse->nTab++; + assert( pItem->iCursor < aCsrMap[0] ); + if( !pItem->fg.isRecursive || aCsrMap[pItem->iCursor+1]==0 ){ + aCsrMap[pItem->iCursor+1] = pParse->nTab++; } - pItem->iCursor = aCsrMap[pItem->iCursor]; + pItem->iCursor = aCsrMap[pItem->iCursor+1]; for(p=pItem->pSelect; p; p=p->pPrior){ srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1); } @@ -3785,17 +3818,27 @@ static void srclistRenumberCursors( } /* +** *piCursor is a cursor number. Change it if it needs to be mapped. +*/ +static void renumberCursorDoMapping(Walker *pWalker, int *piCursor){ + int *aCsrMap = pWalker->u.aiCol; + int iCsr = *piCursor; + if( iCsr < aCsrMap[0] && aCsrMap[iCsr+1]>0 ){ + *piCursor = aCsrMap[iCsr+1]; + } +} + +/* ** Expression walker callback used by renumberCursors() to update ** Expr objects to match newly assigned cursor numbers. */ static int renumberCursorsCb(Walker *pWalker, Expr *pExpr){ - int *aCsrMap = pWalker->u.aiCol; int op = pExpr->op; - if( (op==TK_COLUMN || op==TK_IF_NULL_ROW) && aCsrMap[pExpr->iTable] ){ - pExpr->iTable = aCsrMap[pExpr->iTable]; + if( op==TK_COLUMN || op==TK_IF_NULL_ROW ){ + renumberCursorDoMapping(pWalker, &pExpr->iTable); } - if( ExprHasProperty(pExpr, EP_FromJoin) && aCsrMap[pExpr->iRightJoinTable] ){ - pExpr->iRightJoinTable = aCsrMap[pExpr->iRightJoinTable]; + if( ExprHasProperty(pExpr, EP_FromJoin) ){ + renumberCursorDoMapping(pWalker, &pExpr->iRightJoinTable); } return WRC_Continue; } @@ -4139,7 +4182,8 @@ static int flattenSubquery( if( pSrc->nSrc>1 ){ if( pParse->nSelect>500 ) return 0; - aCsrMap = sqlite3DbMallocZero(db, pParse->nTab*sizeof(int)); + aCsrMap = sqlite3DbMallocZero(db, ((i64)pParse->nTab+1)*sizeof(int)); + if( aCsrMap ) aCsrMap[0] = pParse->nTab; } } @@ -4862,7 +4906,7 @@ static int pushDownWhereTerms( */ static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){ int eRet = WHERE_ORDERBY_NORMAL; /* Return value */ - ExprList *pEList = pFunc->x.pList; /* Arguments to agg function */ + ExprList *pEList; /* Arguments to agg function */ const char *zFunc; /* Name of aggregate function pFunc */ ExprList *pOrderBy; u8 sortFlags = 0; @@ -4870,6 +4914,8 @@ static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){ assert( *ppMinMax==0 ); assert( pFunc->op==TK_AGG_FUNCTION ); assert( !IsWindowFunc(pFunc) ); + assert( ExprUseXList(pFunc) ); + pEList = pFunc->x.pList; if( pEList==0 || pEList->nExpr!=1 || ExprHasProperty(pFunc, EP_WinFunc) @@ -4877,6 +4923,7 @@ static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){ ){ return eRet; } + assert( !ExprHasProperty(pFunc, EP_IntValue) ); zFunc = pFunc->u.zToken; if( sqlite3StrICmp(zFunc, "min")==0 ){ eRet = WHERE_ORDERBY_MIN; @@ -4904,7 +4951,13 @@ static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){ ** ** where table is a database table, not a sub-select or view. If the query ** does match this pattern, then a pointer to the Table object representing -** is returned. Otherwise, 0 is returned. +** is returned. Otherwise, NULL is returned. +** +** This routine checks to see if it is safe to use the count optimization. +** A correct answer is still obtained (though perhaps more slowly) if +** this routine returns NULL when it could have returned a table pointer. +** But returning the pointer when NULL should have been returned can +** result in incorrect answers and/or crashes. So, when in doubt, return NULL. */ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){ Table *pTab; @@ -4912,19 +4965,26 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){ assert( !p->pGroupBy ); - if( p->pWhere || p->pEList->nExpr!=1 - || p->pSrc->nSrc!=1 || p->pSrc->a[0].pSelect + if( p->pWhere + || p->pEList->nExpr!=1 + || p->pSrc->nSrc!=1 + || p->pSrc->a[0].pSelect + || pAggInfo->nFunc!=1 ){ return 0; } pTab = p->pSrc->a[0].pTab; + assert( pTab!=0 ); + assert( !IsView(pTab) ); + if( !IsOrdinaryTable(pTab) ) return 0; pExpr = p->pEList->a[0].pExpr; - assert( pTab && !pTab->pSelect && pExpr ); - - if( IsVirtual(pTab) ) return 0; + assert( pExpr!=0 ); if( pExpr->op!=TK_AGG_FUNCTION ) return 0; - if( NEVER(pAggInfo->nFunc==0) ) return 0; + if( pExpr->pAggInfo!=pAggInfo ) return 0; if( (pAggInfo->aFunc[0].pFunc->funcFlags&SQLITE_FUNC_COUNT)==0 ) return 0; + assert( pAggInfo->aFunc[0].pFExpr==pExpr ); + testcase( ExprHasProperty(pExpr, EP_Distinct) ); + testcase( ExprHasProperty(pExpr, EP_WinFunc) ); if( ExprHasProperty(pExpr, EP_Distinct|EP_WinFunc) ) return 0; return pTab; @@ -4953,6 +5013,7 @@ int sqlite3IndexedByLookup(Parse *pParse, SrcItem *pFrom){ pParse->checkSchema = 1; return SQLITE_ERROR; } + assert( pFrom->fg.isCte==0 ); pFrom->u2.pIBIndex = pIdx; return SQLITE_OK; } @@ -5210,6 +5271,10 @@ static int resolveFromTermToCte( if( db->mallocFailed ) return 2; pFrom->pSelect->selFlags |= SF_CopyCte; assert( pFrom->pSelect ); + if( pFrom->fg.isIndexedBy ){ + sqlite3ErrorMsg(pParse, "no such index: \"%s\"", pFrom->u1.zIndexedBy); + return 2; + } pFrom->fg.isCte = 1; pFrom->u2.pCteUse = pCteUse; pCteUse->nUse++; @@ -5464,30 +5529,31 @@ static int selectExpander(Walker *pWalker, Select *p){ return WRC_Abort; } #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) - if( IsVirtual(pTab) || pTab->pSelect ){ + if( !IsOrdinaryTable(pTab) ){ i16 nCol; u8 eCodeOrig = pWalker->eCode; if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort; assert( pFrom->pSelect==0 ); - if( pTab->pSelect - && (db->flags & SQLITE_EnableView)==0 - && pTab->pSchema!=db->aDb[1].pSchema - ){ - sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited", - pTab->zName); + if( IsView(pTab) ){ + if( (db->flags & SQLITE_EnableView)==0 + && pTab->pSchema!=db->aDb[1].pSchema + ){ + sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited", + pTab->zName); + } + pFrom->pSelect = sqlite3SelectDup(db, pTab->u.view.pSelect, 0); } #ifndef SQLITE_OMIT_VIRTUALTABLE - assert( SQLITE_VTABRISK_Normal==1 && SQLITE_VTABRISK_High==2 ); - if( IsVirtual(pTab) + else if( ALWAYS(IsVirtual(pTab)) && pFrom->fg.fromDDL - && ALWAYS(pTab->pVTable!=0) - && pTab->pVTable->eVtabRisk > ((db->flags & SQLITE_TrustedSchema)!=0) + && ALWAYS(pTab->u.vtab.p!=0) + && pTab->u.vtab.p->eVtabRisk > ((db->flags & SQLITE_TrustedSchema)!=0) ){ sqlite3ErrorMsg(pParse, "unsafe use of virtual table \"%s\"", pTab->zName); } + assert( SQLITE_VTABRISK_Normal==1 && SQLITE_VTABRISK_High==2 ); #endif - pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0); nCol = pTab->nCol; pTab->nCol = -1; pWalker->eCode = 1; /* Turn on Select.selId renumbering */ @@ -5587,7 +5653,7 @@ static int selectExpander(Walker *pWalker, Select *p){ zSchemaName = iDb>=0 ? db->aDb[iDb].zDbSName : "*"; } for(j=0; jnCol; j++){ - char *zName = pTab->aCol[j].zName; + char *zName = pTab->aCol[j].zCnName; char *zColname; /* The computed column name */ char *zToFree; /* Malloced string that needs to be freed */ Token sColname; /* Computed column name as a token */ @@ -5844,7 +5910,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){ for(pFunc=pAggInfo->aFunc, i=0; inFunc; i++, pFunc++){ if( pFunc->iDistinct>=0 ){ Expr *pE = pFunc->pFExpr; - assert( !ExprHasProperty(pE, EP_xIsSelect) ); + assert( ExprUseXList(pE) ); if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){ sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one " "argument"); @@ -5869,8 +5935,9 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){ int i; struct AggInfo_func *pF; for(i=0, pF=pAggInfo->aFunc; inFunc; i++, pF++){ - ExprList *pList = pF->pFExpr->x.pList; - assert( !ExprHasProperty(pF->pFExpr, EP_xIsSelect) ); + ExprList *pList; + assert( ExprUseXList(pF->pFExpr) ); + pList = pF->pFExpr->x.pList; sqlite3VdbeAddOp2(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0); sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); } @@ -5904,9 +5971,10 @@ static void updateAccumulator( int nArg; int addrNext = 0; int regAgg; - ExprList *pList = pF->pFExpr->x.pList; - assert( !ExprHasProperty(pF->pFExpr, EP_xIsSelect) ); + ExprList *pList; + assert( ExprUseXList(pF->pFExpr) ); assert( !IsWindowFunc(pF->pFExpr) ); + pList = pF->pFExpr->x.pList; if( ExprHasProperty(pF->pFExpr, EP_WinFunc) ){ Expr *pFilter = pF->pFExpr->y.pWin->pFilter; if( pAggInfo->nAccumulator @@ -6019,8 +6087,16 @@ static void explainSimpleCount( static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){ if( pExpr->op!=TK_AND ){ Select *pS = pWalker->u.pSelect; + /* This routine is called before the HAVING clause of the current + ** SELECT is analyzed for aggregates. So if pExpr->pAggInfo is set + ** here, it indicates that the expression is a correlated reference to a + ** column from an outer aggregate query, or an aggregate function that + ** belongs to an outer query. Do not move the expression to the WHERE + ** clause in this obscure case, as doing so may corrupt the outer Select + ** statements AggInfo structure. */ if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, pS->pGroupBy) && ExprAlwaysFalse(pExpr)==0 + && pExpr->pAggInfo==0 ){ sqlite3 *db = pWalker->pParse->db; Expr *pNew = sqlite3Expr(db, TK_INTEGER, "1"); @@ -6144,7 +6220,9 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ if( p->pGroupBy ) return 0; pExpr = p->pEList->a[0].pExpr; if( pExpr->op!=TK_AGG_FUNCTION ) return 0; /* Result is an aggregate */ + assert( ExprUseUToken(pExpr) ); if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Is count() */ + assert( ExprUseXList(pExpr) ); if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */ if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */ pSub = p->pSrc->a[0].pSelect; @@ -6286,11 +6364,16 @@ int sqlite3Select( } #endif - /* If the SF_UpdateFrom flag is set, then this function is being called + /* If the SF_UFSrcCheck flag is set, then this function is being called ** as part of populating the temp table for an UPDATE...FROM statement. ** In this case, it is an error if the target object (pSrc->a[0]) name - ** or alias is duplicated within FROM clause (pSrc->a[1..n]). */ - if( p->selFlags & SF_UpdateFrom ){ + ** or alias is duplicated within FROM clause (pSrc->a[1..n]). + ** + ** Postgres disallows this case too. The reason is that some other + ** systems handle this case differently, and not all the same way, + ** which is just confusing. To avoid this, we follow PG's lead and + ** disallow it altogether. */ + if( p->selFlags & SF_UFSrcCheck ){ SrcItem *p0 = &p->pSrc->a[0]; for(i=1; ipSrc->nSrc; i++){ SrcItem *p1 = &p->pSrc->a[i]; @@ -6302,6 +6385,12 @@ int sqlite3Select( goto select_end; } } + + /* Clear the SF_UFSrcCheck flag. The check has already been performed, + ** and leaving this flag set can cause errors if a compound sub-query + ** in p->pSrc is flattened into this query and this function called + ** again as part of compound SELECT processing. */ + p->selFlags &= ~SF_UFSrcCheck; } if( pDest->eDest==SRT_Output ){ @@ -6373,6 +6462,39 @@ int sqlite3Select( if( (pSub->selFlags & SF_Aggregate)!=0 ) continue; assert( pSub->pGroupBy==0 ); + /* If a FROM-clause subquery has an ORDER BY clause that is not + ** really doing anything, then delete it now so that it does not + ** interfere with query flattening. See the discussion at + ** https://sqlite.org/forum/forumpost/2d76f2bcf65d256a + ** + ** Beware of these cases where the ORDER BY clause may not be safely + ** omitted: + ** + ** (1) There is also a LIMIT clause + ** (2) The subquery was added to help with window-function + ** processing + ** (3) The subquery is in the FROM clause of an UPDATE + ** (4) The outer query uses an aggregate function other than + ** the built-in count(), min(), or max(). + ** (5) The ORDER BY isn't going to accomplish anything because + ** one of: + ** (a) The outer query has a different ORDER BY clause + ** (b) The subquery is part of a join + ** See forum post 062d576715d277c8 + */ + if( pSub->pOrderBy!=0 + && (p->pOrderBy!=0 || pTabList->nSrc>1) /* Condition (5) */ + && pSub->pLimit==0 /* Condition (1) */ + && (pSub->selFlags & SF_OrderByReqd)==0 /* Condition (2) */ + && (p->selFlags & SF_OrderByReqd)==0 /* Condition (3) and (4) */ + && OptimizationEnabled(db, SQLITE_OmitOrderBy) + ){ + SELECTTRACE(0x100,pParse,p, + ("omit superfluous ORDER BY on %r FROM-clause subquery\n",i+1)); + sqlite3ExprListDelete(db, pSub->pOrderBy); + pSub->pOrderBy = 0; + } + /* If the outer query contains a "complex" result set (that is, ** if the result set of the outer query uses functions or subqueries) ** and if the subquery contains an ORDER BY clause and if @@ -6515,7 +6637,8 @@ int sqlite3Select( ** inside the subquery. This can help the subquery to run more efficiently. */ if( OptimizationEnabled(db, SQLITE_PushDown) - && (pItem->fg.isCte==0 || pItem->u2.pCteUse->eM10d!=M10d_Yes) + && (pItem->fg.isCte==0 + || (pItem->u2.pCteUse->eM10d!=M10d_Yes && pItem->u2.pCteUse->nUse<2)) && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor, (pItem->fg.jointype & JT_OUTER)!=0) ){ @@ -6576,6 +6699,7 @@ int sqlite3Select( sqlite3VdbeAddOp2(v, OP_Gosub, pCteUse->regRtn, pCteUse->addrM9e); if( pItem->iCursor!=pCteUse->iCur ){ sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pCteUse->iCur); + VdbeComment((v, "%!S", pItem)); } pSub->nSelectRow = pCteUse->nRowEst; }else if( (pPrior = isSelfJoinView(pTabList, pItem))!=0 ){ @@ -6913,7 +7037,7 @@ int sqlite3Select( } for(i=0; inFunc; i++){ Expr *pExpr = pAggInfo->aFunc[i].pFExpr; - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + assert( ExprUseXList(pExpr) ); sNC.ncFlags |= NC_InAggFunc; sqlite3ExprAnalyzeAggList(&sNC, pExpr->x.pList); #ifndef SQLITE_OMIT_WINDOWFUNC @@ -6968,7 +7092,9 @@ int sqlite3Select( if( pAggInfo->nFunc==1 && pAggInfo->aFunc[0].iDistinct>=0 - && pAggInfo->aFunc[0].pFExpr->x.pList + && ALWAYS(pAggInfo->aFunc[0].pFExpr!=0) + && ALWAYS(ExprUseXList(pAggInfo->aFunc[0].pFExpr)) + && pAggInfo->aFunc[0].pFExpr->x.pList!=0 ){ Expr *pExpr = pAggInfo->aFunc[0].pFExpr->x.pList->a[0].pExpr; pExpr = sqlite3ExprDup(db, pExpr, 0); @@ -7289,6 +7415,7 @@ int sqlite3Select( sqlite3VdbeAddOp2(v, OP_Integer, 0, regAcc); } }else if( pAggInfo->nFunc==1 && pAggInfo->aFunc[0].iDistinct>=0 ){ + assert( ExprUseXList(pAggInfo->aFunc[0].pFExpr) ); pDistinct = pAggInfo->aFunc[0].pFExpr->x.pList; distFlag = pDistinct ? (WHERE_WANT_DISTINCT|WHERE_AGG_DISTINCT) : 0; } diff --git a/src/shell.c.in b/src/shell.c.in index 0f8de61a..543141c9 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -18,6 +18,18 @@ #endif /* +** Optionally #include a user-defined header, whereby compilation options +** may be set prior to where they take effect, but after platform setup. +** If SQLITE_CUSTOM_INCLUDE=? is defined, its value names the #include +** file. Note that this macro has a like effect on sqlite3.c compilation. +*/ +#ifdef SQLITE_CUSTOM_INCLUDE +# define INC_STRINGIFY_(f) #f +# define INC_STRINGIFY(f) INC_STRINGIFY_(f) +# include INC_STRINGIFY(SQLITE_CUSTOM_INCLUDE) +#endif + +/* ** Determine if we are dealing with WinRT, which provides only a subset of ** the full Win32 API. */ @@ -623,19 +635,38 @@ static int strlenChar(const char *z){ } /* -** Return true if zFile does not exist or if it is not an ordinary file. +** Return open FILE * if zFile exists, can be opened for read +** and is an ordinary file or a character stream source. +** Otherwise return 0. */ +static FILE * openChrSource(const char *zFile){ #ifdef _WIN32 -# define notNormalFile(X) 0 + struct _stat x = {0}; +# define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0) + /* On Windows, open first, then check the stream nature. This order + ** is necessary because _stat() and sibs, when checking a named pipe, + ** effectively break the pipe as its supplier sees it. */ + FILE *rv = fopen(zFile, "rb"); + if( rv==0 ) return 0; + if( _fstat(_fileno(rv), &x) != 0 + || !STAT_CHR_SRC(x.st_mode)){ + fclose(rv); + rv = 0; + } + return rv; #else -static int notNormalFile(const char *zFile){ - struct stat x; - int rc; - memset(&x, 0, sizeof(x)); - rc = stat(zFile, &x); - return rc || !S_ISREG(x.st_mode); -} + struct stat x = {0}; + int rc = stat(zFile, &x); +# define STAT_CHR_SRC(mode) (S_ISREG(mode)||S_ISFIFO(mode)||S_ISCHR(mode)) + if( rc!=0 ) return 0; + if( STAT_CHR_SRC(x.st_mode) ){ + return fopen(zFile, "rb"); + }else{ + return 0; + } #endif +#undef STAT_CHR_SRC +} /* ** This routine reads a line of text from FILE in, stores @@ -825,7 +856,7 @@ static void appendText(ShellText *p, char const *zAppend, char quote){ } } - if( p->n+len>=p->nAlloc ){ + if( p->z==0 || p->n+len>=p->nAlloc ){ p->nAlloc = p->nAlloc*2 + len + 20; p->z = realloc(p->z, p->nAlloc); if( p->z==0 ) shell_out_of_memory(); @@ -971,7 +1002,7 @@ static void shellAddSchemaName( sqlite3 *db = sqlite3_context_db_handle(pCtx); UNUSED_PARAMETER(nVal); if( zIn!=0 && strncmp(zIn, "CREATE ", 7)==0 ){ - for(i=0; i<(int)(sizeof(aPrefix)/sizeof(aPrefix[0])); i++){ + for(i=0; ibSafeMode ){ + va_list ap; + char *zMsg; + va_start(ap, zErrMsg); + zMsg = sqlite3_vmprintf(zErrMsg, ap); + va_end(ap); + raw_printf(stderr, "line %d: ", p->lineno); + utf8_printf(stderr, "%s\n", zMsg); + exit(1); + } +} + +/* ** SQL function: edit(VALUE) ** edit(VALUE,EDITOR) ** @@ -1397,7 +1455,6 @@ static void editFunc( sqlite3_int64 i, j; if( hasCRNL ){ /* If the original contains \r\n then do no conversions back to \n */ - j = sz; }else{ /* If the file did not originally contain \r\n then convert any new ** \r\n back into \n */ @@ -1705,17 +1762,14 @@ static void output_csv(ShellState *p, const char *z, int bSep){ if( z==0 ){ utf8_printf(out,"%s",p->nullValue); }else{ - int i; - int nSep = strlen30(p->colSeparator); + unsigned i; for(i=0; z[i]; i++){ - if( needCsvQuote[((unsigned char*)z)[i]] - || (z[i]==p->colSeparator[0] && - (nSep==1 || memcmp(z, p->colSeparator, nSep)==0)) ){ + if( needCsvQuote[((unsigned char*)z)[i]] ){ i = 0; break; } } - if( i==0 ){ + if( i==0 || strstr(z, p->colSeparator)!=0 ){ char *zQuoted = sqlite3_mprintf("\"%w\"", z); utf8_printf(out, "%s", zQuoted); sqlite3_free(zQuoted); @@ -1755,6 +1809,49 @@ static BOOL WINAPI ConsoleCtrlHandler( #ifndef SQLITE_OMIT_AUTHORIZATION /* +** This authorizer runs in safe mode. +*/ +static int safeModeAuth( + void *pClientData, + int op, + const char *zA1, + const char *zA2, + const char *zA3, + const char *zA4 +){ + ShellState *p = (ShellState*)pClientData; + static const char *azProhibitedFunctions[] = { + "edit", + "fts3_tokenizer", + "load_extension", + "readfile", + "writefile", + "zipfile", + "zipfile_cds", + }; + UNUSED_PARAMETER(zA2); + UNUSED_PARAMETER(zA3); + UNUSED_PARAMETER(zA4); + switch( op ){ + case SQLITE_ATTACH: { + failIfSafeMode(p, "cannot run ATTACH in safe mode"); + break; + } + case SQLITE_FUNCTION: { + int i; + for(i=0; iout, "\n"); + if( p->bSafeMode ) (void)safeModeAuth(pClientData, op, zA1, zA2, zA3, zA4); return SQLITE_OK; } #endif @@ -2505,17 +2603,16 @@ static int run_table_dump_query( } /* -** Allocate space and save off current error string. +** Allocate space and save off string indicating current error. */ static char *save_err_msg( - sqlite3 *db /* Database to query */ + sqlite3 *db, /* Database to query */ + const char *zWhen, /* Qualifier (format) wrapper */ + int rc /* Error code returned from API */ ){ - int nErrMsg = 1+strlen30(sqlite3_errmsg(db)); - char *zErrMsg = sqlite3_malloc64(nErrMsg); - if( zErrMsg ){ - memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg); - } - return zErrMsg; + if( zWhen==0 ) + zWhen = "%s (%d)"; + return sqlite3_mprintf(zWhen, sqlite3_errmsg(db), rc); } #ifdef __linux__ @@ -3082,9 +3179,9 @@ static void exec_prepared_stmt_columnar( z = (const char*)sqlite3_column_text(pStmt,i); azData[nRow*nColumn + i] = z ? strdup(z) : 0; } - }while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ); + }while( sqlite3_step(pStmt)==SQLITE_ROW ); if( nColumn>p->nWidth ){ - p->colWidth = realloc(p->colWidth, nColumn*2*sizeof(int)); + p->colWidth = realloc(p->colWidth, (nColumn+1)*2*sizeof(int)); if( p->colWidth==0 ) shell_out_of_memory(); for(i=p->nWidth; icolWidth[i] = 0; p->nWidth = nColumn; @@ -3226,7 +3323,7 @@ static void exec_prepared_stmt( int nCol = sqlite3_column_count(pStmt); void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1); if( !pData ){ - rc = SQLITE_NOMEM; + shell_out_of_memory(); }else{ char **azCols = (char **)pData; /* Names of result columns */ char **azVals = &azCols[nCol]; /* Results */ @@ -3437,7 +3534,7 @@ static int shell_exec( rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); if( SQLITE_OK != rc ){ if( pzErrMsg ){ - *pzErrMsg = save_err_msg(db); + *pzErrMsg = save_err_msg(db, "in prepare, %s (%d)", rc); } }else{ if( !pStmt ){ @@ -3551,7 +3648,7 @@ static int shell_exec( zSql = zLeftover; while( IsSpace(zSql[0]) ) zSql++; }else if( pzErrMsg ){ - *pzErrMsg = save_err_msg(db); + *pzErrMsg = save_err_msg(db, "stepping, %s (%d)", rc); } /* clear saved stmt handle */ @@ -3865,6 +3962,7 @@ static const char *(azHelp[]) = { " -c, --create Create a new archive", " -u, --update Add or update files with changed mtime", " -i, --insert Like -u but always add even if unchanged", + " -r, --remove Remove files from archive", " -t, --list List contents of archive", " -x, --extract Extract files from archive", " Optional arguments:", @@ -3872,6 +3970,7 @@ static const char *(azHelp[]) = { " -f FILE, --file FILE Use archive FILE (default is current db)", " -a FILE, --append FILE Open FILE using the apndvfs VFS", " -C DIR, --directory DIR Read/extract files from directory DIR", + " -g, --glob Use glob matching for names in archive", " -n, --dryrun Show the SQL that would have occurred", " Examples:", " .ar -cf ARCHIVE foo bar # Create ARCHIVE from files foo and bar", @@ -3892,6 +3991,7 @@ static const char *(azHelp[]) = { ".changes on|off Show number of rows changed by SQL", ".check GLOB Fail if output since .testcase does not match", ".clone NEWDB Clone data into NEWDB from the existing database", + ".connection [close] [#] Open or close an auxiliary database connection", ".databases List names and files of attached databases", ".dbconfig ?op? ?val? List or change sqlite3_db_config() options", ".dbinfo ?DB? Show status information about the database", @@ -3968,6 +4068,7 @@ static const char *(azHelp[]) = { " table ASCII-art table", " tabs Tab-separated values", " tcl TCL list elements", + ".nonce STRING Disable safe mode for one command if the nonce matches", ".nullvalue STRING Use STRING in place of NULL values", ".once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE", " If FILE begins with '|' then open as a pipe", @@ -4232,15 +4333,16 @@ static void session_close(OpenSession *pSession){ ** Close all OpenSession objects and release all associated resources. */ #if defined(SQLITE_ENABLE_SESSION) -static void session_close_all(ShellState *p){ - int i; - for(i=0; inSession; i++){ - session_close(&p->aSession[i]); +static void session_close_all(ShellState *p, int i){ + int j; + struct AuxDb *pAuxDb = i<0 ? p->pAuxDb : &p->aAuxDb[i]; + for(j=0; jnSession; j++){ + session_close(&pAuxDb->aSession[j]); } - p->nSession = 0; + pAuxDb->nSession = 0; } #else -# define session_close_all(X) +# define session_close_all(X,Y) #endif /* @@ -4305,8 +4407,8 @@ int deduceDatabaseType(const char *zName, int dfltZip){ #ifndef SQLITE_OMIT_DESERIALIZE /* ** Reconstruct an in-memory database using the output from the "dbtotxt" -** program. Read content from the file in p->zDbFilename. If p->zDbFilename -** is 0, then read from standard input. +** program. Read content from the file in p->aAuxDb[].zDbFilename. +** If p->aAuxDb[].zDbFilename is 0, then read from standard input. */ static unsigned char *readHexDb(ShellState *p, int *pnData){ unsigned char *a = 0; @@ -4317,12 +4419,13 @@ static unsigned char *readHexDb(ShellState *p, int *pnData){ int j, k; int rc; FILE *in; + const char *zDbFilename = p->pAuxDb->zDbFilename; unsigned int x[16]; char zLine[1000]; - if( p->zDbFilename ){ - in = fopen(p->zDbFilename, "r"); + if( zDbFilename ){ + in = fopen(zDbFilename, "r"); if( in==0 ){ - utf8_printf(stderr, "cannot open \"%s\" for reading\n", p->zDbFilename); + utf8_printf(stderr, "cannot open \"%s\" for reading\n", zDbFilename); return 0; } nLine = 0; @@ -4363,7 +4466,7 @@ static unsigned char *readHexDb(ShellState *p, int *pnData){ &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], &x[15]); if( rc==17 ){ k = iOffset+j; - if( k+16<=n ){ + if( k+16<=n && k>=0 ){ int ii; for(ii=0; ii<16; ii++) a[k+ii] = x[ii]&0xff; } @@ -4564,17 +4667,18 @@ static void shellEscapeCrnl( */ static void open_db(ShellState *p, int openFlags){ if( p->db==0 ){ + const char *zDbFilename = p->pAuxDb->zDbFilename; if( p->openMode==SHELL_OPEN_UNSPEC ){ - if( p->zDbFilename==0 || p->zDbFilename[0]==0 ){ + if( zDbFilename==0 || zDbFilename[0]==0 ){ p->openMode = SHELL_OPEN_NORMAL; }else{ - p->openMode = (u8)deduceDatabaseType(p->zDbFilename, + p->openMode = (u8)deduceDatabaseType(zDbFilename, (openFlags & OPEN_DB_ZIPFILE)!=0); } } switch( p->openMode ){ case SHELL_OPEN_APPENDVFS: { - sqlite3_open_v2(p->zDbFilename, &p->db, + sqlite3_open_v2(zDbFilename, &p->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, "apndvfs"); break; } @@ -4588,13 +4692,13 @@ static void open_db(ShellState *p, int openFlags){ break; } case SHELL_OPEN_READONLY: { - sqlite3_open_v2(p->zDbFilename, &p->db, + sqlite3_open_v2(zDbFilename, &p->db, SQLITE_OPEN_READONLY|p->openFlags, 0); break; } case SHELL_OPEN_UNSPEC: case SHELL_OPEN_NORMAL: { - sqlite3_open_v2(p->zDbFilename, &p->db, + sqlite3_open_v2(zDbFilename, &p->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, 0); break; } @@ -4602,7 +4706,7 @@ static void open_db(ShellState *p, int openFlags){ globalDb = p->db; if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){ utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n", - p->zDbFilename, sqlite3_errmsg(p->db)); + zDbFilename, sqlite3_errmsg(p->db)); if( openFlags & OPEN_DB_KEEPALIVE ){ sqlite3_open(":memory:", &p->db); return; @@ -4649,7 +4753,7 @@ static void open_db(ShellState *p, int openFlags){ #endif if( p->openMode==SHELL_OPEN_ZIPFILE ){ char *zSql = sqlite3_mprintf( - "CREATE VIRTUAL TABLE zip USING zipfile(%Q);", p->zDbFilename); + "CREATE VIRTUAL TABLE zip USING zipfile(%Q);", zDbFilename); sqlite3_exec(p->db, zSql, 0, 0, 0); sqlite3_free(zSql); } @@ -4660,7 +4764,7 @@ static void open_db(ShellState *p, int openFlags){ int nData = 0; unsigned char *aData; if( p->openMode==SHELL_OPEN_DESERIALIZE ){ - aData = (unsigned char*)readFile(p->zDbFilename, &nData); + aData = (unsigned char*)readFile(zDbFilename, &nData); }else{ aData = readHexDb(p, &nData); if( aData==0 ){ @@ -4679,6 +4783,9 @@ static void open_db(ShellState *p, int openFlags){ } #endif } + if( p->bSafeModePersist && p->db!=0 ){ + sqlite3_set_authorizer(p->db, safeModeAuth, p); + } } /* @@ -5276,7 +5383,7 @@ static void tryToCloneSchema( zQuery); goto end_schema_xfer; } - while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){ + while( sqlite3_step(pQuery)==SQLITE_ROW ){ zName = sqlite3_column_text(pQuery, 0); zSql = sqlite3_column_text(pQuery, 1); printf("%s... ", zName); fflush(stdout); @@ -5664,8 +5771,7 @@ static void newTempFile(ShellState *p, const char *zSuffix){ p->zTempFile = sqlite3_mprintf("%z.%s", p->zTempFile, zSuffix); } if( p->zTempFile==0 ){ - raw_printf(stderr, "out of memory\n"); - exit(1); + shell_out_of_memory(); } } @@ -6025,6 +6131,7 @@ struct ArCommand { u8 bZip; /* True if the archive is a ZIP */ u8 bDryRun; /* True if --dry-run */ u8 bAppend; /* True if --append */ + u8 bGlob; /* True if --glob */ u8 fromCmdLine; /* Run from -A instead of .archive */ int nArg; /* Number of command arguments */ char *zSrcTable; /* "sqlar", "zipfile($file)" or "zip" */ @@ -6072,21 +6179,24 @@ static int arErrorMsg(ArCommand *pAr, const char *zFmt, ...){ #define AR_CMD_EXTRACT 4 #define AR_CMD_LIST 5 #define AR_CMD_HELP 6 +#define AR_CMD_REMOVE 7 /* ** Other (non-command) switches. */ -#define AR_SWITCH_VERBOSE 7 -#define AR_SWITCH_FILE 8 -#define AR_SWITCH_DIRECTORY 9 -#define AR_SWITCH_APPEND 10 -#define AR_SWITCH_DRYRUN 11 +#define AR_SWITCH_VERBOSE 8 +#define AR_SWITCH_FILE 9 +#define AR_SWITCH_DIRECTORY 10 +#define AR_SWITCH_APPEND 11 +#define AR_SWITCH_DRYRUN 12 +#define AR_SWITCH_GLOB 13 static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){ switch( eSwitch ){ case AR_CMD_CREATE: case AR_CMD_EXTRACT: case AR_CMD_LIST: + case AR_CMD_REMOVE: case AR_CMD_UPDATE: case AR_CMD_INSERT: case AR_CMD_HELP: @@ -6099,6 +6209,9 @@ static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){ case AR_SWITCH_DRYRUN: pAr->bDryRun = 1; break; + case AR_SWITCH_GLOB: + pAr->bGlob = 1; + break; case AR_SWITCH_VERBOSE: pAr->bVerbose = 1; break; @@ -6137,6 +6250,7 @@ static int arParseCommand( { "extract", 'x', AR_CMD_EXTRACT, 0 }, { "insert", 'i', AR_CMD_INSERT, 0 }, { "list", 't', AR_CMD_LIST, 0 }, + { "remove", 'r', AR_CMD_REMOVE, 0 }, { "update", 'u', AR_CMD_UPDATE, 0 }, { "help", 'h', AR_CMD_HELP, 0 }, { "verbose", 'v', AR_SWITCH_VERBOSE, 0 }, @@ -6144,6 +6258,7 @@ static int arParseCommand( { "append", 'a', AR_SWITCH_APPEND, 1 }, { "directory", 'C', AR_SWITCH_DIRECTORY, 1 }, { "dryrun", 'n', AR_SWITCH_DRYRUN, 0 }, + { "glob", 'g', AR_SWITCH_GLOB, 0 }, }; int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch); struct ArSwitch *pEnd = &aSwitch[nSwitch]; @@ -6260,11 +6375,13 @@ static int arParseCommand( /* ** This function assumes that all arguments within the ArCommand.azArg[] -** array refer to archive members, as for the --extract or --list commands. -** It checks that each of them are present. If any specified file is not -** present in the archive, an error is printed to stderr and an error -** code returned. Otherwise, if all specified arguments are present in -** the archive, SQLITE_OK is returned. +** array refer to archive members, as for the --extract, --list or --remove +** commands. It checks that each of them are "present". If any specified +** file is not present in the archive, an error is printed to stderr and an +** error code returned. Otherwise, if all specified arguments are present +** in the archive, SQLITE_OK is returned. Here, "present" means either an +** exact equality when pAr->bGlob is false or a "name GLOB pattern" match +** when pAr->bGlob is true. ** ** This function strips any trailing '/' characters from each argument. ** This is consistent with the way the [tar] command seems to work on @@ -6275,11 +6392,11 @@ static int arCheckEntries(ArCommand *pAr){ if( pAr->nArg ){ int i, j; sqlite3_stmt *pTest = 0; + const char *zSel = (pAr->bGlob) + ? "SELECT name FROM %s WHERE glob($name,name)" + : "SELECT name FROM %s WHERE name=$name"; - shellPreparePrintf(pAr->db, &rc, &pTest, - "SELECT name FROM %s WHERE name=$name", - pAr->zSrcTable - ); + shellPreparePrintf(pAr->db, &rc, &pTest, zSel, pAr->zSrcTable); j = sqlite3_bind_parameter_index(pTest, "$name"); for(i=0; inArg && rc==SQLITE_OK; i++){ char *z = pAr->azArg[i]; @@ -6307,14 +6424,16 @@ static int arCheckEntries(ArCommand *pAr){ ** identify all archive members that match the command arguments held ** in (*pAr). Leave this WHERE clause in (*pzWhere) before returning. ** The caller is responsible for eventually calling sqlite3_free() on -** any non-NULL (*pzWhere) value. +** any non-NULL (*pzWhere) value. Here, "match" means strict equality +** when pAr->bGlob is false and GLOB match when pAr->bGlob is true. */ static void arWhereClause( int *pRc, - ArCommand *pAr, + ArCommand *pAr, char **pzWhere /* OUT: New WHERE clause */ ){ char *zWhere = 0; + const char *zSameOp = (pAr->bGlob)? "GLOB" : "="; if( *pRc==SQLITE_OK ){ if( pAr->nArg==0 ){ zWhere = sqlite3_mprintf("1"); @@ -6324,8 +6443,8 @@ static void arWhereClause( for(i=0; inArg; i++){ const char *z = pAr->azArg[i]; zWhere = sqlite3_mprintf( - "%z%s name = '%q' OR substr(name,1,%d) = '%q/'", - zWhere, zSep, z, strlen30(z)+1, z + "%z%s name %s '%q' OR substr(name,1,%d) %s '%q/'", + zWhere, zSep, zSameOp, z, strlen30(z)+1, zSameOp, z ); if( zWhere==0 ){ *pRc = SQLITE_NOMEM; @@ -6380,6 +6499,47 @@ static int arListCommand(ArCommand *pAr){ /* +** Implementation of .ar "Remove" command. +*/ +static int arRemoveCommand(ArCommand *pAr){ + int rc = 0; + char *zSql = 0; + char *zWhere = 0; + + if( pAr->nArg ){ + /* Verify that args actually exist within the archive before proceeding. + ** And formulate a WHERE clause to match them. */ + rc = arCheckEntries(pAr); + arWhereClause(&rc, pAr, &zWhere); + } + if( rc==SQLITE_OK ){ + zSql = sqlite3_mprintf("DELETE FROM %s WHERE %s;", + pAr->zSrcTable, zWhere); + if( pAr->bDryRun ){ + utf8_printf(pAr->p->out, "%s\n", zSql); + }else{ + char *zErr = 0; + rc = sqlite3_exec(pAr->db, "SAVEPOINT ar;", 0, 0, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr); + if( rc!=SQLITE_OK ){ + sqlite3_exec(pAr->db, "ROLLBACK TO ar; RELEASE ar;", 0, 0, 0); + }else{ + rc = sqlite3_exec(pAr->db, "RELEASE ar;", 0, 0, 0); + } + } + if( zErr ){ + utf8_printf(stdout, "ERROR: %s\n", zErr); + sqlite3_free(zErr); + } + } + } + sqlite3_free(zWhere); + sqlite3_free(zSql); + return rc; +} + +/* ** Implementation of .ar "eXtract" command. */ static int arExtractCommand(ArCommand *pAr){ @@ -6631,7 +6791,7 @@ static int arDotCommand( int flags; if( cmd.bAppend ) eDbType = SHELL_OPEN_APPENDVFS; if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_INSERT - || cmd.eCmd==AR_CMD_UPDATE ){ + || cmd.eCmd==AR_CMD_REMOVE || cmd.eCmd==AR_CMD_UPDATE ){ flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; }else{ flags = SQLITE_OPEN_READONLY; @@ -6687,6 +6847,10 @@ static int arDotCommand( rc = arCreateOrUpdateCommand(&cmd, 1, 0); break; + case AR_CMD_REMOVE: + rc = arRemoveCommand(&cmd); + break; + default: assert( cmd.eCmd==AR_CMD_UPDATE ); rc = arCreateOrUpdateCommand(&cmd, 1, 1); @@ -7381,7 +7545,6 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){ } #endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */ - /* ** If an input line begins with "." then invoke this routine to ** process that line. @@ -7443,6 +7606,8 @@ static int do_meta_command(char *zLine, ShellState *p){ open_db(p, 0); if( booleanValue(azArg[1]) ){ sqlite3_set_authorizer(p->db, shellAuth, p); + }else if( p->bSafeModePersist ){ + sqlite3_set_authorizer(p->db, safeModeAuth, p); }else{ sqlite3_set_authorizer(p->db, 0, 0); } @@ -7452,6 +7617,7 @@ static int do_meta_command(char *zLine, ShellState *p){ #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) if( c=='a' && strncmp(azArg[0], "archive", n)==0 ){ open_db(p, 0); + failIfSafeMode(p, "cannot run .archive in safe mode"); rc = arDotCommand(p, 0, azArg, nArg); }else #endif @@ -7466,6 +7632,7 @@ static int do_meta_command(char *zLine, ShellState *p){ int j; int bAsync = 0; const char *zVfs = 0; + failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]); for(j=1; j=3 && strncmp(azArg[0], "breakpoint", n)==0 ){ + test_breakpoint(); + }else + if( c=='c' && strcmp(azArg[0],"cd")==0 ){ + failIfSafeMode(p, "cannot run .cd in safe mode"); if( nArg==2 ){ #if defined(_WIN32) || defined(WIN32) wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]); @@ -7565,13 +7740,6 @@ static int do_meta_command(char *zLine, ShellState *p){ } }else - /* The undocumented ".breakpoint" command causes a call to the no-op - ** routine named test_breakpoint(). - */ - if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){ - test_breakpoint(); - }else - if( c=='c' && n>=3 && strncmp(azArg[0], "changes", n)==0 ){ if( nArg==2 ){ setOrClearFlag(p, SHFLG_CountChanges, azArg[1]); @@ -7607,6 +7775,7 @@ static int do_meta_command(char *zLine, ShellState *p){ }else if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){ + failIfSafeMode(p, "cannot run .clone in safe mode"); if( nArg==2 ){ tryToClone(p, azArg[1]); }else{ @@ -7615,6 +7784,52 @@ static int do_meta_command(char *zLine, ShellState *p){ } }else + if( c=='c' && strncmp(azArg[0], "connection", n)==0 ){ + if( nArg==1 ){ + /* List available connections */ + int i; + for(i=0; iaAuxDb); i++){ + const char *zFile = p->aAuxDb[i].zDbFilename; + if( p->aAuxDb[i].db==0 && p->pAuxDb!=&p->aAuxDb[i] ){ + zFile = "(not open)"; + }else if( zFile==0 ){ + zFile = "(memory)"; + }else if( zFile[0]==0 ){ + zFile = "(temporary-file)"; + } + if( p->pAuxDb == &p->aAuxDb[i] ){ + utf8_printf(stdout, "ACTIVE %d: %s\n", i, zFile); + }else if( p->aAuxDb[i].db!=0 ){ + utf8_printf(stdout, " %d: %s\n", i, zFile); + } + } + }else if( nArg==2 && IsDigit(azArg[1][0]) && azArg[1][1]==0 ){ + int i = azArg[1][0] - '0'; + if( p->pAuxDb != &p->aAuxDb[i] && i>=0 && iaAuxDb) ){ + p->pAuxDb->db = p->db; + p->pAuxDb = &p->aAuxDb[i]; + globalDb = p->db = p->pAuxDb->db; + p->pAuxDb->db = 0; + } + }else if( nArg==3 && strcmp(azArg[1], "close")==0 + && IsDigit(azArg[2][0]) && azArg[2][1]==0 ){ + int i = azArg[2][0] - '0'; + if( i<0 || i>=ArraySize(p->aAuxDb) ){ + /* No-op */ + }else if( p->pAuxDb == &p->aAuxDb[i] ){ + raw_printf(stderr, "cannot close the active database connection\n"); + rc = 1; + }else if( p->aAuxDb[i].db ){ + session_close_all(p, i); + close_db(p->aAuxDb[i].db); + p->aAuxDb[i].db = 0; + } + }else{ + raw_printf(stderr, "Usage: .connection [close] [CONNECTION-NUMBER]\n"); + rc = 1; + } + }else + if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){ char **azName = 0; int nName = 0; @@ -8060,7 +8275,7 @@ static int do_meta_command(char *zLine, ShellState *p){ " FROM sqlite_schema UNION ALL" " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_schema) " "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' " - "ORDER BY rowid", + "ORDER BY x", callback, &data, 0 ); if( rc==SQLITE_OK ){ @@ -8076,8 +8291,6 @@ static int do_meta_command(char *zLine, ShellState *p){ raw_printf(p->out, "/* No STAT tables available */\n"); }else{ raw_printf(p->out, "ANALYZE sqlite_schema;\n"); - sqlite3_exec(p->db, "SELECT 'ANALYZE sqlite_schema'", - callback, &data, 0); data.cMode = data.mode = MODE_Insert; data.zDestTable = "sqlite_stat1"; shell_exec(&data, "SELECT * FROM sqlite_stat1", 0); @@ -8124,7 +8337,13 @@ static int do_meta_command(char *zLine, ShellState *p){ int nSkip = 0; /* Initial lines to skip */ int useOutputMode = 1; /* Use output mode to determine separators */ + failIfSafeMode(p, "cannot run .import in safe mode"); memset(&sCtx, 0, sizeof(sCtx)); + sCtx.z = sqlite3_malloc64(120); + if( sCtx.z==0 ){ + import_cleanup(&sCtx); + shell_out_of_memory(); + } if( p->mode==MODE_Ascii ){ xRead = ascii_read_one_field; }else{ @@ -8234,6 +8453,7 @@ static int do_meta_command(char *zLine, ShellState *p){ if( sCtx.in==0 ){ utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile); rc = 1; + import_cleanup(&sCtx); goto meta_command_exit; } if( eVerbose>=2 || (eVerbose>=1 && useOutputMode) ){ @@ -8430,7 +8650,7 @@ static int do_meta_command(char *zLine, ShellState *p){ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); i = 0; - while( sqlite3_step(pStmt)==SQLITE_ROW ){ + while( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ char zLabel[20]; const char *zCol = (const char*)sqlite3_column_text(pStmt,2); i++; @@ -8575,6 +8795,7 @@ static int do_meta_command(char *zLine, ShellState *p){ if( c=='l' && strncmp(azArg[0], "load", n)==0 ){ const char *zFile, *zProc; char *zErrMsg = 0; + failIfSafeMode(p, "cannot run .load in safe mode"); if( nArg<2 ){ raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n"); rc = 1; @@ -8593,6 +8814,7 @@ static int do_meta_command(char *zLine, ShellState *p){ #endif if( c=='l' && strncmp(azArg[0], "log", n)==0 ){ + failIfSafeMode(p, "cannot run .log in safe mode"); if( nArg!=2 ){ raw_printf(stderr, "Usage: .log FILENAME\n"); rc = 1; @@ -8663,6 +8885,20 @@ static int do_meta_command(char *zLine, ShellState *p){ p->cMode = p->mode; }else + if( c=='n' && strcmp(azArg[0], "nonce")==0 ){ + if( nArg!=2 ){ + raw_printf(stderr, "Usage: .nonce NONCE\n"); + rc = 1; + }else if( p->zNonce==0 || strcmp(azArg[1],p->zNonce)!=0 ){ + raw_printf(stderr, "line %d: incorrect nonce: \"%s\"\n", p->lineno, azArg[1]); + exit(1); + }else{ + p->bSafeMode = 0; + return 0; /* Return immediately to bypass the safe mode reset + ** at the end of this procedure */ + } + }else + if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){ if( nArg==2 ){ sqlite3_snprintf(sizeof(p->nullValue), p->nullValue, @@ -8705,16 +8941,8 @@ static int do_meta_command(char *zLine, ShellState *p){ char *zNewFilename = 0; /* Name of the database file to open */ int iName = 1; /* Index in azArg[] of the filename */ int newFlag = 0; /* True to delete file before opening */ - /* Close the existing database */ - session_close_all(p); - close_db(p->db); - p->db = 0; - p->zDbFilename = 0; - sqlite3_free(p->zFreeOnClose); - p->zFreeOnClose = 0; - p->openMode = SHELL_OPEN_UNSPEC; - p->openFlags = 0; - p->szMax = 0; + int openMode = SHELL_OPEN_UNSPEC; + /* Check for command-line arguments */ for(iName=1; iNameopenMode = SHELL_OPEN_ZIPFILE; + openMode = SHELL_OPEN_ZIPFILE; #endif }else if( optionMatch(z, "append") ){ - p->openMode = SHELL_OPEN_APPENDVFS; + openMode = SHELL_OPEN_APPENDVFS; }else if( optionMatch(z, "readonly") ){ - p->openMode = SHELL_OPEN_READONLY; + openMode = SHELL_OPEN_READONLY; }else if( optionMatch(z, "nofollow") ){ p->openFlags |= SQLITE_OPEN_NOFOLLOW; #ifndef SQLITE_OMIT_DESERIALIZE }else if( optionMatch(z, "deserialize") ){ - p->openMode = SHELL_OPEN_DESERIALIZE; + openMode = SHELL_OPEN_DESERIALIZE; }else if( optionMatch(z, "hexdb") ){ - p->openMode = SHELL_OPEN_HEXDB; + openMode = SHELL_OPEN_HEXDB; }else if( optionMatch(z, "maxsize") && iName+1szMax = integerValue(azArg[++iName]); #endif /* SQLITE_OMIT_DESERIALIZE */ @@ -8750,21 +8978,40 @@ static int do_meta_command(char *zLine, ShellState *p){ zNewFilename = sqlite3_mprintf("%s", z); } } + + /* Close the existing database */ + session_close_all(p, -1); + close_db(p->db); + p->db = 0; + p->pAuxDb->zDbFilename = 0; + sqlite3_free(p->pAuxDb->zFreeOnClose); + p->pAuxDb->zFreeOnClose = 0; + p->openMode = openMode; + p->openFlags = 0; + p->szMax = 0; + /* If a filename is specified, try to open it first */ if( zNewFilename || p->openMode==SHELL_OPEN_HEXDB ){ - if( newFlag ) shellDeleteFile(zNewFilename); - p->zDbFilename = zNewFilename; + if( newFlag && !p->bSafeMode ) shellDeleteFile(zNewFilename); + if( p->bSafeMode + && p->openMode!=SHELL_OPEN_HEXDB + && zNewFilename + && strcmp(zNewFilename,":memory:")!=0 + ){ + failIfSafeMode(p, "cannot open disk-based database files in safe mode"); + } + p->pAuxDb->zDbFilename = zNewFilename; open_db(p, OPEN_DB_KEEPALIVE); if( p->db==0 ){ utf8_printf(stderr, "Error: cannot open '%s'\n", zNewFilename); sqlite3_free(zNewFilename); }else{ - p->zFreeOnClose = zNewFilename; + p->pAuxDb->zFreeOnClose = zNewFilename; } } if( p->db==0 ){ /* As a fall-back open a TEMP database */ - p->zDbFilename = 0; + p->pAuxDb->zDbFilename = 0; open_db(p, 0); } }else @@ -8780,6 +9027,7 @@ static int do_meta_command(char *zLine, ShellState *p){ int bBOM = 0; int bOnce = 0; /* 0: .output, 1: .once, 2: .excel */ + failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]); if( c=='e' ){ eMode = 'x'; bOnce = 2; @@ -8909,7 +9157,7 @@ static int do_meta_command(char *zLine, ShellState *p){ rx = sqlite3_prepare_v2(p->db, "SELECT key, quote(value) " "FROM temp.sqlite_parameters;", -1, &pStmt, 0); - while( sqlite3_step(pStmt)==SQLITE_ROW ){ + while( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ utf8_printf(p->out, "%-*s %s\n", len, sqlite3_column_text(pStmt,0), sqlite3_column_text(pStmt,1)); } @@ -9052,6 +9300,7 @@ static int do_meta_command(char *zLine, ShellState *p){ if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){ FILE *inSaved = p->in; int savedLineno = p->lineno; + failIfSafeMode(p, "cannot run .read in safe mode"); if( nArg!=2 ){ raw_printf(stderr, "Usage: .read FILE\n"); rc = 1; @@ -9072,7 +9321,7 @@ static int do_meta_command(char *zLine, ShellState *p){ pclose(p->in); } #endif - }else if( notNormalFile(azArg[1]) || (p->in = fopen(azArg[1], "rb"))==0 ){ + }else if( (p->in = openChrSource(azArg[1]))==0 ){ utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]); rc = 1; }else{ @@ -9090,6 +9339,7 @@ static int do_meta_command(char *zLine, ShellState *p){ sqlite3_backup *pBackup; int nTimeout = 0; + failIfSafeMode(p, "cannot run .restore in safe mode"); if( nArg==2 ){ zSrcFile = azArg[1]; zDb = "main"; @@ -9293,7 +9543,8 @@ static int do_meta_command(char *zLine, ShellState *p){ #if defined(SQLITE_ENABLE_SESSION) if( c=='s' && strncmp(azArg[0],"session",n)==0 && n>=3 ){ - OpenSession *pSession = &p->aSession[0]; + struct AuxDb *pAuxDb = p->pAuxDb; + OpenSession *pSession = &pAuxDb->aSession[0]; char **azCmd = &azArg[1]; int iSes = 0; int nCmd = nArg - 1; @@ -9301,15 +9552,15 @@ static int do_meta_command(char *zLine, ShellState *p){ if( nArg<=1 ) goto session_syntax_error; open_db(p, 0); if( nArg>=3 ){ - for(iSes=0; iSesnSession; iSes++){ - if( strcmp(p->aSession[iSes].zName, azArg[1])==0 ) break; + for(iSes=0; iSesnSession; iSes++){ + if( strcmp(pAuxDb->aSession[iSes].zName, azArg[1])==0 ) break; } - if( iSesnSession ){ - pSession = &p->aSession[iSes]; + if( iSesnSession ){ + pSession = &pAuxDb->aSession[iSes]; azCmd++; nCmd--; }else{ - pSession = &p->aSession[0]; + pSession = &pAuxDb->aSession[0]; iSes = 0; } } @@ -9338,6 +9589,7 @@ static int do_meta_command(char *zLine, ShellState *p){ */ if( strcmp(azCmd[0],"changeset")==0 || strcmp(azCmd[0],"patchset")==0 ){ FILE *out = 0; + failIfSafeMode(p, "cannot run \".session %s\" in safe mode", azCmd[0]); if( nCmd!=2 ) goto session_syntax_error; if( pSession->p==0 ) goto session_not_open; out = fopen(azCmd[1], "wb"); @@ -9371,9 +9623,9 @@ static int do_meta_command(char *zLine, ShellState *p){ */ if( strcmp(azCmd[0], "close")==0 ){ if( nCmd!=1 ) goto session_syntax_error; - if( p->nSession ){ + if( pAuxDb->nSession ){ session_close(pSession); - p->aSession[iSes] = p->aSession[--p->nSession]; + pAuxDb->aSession[iSes] = pAuxDb->aSession[--pAuxDb->nSession]; } }else @@ -9384,7 +9636,7 @@ static int do_meta_command(char *zLine, ShellState *p){ int ii; if( nCmd>2 ) goto session_syntax_error; ii = nCmd==1 ? -1 : booleanValue(azCmd[1]); - if( p->nSession ){ + if( pAuxDb->nSession ){ ii = sqlite3session_enable(pSession->p, ii); utf8_printf(p->out, "session %s enable flag = %d\n", pSession->zName, ii); @@ -9397,7 +9649,7 @@ static int do_meta_command(char *zLine, ShellState *p){ if( strcmp(azCmd[0], "filter")==0 ){ int ii, nByte; if( nCmd<2 ) goto session_syntax_error; - if( p->nSession ){ + if( pAuxDb->nSession ){ for(ii=0; iinFilter; ii++){ sqlite3_free(pSession->azFilter[ii]); } @@ -9422,7 +9674,7 @@ static int do_meta_command(char *zLine, ShellState *p){ int ii; if( nCmd>2 ) goto session_syntax_error; ii = nCmd==1 ? -1 : booleanValue(azCmd[1]); - if( p->nSession ){ + if( pAuxDb->nSession ){ ii = sqlite3session_indirect(pSession->p, ii); utf8_printf(p->out, "session %s indirect flag = %d\n", pSession->zName, ii); @@ -9435,7 +9687,7 @@ static int do_meta_command(char *zLine, ShellState *p){ if( strcmp(azCmd[0], "isempty")==0 ){ int ii; if( nCmd!=1 ) goto session_syntax_error; - if( p->nSession ){ + if( pAuxDb->nSession ){ ii = sqlite3session_isempty(pSession->p); utf8_printf(p->out, "session %s isempty flag = %d\n", pSession->zName, ii); @@ -9446,8 +9698,8 @@ static int do_meta_command(char *zLine, ShellState *p){ ** List all currently open sessions */ if( strcmp(azCmd[0],"list")==0 ){ - for(i=0; inSession; i++){ - utf8_printf(p->out, "%d %s\n", i, p->aSession[i].zName); + for(i=0; inSession; i++){ + utf8_printf(p->out, "%d %s\n", i, pAuxDb->aSession[i].zName); } }else @@ -9460,17 +9712,17 @@ static int do_meta_command(char *zLine, ShellState *p){ if( nCmd!=3 ) goto session_syntax_error; zName = azCmd[2]; if( zName[0]==0 ) goto session_syntax_error; - for(i=0; inSession; i++){ - if( strcmp(p->aSession[i].zName,zName)==0 ){ + for(i=0; inSession; i++){ + if( strcmp(pAuxDb->aSession[i].zName,zName)==0 ){ utf8_printf(stderr, "Session \"%s\" already exists\n", zName); goto meta_command_exit; } } - if( p->nSession>=ArraySize(p->aSession) ){ - raw_printf(stderr, "Maximum of %d sessions\n", ArraySize(p->aSession)); + if( pAuxDb->nSession>=ArraySize(pAuxDb->aSession) ){ + raw_printf(stderr, "Maximum of %d sessions\n", ArraySize(pAuxDb->aSession)); goto meta_command_exit; } - pSession = &p->aSession[p->nSession]; + pSession = &pAuxDb->aSession[pAuxDb->nSession]; rc = sqlite3session_create(p->db, azCmd[1], &pSession->p); if( rc ){ raw_printf(stderr, "Cannot open session: error code=%d\n", rc); @@ -9479,7 +9731,7 @@ static int do_meta_command(char *zLine, ShellState *p){ } pSession->nFilter = 0; sqlite3session_table_filter(pSession->p, session_filter, pSession); - p->nSession++; + pAuxDb->nSession++; pSession->zName = sqlite3_mprintf("%s", zName); }else /* If no command name matches, show a syntax error */ @@ -9752,6 +10004,7 @@ static int do_meta_command(char *zLine, ShellState *p){ ){ char *zCmd; int i, x; + failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]); if( nArg<2 ){ raw_printf(stderr, "Usage: .system COMMAND\n"); rc = 1; @@ -9808,7 +10061,7 @@ static int do_meta_command(char *zLine, ShellState *p){ } raw_printf(p->out, "\n"); utf8_printf(p->out, "%12.12s: %s\n", "filename", - p->zDbFilename ? p->zDbFilename : ""); + p->pAuxDb->zDbFilename ? p->pAuxDb->zDbFilename : ""); }else if( c=='s' && strncmp(azArg[0], "stats", n)==0 ){ @@ -9877,8 +10130,10 @@ static int do_meta_command(char *zLine, ShellState *p){ } } rc = sqlite3_finalize(pStmt); - appendText(&s, " ORDER BY 1", 0); - rc = sqlite3_prepare_v2(p->db, s.z, -1, &pStmt, 0); + if( rc==SQLITE_OK ){ + appendText(&s, " ORDER BY 1", 0); + rc = sqlite3_prepare_v2(p->db, s.z, -1, &pStmt, 0); + } freeText(&s); if( rc ) return shellDatabaseError(p->db); @@ -9953,29 +10208,31 @@ static int do_meta_command(char *zLine, ShellState *p){ static const struct { const char *zCtrlName; /* Name of a test-control option */ int ctrlCode; /* Integer code for that option */ + int unSafe; /* Not valid for --safe mode */ const char *zUsage; /* Usage notes */ } aCtrl[] = { - { "always", SQLITE_TESTCTRL_ALWAYS, "BOOLEAN" }, - { "assert", SQLITE_TESTCTRL_ASSERT, "BOOLEAN" }, - /*{ "benign_malloc_hooks",SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, "" },*/ - /*{ "bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST, "" },*/ - { "byteorder", SQLITE_TESTCTRL_BYTEORDER, "" }, - { "extra_schema_checks",SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS,"BOOLEAN" }, - /*{ "fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, "" },*/ - { "imposter", SQLITE_TESTCTRL_IMPOSTER, "SCHEMA ON/OFF ROOTPAGE"}, - { "internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, "" }, - { "localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,"BOOLEAN" }, - { "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT, "BOOLEAN" }, - { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS, "DISABLE-MASK" }, + { "always", SQLITE_TESTCTRL_ALWAYS, 1, "BOOLEAN" }, + { "assert", SQLITE_TESTCTRL_ASSERT, 1, "BOOLEAN" }, + /*{ "benign_malloc_hooks",SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,1, "" },*/ + /*{ "bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST, 1, "" },*/ + { "byteorder", SQLITE_TESTCTRL_BYTEORDER, 0, "" }, + { "extra_schema_checks",SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS,0,"BOOLEAN" }, + /*{ "fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, 1,"" },*/ + { "imposter", SQLITE_TESTCTRL_IMPOSTER,1,"SCHEMA ON/OFF ROOTPAGE"}, + { "internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS,0,"" }, + { "localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,0,"BOOLEAN" }, + { "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT,1, "BOOLEAN" }, + { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS,0,"DISABLE-MASK" }, #ifdef YYCOVERAGE - { "parser_coverage", SQLITE_TESTCTRL_PARSER_COVERAGE, "" }, -#endif - { "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE, "OFFSET " }, - { "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE, "" }, - { "prng_save", SQLITE_TESTCTRL_PRNG_SAVE, "" }, - { "prng_seed", SQLITE_TESTCTRL_PRNG_SEED, "SEED ?db?" }, - { "seek_count", SQLITE_TESTCTRL_SEEK_COUNT, "" }, - { "tune", SQLITE_TESTCTRL_TUNE, "ID VALUE" }, + { "parser_coverage", SQLITE_TESTCTRL_PARSER_COVERAGE,0,"" }, +#endif + { "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE,0, "OFFSET " }, + { "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE,0, "" }, + { "prng_save", SQLITE_TESTCTRL_PRNG_SAVE, 0, "" }, + { "prng_seed", SQLITE_TESTCTRL_PRNG_SEED, 0, "SEED ?db?" }, + { "seek_count", SQLITE_TESTCTRL_SEEK_COUNT, 0, "" }, + { "sorter_mmap", SQLITE_TESTCTRL_SORTER_MMAP, 0, "NMAX" }, + { "tune", SQLITE_TESTCTRL_TUNE, 1, "ID VALUE" }, }; int testctrl = -1; int iCtrl = -1; @@ -10023,6 +10280,11 @@ static int do_meta_command(char *zLine, ShellState *p){ if( testctrl<0 ){ utf8_printf(stderr,"Error: unknown test-control: %s\n" "Use \".testctrl --help\" for help\n", zCmd); + }else if( aCtrl[iCtrl].unSafe && p->bSafeMode ){ + utf8_printf(stderr, + "line %d: \".testctrl %s\" may not be used in safe mode\n", + p->lineno, aCtrl[iCtrl].zCtrlName); + exit(1); }else{ switch(testctrl){ @@ -10155,6 +10417,13 @@ static int do_meta_command(char *zLine, ShellState *p){ break; } #endif + case SQLITE_TESTCTRL_SORTER_MMAP: + if( nArg==3 ){ + int opt = (unsigned int)integerValue(azArg[2]); + rc2 = sqlite3_test_control(testctrl, p->db, opt); + isOk = 3; + } + break; } } if( isOk==0 && iCtrl>=0 ){ @@ -10396,7 +10665,7 @@ static int do_meta_command(char *zLine, ShellState *p){ int j; assert( nArg<=ArraySize(azArg) ); p->nWidth = nArg-1; - p->colWidth = realloc(p->colWidth, p->nWidth*sizeof(int)*2); + p->colWidth = realloc(p->colWidth, (p->nWidth+1)*sizeof(int)*2); if( p->colWidth==0 && p->nWidth>0 ) shell_out_of_memory(); if( p->nWidth ) p->actualWidth = &p->colWidth[p->nWidth]; for(j=1; joutCount--; if( p->outCount==0 ) output_reset(p); } + p->bSafeMode = p->bSafeModePersist; return rc; } -/* -** Return TRUE if a semicolon occurs anywhere in the first N characters -** of string z[]. +/* Line scan result and intermediate states (supporting scan resumption) */ -static int line_contains_semicolon(const char *z, int N){ - int i; - for(i=0; iout, "changes: %3d total_changes: %d\n", - sqlite3_changes(p->db), sqlite3_total_changes(p->db)); + char zLineBuf[2000]; + sqlite3_snprintf(sizeof(zLineBuf), zLineBuf, + "changes: %lld total_changes: %lld", + sqlite3_changes64(p->db), sqlite3_total_changes64(p->db)); + raw_printf(p->out, "%s\n", zLineBuf); } return 0; } @@ -10545,10 +10874,10 @@ static int process_input(ShellState *p){ int nLine; /* Length of current line */ int nSql = 0; /* Bytes of zSql[] used */ int nAlloc = 0; /* Allocated zSql[] space */ - int nSqlPrior = 0; /* Bytes of zSql[] used by prior line */ int rc; /* Error code */ int errCnt = 0; /* Number of errors seen */ int startline = 0; /* Line number for start of current input */ + QuickScanState qss = QSS_Start; /* Accumulated line status (so far) */ p->lineno = 0; while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){ @@ -10564,8 +10893,17 @@ static int process_input(ShellState *p){ seenInterrupt = 0; } p->lineno++; - if( nSql==0 && _all_whitespace(zLine) ){ - if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine); + if( QSS_INPLAIN(qss) + && line_is_command_terminator(zLine) + && line_is_complete(zSql, nSql) ){ + memcpy(zLine,";",2); + } + qss = quickscan(zLine, qss); + if( QSS_PLAINWHITE(qss) && nSql==0 ){ + if( ShellHasFlag(p, SHFLG_Echo) ) + printf("%s\n", zLine); + /* Just swallow single-line whitespace */ + qss = QSS_Start; continue; } if( zLine && (zLine[0]=='.' || zLine[0]=='#') && nSql==0 ){ @@ -10578,18 +10916,17 @@ static int process_input(ShellState *p){ errCnt++; } } + qss = QSS_Start; continue; } - if( line_is_command_terminator(zLine) && line_is_complete(zSql, nSql) ){ - memcpy(zLine,";",2); - } + /* No single-line dispositions remain; accumulate line(s). */ nLine = strlen30(zLine); if( nSql+nLine+2>=nAlloc ){ - nAlloc = nSql+nLine+100; + /* Grow buffer by half-again increments when big. */ + nAlloc = nSql+(nSql>>1)+nLine+100; zSql = realloc(zSql, nAlloc); if( zSql==0 ) shell_out_of_memory(); } - nSqlPrior = nSql; if( nSql==0 ){ int i; for(i=0; zLine[i] && IsSpace(zLine[i]); i++){} @@ -10602,8 +10939,7 @@ static int process_input(ShellState *p){ memcpy(zSql+nSql, zLine, nLine+1); nSql += nLine; } - if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior) - && sqlite3_complete(zSql) ){ + if( nSql && QSS_SEMITERM(qss) && sqlite3_complete(zSql) ){ errCnt += runOneSqlLine(p, zSql, p->in, startline); nSql = 0; if( p->outCount ){ @@ -10612,12 +10948,15 @@ static int process_input(ShellState *p){ }else{ clearTempFile(p); } - }else if( nSql && _all_whitespace(zSql) ){ + p->bSafeMode = p->bSafeModePersist; + qss = QSS_Start; + }else if( nSql && QSS_PLAINWHITE(qss) ){ if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zSql); nSql = 0; + qss = QSS_Start; } } - if( nSql && !_all_whitespace(zSql) ){ + if( nSql && QSS_PLAINDARK(qss) ){ errCnt += runOneSqlLine(p, zSql, p->in, startline); } free(zSql); @@ -10778,10 +11117,12 @@ static const char zOptions[] = #endif " -newline SEP set output row separator. Default: '\\n'\n" " -nofollow refuse to open symbolic links to database files\n" + " -nonce STRING set the safe-mode escape nonce\n" " -nullvalue TEXT set text string for NULL values. Default ''\n" " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n" " -quote set output mode to 'quote'\n" " -readonly open the database read-only\n" + " -safe enable safe-mode\n" " -separator SEP set output column separator. Default: '|'\n" #ifdef SQLITE_ENABLE_SORTER_REFERENCES " -sorterref SIZE sorter references threshold size\n" @@ -10829,6 +11170,7 @@ static void main_init(ShellState *data) { memset(data, 0, sizeof(*data)); data->normalMode = data->cMode = data->mode = MODE_List; data->autoExplain = 1; + data->pAuxDb = &data->aAuxDb[0]; memcpy(data->colSeparator,SEP_Column, 2); memcpy(data->rowSeparator,SEP_Row, 2); data->showHeader = 0; @@ -10992,7 +11334,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ ** this compile-time option to embed this shell program in larger ** applications. */ extern void SQLITE_SHELL_DBNAME_PROC(const char**); - SQLITE_SHELL_DBNAME_PROC(&data.zDbFilename); + SQLITE_SHELL_DBNAME_PROC(&data.pAuxDb->zDbFilename); warnInmemoryDb = 0; } #endif @@ -11007,8 +11349,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ char *z; z = argv[i]; if( z[0]!='-' ){ - if( data.zDbFilename==0 ){ - data.zDbFilename = z; + if( data.aAuxDb->zDbFilename==0 ){ + data.aAuxDb->zDbFilename = z; }else{ /* Excesss arguments are interpreted as SQL (or dot-commands) and ** mean that nothing is read from stdin */ @@ -11066,6 +11408,14 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ if( n<0 ) n = 0; sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, n); if( sz*n==0 ) data.shellFlgs &= ~SHFLG_Lookaside; + }else if( strcmp(z,"-threadsafe")==0 ){ + int n; + n = (int)integerValue(cmdline_option_value(argc,argv,++i)); + switch( n ){ + case 0: sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); break; + case 2: sqlite3_config(SQLITE_CONFIG_MULTITHREAD); break; + default: sqlite3_config(SQLITE_CONFIG_SERIALIZED); break; + } #ifdef SQLITE_ENABLE_VFSTRACE }else if( strcmp(z,"-vfstrace")==0 ){ extern int vfstrace_register( @@ -11118,6 +11468,11 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ sqlite3MemTraceActivate(stderr); }else if( strcmp(z,"-bail")==0 ){ bail_on_error = 1; + }else if( strcmp(z,"-nonce")==0 ){ + free(data.zNonce); + data.zNonce = strdup(argv[++i]); + }else if( strcmp(z,"-safe")==0 ){ + /* no-op - catch this on the second pass */ } } verify_uninitialized(); @@ -11148,9 +11503,9 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ } } - if( data.zDbFilename==0 ){ + if( data.pAuxDb->zDbFilename==0 ){ #ifndef SQLITE_OMIT_MEMORYDB - data.zDbFilename = ":memory:"; + data.pAuxDb->zDbFilename = ":memory:"; warnInmemoryDb = argc==1; #else utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0); @@ -11165,7 +11520,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ ** files from being created if a user mistypes the database name argument ** to the sqlite command-line tool. */ - if( access(data.zDbFilename, 0)==0 ){ + if( access(data.pAuxDb->zDbFilename, 0)==0 ){ open_db(&data, 0); } @@ -11244,8 +11599,10 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ "%s",cmdline_option_value(argc,argv,++i)); }else if( strcmp(z,"-header")==0 ){ data.showHeader = 1; - }else if( strcmp(z,"-noheader")==0 ){ + ShellSetFlag(&data, SHFLG_HeaderSet); + }else if( strcmp(z,"-noheader")==0 ){ data.showHeader = 0; + ShellSetFlag(&data, SHFLG_HeaderSet); }else if( strcmp(z,"-echo")==0 ){ ShellSetFlag(&data, SHFLG_Echo); }else if( strcmp(z,"-eqp")==0 ){ @@ -11278,6 +11635,10 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ i+=2; }else if( strcmp(z,"-lookaside")==0 ){ i+=2; + }else if( strcmp(z,"-threadsafe")==0 ){ + i+=2; + }else if( strcmp(z,"-nonce")==0 ){ + i += 2; }else if( strcmp(z,"-mmap")==0 ){ i++; }else if( strcmp(z,"-memtrace")==0 ){ @@ -11336,6 +11697,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ readStdin = 0; break; #endif + }else if( strcmp(z,"-safe")==0 ){ + data.bSafeMode = data.bSafeModePersist = 1; }else{ utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z); raw_printf(stderr,"Use -help for a list of options.\n"); @@ -11419,10 +11782,16 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ free(azCmd); set_table_name(&data, 0); if( data.db ){ - session_close_all(&data); + session_close_all(&data, -1); close_db(data.db); } - sqlite3_free(data.zFreeOnClose); + for(i=0; i */ int sqlite3_changes(sqlite3*); +sqlite3_int64 sqlite3_changes64(sqlite3*); /* ** CAPI3REF: Total Number Of Rows Modified ** METHOD: sqlite3 ** -** ^This function returns the total number of rows inserted, modified or +** ^These functions return the total number of rows inserted, modified or ** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed ** since the database connection was opened, including those executed as -** part of trigger programs. ^Executing any other type of SQL statement -** does not affect the value returned by sqlite3_total_changes(). +** part of trigger programs. The two functions are identical except for the +** type of the return value and that if the number of rows modified by the +** connection exceeds the maximum value supported by type "int", then +** the return value of sqlite3_total_changes() is undefined. ^Executing +** any other type of SQL statement does not affect the value returned by +** sqlite3_total_changes(). ** ** ^Changes made as part of [foreign key actions] are included in the ** count, but those made as part of REPLACE constraint resolution are @@ -2554,6 +2600,7 @@ int sqlite3_changes(sqlite3*); ** */ int sqlite3_total_changes(sqlite3*); +sqlite3_int64 sqlite3_total_changes64(sqlite3*); /* ** CAPI3REF: Interrupt A Long-Running Query @@ -3383,6 +3430,14 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** the default shared cache setting provided by ** [sqlite3_enable_shared_cache()].)^ ** +** [[OPEN_EXRESCODE]] ^(
[SQLITE_OPEN_EXRESCODE]
+**
The database connection comes up in "extended result code mode". +** In other words, the database behaves has if +** [sqlite3_extended_result_codes(db,1)] where called on the database +** connection as soon as the connection is created. In addition to setting +** the extended result code mode, this flag also causes [sqlite3_open_v2()] +** to return an extended result code.
+** ** [[OPEN_NOFOLLOW]] ^(
[SQLITE_OPEN_NOFOLLOW]
**
The database filename is not allowed to be a symbolic link
** )^ @@ -3390,7 +3445,15 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** If the 3rd parameter to sqlite3_open_v2() is not one of the ** required combinations shown above optionally combined with other ** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits] -** then the behavior is undefined. +** then the behavior is undefined. Historic versions of SQLite +** have silently ignored surplus bits in the flags parameter to +** sqlite3_open_v2(), however that behavior might not be carried through +** into future versions of SQLite and so applications should not rely +** upon it. Note in particular that the SQLITE_OPEN_EXCLUSIVE flag is a no-op +** for sqlite3_open_v2(). The SQLITE_OPEN_EXCLUSIVE does *not* cause +** the open to fail if the database already exists. The SQLITE_OPEN_EXCLUSIVE +** flag is intended for use by the [sqlite3_vfs|VFS interface] only, and not +** by sqlite3_open_v2(). ** ** ^The fourth parameter to sqlite3_open_v2() is the name of the ** [sqlite3_vfs] object that defines the operating system interface that @@ -4158,12 +4221,17 @@ int sqlite3_prepare16_v3( ** are managed by SQLite and are automatically freed when the prepared ** statement is finalized. ** ^The string returned by sqlite3_expanded_sql(P), on the other hand, -** is obtained from [sqlite3_malloc()] and must be free by the application +** is obtained from [sqlite3_malloc()] and must be freed by the application ** by passing it to [sqlite3_free()]. +** +** ^The sqlite3_normalized_sql() interface is only available if +** the [SQLITE_ENABLE_NORMALIZE] compile-time option is defined. */ const char *sqlite3_sql(sqlite3_stmt *pStmt); char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); +#ifdef SQLITE_ENABLE_NORMALIZE const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt); +#endif /* ** CAPI3REF: Determine If An SQL Statement Writes The Database @@ -6348,6 +6416,72 @@ void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*); void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); /* +** CAPI3REF: Autovacuum Compaction Amount Callback +** METHOD: sqlite3 +** +** ^The sqlite3_autovacuum_pages(D,C,P,X) interface registers a callback +** function C that is invoked prior to each autovacuum of the database +** file. ^The callback is passed a copy of the generic data pointer (P), +** the schema-name of the attached database that is being autovacuumed, +** the the size of the database file in pages, the number of free pages, +** and the number of bytes per page, respectively. The callback should +** return the number of free pages that should be removed by the +** autovacuum. ^If the callback returns zero, then no autovacuum happens. +** ^If the value returned is greater than or equal to the number of +** free pages, then a complete autovacuum happens. +** +**

^If there are multiple ATTACH-ed database files that are being +** modified as part of a transaction commit, then the autovacuum pages +** callback is invoked separately for each file. +** +**

The callback is not reentrant. The callback function should +** not attempt to invoke any other SQLite interface. If it does, bad +** things may happen, including segmentation faults and corrupt database +** files. The callback function should be a simple function that +** does some arithmetic on its input parameters and returns a result. +** +** ^The X parameter to sqlite3_autovacuum_pages(D,C,P,X) is an optional +** destructor for the P parameter. ^If X is not NULL, then X(P) is +** invoked whenever the database connection closes or when the callback +** is overwritten by another invocation of sqlite3_autovacuum_pages(). +** +**

^There is only one autovacuum pages callback per database connection. +** ^Each call to the sqlite3_autovacuum_pages() interface overrides all +** previous invocations for that database connection. ^If the callback +** argument (C) to sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer, +** then the autovacuum steps callback is cancelled. The return value +** from sqlite3_autovacuum_pages() is normally SQLITE_OK, but might +** be some other error code if something goes wrong. The current +** implementation will only return SQLITE_OK or SQLITE_MISUSE, but other +** return codes might be added in future releases. +** +**

If no autovacuum pages callback is specified (the usual case) or +** a NULL pointer is provided for the callback, +** then the default behavior is to vacuum all free pages. So, in other +** words, the default behavior is the same as if the callback function +** were something like this: +** +**

+**     unsigned int demonstration_autovac_pages_callback(
+**       void *pClientData,
+**       const char *zSchema,
+**       unsigned int nDbPage,
+**       unsigned int nFreePage,
+**       unsigned int nBytePerPage
+**     ){
+**       return nFreePage;
+**     }
+** 
+*/ +int sqlite3_autovacuum_pages( + sqlite3 *db, + unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), + void*, + void(*)(void*) +); + + +/* ** CAPI3REF: Data Change Notification Callbacks ** METHOD: sqlite3 ** @@ -9010,8 +9144,9 @@ void sqlite3_log(int iErrCode, const char *zFormat, ...); ** ** A single database handle may have at most a single write-ahead log callback ** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any -** previously registered write-ahead log callback. ^Note that the -** [sqlite3_wal_autocheckpoint()] interface and the +** previously registered write-ahead log callback. ^The return value is +** a copy of the third parameter from the previous call, if any, or 0. +** ^Note that the [sqlite3_wal_autocheckpoint()] interface and the ** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will ** overwrite any prior [sqlite3_wal_hook()] settings. */ @@ -9878,6 +10013,10 @@ unsigned char *sqlite3_serialize( ** database is currently in a read transaction or is involved in a backup ** operation. ** +** It is not possible to deserialized into the TEMP database. If the +** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the +** function returns SQLITE_ERROR. +** ** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the ** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then ** [sqlite3_free()] is invoked on argument P prior to returning. diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h index 217601fd..9767daa0 100644 --- a/src/sqlite3ext.h +++ b/src/sqlite3ext.h @@ -337,6 +337,13 @@ struct sqlite3_api_routines { sqlite3_file *(*database_file_object)(const char*); /* Version 3.34.0 and later */ int (*txn_state)(sqlite3*,const char*); + /* Version 3.36.1 and later */ + sqlite3_int64 (*changes64)(sqlite3*); + sqlite3_int64 (*total_changes64)(sqlite3*); + /* Version 3.37.0 and later */ + int (*autovacuum_pages)(sqlite3*, + unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), + void*, void(*)(void*)); }; /* @@ -643,6 +650,11 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_database_file_object sqlite3_api->database_file_object /* Version 3.34.0 and later */ #define sqlite3_txn_state sqlite3_api->txn_state +/* Version 3.36.1 and later */ +#define sqlite3_changes64 sqlite3_api->changes64 +#define sqlite3_total_changes64 sqlite3_api->total_changes64 +/* Version 3.37.0 and later */ +#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 91af412b..12534c6f 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -181,6 +181,17 @@ # define _USE_32BIT_TIME_T #endif +/* Optionally #include a user-defined header, whereby compilation options +** may be set prior to where they take effect, but after platform setup. +** If SQLITE_CUSTOM_INCLUDE=? is defined, its value names the #include +** file. +*/ +#ifdef SQLITE_CUSTOM_INCLUDE +# define INC_STRINGIFY_(f) #f +# define INC_STRINGIFY(f) INC_STRINGIFY_(f) +# include INC_STRINGIFY(SQLITE_CUSTOM_INCLUDE) +#endif + /* The public SQLite interface. The _FILE_OFFSET_BITS macro must appear ** first in QNX. Also, the _USE_32BIT_TIME_T macro must appear first for ** MinGW. @@ -214,11 +225,12 @@ #ifndef __has_extension # define __has_extension(x) 0 /* compatibility with non-clang compilers */ #endif -#if GCC_VERSION>=4007000 || \ - (__has_extension(c_atomic) && __has_extension(c_atomic_store_n)) +#if GCC_VERSION>=4007000 || __has_extension(c_atomic) +# define SQLITE_ATOMIC_INTRINSICS 1 # define AtomicLoad(PTR) __atomic_load_n((PTR),__ATOMIC_RELAXED) # define AtomicStore(PTR,VAL) __atomic_store_n((PTR),(VAL),__ATOMIC_RELAXED) #else +# define SQLITE_ATOMIC_INTRINSICS 0 # define AtomicLoad(PTR) (*(PTR)) # define AtomicStore(PTR,VAL) (*(PTR) = (VAL)) #endif @@ -423,11 +435,12 @@ ** is significant and used at least once. On switch statements ** where multiple cases go to the same block of code, testcase() ** can insure that all cases are evaluated. -** */ -#ifdef SQLITE_COVERAGE_TEST - void sqlite3Coverage(int); -# define testcase(X) if( X ){ sqlite3Coverage(__LINE__); } +#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) +# ifndef SQLITE_AMALGAMATION + extern unsigned int sqlite3CoverageCounter; +# endif +# define testcase(X) if( X ){ sqlite3CoverageCounter += (unsigned)__LINE__; } #else # define testcase(X) #endif @@ -458,6 +471,14 @@ #endif /* +** Disable ALWAYS() and NEVER() (make them pass-throughs) for coverage +** and mutation testing +*/ +#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) +# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 +#endif + +/* ** The ALWAYS and NEVER macros surround boolean expressions which ** are intended to always be true or false, respectively. Such ** expressions could be omitted from the code completely. But they @@ -472,7 +493,7 @@ ** be true and false so that the unreachable code they specify will ** not be counted as untested code. */ -#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) +#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) # define ALWAYS(X) (1) # define NEVER(X) (0) #elif !defined(NDEBUG) @@ -484,26 +505,6 @@ #endif /* -** The harmless(X) macro indicates that expression X is usually false -** but can be true without causing any problems, but we don't know of -** any way to cause X to be true. -** -** In debugging and testing builds, this macro will abort if X is ever -** true. In this way, developers are alerted to a possible test case -** that causes X to be true. If a harmless macro ever fails, that is -** an opportunity to change the macro into a testcase() and add a new -** test case to the test suite. -** -** For normal production builds, harmless(X) is a no-op, since it does -** not matter whether expression X is true or false. -*/ -#ifdef SQLITE_DEBUG -# define harmless(X) assert(!(X)); -#else -# define harmless(X) -#endif - -/* ** Some conditionals are optimizations only. In other words, if the ** conditionals are replaced with a constant 1 (true) or 0 (false) then ** the correct answer is still obtained, though perhaps not as quickly. @@ -567,6 +568,13 @@ #endif /* +** SQLITE_OMIT_VIRTUALTABLE implies SQLITE_OMIT_ALTERTABLE +*/ +#if defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_ALTERTABLE) +# define SQLITE_OMIT_ALTERTABLE +#endif + +/* ** Return true (non-zero) if the input is an integer that is too large ** to fit in 32-bits. This macro is used inside of various testcase() ** macros to verify that we have tested SQLite for large-file support. @@ -687,7 +695,7 @@ ** number of pages. A negative number N translations means that a buffer ** of -1024*N bytes is allocated and used for as many pages as it will hold. ** -** The default value of "20" was choosen to minimize the run-time of the +** The default value of "20" was chosen to minimize the run-time of the ** speedtest1 test program with options: --shrink-memory --reprepare */ #ifndef SQLITE_DEFAULT_PCACHE_INITSZ @@ -849,6 +857,7 @@ typedef INT16_TYPE LogEst; # define SQLITE_PTRSIZE __SIZEOF_POINTER__ # elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \ defined(_M_ARM) || defined(__arm__) || defined(__x86) || \ + (defined(__APPLE__) && defined(__POWERPC__)) || \ (defined(__TOS_AIX__) && !defined(__64BIT__)) # define SQLITE_PTRSIZE 4 # else @@ -1043,11 +1052,25 @@ struct BusyHandler { /* ** Name of table that holds the database schema. +** +** The PREFERRED names are used whereever possible. But LEGACY is also +** used for backwards compatibility. +** +** 1. Queries can use either the PREFERRED or the LEGACY names +** 2. The sqlite3_set_authorizer() callback uses the LEGACY name +** 3. The PRAGMA table_list statement uses the PREFERRED name +** +** The LEGACY names are stored in the internal symbol hash table +** in support of (2). Names are translated using sqlite3PreferredTableName() +** for (3). The sqlite3FindTable() function takes care of translating +** names for (1). +** +** Note that "sqlite_temp_schema" can also be called "temp.sqlite_schema". */ -#define DFLT_SCHEMA_TABLE "sqlite_master" -#define DFLT_TEMP_SCHEMA_TABLE "sqlite_temp_master" -#define ALT_SCHEMA_TABLE "sqlite_schema" -#define ALT_TEMP_SCHEMA_TABLE "sqlite_temp_schema" +#define LEGACY_SCHEMA_TABLE "sqlite_master" +#define LEGACY_TEMP_SCHEMA_TABLE "sqlite_temp_master" +#define PREFERRED_SCHEMA_TABLE "sqlite_schema" +#define PREFERRED_TEMP_SCHEMA_TABLE "sqlite_temp_schema" /* @@ -1059,7 +1082,7 @@ struct BusyHandler { ** The name of the schema table. The name is different for TEMP. */ #define SCHEMA_TABLE(x) \ - ((!OMIT_TEMPDB)&&(x==1)?DFLT_TEMP_SCHEMA_TABLE:DFLT_SCHEMA_TABLE) + ((!OMIT_TEMPDB)&&(x==1)?LEGACY_TEMP_SCHEMA_TABLE:LEGACY_SCHEMA_TABLE) /* ** A convenience macro that returns the number of elements in @@ -1520,10 +1543,10 @@ struct sqlite3 { u8 mTrace; /* zero or more SQLITE_TRACE flags */ u8 noSharedCache; /* True if no shared-cache backends */ u8 nSqlExec; /* Number of pending OP_SqlExec opcodes */ + u8 eOpenState; /* Current condition of the connection */ int nextPagesize; /* Pagesize after VACUUM if >0 */ - u32 magic; /* Magic number for detect library misuse */ - int nChange; /* Value returned by sqlite3_changes() */ - int nTotalChange; /* Value returned by sqlite3_total_changes() */ + i64 nChange; /* Value returned by sqlite3_changes() */ + i64 nTotalChange; /* Value returned by sqlite3_total_changes() */ int aLimit[SQLITE_N_LIMIT]; /* Limits */ int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */ struct sqlite3InitInfo { /* Information used during initialization */ @@ -1533,7 +1556,7 @@ struct sqlite3 { unsigned orphanTrigger : 1; /* Last statement is orphaned TEMP trigger */ unsigned imposterTable : 1; /* Building an imposter table */ unsigned reopenMemdb : 1; /* ATTACH is really a reopen using MemDB */ - char **azInit; /* "type", "name", and "tbl_name" columns */ + const char **azInit; /* "type", "name", and "tbl_name" columns */ } init; int nVdbeActive; /* Number of VDBEs currently running */ int nVdbeRead; /* Number of active VDBEs that read or write */ @@ -1543,10 +1566,10 @@ struct sqlite3 { int nExtension; /* Number of loaded extensions */ void **aExtension; /* Array of shared library handles */ union { - void (*xLegacy)(void*,const char*); /* Legacy trace function */ - int (*xV2)(u32,void*,void*,void*); /* V2 Trace function */ + void (*xLegacy)(void*,const char*); /* mTrace==SQLITE_TRACE_LEGACY */ + int (*xV2)(u32,void*,void*,void*); /* All other mTrace values */ } trace; - void *pTraceArg; /* Argument to the trace function */ + void *pTraceArg; /* Argument to the trace function */ #ifndef SQLITE_OMIT_DEPRECATED void (*xProfile)(void*,const char*,u64); /* Profiling function */ void *pProfileArg; /* Argument to profile function */ @@ -1557,6 +1580,9 @@ struct sqlite3 { void (*xRollbackCallback)(void*); /* Invoked at every commit. */ void *pUpdateArg; void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64); + void *pAutovacPagesArg; /* Client argument to autovac_pages */ + void (*xAutovacDestr)(void*); /* Destructor for pAutovacPAgesArg */ + unsigned int (*xAutovacPages)(void*,const char*,u32,u32,u32); Parse *pParse; /* Current parse */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK void *pPreUpdateArg; /* First argument to xPreUpdateCallback */ @@ -1686,6 +1712,7 @@ struct sqlite3 { #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 */ /* Flags used only if debugging */ #ifdef SQLITE_DEBUG @@ -1732,6 +1759,8 @@ struct sqlite3 { #define SQLITE_PropagateConst 0x00008000 /* The constant propagation opt */ #define SQLITE_MinMaxOpt 0x00010000 /* The min/max optimization */ #define SQLITE_SeekScan 0x00020000 /* The OP_SeekScan optimization */ +#define SQLITE_OmitOrderBy 0x00040000 /* Omit pointless ORDER BY */ + /* TH3 expects this value ^^^^^^^^^^ to be 0x40000. Coordinate any change */ #define SQLITE_AllOpts 0xffffffff /* All optimizations */ /* @@ -1746,17 +1775,16 @@ struct sqlite3 { */ #define ConstFactorOk(P) ((P)->okConstFactor) -/* -** Possible values for the sqlite.magic field. -** The numbers are obtained at random and have no special meaning, other -** than being distinct from one another. +/* Possible values for the sqlite3.eOpenState field. +** The numbers are randomly selected such that a minimum of three bits must +** change to convert any number to another or to zero */ -#define SQLITE_MAGIC_OPEN 0xa029a697 /* Database is open */ -#define SQLITE_MAGIC_CLOSED 0x9f3c2d33 /* Database is closed */ -#define SQLITE_MAGIC_SICK 0x4b771290 /* Error and awaiting close */ -#define SQLITE_MAGIC_BUSY 0xf03b7906 /* Database currently in use */ -#define SQLITE_MAGIC_ERROR 0xb5357930 /* An SQLITE_MISUSE error occurred */ -#define SQLITE_MAGIC_ZOMBIE 0x64cffc7f /* Close with last statement close */ +#define SQLITE_STATE_OPEN 0x76 /* Database is open */ +#define SQLITE_STATE_CLOSED 0xce /* Database is closed */ +#define SQLITE_STATE_SICK 0xba /* Error and awaiting close */ +#define SQLITE_STATE_BUSY 0x6d /* Database currently in use */ +#define SQLITE_STATE_ERROR 0xd5 /* An SQLITE_MISUSE error occurred */ +#define SQLITE_STATE_ZOMBIE 0xa7 /* Close with last statement close */ /* ** Each SQL function is defined by an instance of the following @@ -1781,7 +1809,7 @@ struct FuncDef { union { FuncDef *pHash; /* Next with a different name but the same hash */ FuncDestructor *pDestructor; /* Reference counted destructor function */ - } u; + } u; /* pHash if SQLITE_FUNC_BUILTIN, pDestructor otherwise */ }; /* @@ -1811,12 +1839,13 @@ struct FuncDestructor { ** are assert() statements in the code to verify this. ** ** Value constraints (enforced via assert()): -** SQLITE_FUNC_MINMAX == NC_MinMaxAgg == SF_MinMaxAgg -** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG -** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG -** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API -** SQLITE_FUNC_DIRECT == SQLITE_DIRECTONLY from the API -** SQLITE_FUNC_UNSAFE == SQLITE_INNOCUOUS +** SQLITE_FUNC_MINMAX == NC_MinMaxAgg == SF_MinMaxAgg +** SQLITE_FUNC_ANYORDER == NC_OrderAgg == SF_OrderByReqd +** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG +** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG +** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API +** SQLITE_FUNC_DIRECT == SQLITE_DIRECTONLY from the API +** SQLITE_FUNC_UNSAFE == SQLITE_INNOCUOUS ** SQLITE_FUNC_ENCMASK depends on SQLITE_UTF* macros in the API */ #define SQLITE_FUNC_ENCMASK 0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */ @@ -1841,6 +1870,8 @@ struct FuncDestructor { #define SQLITE_FUNC_SUBTYPE 0x00100000 /* Result likely to have sub-type */ #define SQLITE_FUNC_UNSAFE 0x00200000 /* Function has side effects */ #define SQLITE_FUNC_INLINE 0x00400000 /* Functions implemented in-line */ +#define SQLITE_FUNC_BUILTIN 0x00800000 /* This is a built-in function */ +#define SQLITE_FUNC_ANYORDER 0x08000000 /* count/min/max aggregate */ /* Identifier numbers for each in-line function */ #define INLINEFUNC_coalesce 0 @@ -1918,44 +1949,51 @@ struct FuncDestructor { ** parameter. */ #define FUNCTION(zName, nArg, iArg, bNC, xFunc) \ - {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ + {nArg, SQLITE_FUNC_BUILTIN|\ + SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \ - {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define SFUNCTION(zName, nArg, iArg, bNC, xFunc) \ - {nArg, SQLITE_UTF8|SQLITE_DIRECTONLY|SQLITE_FUNC_UNSAFE, \ + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_DIRECTONLY|SQLITE_FUNC_UNSAFE, \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define MFUNCTION(zName, nArg, xPtr, xFunc) \ - {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \ + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \ xPtr, 0, xFunc, 0, 0, 0, #zName, {0} } #define INLINE_FUNC(zName, nArg, iArg, mFlags) \ - {nArg, SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \ + {nArg, SQLITE_FUNC_BUILTIN|\ + SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \ SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} } #define TEST_FUNC(zName, nArg, iArg, mFlags) \ - {nArg, SQLITE_UTF8|SQLITE_FUNC_INTERNAL|SQLITE_FUNC_TEST| \ + {nArg, SQLITE_FUNC_BUILTIN|\ + SQLITE_UTF8|SQLITE_FUNC_INTERNAL|SQLITE_FUNC_TEST| \ SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \ SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} } #define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \ - {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8, \ + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_SLOCHNG|SQLITE_UTF8, \ 0, 0, xFunc, 0, 0, 0, #zName, {0} } #define PURE_DATE(zName, nArg, iArg, bNC, xFunc) \ - {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \ + {nArg, SQLITE_FUNC_BUILTIN|\ + SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \ (void*)&sqlite3Config, 0, xFunc, 0, 0, 0, #zName, {0} } #define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \ - {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\ + {nArg, SQLITE_FUNC_BUILTIN|\ + SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \ - {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ + {nArg, SQLITE_FUNC_BUILTIN|\ + SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ pArg, 0, xFunc, 0, 0, 0, #zName, } #define LIKEFUNC(zName, nArg, arg, flags) \ - {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \ + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \ (void *)arg, 0, likeFunc, 0, 0, 0, #zName, {0} } #define WAGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue, xInverse, f) \ - {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|f, \ + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|f, \ SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,xInverse,#zName, {0}} #define INTERNAL_FUNCTION(zName, nArg, xFunc) \ - {nArg, SQLITE_FUNC_INTERNAL|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \ + {nArg, SQLITE_FUNC_BUILTIN|\ + SQLITE_FUNC_INTERNAL|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \ 0, 0, xFunc, 0, 0, 0, #zName, {0} } @@ -2011,18 +2049,42 @@ struct Module { ** or equal to the table column index. It is ** equal if and only if there are no VIRTUAL ** columns to the left. +** +** Notes on zCnName: +** The zCnName field stores the name of the column, the datatype of the +** column, and the collating sequence for the column, in that order, all in +** a single allocation. Each string is 0x00 terminated. The datatype +** is only included if the COLFLAG_HASTYPE bit of colFlags is set and the +** collating sequence name is only included if the COLFLAG_HASCOLL bit is +** set. */ struct Column { - char *zName; /* Name of this column, \000, then the type */ - Expr *pDflt; /* Default value or GENERATED ALWAYS AS value */ - char *zColl; /* Collating sequence. If NULL, use the default */ - u8 notNull; /* An OE_ code for handling a NOT NULL constraint */ - char affinity; /* One of the SQLITE_AFF_... values */ - u8 szEst; /* Estimated size of value in this column. sizeof(INT)==1 */ - u8 hName; /* Column name hash for faster lookup */ - u16 colFlags; /* Boolean properties. See COLFLAG_ defines below */ + char *zCnName; /* Name of this column */ + unsigned notNull :4; /* An OE_ code for handling a NOT NULL constraint */ + unsigned eCType :4; /* One of the standard types */ + char affinity; /* One of the SQLITE_AFF_... values */ + u8 szEst; /* Est size of value in this column. sizeof(INT)==1 */ + u8 hName; /* Column name hash for faster lookup */ + u16 iDflt; /* 1-based index of DEFAULT. 0 means "none" */ + u16 colFlags; /* Boolean properties. See COLFLAG_ defines below */ }; +/* Allowed values for Column.eCType. +** +** Values must match entries in the global constant arrays +** sqlite3StdTypeLen[] and sqlite3StdType[]. Each value is one more +** than the offset into these arrays for the corresponding name. +** Adjust the SQLITE_N_STDTYPE value if adding or removing entries. +*/ +#define COLTYPE_CUSTOM 0 /* Type appended to zName */ +#define COLTYPE_ANY 1 +#define COLTYPE_BLOB 2 +#define COLTYPE_INT 3 +#define COLTYPE_INTEGER 4 +#define COLTYPE_REAL 5 +#define COLTYPE_TEXT 6 +#define SQLITE_N_STDTYPE 6 /* Number of standard types */ + /* Allowed values for Column.colFlags. ** ** Constraints: @@ -2039,6 +2101,7 @@ struct Column { #define COLFLAG_STORED 0x0040 /* GENERATED ALWAYS AS ... STORED */ #define COLFLAG_NOTAVAIL 0x0080 /* STORED column not yet calculated */ #define COLFLAG_BUSY 0x0100 /* Blocks recursion on GENERATED columns */ +#define COLFLAG_HASCOLL 0x0200 /* Has collating sequence name in zCnName */ #define COLFLAG_GENERATED 0x0060 /* Combo: _STORED, _VIRTUAL */ #define COLFLAG_NOINSERT 0x0062 /* Combo: _HIDDEN, _STORED, _VIRTUAL */ @@ -2168,15 +2231,13 @@ struct VTable { #define SQLITE_VTABRISK_High 2 /* -** The schema for each SQL table and view is represented in memory -** by an instance of the following structure. +** The schema for each SQL table, virtual table, and view is represented +** in memory by an instance of the following structure. */ struct Table { char *zName; /* Name of the table or view */ Column *aCol; /* Information about each column */ Index *pIndex; /* List of SQL indexes on this table. */ - Select *pSelect; /* NULL for tables. Points to definition if a view. */ - FKey *pFKey; /* Linked list of all foreign keys in this table */ char *zColAff; /* String defining the affinity of each column */ ExprList *pCheck; /* All CHECK constraints */ /* ... also used as column name list in a VIEW */ @@ -2192,15 +2253,24 @@ struct Table { LogEst costMult; /* Cost multiplier for using this table */ #endif u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ -#ifndef SQLITE_OMIT_ALTERTABLE - int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */ -#endif -#ifndef SQLITE_OMIT_VIRTUALTABLE - int nModuleArg; /* Number of arguments to the module */ - char **azModuleArg; /* 0: module 1: schema 2: vtab name 3...: args */ - VTable *pVTable; /* List of VTable objects. */ -#endif - Trigger *pTrigger; /* List of triggers stored in pSchema */ + u8 eTabType; /* 0: normal, 1: virtual, 2: view */ + union { + struct { /* Used by ordinary tables: */ + int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */ + FKey *pFKey; /* Linked list of all foreign keys in this table */ + ExprList *pDfltList; /* DEFAULT clauses on various columns. + ** Or the AS clause for generated columns. */ + } tab; + struct { /* Used by views: */ + Select *pSelect; /* View definition */ + } view; + struct { /* Used by virtual tables only: */ + int nArg; /* Number of arguments to the module */ + char **azArg; /* 0: module 1: schema 2: vtab name 3...: args */ + VTable *p; /* List of VTable objects. */ + } vtab; + } u; + Trigger *pTrigger; /* List of triggers on this object */ Schema *pSchema; /* Schema that contains this table */ }; @@ -2219,24 +2289,35 @@ struct Table { ** TF_HasStored == COLFLAG_STORED ** TF_HasHidden == COLFLAG_HIDDEN */ -#define TF_Readonly 0x0001 /* Read-only system table */ -#define TF_HasHidden 0x0002 /* Has one or more hidden columns */ -#define TF_HasPrimaryKey 0x0004 /* Table has a primary key */ -#define TF_Autoincrement 0x0008 /* Integer primary key is autoincrement */ -#define TF_HasStat1 0x0010 /* nRowLogEst set from sqlite_stat1 */ -#define TF_HasVirtual 0x0020 /* Has one or more VIRTUAL columns */ -#define TF_HasStored 0x0040 /* Has one or more STORED columns */ -#define TF_HasGenerated 0x0060 /* Combo: HasVirtual + HasStored */ -#define TF_WithoutRowid 0x0080 /* No rowid. PRIMARY KEY is the key */ -#define TF_StatsUsed 0x0100 /* Query planner decisions affected by +#define TF_Readonly 0x00000001 /* Read-only system table */ +#define TF_HasHidden 0x00000002 /* Has one or more hidden columns */ +#define TF_HasPrimaryKey 0x00000004 /* Table has a primary key */ +#define TF_Autoincrement 0x00000008 /* Integer primary key is autoincrement */ +#define TF_HasStat1 0x00000010 /* nRowLogEst set from sqlite_stat1 */ +#define TF_HasVirtual 0x00000020 /* Has one or more VIRTUAL columns */ +#define TF_HasStored 0x00000040 /* Has one or more STORED columns */ +#define TF_HasGenerated 0x00000060 /* Combo: HasVirtual + HasStored */ +#define TF_WithoutRowid 0x00000080 /* No rowid. PRIMARY KEY is the key */ +#define TF_StatsUsed 0x00000100 /* Query planner decisions affected by ** Index.aiRowLogEst[] values */ -#define TF_NoVisibleRowid 0x0200 /* No user-visible "rowid" column */ -#define TF_OOOHidden 0x0400 /* Out-of-Order hidden columns */ -#define TF_HasNotNull 0x0800 /* Contains NOT NULL constraints */ -#define TF_Shadow 0x1000 /* True for a shadow table */ -#define TF_HasStat4 0x2000 /* STAT4 info available for this table */ -#define TF_Ephemeral 0x4000 /* An ephemeral table */ -#define TF_Eponymous 0x8000 /* An eponymous virtual table */ +#define TF_NoVisibleRowid 0x00000200 /* No user-visible "rowid" column */ +#define TF_OOOHidden 0x00000400 /* Out-of-Order hidden columns */ +#define TF_HasNotNull 0x00000800 /* Contains NOT NULL constraints */ +#define TF_Shadow 0x00001000 /* True for a shadow table */ +#define TF_HasStat4 0x00002000 /* STAT4 info available for this table */ +#define TF_Ephemeral 0x00004000 /* An ephemeral table */ +#define TF_Eponymous 0x00008000 /* An eponymous virtual table */ +#define TF_Strict 0x00010000 /* STRICT mode */ + +/* +** Allowed values for Table.eTabType +*/ +#define TABTYP_NORM 0 /* Ordinary table */ +#define TABTYP_VTAB 1 /* Virtual table */ +#define TABTYP_VIEW 2 /* A view */ + +#define IsView(X) ((X)->eTabType==TABTYP_VIEW) +#define IsOrdinaryTable(X) ((X)->eTabType==TABTYP_NORM) /* ** Test to see whether or not a table is a virtual table. This is @@ -2244,9 +2325,9 @@ struct Table { ** table support is omitted from the build. */ #ifndef SQLITE_OMIT_VIRTUALTABLE -# define IsVirtual(X) ((X)->nModuleArg) +# define IsVirtual(X) ((X)->eTabType==TABTYP_VTAB) # define ExprIsVtab(X) \ - ((X)->op==TK_COLUMN && (X)->y.pTab!=0 && (X)->y.pTab->nModuleArg) + ((X)->op==TK_COLUMN && (X)->y.pTab!=0 && (X)->y.pTab->eTabType==TABTYP_VTAB) #else # define IsVirtual(X) 0 # define ExprIsVtab(X) 0 @@ -2635,10 +2716,10 @@ typedef int ynVar; ** tree. ** ** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB, -** or TK_STRING), then Expr.token contains the text of the SQL literal. If -** the expression is a variable (TK_VARIABLE), then Expr.token contains the +** or TK_STRING), then Expr.u.zToken contains the text of the SQL literal. If +** the expression is a variable (TK_VARIABLE), then Expr.u.zToken contains the ** variable name. Finally, if the expression is an SQL function (TK_FUNCTION), -** then Expr.token contains the name of the function. +** then Expr.u.zToken contains the name of the function. ** ** Expr.pRight and Expr.pLeft are the left and right subexpressions of a ** binary operator. Either or both may be NULL. @@ -2678,7 +2759,7 @@ typedef int ynVar; ** help reduce memory requirements, sometimes an Expr object will be ** truncated. And to reduce the number of memory allocations, sometimes ** two or more Expr objects will be stored in a single memory allocation, -** together with Expr.zToken strings. +** together with Expr.u.zToken strings. ** ** If the EP_Reduced and EP_TokenOnly flags are set when ** an Expr object is truncated. When EP_Reduced is set, then all @@ -2747,8 +2828,7 @@ struct Expr { } y; }; -/* -** The following are the meanings of bits in the Expr.flags field. +/* The following are the meanings of bits in the Expr.flags field. ** Value restrictions: ** ** EP_Agg == NC_HasAgg == SF_HasAgg @@ -2787,14 +2867,12 @@ struct Expr { #define EP_FromDDL 0x40000000 /* Originates from sqlite_schema */ /* 0x80000000 // Available */ -/* -** The EP_Propagate mask is a set of properties that automatically propagate +/* The EP_Propagate mask is a set of properties that automatically propagate ** upwards into parent nodes. */ #define EP_Propagate (EP_Collate|EP_Subquery|EP_HasFunc) -/* -** These macros can be used to test, set, or clear bits in the +/* Macros can be used to test, set, or clear bits in the ** Expr.flags field. */ #define ExprHasProperty(E,P) (((E)->flags&(P))!=0) @@ -2804,6 +2882,16 @@ struct Expr { #define ExprAlwaysTrue(E) (((E)->flags&(EP_FromJoin|EP_IsTrue))==EP_IsTrue) #define ExprAlwaysFalse(E) (((E)->flags&(EP_FromJoin|EP_IsFalse))==EP_IsFalse) +/* Macros used to ensure that the correct members of unions are accessed +** in Expr. +*/ +#define ExprUseUToken(E) (((E)->flags&EP_IntValue)==0) +#define ExprUseUValue(E) (((E)->flags&EP_IntValue)!=0) +#define ExprUseXList(E) (((E)->flags&EP_xIsSelect)==0) +#define ExprUseXSelect(E) (((E)->flags&EP_xIsSelect)!=0) +#define ExprUseYTab(E) (((E)->flags&(EP_WinFunc|EP_Subrtn))==0) +#define ExprUseYWin(E) (((E)->flags&EP_WinFunc)!=0) +#define ExprUseYSub(E) (((E)->flags&EP_Subrtn)!=0) /* Flags for use with Expr.vvaFlags */ @@ -2886,11 +2974,12 @@ struct ExprList { unsigned bSorterRef :1; /* Defer evaluation until after sorting */ unsigned bNulls: 1; /* True if explicit "NULLS FIRST/LAST" */ union { - struct { + struct { /* Used by any ExprList other than Parse.pConsExpr */ u16 iOrderByCol; /* For ORDER BY, column number in result set */ u16 iAlias; /* Index into Parse.aAlias[] for zName */ } x; - int iConstExprReg; /* Register in which Expr value is cached */ + int iConstExprReg; /* Register in which Expr value is cached. Used only + ** by Parse.pConstExpr */ } u; } a[1]; /* One slot for each expression in the list */ }; @@ -2928,6 +3017,13 @@ struct IdList { /* ** The SrcItem object represents a single term in the FROM clause of a query. ** The SrcList object is mostly an array of SrcItems. +** +** Union member validity: +** +** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc +** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy +** u2.pIBIndex fg.isIndexedBy && !fg.isCte +** u2.pCteUse fg.isCte && !fg.isIndexedBy */ struct SrcItem { Schema *pSchema; /* Schema to which this item is fixed */ @@ -3076,31 +3172,33 @@ struct NameContext { ** Allowed values for the NameContext, ncFlags field. ** ** Value constraints (all checked via assert()): -** NC_HasAgg == SF_HasAgg == EP_Agg -** NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX +** NC_HasAgg == SF_HasAgg == EP_Agg +** NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX +** NC_OrderAgg == SF_OrderByReqd == SQLITE_FUNC_ANYORDER ** NC_HasWin == EP_Win ** */ -#define NC_AllowAgg 0x00001 /* Aggregate functions are allowed here */ -#define NC_PartIdx 0x00002 /* True if resolving a partial index WHERE */ -#define NC_IsCheck 0x00004 /* True if resolving a CHECK constraint */ -#define NC_GenCol 0x00008 /* True for a GENERATED ALWAYS AS clause */ -#define NC_HasAgg 0x00010 /* One or more aggregate functions seen */ -#define NC_IdxExpr 0x00020 /* True if resolving columns of CREATE INDEX */ -#define NC_SelfRef 0x0002e /* Combo: PartIdx, isCheck, GenCol, and IdxExpr */ -#define NC_VarSelect 0x00040 /* A correlated subquery has been seen */ -#define NC_UEList 0x00080 /* True if uNC.pEList is used */ -#define NC_UAggInfo 0x00100 /* True if uNC.pAggInfo is used */ -#define NC_UUpsert 0x00200 /* True if uNC.pUpsert is used */ -#define NC_UBaseReg 0x00400 /* True if uNC.iBaseReg is used */ -#define NC_MinMaxAgg 0x01000 /* min/max aggregates seen. See note above */ -#define NC_Complex 0x02000 /* True if a function or subquery seen */ -#define NC_AllowWin 0x04000 /* Window functions are allowed here */ -#define NC_HasWin 0x08000 /* One or more window functions seen */ -#define NC_IsDDL 0x10000 /* Resolving names in a CREATE statement */ -#define NC_InAggFunc 0x20000 /* True if analyzing arguments to an agg func */ -#define NC_FromDDL 0x40000 /* SQL text comes from sqlite_schema */ -#define NC_NoSelect 0x80000 /* Do not descend into sub-selects */ +#define NC_AllowAgg 0x000001 /* Aggregate functions are allowed here */ +#define NC_PartIdx 0x000002 /* True if resolving a partial index WHERE */ +#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_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 */ +#define NC_Complex 0x002000 /* True if a function or subquery seen */ +#define NC_AllowWin 0x004000 /* Window functions are allowed here */ +#define NC_HasWin 0x008000 /* One or more window functions seen */ +#define NC_IsDDL 0x010000 /* Resolving names in a CREATE statement */ +#define NC_InAggFunc 0x020000 /* True if analyzing arguments to an agg func */ +#define NC_FromDDL 0x040000 /* SQL text comes from sqlite_schema */ +#define NC_NoSelect 0x080000 /* Do not descend into sub-selects */ +#define NC_OrderAgg 0x8000000 /* Has an aggregate other than count/min/max */ /* ** An instance of the following object describes a single ON CONFLICT @@ -3183,9 +3281,10 @@ struct Select { ** "Select Flag". ** ** Value constraints (all checked via assert()) -** SF_HasAgg == NC_HasAgg -** SF_MinMaxAgg == NC_MinMaxAgg == SQLITE_FUNC_MINMAX -** SF_FixedLimit == WHERE_USE_LIMIT +** SF_HasAgg == NC_HasAgg +** SF_MinMaxAgg == NC_MinMaxAgg == SQLITE_FUNC_MINMAX +** SF_OrderByReqd == NC_OrderAgg == SQLITE_FUNC_ANYORDER +** SF_FixedLimit == WHERE_USE_LIMIT */ #define SF_Distinct 0x0000001 /* Output should be DISTINCT */ #define SF_All 0x0000002 /* Includes the ALL keyword */ @@ -3210,10 +3309,11 @@ struct Select { #define SF_WinRewrite 0x0100000 /* Window function rewrite accomplished */ #define SF_View 0x0200000 /* SELECT statement is a view */ #define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */ -#define SF_UpdateFrom 0x0800000 /* Statement is an UPDATE...FROM */ +#define SF_UFSrcCheck 0x0800000 /* Check pSrc as required by UPDATE...FROM */ #define SF_PushDown 0x1000000 /* SELECT has be modified by push-down opt */ #define SF_MultiPart 0x2000000 /* Has multiple incompatible PARTITIONs */ #define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */ +#define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */ /* ** The results of a SELECT can be distributed in several ways, as defined @@ -3455,7 +3555,8 @@ struct Parse { AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */ Parse *pToplevel; /* Parse structure for main program (or NULL) */ Table *pTriggerTab; /* Table triggers are being coded for */ - Parse *pParentParse; /* Parent parser if this parser is nested */ + TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ + ParseCleanup *pCleanup; /* List of cleanup operations to run after parse */ union { int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */ Returning *pReturning; /* The RETURNING clause */ @@ -3510,14 +3611,14 @@ struct Parse { Token sArg; /* Complete text of a module argument */ Table **apVtabLock; /* Pointer to virtual tables needing locking */ #endif - TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ With *pWith; /* Current WITH clause, or NULL */ - ParseCleanup *pCleanup; /* List of cleanup operations to run after parse */ #ifndef SQLITE_OMIT_ALTERTABLE RenameToken *pRename; /* Tokens subject to renaming by ALTER TABLE */ #endif }; +/* Allowed values for Parse.eParseMode +*/ #define PARSE_MODE_NORMAL 0 #define PARSE_MODE_DECLARE_VTAB 1 #define PARSE_MODE_RENAME 2 @@ -3739,8 +3840,10 @@ typedef struct { /* ** Allowed values for mInitFlags */ +#define INITFLAG_AlterMask 0x0003 /* Types of ALTER */ #define INITFLAG_AlterRename 0x0001 /* Reparse after a RENAME */ #define INITFLAG_AlterDrop 0x0002 /* Reparse after a DROP COLUMN */ +#define INITFLAG_AlterAdd 0x0003 /* Reparse after an ADD COLUMN */ /* Tuning parameters are set using SQLITE_TESTCTRL_TUNE and are controlled ** on debug-builds of the CLI using ".testctrl tune ID VALUE". Tuning @@ -3861,8 +3964,8 @@ struct Walker { int n; /* A counter */ int iCur; /* A cursor number */ SrcList *pSrcList; /* FROM clause */ - struct SrcCount *pSrcCount; /* Counting column references */ struct CCurHint *pCCurHint; /* Used by codeCursorHint() */ + struct RefSrcList *pRefSrcList; /* sqlite3ReferencesSrcList() */ int *aiCol; /* array of column indexes */ struct IdxCover *pIdxCover; /* Check for index coverage */ struct IdxExprTrans *pIdxTrans; /* Convert idxed expr to column */ @@ -4047,7 +4150,7 @@ void sqlite3WindowListDelete(sqlite3 *db, Window *p); Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8); void sqlite3WindowAttach(Parse*, Expr*, Window*); void sqlite3WindowLink(Select *pSel, Window *pWin); -int sqlite3WindowCompare(Parse*, Window*, Window*, int); +int sqlite3WindowCompare(const Parse*, const Window*, const Window*, int); void sqlite3WindowCodeInit(Parse*, Select*); void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int); int sqlite3WindowRewrite(Parse*, Select*); @@ -4179,8 +4282,8 @@ void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64); void *sqlite3DbRealloc(sqlite3 *, void *, u64); void sqlite3DbFree(sqlite3*, void*); void sqlite3DbFreeNN(sqlite3*, void*); -int sqlite3MallocSize(void*); -int sqlite3DbMallocSize(sqlite3*, void*); +int sqlite3MallocSize(const void*); +int sqlite3DbMallocSize(sqlite3*, const void*); void *sqlite3PageMalloc(int); void sqlite3PageFree(void*); void sqlite3MemSetDefault(void); @@ -4296,6 +4399,7 @@ void sqlite3ErrorMsg(Parse*, const char*, ...); int sqlite3ErrorToParser(sqlite3*,int); void sqlite3Dequote(char*); void sqlite3DequoteExpr(Expr*); +void sqlite3DequoteToken(Token*); void sqlite3TokenInit(Token*,char*); int sqlite3KeywordCode(const unsigned char*, int); int sqlite3RunParser(Parse*, const char*, char **); @@ -4315,16 +4419,17 @@ Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*); void sqlite3PExprAddSelect(Parse*, Expr*, Select*); Expr *sqlite3ExprAnd(Parse*,Expr*, Expr*); Expr *sqlite3ExprSimplifiedAndOr(Expr*); -Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*, int); -void sqlite3ExprFunctionUsable(Parse*,Expr*,FuncDef*); +Expr *sqlite3ExprFunction(Parse*,ExprList*, const Token*, int); +void sqlite3ExprFunctionUsable(Parse*,const Expr*,const FuncDef*); void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32); void sqlite3ExprDelete(sqlite3*, Expr*); void sqlite3ExprDeferredDelete(Parse*, Expr*); void sqlite3ExprUnmapAndDelete(Parse*, Expr*); ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*); +Select *sqlite3ExprListToValues(Parse*, int, ExprList*); void sqlite3ExprListSetSortOrder(ExprList*,int,int); -void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int); +void sqlite3ExprListSetName(Parse*,ExprList*,const Token*,int); void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*); void sqlite3ExprListDelete(sqlite3*, ExprList*); u32 sqlite3ExprListFlags(const ExprList*); @@ -4340,6 +4445,10 @@ void sqlite3ResetAllSchemasOfConnection(sqlite3*); void sqlite3ResetOneSchema(sqlite3*,int); void sqlite3CollapseDatabaseArray(sqlite3*); void sqlite3CommitInternalChanges(sqlite3*); +void sqlite3ColumnSetExpr(Parse*,Table*,Column*,Expr*); +Expr *sqlite3ColumnExpr(Table*,Column*); +void sqlite3ColumnSetColl(sqlite3*,Column*,const char*zColl); +const char *sqlite3ColumnColl(Column*); void sqlite3DeleteColumnNames(sqlite3*,Table*); void sqlite3GenerateColumnNames(Parse *pParse, Select *pSelect); int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**); @@ -4361,14 +4470,14 @@ void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int); #else # define sqlite3ColumnPropertiesFromName(T,C) /* no-op */ #endif -void sqlite3AddColumn(Parse*,Token*,Token*); +void sqlite3AddColumn(Parse*,Token,Token); void sqlite3AddNotNull(Parse*, int); void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int); void sqlite3AddCheckConstraint(Parse*, Expr*, const char*, const char*); void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*); void sqlite3AddCollateType(Parse*, Token*); void sqlite3AddGenerated(Parse*,Expr*,Token*); -void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*); +void sqlite3EndTable(Parse*,Token*,Token*,u32,Select*); void sqlite3AddReturning(Parse*,ExprList*); int sqlite3ParseUri(const char*,const char*,unsigned int*, sqlite3_vfs**,char**,char **); @@ -4478,7 +4587,7 @@ void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); void sqlite3ExprCodeMove(Parse*, int, int, int); void sqlite3ExprCode(Parse*, Expr*, int); #ifndef SQLITE_OMIT_GENERATED_COLUMNS -void sqlite3ExprCodeGeneratedColumn(Parse*, Column*, int); +void sqlite3ExprCodeGeneratedColumn(Parse*, Table*, Column*, int); #endif void sqlite3ExprCodeCopy(Parse*, Expr*, int); void sqlite3ExprCodeFactorable(Parse*, Expr*, int); @@ -4497,23 +4606,24 @@ Table *sqlite3FindTable(sqlite3*,const char*, const char*); #define LOCATE_VIEW 0x01 #define LOCATE_NOERR 0x02 Table *sqlite3LocateTable(Parse*,u32 flags,const char*, const char*); +const char *sqlite3PreferredTableName(const char*); Table *sqlite3LocateTableItem(Parse*,u32 flags,SrcItem *); Index *sqlite3FindIndex(sqlite3*,const char*, const char*); void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*); void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*); void sqlite3Vacuum(Parse*,Token*,Expr*); int sqlite3RunVacuum(char**, sqlite3*, int, sqlite3_value*); -char *sqlite3NameFromToken(sqlite3*, Token*); -int sqlite3ExprCompare(Parse*,Expr*, Expr*, int); -int sqlite3ExprCompareSkip(Expr*, Expr*, int); -int sqlite3ExprListCompare(ExprList*, ExprList*, int); -int sqlite3ExprImpliesExpr(Parse*,Expr*, Expr*, int); +char *sqlite3NameFromToken(sqlite3*, const Token*); +int sqlite3ExprCompare(const Parse*,const Expr*,const Expr*, int); +int sqlite3ExprCompareSkip(Expr*,Expr*,int); +int sqlite3ExprListCompare(const ExprList*,const ExprList*, int); +int sqlite3ExprImpliesExpr(const Parse*,const Expr*,const Expr*, int); int sqlite3ExprImpliesNonNullRow(Expr*,int); void sqlite3AggInfoPersistWalkerInit(Walker*,Parse*); void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx); -int sqlite3FunctionUsesThisSrc(Expr*, SrcList*); +int sqlite3ReferencesSrcList(Parse*, Expr*, SrcList*); Vdbe *sqlite3GetVdbe(Parse*); #ifndef SQLITE_UNTESTABLE void sqlite3PrngSaveState(void); @@ -4538,7 +4648,7 @@ int sqlite3ExprIsTableConstant(Expr*,int); #ifdef SQLITE_ENABLE_CURSOR_HINTS int sqlite3ExprContainsSubquery(Expr*); #endif -int sqlite3ExprIsInteger(Expr*, int*); +int sqlite3ExprIsInteger(const Expr*, int*); int sqlite3ExprCanBeNull(const Expr*); int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); int sqlite3IsRowid(const char*); @@ -4563,11 +4673,11 @@ void sqlite3MayAbort(Parse*); void sqlite3HaltConstraint(Parse*, int, int, char*, i8, u8); void sqlite3UniqueConstraint(Parse*, int, Index*); void sqlite3RowidConstraint(Parse*, int, Table*); -Expr *sqlite3ExprDup(sqlite3*,Expr*,int); -ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int); -SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int); -IdList *sqlite3IdListDup(sqlite3*,IdList*); -Select *sqlite3SelectDup(sqlite3*,Select*,int); +Expr *sqlite3ExprDup(sqlite3*,const Expr*,int); +ExprList *sqlite3ExprListDup(sqlite3*,const ExprList*,int); +SrcList *sqlite3SrcListDup(sqlite3*,const SrcList*,int); +IdList *sqlite3IdListDup(sqlite3*,const IdList*); +Select *sqlite3SelectDup(sqlite3*,const Select*,int); FuncDef *sqlite3FunctionSearch(int,const char*); void sqlite3InsertBuiltinFuncs(FuncDef*,int); FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8); @@ -4705,7 +4815,7 @@ const char *sqlite3IndexAffinityStr(sqlite3*, Index*); void sqlite3TableAffinity(Vdbe*, Table*, int); char sqlite3CompareAffinity(const Expr *pExpr, char aff2); int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity); -char sqlite3TableColumnAffinity(Table*,int); +char sqlite3TableColumnAffinity(const Table*,int); char sqlite3ExprAffinity(const Expr *pExpr); int sqlite3Atoi64(const char*, i64*, int, u8); int sqlite3DecOrHexToI64(const char*, i64*); @@ -4734,14 +4844,14 @@ void sqlite3SetTextEncoding(sqlite3 *db, u8); CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr); CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, const Expr *pExpr); int sqlite3ExprCollSeqMatch(Parse*,const Expr*,const Expr*); -Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int); -Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); +Expr *sqlite3ExprAddCollateToken(const Parse *pParse, Expr*, const Token*, int); +Expr *sqlite3ExprAddCollateString(const Parse*,Expr*,const char*); Expr *sqlite3ExprSkipCollate(Expr*); Expr *sqlite3ExprSkipCollateAndLikely(Expr*); int sqlite3CheckCollSeq(Parse *, CollSeq *); int sqlite3WritableSchema(sqlite3*); int sqlite3CheckObjectName(Parse*, const char*,const char*,const char*); -void sqlite3VdbeSetChanges(sqlite3 *, int); +void sqlite3VdbeSetChanges(sqlite3 *, i64); int sqlite3AddInt64(i64*,i64); int sqlite3SubInt64(i64*,i64); int sqlite3MulInt64(i64*,i64); @@ -4766,11 +4876,15 @@ sqlite3_value *sqlite3ValueNew(sqlite3 *); #ifndef SQLITE_OMIT_UTF16 char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8); #endif -int sqlite3ValueFromExpr(sqlite3 *, Expr *, u8, u8, sqlite3_value **); +int sqlite3ValueFromExpr(sqlite3 *, const Expr *, u8, u8, sqlite3_value **); void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8); #ifndef SQLITE_AMALGAMATION extern const unsigned char sqlite3OpcodeProperty[]; extern const char sqlite3StrBINARY[]; +extern const unsigned char sqlite3StdTypeLen[]; +extern const char sqlite3StdTypeAffinity[]; +extern const char sqlite3StdTypeMap[]; +extern const char *sqlite3StdType[]; extern const unsigned char sqlite3UpperToLower[]; extern const unsigned char *sqlite3aLTb; extern const unsigned char *sqlite3aEQb; @@ -4814,9 +4928,9 @@ int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*); void sqlite3ColumnDefault(Vdbe *, Table *, int, int); void sqlite3AlterFinishAddColumn(Parse *, Token *); void sqlite3AlterBeginAddColumn(Parse *, SrcList *); -void sqlite3AlterDropColumn(Parse*, SrcList*, Token*); -void *sqlite3RenameTokenMap(Parse*, void*, Token*); -void sqlite3RenameTokenRemap(Parse*, void *pTo, void *pFrom); +void sqlite3AlterDropColumn(Parse*, SrcList*, const Token*); +const void *sqlite3RenameTokenMap(Parse*, const void*, const Token*); +void sqlite3RenameTokenRemap(Parse*, const void *pTo, const void *pFrom); void sqlite3RenameExprUnmap(Parse*, Expr*); void sqlite3RenameExprlistUnmap(Parse*, ExprList*); CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*); @@ -4860,6 +4974,8 @@ int sqlite3OpenTempDatabase(Parse *); void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int); char *sqlite3StrAccumFinish(StrAccum*); +void sqlite3StrAccumSetError(StrAccum*, u8); +void sqlite3ResultStrAccum(sqlite3_context*,StrAccum*); void sqlite3SelectDestInit(SelectDest*,int,int); Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int); @@ -4912,7 +5028,7 @@ void sqlite3AutoLoadExtensions(sqlite3*); #endif #ifdef SQLITE_OMIT_VIRTUALTABLE -# define sqlite3VtabClear(Y) +# define sqlite3VtabClear(D,T) # define sqlite3VtabSync(X,Y) SQLITE_OK # define sqlite3VtabRollback(X) # define sqlite3VtabCommit(X) @@ -4949,9 +5065,11 @@ int sqlite3ReadOnlyShadowTables(sqlite3 *db); #ifndef SQLITE_OMIT_VIRTUALTABLE int sqlite3ShadowTableName(sqlite3 *db, const char *zName); int sqlite3IsShadowTableOf(sqlite3*,Table*,const char*); + void sqlite3MarkAllShadowTablesOf(sqlite3*, Table*); #else # define sqlite3ShadowTableName(A,B) 0 # define sqlite3IsShadowTableOf(A,B,C) 0 +# define sqlite3MarkAllShadowTablesOf(A,B) #endif int sqlite3VtabEponymousTableInit(Parse*,Module*); void sqlite3VtabEponymousTableClear(sqlite3*,Module*); @@ -4994,7 +5112,7 @@ const char *sqlite3JournalModename(int); # define sqlite3CteDelete(D,C) # define sqlite3CteWithAdd(P,W,C) ((void*)0) # define sqlite3WithDelete(x,y) -# define sqlite3WithPush(x,y,z) +# define sqlite3WithPush(x,y,z) ((void*)0) #endif #ifndef SQLITE_OMIT_UPSERT Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*,Upsert*); @@ -5027,6 +5145,7 @@ const char *sqlite3JournalModename(int); int sqlite3FkRequired(Parse*, Table*, int*, int); u32 sqlite3FkOldmask(Parse*, Table*); FKey *sqlite3FkReferences(Table *); + void sqlite3FkClearTriggerCache(sqlite3*,int); #else #define sqlite3FkActions(a,b,c,d,e,f) #define sqlite3FkCheck(a,b,c,d,e,f) @@ -5034,6 +5153,7 @@ const char *sqlite3JournalModename(int); #define sqlite3FkOldmask(a,b) 0 #define sqlite3FkRequired(a,b,c,d) 0 #define sqlite3FkReferences(a) 0 + #define sqlite3FkClearTriggerCache(a,b) #endif #ifndef SQLITE_OMIT_FOREIGN_KEY void sqlite3FkDelete(sqlite3 *, Table*); @@ -5091,7 +5211,7 @@ void sqlite3MemJournalOpen(sqlite3_file *); void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p); #if SQLITE_MAX_EXPR_DEPTH>0 - int sqlite3SelectExprHeight(Select *); + int sqlite3SelectExprHeight(const Select *); int sqlite3ExprCheckHeight(Parse*, int); #else #define sqlite3SelectExprHeight(x) 0 @@ -5162,8 +5282,8 @@ SQLITE_API SQLITE_EXTERN void (SQLITE_CDECL *sqlite3IoTrace)(const char*,...); */ #ifdef SQLITE_MEMDEBUG void sqlite3MemdebugSetType(void*,u8); - int sqlite3MemdebugHasType(void*,u8); - int sqlite3MemdebugNoType(void*,u8); + int sqlite3MemdebugHasType(const void*,u8); + int sqlite3MemdebugNoType(const void*,u8); #else # define sqlite3MemdebugSetType(X,Y) /* no-op */ # define sqlite3MemdebugHasType(X,Y) 1 @@ -5188,10 +5308,10 @@ int sqlite3DbpageRegister(sqlite3*); int sqlite3DbstatRegister(sqlite3*); #endif -int sqlite3ExprVectorSize(Expr *pExpr); -int sqlite3ExprIsVector(Expr *pExpr); +int sqlite3ExprVectorSize(const Expr *pExpr); +int sqlite3ExprIsVector(const Expr *pExpr); Expr *sqlite3VectorFieldSubexpr(Expr*, int); -Expr *sqlite3ExprForVectorField(Parse*,Expr*,int); +Expr *sqlite3ExprForVectorField(Parse*,Expr*,int,int); void sqlite3VectorErrorMsg(Parse*, Expr*); #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 2206bca3..d379f8d5 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -181,6 +181,7 @@ struct SqliteDb { int nVMStep; /* Another statistic for most recent operation */ int nTransaction; /* Number of nested [transaction] methods */ int openFlags; /* Flags used to open. (SQLITE_OPEN_URI) */ + int nRef; /* Delete object when this reaches 0 */ #ifdef SQLITE_TEST int bLegacyPrepare; /* True to use sqlite3_prepare() */ #endif @@ -518,63 +519,83 @@ static void flushStmtCache(SqliteDb *pDb){ } /* +** Increment the reference counter on the SqliteDb object. The reference +** should be released by calling delDatabaseRef(). +*/ +static void addDatabaseRef(SqliteDb *pDb){ + pDb->nRef++; +} + +/* +** Decrement the reference counter associated with the SqliteDb object. +** If it reaches zero, delete the object. +*/ +static void delDatabaseRef(SqliteDb *pDb){ + assert( pDb->nRef>0 ); + pDb->nRef--; + if( pDb->nRef==0 ){ + flushStmtCache(pDb); + closeIncrblobChannels(pDb); + sqlite3_close(pDb->db); + while( pDb->pFunc ){ + SqlFunc *pFunc = pDb->pFunc; + pDb->pFunc = pFunc->pNext; + assert( pFunc->pDb==pDb ); + Tcl_DecrRefCount(pFunc->pScript); + Tcl_Free((char*)pFunc); + } + while( pDb->pCollate ){ + SqlCollate *pCollate = pDb->pCollate; + pDb->pCollate = pCollate->pNext; + Tcl_Free((char*)pCollate); + } + if( pDb->zBusy ){ + Tcl_Free(pDb->zBusy); + } + if( pDb->zTrace ){ + Tcl_Free(pDb->zTrace); + } + if( pDb->zTraceV2 ){ + Tcl_Free(pDb->zTraceV2); + } + if( pDb->zProfile ){ + Tcl_Free(pDb->zProfile); + } + if( pDb->zBindFallback ){ + Tcl_Free(pDb->zBindFallback); + } + if( pDb->zAuth ){ + Tcl_Free(pDb->zAuth); + } + if( pDb->zNull ){ + Tcl_Free(pDb->zNull); + } + if( pDb->pUpdateHook ){ + Tcl_DecrRefCount(pDb->pUpdateHook); + } + if( pDb->pPreUpdateHook ){ + Tcl_DecrRefCount(pDb->pPreUpdateHook); + } + if( pDb->pRollbackHook ){ + Tcl_DecrRefCount(pDb->pRollbackHook); + } + if( pDb->pWalHook ){ + Tcl_DecrRefCount(pDb->pWalHook); + } + if( pDb->pCollateNeeded ){ + Tcl_DecrRefCount(pDb->pCollateNeeded); + } + Tcl_Free((char*)pDb); + } +} + +/* ** TCL calls this procedure when an sqlite3 database command is ** deleted. */ static void SQLITE_TCLAPI DbDeleteCmd(void *db){ SqliteDb *pDb = (SqliteDb*)db; - flushStmtCache(pDb); - closeIncrblobChannels(pDb); - sqlite3_close(pDb->db); - while( pDb->pFunc ){ - SqlFunc *pFunc = pDb->pFunc; - pDb->pFunc = pFunc->pNext; - assert( pFunc->pDb==pDb ); - Tcl_DecrRefCount(pFunc->pScript); - Tcl_Free((char*)pFunc); - } - while( pDb->pCollate ){ - SqlCollate *pCollate = pDb->pCollate; - pDb->pCollate = pCollate->pNext; - Tcl_Free((char*)pCollate); - } - if( pDb->zBusy ){ - Tcl_Free(pDb->zBusy); - } - if( pDb->zTrace ){ - Tcl_Free(pDb->zTrace); - } - if( pDb->zTraceV2 ){ - Tcl_Free(pDb->zTraceV2); - } - if( pDb->zProfile ){ - Tcl_Free(pDb->zProfile); - } - if( pDb->zBindFallback ){ - Tcl_Free(pDb->zBindFallback); - } - if( pDb->zAuth ){ - Tcl_Free(pDb->zAuth); - } - if( pDb->zNull ){ - Tcl_Free(pDb->zNull); - } - if( pDb->pUpdateHook ){ - Tcl_DecrRefCount(pDb->pUpdateHook); - } - if( pDb->pPreUpdateHook ){ - Tcl_DecrRefCount(pDb->pPreUpdateHook); - } - if( pDb->pRollbackHook ){ - Tcl_DecrRefCount(pDb->pRollbackHook); - } - if( pDb->pWalHook ){ - Tcl_DecrRefCount(pDb->pWalHook); - } - if( pDb->pCollateNeeded ){ - Tcl_DecrRefCount(pDb->pCollateNeeded); - } - Tcl_Free((char*)pDb); + delDatabaseRef(pDb); } /* @@ -1246,6 +1267,7 @@ static int SQLITE_TCLAPI DbTransPostCmd( } pDb->disableAuth--; + delDatabaseRef(pDb); return rc; } @@ -1579,6 +1601,7 @@ static void dbEvalInit( Tcl_IncrRefCount(pArray); } p->evalFlags = evalFlags; + addDatabaseRef(p->pDb); } /* @@ -1719,6 +1742,7 @@ static void dbEvalFinalize(DbEvalContext *p){ } Tcl_DecrRefCount(p->pSql); dbReleaseColumnNames(p); + delDatabaseRef(p->pDb); } /* @@ -2207,7 +2231,7 @@ static int SQLITE_TCLAPI DbObjCmd( return TCL_ERROR; } pResult = Tcl_GetObjResult(interp); - Tcl_SetIntObj(pResult, sqlite3_changes(pDb->db)); + Tcl_SetWideIntObj(pResult, sqlite3_changes64(pDb->db)); break; } @@ -2623,8 +2647,10 @@ static int SQLITE_TCLAPI DbObjCmd( for(i=2; idb)); + Tcl_SetWideIntObj(pResult, sqlite3_total_changes64(pDb->db)); break; } @@ -3435,6 +3461,7 @@ deserialize_error: ** opened above. If not using NRE, evaluate the script directly, then ** call function DbTransPostCmd() to commit (or rollback) the transaction ** or savepoint. */ + addDatabaseRef(pDb); /* DbTransPostCmd() calls delDatabaseRef() */ if( DbUseNre() ){ Tcl_NRAddCallback(interp, DbTransPostCmd, cd, 0, 0, 0); (void)Tcl_NREvalObj(interp, pScript, 0); @@ -3842,6 +3869,7 @@ static int SQLITE_TCLAPI DbMain( }else{ Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd); } + p->nRef = 1; return TCL_OK; } @@ -3949,7 +3977,9 @@ static const char *tclsh_main_loop(void){ return zMainloop; } -#define TCLSH_MAIN main /* Needed to fake out mktclapp */ +#ifndef TCLSH_MAIN +# define TCLSH_MAIN main +#endif int SQLITE_CDECL TCLSH_MAIN(int argc, char **argv){ Tcl_Interp *interp; int i; diff --git a/src/test1.c b/src/test1.c index 7cb56d3b..6060290b 100644 --- a/src/test1.c +++ b/src/test1.c @@ -4850,6 +4850,7 @@ static int SQLITE_TCLAPI test_open_v2( { "SQLITE_OPEN_PRIVATECACHE", SQLITE_OPEN_PRIVATECACHE }, { "SQLITE_OPEN_WAL", SQLITE_OPEN_WAL }, { "SQLITE_OPEN_URI", SQLITE_OPEN_URI }, + { "SQLITE_OPEN_EXRESCODE", SQLITE_OPEN_EXRESCODE }, { 0, 0 } }; rc = Tcl_GetIndexFromObjStruct(interp, apFlag[i], aFlag, sizeof(aFlag[0]), @@ -5348,37 +5349,6 @@ static int SQLITE_TCLAPI test_stmt_int( return TCL_OK; } -/* -** Usage: sqlite_set_magic DB MAGIC-NUMBER -** -** Set the db->magic value. This is used to test error recovery logic. -*/ -static int SQLITE_TCLAPI sqlite_set_magic( - void * clientData, - Tcl_Interp *interp, - int argc, - char **argv -){ - sqlite3 *db; - if( argc!=3 ){ - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " DB MAGIC", 0); - return TCL_ERROR; - } - if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; - if( strcmp(argv[2], "SQLITE_MAGIC_OPEN")==0 ){ - db->magic = SQLITE_MAGIC_OPEN; - }else if( strcmp(argv[2], "SQLITE_MAGIC_CLOSED")==0 ){ - db->magic = SQLITE_MAGIC_CLOSED; - }else if( strcmp(argv[2], "SQLITE_MAGIC_BUSY")==0 ){ - db->magic = SQLITE_MAGIC_BUSY; - }else if( strcmp(argv[2], "SQLITE_MAGIC_ERROR")==0 ){ - db->magic = SQLITE_MAGIC_ERROR; - }else if( Tcl_GetInt(interp, argv[2], (int*)&db->magic) ){ - return TCL_ERROR; - } - return TCL_OK; -} /* ** Usage: sqlite3_interrupt DB @@ -8264,6 +8234,96 @@ static int SQLITE_TCLAPI test_decode_hexdb( return TCL_OK; } +/* +** Client data for the autovacuum_pages callback. +*/ +struct AutovacPageData { + Tcl_Interp *interp; + char *zScript; +}; +typedef struct AutovacPageData AutovacPageData; + +/* +** Callback functions for sqlite3_autovacuum_pages +*/ +static unsigned int test_autovacuum_pages_callback( + void *pClientData, + const char *zSchema, + unsigned int nFilePages, + unsigned int nFreePages, + unsigned int nBytePerPage +){ + AutovacPageData *pData = (AutovacPageData*)pClientData; + Tcl_DString str; + unsigned int x; + char zBuf[100]; + Tcl_DStringInit(&str); + Tcl_DStringAppend(&str, pData->zScript, -1); + Tcl_DStringAppendElement(&str, zSchema); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%u", nFilePages); + Tcl_DStringAppendElement(&str, zBuf); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%u", nFreePages); + Tcl_DStringAppendElement(&str, zBuf); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%u", nBytePerPage); + Tcl_DStringAppendElement(&str, zBuf); + Tcl_ResetResult(pData->interp); + Tcl_Eval(pData->interp, Tcl_DStringValue(&str)); + Tcl_DStringFree(&str); + x = nFreePages; + (void)Tcl_GetIntFromObj(0, Tcl_GetObjResult(pData->interp), (int*)&x); + return x; +} + +/* +** Usage: sqlite3_autovacuum_pages DB SCRIPT +** +** Add an autovacuum-pages callback to database connection DB. The callback +** will invoke SCRIPT, after appending parameters. +** +** If SCRIPT is an empty string or is omitted, then the callback is +** cancelled. +*/ +static int SQLITE_TCLAPI test_autovacuum_pages( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + AutovacPageData *pData; + sqlite3 *db; + int rc; + const char *zScript; + if( objc!=2 && objc!=3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB ?SCRIPT?"); + return TCL_ERROR; + } + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; + zScript = objc==3 ? Tcl_GetString(objv[2]) : 0; + if( zScript ){ + size_t nScript = strlen(zScript); + pData = sqlite3_malloc64( sizeof(*pData) + nScript + 1 ); + if( pData==0 ){ + Tcl_AppendResult(interp, "out of memory", (void*)0); + return TCL_ERROR; + } + pData->interp = interp; + pData->zScript = (char*)&pData[1]; + memcpy(pData->zScript, zScript, nScript+1); + rc = sqlite3_autovacuum_pages(db,test_autovacuum_pages_callback, + pData, sqlite3_free); + }else{ + rc = sqlite3_autovacuum_pages(db, 0, 0, 0); + } + if( rc ){ + char zBuf[1000]; + sqlite3_snprintf(sizeof(zBuf), zBuf, + "sqlite3_autovacuum_pages() returns %d", rc); + Tcl_AppendResult(interp, zBuf, (void*)0); + return TCL_ERROR; + } + return TCL_OK; +} + /* ** Register commands with the TCL interpreter. @@ -8319,7 +8379,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "breakpoint", (Tcl_CmdProc*)test_breakpoint }, { "sqlite3_key", (Tcl_CmdProc*)test_key }, { "sqlite3_rekey", (Tcl_CmdProc*)test_rekey }, - { "sqlite_set_magic", (Tcl_CmdProc*)sqlite_set_magic }, { "sqlite3_interrupt", (Tcl_CmdProc*)test_interrupt }, { "sqlite_delete_function", (Tcl_CmdProc*)delete_function }, { "sqlite_delete_collation", (Tcl_CmdProc*)delete_collation }, @@ -8556,6 +8615,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "atomic_batch_write", test_atomic_batch_write, 0 }, { "sqlite3_mmap_warm", test_mmap_warm, 0 }, { "sqlite3_config_sorterref", test_config_sorterref, 0 }, + { "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 }, diff --git a/src/test_config.c b/src/test_config.c index 86e4df38..acf98e36 100644 --- a/src/test_config.c +++ b/src/test_config.c @@ -589,7 +589,7 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "sqlite_options", "schema_version", "1", TCL_GLOBAL_ONLY); #endif -#ifdef SQLITE_ENABLE_SESSION +#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK) Tcl_SetVar2(interp, "sqlite_options", "session", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "session", "0", TCL_GLOBAL_ONLY); diff --git a/src/test_multiplex.c b/src/test_multiplex.c index 5ef1ec18..ff128171 100644 --- a/src/test_multiplex.c +++ b/src/test_multiplex.c @@ -962,26 +962,79 @@ static int multiplexFileControl(sqlite3_file *pConn, int op, void *pArg){ ** element is the argument to the pragma or NULL if the pragma has no ** argument. */ - if( aFcntl[1] && sqlite3_stricmp(aFcntl[1],"multiplex_truncate")==0 ){ - if( aFcntl[2] && aFcntl[2][0] ){ - if( sqlite3_stricmp(aFcntl[2], "on")==0 - || sqlite3_stricmp(aFcntl[2], "1")==0 ){ - pGroup->bTruncate = 1; - }else - if( sqlite3_stricmp(aFcntl[2], "off")==0 - || sqlite3_stricmp(aFcntl[2], "0")==0 ){ - pGroup->bTruncate = 0; + if( aFcntl[1] && sqlite3_strnicmp(aFcntl[1],"multiplex_",10)==0 ){ + sqlite3_int64 sz = 0; + (void)multiplexFileSize(pConn, &sz); + /* + ** PRAGMA multiplex_truncate=BOOLEAN; + ** PRAGMA multiplex_truncate; + ** + ** Turn the multiplexor truncate feature on or off. Return either + ** "on" or "off" to indicate the new setting. If the BOOLEAN argument + ** is omitted, just return the current value for the truncate setting. + */ + if( sqlite3_stricmp(aFcntl[1],"multiplex_truncate")==0 ){ + if( aFcntl[2] && aFcntl[2][0] ){ + if( sqlite3_stricmp(aFcntl[2], "on")==0 + || sqlite3_stricmp(aFcntl[2], "1")==0 ){ + pGroup->bTruncate = 1; + }else + if( sqlite3_stricmp(aFcntl[2], "off")==0 + || sqlite3_stricmp(aFcntl[2], "0")==0 ){ + pGroup->bTruncate = 0; + } } + /* EVIDENCE-OF: R-27806-26076 The handler for an SQLITE_FCNTL_PRAGMA + ** file control can optionally make the first element of the char** + ** argument point to a string obtained from sqlite3_mprintf() or the + ** equivalent and that string will become the result of the pragma + ** or the error message if the pragma fails. + */ + aFcntl[0] = sqlite3_mprintf(pGroup->bTruncate ? "on" : "off"); + rc = SQLITE_OK; + break; } - /* EVIDENCE-OF: R-27806-26076 The handler for an SQLITE_FCNTL_PRAGMA - ** file control can optionally make the first element of the char** - ** argument point to a string obtained from sqlite3_mprintf() or the - ** equivalent and that string will become the result of the pragma - ** or the error message if the pragma fails. + /* + ** PRAGMA multiplex_enabled; + ** + ** Return 0 or 1 depending on whether the multiplexor is enabled or + ** disabled, respectively. */ - aFcntl[0] = sqlite3_mprintf(pGroup->bTruncate ? "on" : "off"); - rc = SQLITE_OK; - break; + if( sqlite3_stricmp(aFcntl[1],"multiplex_enabled")==0 ){ + aFcntl[0] = sqlite3_mprintf("%d", pGroup->bEnabled!=0); + rc = SQLITE_OK; + break; + } + /* + ** PRAGMA multiplex_chunksize; + ** + ** Return the chunksize for the multiplexor, or no-op if the + ** multiplexor is not active. + */ + if( sqlite3_stricmp(aFcntl[1],"multiplex_chunksize")==0 + && pGroup->bEnabled + ){ + aFcntl[0] = sqlite3_mprintf("%u", pGroup->szChunk); + rc = SQLITE_OK; + break; + } + /* + ** PRAGMA multiplex_filecount; + ** + ** Return the number of disk files currently in use by the + ** multiplexor. This should be the total database size size + ** divided by the chunksize and rounded up. + */ + if( sqlite3_stricmp(aFcntl[1],"multiplex_filecount")==0 ){ + int n = 0; + int ii; + for(ii=0; iinReal; ii++){ + if( pGroup->aReal[ii].p!=0 ) n++; + } + aFcntl[0] = sqlite3_mprintf("%d", n); + rc = SQLITE_OK; + break; + } } /* If the multiplexor does not handle the pragma, pass it through ** into the default case. */ diff --git a/src/test_tclsh.c b/src/test_tclsh.c index 9988214b..707c1681 100644 --- a/src/test_tclsh.c +++ b/src/test_tclsh.c @@ -87,6 +87,7 @@ const char *sqlite3TestInit(Tcl_Interp *interp){ extern int Sqlitetestintarray_Init(Tcl_Interp*); extern int Sqlitetestvfs_Init(Tcl_Interp *); extern int Sqlitetestrtree_Init(Tcl_Interp*); + extern int Sqlitetestrtreedoc_Init(Tcl_Interp*); extern int Sqlitequota_Init(Tcl_Interp*); extern int Sqlitemultiplex_Init(Tcl_Interp*); extern int SqliteSuperlock_Init(Tcl_Interp*); @@ -156,6 +157,7 @@ const char *sqlite3TestInit(Tcl_Interp *interp){ Sqlitetestintarray_Init(interp); Sqlitetestvfs_Init(interp); Sqlitetestrtree_Init(interp); + Sqlitetestrtreedoc_Init(interp); Sqlitequota_Init(interp); Sqlitemultiplex_Init(interp); SqliteSuperlock_Init(interp); diff --git a/src/tokenize.c b/src/tokenize.c index 5d250e6f..e128d161 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -573,6 +573,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ int lastTokenParsed = -1; /* type of the previous token */ sqlite3 *db = pParse->db; /* The database connection */ int mxSqlLen; /* Max length of an SQL string */ + Parse *pParentParse = 0; /* Outer parse context, if any */ #ifdef sqlite3Parser_ENGINEALWAYSONSTACK yyParser sEngine; /* Space to hold the Lemon-generated Parser object */ #endif @@ -608,7 +609,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ assert( pParse->pNewTrigger==0 ); assert( pParse->nVar==0 ); assert( pParse->pVList==0 ); - pParse->pParentParse = db->pParse; + pParentParse = db->pParse; db->pParse = pParse; while( 1 ){ n = sqlite3GetToken((u8*)zSql, &tokenType); @@ -723,8 +724,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ sqlite3DeleteTrigger(db, pParse->pNewTrigger); } sqlite3DbFree(db, pParse->pVList); - db->pParse = pParse->pParentParse; - pParse->pParentParse = 0; + db->pParse = pParentParse; assert( nErr==0 || pParse->rc!=SQLITE_OK ); return nErr; } diff --git a/src/treeview.c b/src/treeview.c index c737a1b9..1b19ea67 100644 --- a/src/treeview.c +++ b/src/treeview.c @@ -142,6 +142,8 @@ void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){ } if( pItem->fg.jointype & JT_LEFT ){ sqlite3_str_appendf(&x, " LEFT-JOIN"); + }else if( pItem->fg.jointype & JT_CROSS ){ + sqlite3_str_appendf(&x, " CROSS-JOIN"); } if( pItem->fg.fromDDL ){ sqlite3_str_appendf(&x, " DDL"); @@ -440,6 +442,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ sqlite3TreeViewLine(pView, "COLUMN(%d)%s%s", pExpr->iColumn, zFlgs, zOp2); }else{ + assert( ExprUseYTab(pExpr) ); sqlite3TreeViewLine(pView, "{%d:%d} pTab=%p%s", pExpr->iTable, pExpr->iColumn, pExpr->y.pTab, zFlgs); @@ -459,11 +462,13 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ } #ifndef SQLITE_OMIT_FLOATING_POINT case TK_FLOAT: { + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); break; } #endif case TK_STRING: { + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken); break; } @@ -472,17 +477,19 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ break; } case TK_TRUEFALSE: { - sqlite3TreeViewLine(pView, - sqlite3ExprTruthValue(pExpr) ? "TRUE" : "FALSE"); + sqlite3TreeViewLine(pView,"%s%s", + sqlite3ExprTruthValue(pExpr) ? "TRUE" : "FALSE", zFlgs); break; } #ifndef SQLITE_OMIT_BLOB_LITERAL case TK_BLOB: { + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); break; } #endif case TK_VARIABLE: { + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"VARIABLE(%s,%d)", pExpr->u.zToken, pExpr->iColumn); break; @@ -492,12 +499,14 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ break; } case TK_ID: { + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken); break; } #ifndef SQLITE_OMIT_CAST case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"CAST %Q", pExpr->u.zToken); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; @@ -547,6 +556,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ } case TK_SPAN: { + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView, "SPAN %Q", pExpr->u.zToken); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; @@ -558,6 +568,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ ** up in the treeview output as "SOFT-COLLATE". Explicit COLLATE ** operators that appear in the original SQL always have the ** EP_Collate bit set and appear in treeview output as just "COLLATE" */ + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView, "%sCOLLATE %Q%s", !ExprHasProperty(pExpr, EP_Collate) ? "SOFT-" : "", pExpr->u.zToken, zFlgs); @@ -573,6 +584,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ pFarg = 0; pWin = 0; }else{ + assert( ExprUseXList(pExpr) ); pFarg = pExpr->x.pList; #ifndef SQLITE_OMIT_WINDOWFUNC pWin = ExprHasProperty(pExpr, EP_WinFunc) ? pExpr->y.pWin : 0; @@ -580,6 +592,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ pWin = 0; #endif } + assert( !ExprHasProperty(pExpr, EP_IntValue) ); if( pExpr->op==TK_AGG_FUNCTION ){ sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s agg=%d[%d]/%p", pExpr->op2, pExpr->u.zToken, zFlgs, @@ -611,11 +624,13 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: { + assert( ExprUseXSelect(pExpr) ); sqlite3TreeViewLine(pView, "EXISTS-expr flags=0x%x", pExpr->flags); sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); break; } case TK_SELECT: { + assert( ExprUseXSelect(pExpr) ); sqlite3TreeViewLine(pView, "subquery-expr flags=0x%x", pExpr->flags); sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); break; @@ -623,7 +638,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ case TK_IN: { sqlite3TreeViewLine(pView, "IN flags=0x%x", pExpr->flags); sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( ExprUseXSelect(pExpr) ){ sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); }else{ sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); @@ -644,9 +659,12 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ ** Z is stored in pExpr->pList->a[1].pExpr. */ case TK_BETWEEN: { - Expr *pX = pExpr->pLeft; - Expr *pY = pExpr->x.pList->a[0].pExpr; - Expr *pZ = pExpr->x.pList->a[1].pExpr; + const Expr *pX, *pY, *pZ; + pX = pExpr->pLeft; + assert( ExprUseXList(pExpr) ); + assert( pExpr->x.pList->nExpr==2 ); + pY = pExpr->x.pList->a[0].pExpr; + pZ = pExpr->x.pList->a[1].pExpr; sqlite3TreeViewLine(pView, "BETWEEN"); sqlite3TreeViewExpr(pView, pX, 1); sqlite3TreeViewExpr(pView, pY, 1); @@ -668,6 +686,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ case TK_CASE: { sqlite3TreeViewLine(pView, "CASE"); sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); + assert( ExprUseXList(pExpr) ); sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); break; } @@ -680,6 +699,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ case OE_Fail: zType = "fail"; break; case OE_Ignore: zType = "ignore"; break; } + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken); break; } @@ -692,12 +712,16 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ } case TK_VECTOR: { char *z = sqlite3_mprintf("VECTOR%s",zFlgs); + assert( ExprUseXList(pExpr) ); sqlite3TreeViewBareExprList(pView, pExpr->x.pList, z); sqlite3_free(z); break; } case TK_SELECT_COLUMN: { - sqlite3TreeViewLine(pView, "SELECT-COLUMN %d", pExpr->iColumn); + sqlite3TreeViewLine(pView, "SELECT-COLUMN %d of [0..%d]%s", + pExpr->iColumn, pExpr->iTable-1, + pExpr->pRight==pExpr->pLeft ? " (SELECT-owner)" : ""); + assert( ExprUseXSelect(pExpr->pLeft) ); sqlite3TreeViewSelect(pView, pExpr->pLeft->x.pSelect, 0); break; } @@ -714,6 +738,15 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ sqlite3TreeViewExpr(pView, &tmp, 0); break; } + case TK_ROW: { + if( pExpr->iColumn<=0 ){ + sqlite3TreeViewLine(pView, "First FROM table rowid"); + }else{ + sqlite3TreeViewLine(pView, "First FROM table column %d", + pExpr->iColumn-1); + } + break; + } default: { sqlite3TreeViewLine(pView, "op=%d", pExpr->op); break; diff --git a/src/trigger.c b/src/trigger.c index 90e6ef4a..7e3a053a 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -219,12 +219,12 @@ void sqlite3BeginTrigger( /* INSTEAD of triggers are only for views and views only support INSTEAD ** of triggers. */ - if( pTab->pSelect && tr_tm!=TK_INSTEAD ){ + if( IsView(pTab) && tr_tm!=TK_INSTEAD ){ sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S", (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName->a); goto trigger_orphan_error; } - if( !pTab->pSelect && tr_tm==TK_INSTEAD ){ + if( !IsView(pTab) && tr_tm==TK_INSTEAD ){ sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF" " trigger on table: %S", pTableName->a); goto trigger_orphan_error; @@ -361,7 +361,7 @@ void sqlite3FinishTrigger( z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n); testcase( z==0 ); sqlite3NestedParse(pParse, - "INSERT INTO %Q." DFLT_SCHEMA_TABLE + "INSERT INTO %Q." LEGACY_SCHEMA_TABLE " VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", db->aDb[iDb].zDbSName, zName, pTrig->table, z); @@ -675,7 +675,7 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){ */ if( (v = sqlite3GetVdbe(pParse))!=0 ){ sqlite3NestedParse(pParse, - "DELETE FROM %Q." DFLT_SCHEMA_TABLE " WHERE name=%Q AND type='trigger'", + "DELETE FROM %Q." LEGACY_SCHEMA_TABLE " WHERE name=%Q AND type='trigger'", db->aDb[iDb].zDbSName, pTrigger->zName ); sqlite3ChangeCookie(pParse, iDb); @@ -877,11 +877,11 @@ static ExprList *sqlite3ExpandReturning( for(jj=0; jjnCol; jj++){ Expr *pNewExpr; if( IsHiddenColumn(pTab->aCol+jj) ) continue; - pNewExpr = sqlite3Expr(db, TK_ID, pTab->aCol[jj].zName); + pNewExpr = sqlite3Expr(db, TK_ID, pTab->aCol[jj].zCnName); pNew = sqlite3ExprListAppend(pParse, pNew, pNewExpr); if( !db->mallocFailed ){ struct ExprList_item *pItem = &pNew->a[pNew->nExpr-1]; - pItem->zEName = sqlite3DbStrDup(db, pTab->aCol[jj].zName); + pItem->zEName = sqlite3DbStrDup(db, pTab->aCol[jj].zCnName); pItem->eEName = ENAME_NAME; } } @@ -926,13 +926,14 @@ static void codeReturningTrigger( sSelect.pSrc = &sFrom; sFrom.nSrc = 1; sFrom.a[0].pTab = pTab; + sFrom.a[0].iCursor = -1; sqlite3SelectPrep(pParse, &sSelect, 0); if( db->mallocFailed==0 && pParse->nErr==0 ){ sqlite3GenerateColumnNames(pParse, &sSelect); } sqlite3ExprListDelete(db, sSelect.pEList); pNew = sqlite3ExpandReturning(pParse, pReturning->pReturnEL, pTab); - if( pNew ){ + if( !db->mallocFailed ){ NameContext sNC; memset(&sNC, 0, sizeof(sNC)); if( pReturning->nRetCol==0 ){ @@ -944,7 +945,9 @@ static void codeReturningTrigger( sNC.ncFlags = NC_UBaseReg; pParse->eTriggerOp = pTrigger->op; pParse->pTriggerTab = pTab; - if( sqlite3ResolveExprListNames(&sNC, pNew)==SQLITE_OK ){ + if( sqlite3ResolveExprListNames(&sNC, pNew)==SQLITE_OK + && !db->mallocFailed + ){ int i; int nCol = pNew->nExpr; int reg = pParse->nMem+1; @@ -952,16 +955,17 @@ static void codeReturningTrigger( pReturning->iRetReg = reg; for(i=0; ia[i].pExpr; + assert( pCol!=0 ); /* Due to !db->mallocFailed ~9 lines above */ sqlite3ExprCodeFactorable(pParse, pCol, reg+i); } sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, i, reg+i); sqlite3VdbeAddOp2(v, OP_NewRowid, pReturning->iRetCur, reg+i+1); sqlite3VdbeAddOp3(v, OP_Insert, pReturning->iRetCur, reg+i, reg+i+1); } - sqlite3ExprListDelete(db, pNew); - pParse->eTriggerOp = 0; - pParse->pTriggerTab = 0; } + sqlite3ExprListDelete(db, pNew); + pParse->eTriggerOp = 0; + pParse->pTriggerTab = 0; } diff --git a/src/update.c b/src/update.c index 13223272..484bee47 100644 --- a/src/update.c +++ b/src/update.c @@ -60,13 +60,14 @@ static void updateVirtualTable( */ void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){ assert( pTab!=0 ); - if( !pTab->pSelect ){ + if( !IsView(pTab) ){ sqlite3_value *pValue = 0; u8 enc = ENC(sqlite3VdbeDb(v)); Column *pCol = &pTab->aCol[i]; - VdbeComment((v, "%s.%s", pTab->zName, pCol->zName)); + VdbeComment((v, "%s.%s", pTab->zName, pCol->zCnName)); assert( inCol ); - sqlite3ValueFromExpr(sqlite3VdbeDb(v), pCol->pDflt, enc, + sqlite3ValueFromExpr(sqlite3VdbeDb(v), + sqlite3ColumnExpr(pTab,pCol), enc, pCol->affinity, &pValue); if( pValue ){ sqlite3VdbeAppendP4(v, pValue, P4_MEM); @@ -236,7 +237,7 @@ static void updateFromSelect( pList = sqlite3ExprListAppend(pParse, pList, pNew); } eDest = IsVirtual(pTab) ? SRT_Table : SRT_Upfrom; - }else if( pTab->pSelect ){ + }else if( IsView(pTab) ){ for(i=0; inCol; i++){ pList = sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i)); } @@ -259,8 +260,9 @@ static void updateFromSelect( } } pSelect = sqlite3SelectNew(pParse, pList, - pSrc, pWhere2, pGrp, 0, pOrderBy2, SF_UpdateFrom|SF_IncludeHidden, pLimit2 + pSrc, pWhere2, pGrp, 0, pOrderBy2, SF_UFSrcCheck|SF_IncludeHidden, pLimit2 ); + if( pSelect ) pSelect->selFlags |= SF_OrderByReqd; sqlite3SelectDestInit(&dest, eDest, iEph); dest.iSDParm2 = (pPk ? pPk->nKeyCol : -1); sqlite3Select(pParse, pSelect, &dest); @@ -360,7 +362,7 @@ void sqlite3Update( */ #ifndef SQLITE_OMIT_TRIGGER pTrigger = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges, &tmask); - isView = pTab->pSelect!=0; + isView = IsView(pTab); assert( pTrigger || tmask==0 ); #else # define pTrigger 0 @@ -449,13 +451,16 @@ void sqlite3Update( */ chngRowid = chngPk = 0; for(i=0; inExpr; i++){ + u8 hCol = sqlite3StrIHash(pChanges->a[i].zEName); /* If this is an UPDATE with a FROM clause, do not resolve expressions ** here. The call to sqlite3Select() below will do that. */ if( nChangeFrom==0 && sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){ goto update_cleanup; } for(j=0; jnCol; j++){ - if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zEName)==0 ){ + if( pTab->aCol[j].hName==hCol + && sqlite3StrICmp(pTab->aCol[j].zCnName, pChanges->a[i].zEName)==0 + ){ if( j==pTab->iPKey ){ chngRowid = 1; pRowidExpr = pChanges->a[i].pExpr; @@ -469,7 +474,7 @@ void sqlite3Update( testcase( pTab->aCol[j].colFlags & COLFLAG_STORED ); sqlite3ErrorMsg(pParse, "cannot UPDATE generated column \"%s\"", - pTab->aCol[j].zName); + pTab->aCol[j].zCnName); goto update_cleanup; } #endif @@ -493,7 +498,7 @@ void sqlite3Update( { int rc; rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName, - j<0 ? "ROWID" : pTab->aCol[j].zName, + j<0 ? "ROWID" : pTab->aCol[j].zCnName, db->aDb[iDb].zDbSName); if( rc==SQLITE_DENY ){ goto update_cleanup; @@ -525,8 +530,10 @@ void sqlite3Update( for(i=0; inCol; i++){ if( aXRef[i]>=0 ) continue; if( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 ) continue; - if( sqlite3ExprReferencesUpdatedColumn(pTab->aCol[i].pDflt, - aXRef, chngRowid) ){ + if( sqlite3ExprReferencesUpdatedColumn( + sqlite3ColumnExpr(pTab, &pTab->aCol[i]), + aXRef, chngRowid) + ){ aXRef[i] = 99999; bProgress = 1; } diff --git a/src/upsert.c b/src/upsert.c index 982dc7db..fb6c7c0c 100644 --- a/src/upsert.c +++ b/src/upsert.c @@ -287,7 +287,7 @@ void sqlite3UpsertDoUpdate( k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]); sqlite3VdbeAddOp3(v, OP_Column, iCur, k, iPk+i); VdbeComment((v, "%s.%s", pIdx->zName, - pTab->aCol[pPk->aiColumn[i]].zName)); + pTab->aCol[pPk->aiColumn[i]].zCnName)); } sqlite3VdbeVerifyAbortable(v, OE_Abort); i = sqlite3VdbeAddOp4Int(v, OP_Found, iDataCur, 0, iPk, nPk); diff --git a/src/util.c b/src/util.c index fc0c2042..8452aea6 100644 --- a/src/util.c +++ b/src/util.c @@ -22,16 +22,6 @@ #endif /* -** Routine needed to support the testcase() macro. -*/ -#ifdef SQLITE_COVERAGE_TEST -void sqlite3Coverage(int x){ - static unsigned dummy = 0; - dummy += (unsigned)x; -} -#endif - -/* ** Calls to sqlite3FaultSim() are used to simulate a failure during testing, ** or to bypass normal error detection during testing in order to let ** execute proceed futher downstream. @@ -60,11 +50,21 @@ int sqlite3FaultSim(int iTest){ #ifndef SQLITE_OMIT_FLOATING_POINT /* ** Return true if the floating point value is Not a Number (NaN). +** +** Use the math library isnan() function if compiled with SQLITE_HAVE_ISNAN. +** Otherwise, we have our own implementation that works on most systems. */ int sqlite3IsNaN(double x){ + int rc; /* The value return */ +#if !SQLITE_HAVE_ISNAN && !HAVE_ISNAN u64 y; memcpy(&y,&x,sizeof(y)); - return IsNaN(y); + rc = IsNaN(y); +#else + rc = isnan(x); +#endif /* HAVE_ISNAN */ + testcase( rc ); + return rc; } #endif /* SQLITE_OMIT_FLOATING_POINT */ @@ -89,8 +89,14 @@ int sqlite3Strlen30(const char *z){ ** the column name if and only if the COLFLAG_HASTYPE flag is set. */ char *sqlite3ColumnType(Column *pCol, char *zDflt){ - if( (pCol->colFlags & COLFLAG_HASTYPE)==0 ) return zDflt; - return pCol->zName + strlen(pCol->zName) + 1; + if( pCol->colFlags & COLFLAG_HASTYPE ){ + return pCol->zCnName + strlen(pCol->zCnName) + 1; + }else if( pCol->eCType ){ + assert( pCol->eCType<=SQLITE_N_STDTYPE ); + return (char*)sqlite3StdType[pCol->eCType-1]; + }else{ + return zDflt; + } } /* @@ -261,12 +267,35 @@ void sqlite3Dequote(char *z){ z[j] = 0; } void sqlite3DequoteExpr(Expr *p){ + assert( !ExprHasProperty(p, EP_IntValue) ); assert( sqlite3Isquote(p->u.zToken[0]) ); p->flags |= p->u.zToken[0]=='"' ? EP_Quoted|EP_DblQuoted : EP_Quoted; sqlite3Dequote(p->u.zToken); } /* +** If the input token p is quoted, try to adjust the token to remove +** the quotes. This is not always possible: +** +** "abc" -> abc +** "ab""cd" -> (not possible because of the interior "") +** +** Remove the quotes if possible. This is a optimization. The overall +** system should still return the correct answer even if this routine +** is always a no-op. +*/ +void sqlite3DequoteToken(Token *p){ + unsigned int i; + if( p->n<2 ) return; + if( !sqlite3Isquote(p->z[0]) ) return; + for(i=1; in-1; i++){ + if( sqlite3Isquote(p->z[i]) ) return; + } + p->n -= 2; + p->z++; +} + +/* ** Generate a Token object from a string */ void sqlite3TokenInit(Token *p, char *z){ @@ -1371,13 +1400,13 @@ static void logBadConnection(const char *zType){ ** used as an argument to sqlite3_errmsg() or sqlite3_close(). */ int sqlite3SafetyCheckOk(sqlite3 *db){ - u32 magic; + u8 eOpenState; if( db==0 ){ logBadConnection("NULL"); return 0; } - magic = db->magic; - if( magic!=SQLITE_MAGIC_OPEN ){ + eOpenState = db->eOpenState; + if( eOpenState!=SQLITE_STATE_OPEN ){ if( sqlite3SafetyCheckSickOrOk(db) ){ testcase( sqlite3GlobalConfig.xLog!=0 ); logBadConnection("unopened"); @@ -1388,11 +1417,11 @@ int sqlite3SafetyCheckOk(sqlite3 *db){ } } int sqlite3SafetyCheckSickOrOk(sqlite3 *db){ - u32 magic; - magic = db->magic; - if( magic!=SQLITE_MAGIC_SICK && - magic!=SQLITE_MAGIC_OPEN && - magic!=SQLITE_MAGIC_BUSY ){ + u8 eOpenState; + eOpenState = db->eOpenState; + if( eOpenState!=SQLITE_STATE_SICK && + eOpenState!=SQLITE_STATE_OPEN && + eOpenState!=SQLITE_STATE_BUSY ){ testcase( sqlite3GlobalConfig.xLog!=0 ); logBadConnection("invalid"); return 0; diff --git a/src/vacuum.c b/src/vacuum.c index 93e2307d..bcab1de1 100644 --- a/src/vacuum.c +++ b/src/vacuum.c @@ -151,8 +151,8 @@ SQLITE_NOINLINE int sqlite3RunVacuum( Btree *pTemp; /* The temporary database we vacuum into */ u32 saved_mDbFlags; /* Saved value of db->mDbFlags */ u64 saved_flags; /* Saved value of db->flags */ - int saved_nChange; /* Saved value of db->nChange */ - int saved_nTotalChange; /* Saved value of db->nTotalChange */ + i64 saved_nChange; /* Saved value of db->nChange */ + i64 saved_nTotalChange; /* Saved value of db->nTotalChange */ u32 saved_openFlags; /* Saved value of db->openFlags */ u8 saved_mTrace; /* Saved trace settings */ Db *pDb = 0; /* Database to detach at end of vacuum */ @@ -250,7 +250,9 @@ SQLITE_NOINLINE int sqlite3RunVacuum( /* Do not attempt to change the page size for a WAL database */ if( sqlite3PagerGetJournalMode(sqlite3BtreePager(pMain)) - ==PAGER_JOURNALMODE_WAL ){ + ==PAGER_JOURNALMODE_WAL + && pOut==0 + ){ db->nextPagesize = 0; } diff --git a/src/vdbe.c b/src/vdbe.c index 4442f7d9..5ca253a0 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -671,6 +671,19 @@ static Mem *out2Prerelease(Vdbe *p, VdbeOp *pOp){ } } +/* +** Return the symbolic name for the data type of a pMem +*/ +static const char *vdbeMemTypeName(Mem *pMem){ + static const char *azTypes[] = { + /* SQLITE_INTEGER */ "INT", + /* SQLITE_FLOAT */ "REAL", + /* SQLITE_TEXT */ "TEXT", + /* SQLITE_BLOB */ "BLOB", + /* SQLITE_NULL */ "NULL" + }; + return azTypes[sqlite3_value_type(pMem)-1]; +} /* ** Execute as much of a VDBE program as we can. @@ -2502,6 +2515,22 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */ break; } +/* Opcode: IsNullOrType P1 P2 P3 * * +** Synopsis: if typeof(r[P1]) IN (P3,5) goto P2 +** +** Jump to P2 if the value in register P1 is NULL or has a datatype P3. +** P3 is an integer which should be one of SQLITE_INTEGER, SQLITE_FLOAT, +** SQLITE_BLOB, SQLITE_NULL, or SQLITE_TEXT. +*/ +case OP_IsNullOrType: { /* jump, in1 */ + int doTheJump; + pIn1 = &aMem[pOp->p1]; + doTheJump = (pIn1->flags & MEM_Null)!=0 || sqlite3_value_type(pIn1)==pOp->p3; + VdbeBranchTaken( doTheJump, 2); + if( doTheJump ) goto jump_to_p2; + break; +} + /* Opcode: ZeroOrNull P1 P2 P3 * * ** Synopsis: r[P2] = 0 OR NULL ** @@ -2870,6 +2899,108 @@ op_column_corrupt: } } +/* Opcode: TypeCheck P1 P2 P3 P4 * +** Synopsis: typecheck(r[P1@P2]) +** +** Apply affinities to the range of P2 registers beginning with P1. +** Take the affinities from the Table object in P4. If any value +** cannot be coerced into the correct type, then raise an error. +** +** This opcode is similar to OP_Affinity except that this opcode +** forces the register type to the Table column type. This is used +** to implement "strict affinity". +** +** GENERATED ALWAYS AS ... STATIC columns are only checked if P3 +** is zero. When P3 is non-zero, no type checking occurs for +** static generated columns. Virtual columns are computed at query time +** and so they are never checked. +** +** Preconditions: +** +**
    +**
  • P2 should be the number of non-virtual columns in the +** table of P4. +**
  • Table P4 should be a STRICT table. +**
+** +** If any precondition is false, an assertion fault occurs. +*/ +case OP_TypeCheck: { + Table *pTab; + Column *aCol; + int i; + + assert( pOp->p4type==P4_TABLE ); + pTab = pOp->p4.pTab; + assert( pTab->tabFlags & TF_Strict ); + assert( pTab->nNVCol==pOp->p2 ); + aCol = pTab->aCol; + pIn1 = &aMem[pOp->p1]; + for(i=0; inCol; i++){ + if( aCol[i].colFlags & COLFLAG_GENERATED ){ + if( aCol[i].colFlags & COLFLAG_VIRTUAL ) continue; + if( pOp->p3 ){ pIn1++; continue; } + } + assert( pIn1 < &aMem[pOp->p1+pOp->p2] ); + applyAffinity(pIn1, aCol[i].affinity, encoding); + if( (pIn1->flags & MEM_Null)==0 ){ + switch( aCol[i].eCType ){ + case COLTYPE_BLOB: { + if( (pIn1->flags & MEM_Blob)==0 ) goto vdbe_type_error; + break; + } + case COLTYPE_INTEGER: + case COLTYPE_INT: { + if( (pIn1->flags & MEM_Int)==0 ) goto vdbe_type_error; + break; + } + case COLTYPE_TEXT: { + if( (pIn1->flags & MEM_Str)==0 ) goto vdbe_type_error; + break; + } + case COLTYPE_REAL: { + if( pIn1->flags & MEM_Int ){ + /* When applying REAL affinity, if the result is still an MEM_Int + ** that will fit in 6 bytes, then change the type to MEM_IntReal + ** so that we keep the high-resolution integer value but know that + ** the type really wants to be REAL. */ + testcase( pIn1->u.i==140737488355328LL ); + testcase( pIn1->u.i==140737488355327LL ); + testcase( pIn1->u.i==-140737488355328LL ); + testcase( pIn1->u.i==-140737488355329LL ); + if( pIn1->u.i<=140737488355327LL && pIn1->u.i>=-140737488355328LL){ + pIn1->flags |= MEM_IntReal; + pIn1->flags &= ~MEM_Int; + }else{ + pIn1->u.r = (double)pIn1->u.i; + pIn1->flags |= MEM_Real; + pIn1->flags &= ~MEM_Int; + } + }else if( (pIn1->flags & MEM_Real)==0 ){ + goto vdbe_type_error; + } + break; + } + default: { + /* COLTYPE_ANY. Accept anything. */ + break; + } + } + } + REGISTER_TRACE((int)(pIn1-aMem), pIn1); + pIn1++; + } + assert( pIn1 == &aMem[pOp->p1+pOp->p2] ); + break; + +vdbe_type_error: + sqlite3VdbeError(p, "cannot store %s value in %s column %s.%s", + vdbeMemTypeName(pIn1), sqlite3StdType[aCol[i].eCType-1], + pTab->zName, aCol[i].zCnName); + rc = SQLITE_CONSTRAINT_DATATYPE; + goto abort_due_to_error; +} + /* Opcode: Affinity P1 P2 * P4 * ** Synopsis: affinity(r[P1@P2]) ** @@ -3533,8 +3664,16 @@ case OP_Transaction: { assert( pOp->p2>=0 && pOp->p2<=2 ); assert( pOp->p1>=0 && pOp->p1nDb ); assert( DbMaskTest(p->btreeMask, pOp->p1) ); - if( pOp->p2 && (db->flags & SQLITE_QueryOnly)!=0 ){ - rc = SQLITE_READONLY; + assert( rc==SQLITE_OK ); + if( pOp->p2 && (db->flags & (SQLITE_QueryOnly|SQLITE_CorruptRdOnly))!=0 ){ + if( db->flags & SQLITE_QueryOnly ){ + /* Writes prohibited by the "PRAGMA query_only=TRUE" statement */ + rc = SQLITE_READONLY; + }else{ + /* Writes prohibited due to a prior SQLITE_CORRUPT in the current + ** transaction */ + rc = SQLITE_CORRUPT; + } goto abort_due_to_error; } pBt = db->aDb[pOp->p1].pBt; @@ -3576,7 +3715,8 @@ case OP_Transaction: { } } assert( pOp->p5==0 || pOp->p4type==P4_INT32 ); - if( pOp->p5 + if( rc==SQLITE_OK + && pOp->p5 && (iMeta!=pOp->p3 || db->aDb[pOp->p1].pSchema->iGeneration!=pOp->p4.i) ){ @@ -3673,6 +3813,7 @@ case OP_SetCookie: { /* When the schema cookie changes, record the new cookie internally */ pDb->pSchema->schema_cookie = pOp->p3 - pOp->p5; db->mDbFlags |= DBFLAG_SchemaChange; + sqlite3FkClearTriggerCache(db, pOp->p1); }else if( pOp->p2==BTREE_FILE_FORMAT ){ /* Record changes in the file format */ pDb->pSchema->file_format = pOp->p3; @@ -3786,6 +3927,8 @@ case OP_ReopenIdx: { pCur = p->apCsr[pOp->p1]; if( pCur && pCur->pgnoRoot==(u32)pOp->p2 ){ assert( pCur->iDb==pOp->p3 ); /* Guaranteed by the code generator */ + assert( pCur->eCurType==CURTYPE_BTREE ); + sqlite3BtreeClearCursor(pCur->uc.pCursor); goto open_cursor_set_hints; } /* If the cursor is not currently open or is open on a different @@ -3968,7 +4111,7 @@ case OP_OpenEphemeral: { aMem[pOp->p3].z = ""; } pCx = p->apCsr[pOp->p1]; - if( pCx && !pCx->hasBeenDuped ){ + if( pCx && !pCx->hasBeenDuped && ALWAYS(pOp->p2<=pCx->nField) ){ /* If the ephermeral table is already open and has no duplicates from ** OP_OpenDup, then erase all existing content so that the table is ** empty again, rather than creating a new table. */ @@ -4273,6 +4416,7 @@ case OP_SeekGT: { /* jump, in3, group */ /* If the P3 value could not be converted into an integer without ** loss of information, then special processing is required... */ if( (newType & (MEM_Int|MEM_IntReal))==0 ){ + int c; if( (newType & MEM_Real)==0 ){ if( (newType & MEM_Null) || oc>=OP_SeekGE ){ VdbeBranchTaken(1,2); @@ -4282,7 +4426,8 @@ case OP_SeekGT: { /* jump, in3, group */ if( rc!=SQLITE_OK ) goto abort_due_to_error; goto seek_not_found; } - }else + } + c = sqlite3IntFloatCompare(iKey, pIn3->u.r); /* If the approximation iKey is larger than the actual real search ** term, substitute >= for > and < for <=. e.g. if the search term @@ -4291,7 +4436,7 @@ case OP_SeekGT: { /* jump, in3, group */ ** (x > 4.9) -> (x >= 5) ** (x <= 4.9) -> (x < 5) */ - if( pIn3->u.r<(double)iKey ){ + if( c>0 ){ assert( OP_SeekGE==(OP_SeekGT-1) ); assert( OP_SeekLT==(OP_SeekLE-1) ); assert( (OP_SeekLE & 0x0001)==(OP_SeekGT & 0x0001) ); @@ -4300,14 +4445,14 @@ case OP_SeekGT: { /* jump, in3, group */ /* If the approximation iKey is smaller than the actual real search ** term, substitute <= for < and > for >=. */ - else if( pIn3->u.r>(double)iKey ){ + else if( c<0 ){ assert( OP_SeekLE==(OP_SeekLT+1) ); assert( OP_SeekGT==(OP_SeekGE+1) ); assert( (OP_SeekLT & 0x0001)==(OP_SeekGE & 0x0001) ); if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++; } } - rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)iKey, 0, &res); + rc = sqlite3BtreeTableMoveto(pC->uc.pCursor, (u64)iKey, 0, &res); pC->movetoTarget = iKey; /* Used by OP_Delete */ if( rc!=SQLITE_OK ){ goto abort_due_to_error; @@ -4354,7 +4499,7 @@ case OP_SeekGT: { /* jump, in3, group */ { int i; for(i=0; iuc.pCursor, &r, 0, 0, &res); + rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, &r, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } @@ -4773,7 +4918,7 @@ case OP_Found: { /* jump, in3 */ } } } - rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, pIdxKey, 0, 0, &res); + rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, pIdxKey, &res); if( pFree ) sqlite3DbFreeNN(db, pFree); if( rc!=SQLITE_OK ){ goto abort_due_to_error; @@ -4882,7 +5027,7 @@ notExistsWithKey: pCrsr = pC->uc.pCursor; assert( pCrsr!=0 ); res = 0; - rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res); + rc = sqlite3BtreeTableMoveto(pCrsr, iKey, 0, &res); assert( rc==SQLITE_OK || res==0 ); pC->movetoTarget = iKey; /* Used by OP_Delete */ pC->nullRow = 0; @@ -5039,7 +5184,7 @@ case OP_NewRowid: { /* out2 */ do{ sqlite3_randomness(sizeof(v), &v); v &= (MAX_ROWID>>1); v++; /* Ensure that v is greater than zero */ - }while( ((rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)v, + }while( ((rc = sqlite3BtreeTableMoveto(pC->uc.pCursor, (u64)v, 0, &res))==SQLITE_OK) && (res==0) && (++cnt<100)); @@ -5129,7 +5274,7 @@ case OP_Insert: { assert( (pOp->p5 & OPFLAG_ISNOOP) || HasRowid(pTab) ); }else{ pTab = 0; - zDb = 0; /* Not needed. Silence a compiler warning. */ + zDb = 0; } #ifdef SQLITE_ENABLE_PREUPDATE_HOOK @@ -5282,13 +5427,14 @@ case OP_Delete: { pC->movetoTarget = sqlite3BtreeIntegerKey(pC->uc.pCursor); } }else{ - zDb = 0; /* Not needed. Silence a compiler warning. */ - pTab = 0; /* Not needed. Silence a compiler warning. */ + zDb = 0; + pTab = 0; } #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* Invoke the pre-update-hook if required. */ - if( db->xPreUpdateCallback && pOp->p4.pTab ){ + assert( db->xPreUpdateCallback==0 || pTab==pOp->p4.pTab ); + if( db->xPreUpdateCallback && pTab ){ assert( !(opflags & OPFLAG_ISUPDATE) || HasRowid(pTab)==0 || (aMem[pOp->p3].flags & MEM_Int) @@ -5329,7 +5475,7 @@ case OP_Delete: { /* Invoke the update-hook if required. */ if( opflags & OPFLAG_NCHANGE ){ p->nChange++; - if( db->xUpdateCallback && HasRowid(pTab) ){ + if( db->xUpdateCallback && ALWAYS(pTab!=0) && HasRowid(pTab) ){ db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, pTab->zName, pC->movetoTarget); assert( pC->iDb>=0 ); @@ -5916,7 +6062,8 @@ case OP_SorterInsert: { /* in2 */ ** an UPDATE or DELETE statement and the index entry to be updated ** or deleted is not found. For some uses of IdxDelete ** (example: the EXCEPT operator) it does not matter that no matching -** entry is found. For those cases, P5 is zero. +** entry is found. For those cases, P5 is zero. Also, do not raise +** this (self-correcting and non-critical) error if in writable_schema mode. */ case OP_IdxDelete: { VdbeCursor *pC; @@ -5937,12 +6084,12 @@ case OP_IdxDelete: { r.nField = (u16)pOp->p3; r.default_rc = 0; r.aMem = &aMem[pOp->p2]; - rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res); + rc = sqlite3BtreeIndexMoveto(pCrsr, &r, &res); if( rc ) goto abort_due_to_error; if( res==0 ){ rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE); if( rc ) goto abort_due_to_error; - }else if( pOp->p5 ){ + }else if( pOp->p5 && !sqlite3WritableSchema(db) ){ rc = sqlite3ReportError(SQLITE_CORRUPT_INDEX, __LINE__, "index corruption"); goto abort_due_to_error; } @@ -6250,7 +6397,7 @@ case OP_Destroy: { /* out2 */ ** See also: Destroy */ case OP_Clear: { - int nChange; + i64 nChange; sqlite3VdbeIncrWriteCounter(p, 0); nChange = 0; @@ -6376,7 +6523,7 @@ case OP_ParseSchema: { }else #endif { - zSchema = DFLT_SCHEMA_TABLE; + zSchema = LEGACY_SCHEMA_TABLE; initData.db = db; initData.iDb = iDb; initData.pzErrMsg = &p->zErrMsg; @@ -7596,6 +7743,7 @@ case OP_VFilter: { /* jump */ pCur = p->apCsr[pOp->p1]; assert( memIsValid(pQuery) ); REGISTER_TRACE(pOp->p3, pQuery); + assert( pCur!=0 ); assert( pCur->eCurType==CURTYPE_VTAB ); pVCur = pCur->uc.pVCur; pVtab = pVCur->pVtab; @@ -7607,7 +7755,6 @@ case OP_VFilter: { /* jump */ iQuery = (int)pQuery->u.i; /* Invoke the xFilter method */ - res = 0; apArg = p->apArg; for(i = 0; iapCsr[pOp->p1]; + assert( pCur!=0 ); assert( pCur->eCurType==CURTYPE_VTAB ); assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); pDest = &aMem[pOp->p3]; @@ -7697,8 +7845,8 @@ case OP_VNext: { /* jump */ int res; VdbeCursor *pCur; - res = 0; pCur = p->apCsr[pOp->p1]; + assert( pCur!=0 ); assert( pCur->eCurType==CURTYPE_VTAB ); if( pCur->nullRow ){ break; @@ -7794,7 +7942,7 @@ case OP_VUpdate: { const sqlite3_module *pModule; int nArg; int i; - sqlite_int64 rowid; + sqlite_int64 rowid = 0; Mem **apArg; Mem *pX; @@ -8239,6 +8387,18 @@ abort_due_to_error: rc = SQLITE_CORRUPT_BKPT; } assert( rc ); +#ifdef SQLITE_DEBUG + if( db->flags & SQLITE_VdbeTrace ){ + const char *zTrace = p->zSql; + if( zTrace==0 ){ + if( aOp[0].opcode==OP_Trace ){ + zTrace = aOp[0].p4.z; + } + if( zTrace==0 ) zTrace = "???"; + } + printf("ABORT-due-to-error (rc=%d): %s\n", rc, zTrace); + } +#endif if( p->zErrMsg==0 && rc!=SQLITE_IOERR_NOMEM ){ sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc)); } @@ -8249,6 +8409,9 @@ abort_due_to_error: (int)(pOp - aOp), p->zSql, p->zErrMsg); sqlite3VdbeHalt(p); if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db); + if( rc==SQLITE_CORRUPT && db->autoCommit==0 ){ + db->flags |= SQLITE_CorruptRdOnly; + } rc = SQLITE_ERROR; if( resetSchemaOnFault>0 ){ sqlite3ResetOneSchema(db, resetSchemaOnFault-1); diff --git a/src/vdbeInt.h b/src/vdbeInt.h index b6e02888..599d0641 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -180,8 +180,8 @@ struct VdbeFrame { int nMem; /* Number of entries in aMem */ int nChildMem; /* Number of memory cells for child frame */ int nChildCsr; /* Number of cursors for child frame */ - int nChange; /* Statement changes (Vdbe.nChange) */ - int nDbChange; /* Value of db->nChange */ + i64 nChange; /* Statement changes (Vdbe.nChange) */ + i64 nDbChange; /* Value of db->nChange */ }; /* Magic number for sanity checking on VdbeFrame objects */ @@ -388,7 +388,7 @@ struct Vdbe { u32 cacheCtr; /* VdbeCursor row cache generation counter */ int pc; /* The program counter */ int rc; /* Value to return */ - int nChange; /* Number of db changes made since last reset */ + i64 nChange; /* Number of db changes made since last reset */ int iStatement; /* Statement number (or 0 if has no opened stmt) */ i64 iCurrentTime; /* Value of julianday('now') for this statement */ i64 nFkConstraint; /* Number of imm. FK constraints this VM */ @@ -526,13 +526,18 @@ void sqlite3VdbeMemSetInt64(Mem*, i64); void sqlite3VdbeMemSetPointer(Mem*, void*, const char*, void(*)(void*)); void sqlite3VdbeMemInit(Mem*,sqlite3*,u16); void sqlite3VdbeMemSetNull(Mem*); +#ifndef SQLITE_OMIT_INCRBLOB void sqlite3VdbeMemSetZeroBlob(Mem*,int); +#else +int sqlite3VdbeMemSetZeroBlob(Mem*,int); +#endif #ifdef SQLITE_DEBUG int sqlite3VdbeMemIsRowSet(const Mem*); #endif int sqlite3VdbeMemSetRowSet(Mem*); int sqlite3VdbeMemMakeWriteable(Mem*); int sqlite3VdbeMemStringify(Mem*, u8, u8); +int sqlite3IntFloatCompare(i64,double); i64 sqlite3VdbeIntValue(Mem*); int sqlite3VdbeMemIntegerify(Mem*); double sqlite3VdbeRealValue(Mem*); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 5de7c64c..17df807d 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -362,8 +362,8 @@ void sqlite3_value_free(sqlite3_value *pOld){ ** the function result. ** ** The setStrOrError() function calls sqlite3VdbeMemSetStr() to store the -** result as a string or blob but if the string or blob is too large, it -** then sets the error code to SQLITE_TOOBIG +** result as a string or blob. Appropriate errors are set if the string/blob +** is too big or if an OOM occurs. ** ** The invokeValueDestructor(P,X) routine invokes destructor function X() ** on value P is not going to be used and need to be destroyed. @@ -375,8 +375,16 @@ static void setResultStrOrError( u8 enc, /* Encoding of z. 0 for BLOBs */ void (*xDel)(void*) /* Destructor function */ ){ - if( sqlite3VdbeMemSetStr(pCtx->pOut, z, n, enc, xDel)==SQLITE_TOOBIG ){ - sqlite3_result_error_toobig(pCtx); + int rc = sqlite3VdbeMemSetStr(pCtx->pOut, z, n, enc, xDel); + if( rc ){ + if( rc==SQLITE_TOOBIG ){ + sqlite3_result_error_toobig(pCtx); + }else{ + /* The only errors possible from sqlite3VdbeMemSetStr are + ** SQLITE_TOOBIG and SQLITE_NOMEM */ + assert( rc==SQLITE_NOMEM ); + sqlite3_result_error_nomem(pCtx); + } } } static int invokeValueDestructor( @@ -533,8 +541,12 @@ int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){ if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){ return SQLITE_TOOBIG; } +#ifndef SQLITE_OMIT_INCRBLOB sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n); return SQLITE_OK; +#else + return sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n); +#endif } void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){ pCtx->isError = errCode ? errCode : -1; @@ -1546,7 +1558,11 @@ int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){ Vdbe *p = (Vdbe *)pStmt; rc = vdbeUnbind(p, i); if( rc==SQLITE_OK ){ +#ifndef SQLITE_OMIT_INCRBLOB sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n); +#else + rc = sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n); +#endif sqlite3_mutex_leave(p->db->mutex); } return rc; @@ -1834,6 +1850,7 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ u32 nRec; u8 *aRec; + assert( p->pCsr->eCurType==CURTYPE_BTREE ); nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor); aRec = sqlite3DbMallocRaw(db, nRec); if( !aRec ) goto preupdate_old_out; diff --git a/src/vdbeaux.c b/src/vdbeaux.c index d22a6a55..a11d41c4 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -241,8 +241,10 @@ int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){ if( p->nOpAlloc<=i ){ return growOp3(p, op, p1, p2, p3); } + assert( p->aOp!=0 ); p->nOp++; pOp = &p->aOp[i]; + assert( pOp!=0 ); pOp->opcode = (u8)op; pOp->p5 = 0; pOp->p1 = p1; @@ -1485,7 +1487,7 @@ char *sqlite3VdbeDisplayComment( if( zOpName[nOpName+1] ){ int seenCom = 0; char c; - zSynopsis = zOpName += nOpName + 1; + zSynopsis = zOpName + nOpName + 1; if( strncmp(zSynopsis,"IF ",3)==0 ){ sqlite3_snprintf(sizeof(zAlt), zAlt, "if %s goto P2", zSynopsis+3); zSynopsis = zAlt; @@ -1558,6 +1560,7 @@ static void displayP4Expr(StrAccum *p, Expr *pExpr){ const char *zOp = 0; switch( pExpr->op ){ case TK_STRING: + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3_str_appendf(p, "%Q", pExpr->u.zToken); break; case TK_INTEGER: @@ -1660,7 +1663,7 @@ char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){ case P4_COLLSEQ: { static const char *const encnames[] = {"?", "8", "16LE", "16BE"}; CollSeq *pColl = pOp->p4.pColl; - assert( pColl->enc>=0 && pColl->enc<4 ); + assert( pColl->enc<4 ); sqlite3_str_appendf(&x, "%.18s-%s", pColl->zName, encnames[pColl->enc]); break; @@ -1904,8 +1907,8 @@ static void releaseMemArray(Mem *p, int N){ */ testcase( p->flags & MEM_Agg ); testcase( p->flags & MEM_Dyn ); - testcase( p->xDel==sqlite3VdbeFrameMemDel ); if( p->flags&(MEM_Agg|MEM_Dyn) ){ + testcase( (p->flags & MEM_Dyn)!=0 && p->xDel==sqlite3VdbeFrameMemDel ); sqlite3VdbeMemRelease(p); }else if( p->szMalloc ){ sqlite3DbFreeNN(db, p->zMalloc); @@ -3005,9 +3008,9 @@ int sqlite3VdbeCheckFk(Vdbe *p, int deferred){ ** has made changes and is in autocommit mode, then commit those ** changes. If a rollback is needed, then do the rollback. ** -** This routine is the only way to move the state of a VM from -** SQLITE_MAGIC_RUN to SQLITE_MAGIC_HALT. It is harmless to -** call this on a VM that is in the SQLITE_MAGIC_HALT state. +** This routine is the only way to move the sqlite3eOpenState of a VM from +** SQLITE_STATE_RUN to SQLITE_STATE_HALT. It is harmless to +** call this on a VM that is in the SQLITE_STATE_HALT state. ** ** Return an error code. If the commit could not complete because of ** lock contention, return SQLITE_BUSY. If SQLITE_BUSY is returned, it @@ -3053,9 +3056,15 @@ int sqlite3VdbeHalt(Vdbe *p){ sqlite3VdbeEnter(p); /* Check for one of the special errors */ - mrc = p->rc & 0xff; - isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR - || mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL; + if( p->rc ){ + mrc = p->rc & 0xff; + isSpecialError = mrc==SQLITE_NOMEM + || mrc==SQLITE_IOERR + || mrc==SQLITE_INTERRUPT + || mrc==SQLITE_FULL; + }else{ + mrc = isSpecialError = 0; + } if( isSpecialError ){ /* If the query was read-only and the error code is SQLITE_INTERRUPT, ** no rollback is necessary. Otherwise, at least a savepoint @@ -3107,6 +3116,9 @@ int sqlite3VdbeHalt(Vdbe *p){ return SQLITE_ERROR; } rc = SQLITE_CONSTRAINT_FOREIGNKEY; + }else if( db->flags & SQLITE_CorruptRdOnly ){ + rc = SQLITE_CORRUPT; + db->flags &= ~SQLITE_CorruptRdOnly; }else{ /* The auto-commit flag is true, the vdbe program was successful ** or hit an 'OR FAIL' constraint and there are no deferred foreign @@ -3501,7 +3513,7 @@ int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor *p){ assert( p->deferredMoveto ); assert( p->isTable ); assert( p->eCurType==CURTYPE_BTREE ); - rc = sqlite3BtreeMovetoUnpacked(p->uc.pCursor, 0, p->movetoTarget, 0, &res); + rc = sqlite3BtreeTableMoveto(p->uc.pCursor, p->movetoTarget, 0, &res); if( rc ) return rc; if( res!=0 ) return SQLITE_CORRUPT_BKPT; #ifdef SQLITE_TEST @@ -4285,7 +4297,7 @@ SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){ ** number. Return negative, zero, or positive if the first (i64) is less than, ** equal to, or greater than the second (double). */ -static int sqlite3IntFloatCompare(i64 i, double r){ +int sqlite3IntFloatCompare(i64 i, double r){ if( sizeof(LONGDOUBLE_TYPE)>8 ){ LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i; testcase( x0x7fffffff ); assert( m.n>=0 ); if( unlikely(szHdr<3 || szHdr>(unsigned)m.n) ){ @@ -5009,7 +5021,7 @@ int sqlite3VdbeIdxKeyCompare( ** This routine sets the value to be returned by subsequent calls to ** sqlite3_changes() on the database handle 'db'. */ -void sqlite3VdbeSetChanges(sqlite3 *db, int nChange){ +void sqlite3VdbeSetChanges(sqlite3 *db, i64 nChange){ assert( sqlite3_mutex_held(db->mutex) ); db->nChange = nChange; db->nTotalChange += nChange; @@ -5211,6 +5223,8 @@ void sqlite3VdbePreUpdateHook( } } + assert( pCsr!=0 ); + assert( pCsr->eCurType==CURTYPE_BTREE ); assert( pCsr->nField==pTab->nCol || (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1) ); diff --git a/src/vdbeblob.c b/src/vdbeblob.c index a4e79bf8..512442fd 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -75,7 +75,10 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){ } if( rc==SQLITE_ROW ){ VdbeCursor *pC = v->apCsr[0]; - u32 type = pC->nHdrParsed>p->iCol ? pC->aType[p->iCol] : 0; + u32 type; + assert( pC!=0 ); + assert( pC->eCurType==CURTYPE_BTREE ); + type = pC->nHdrParsed>p->iCol ? pC->aType[p->iCol] : 0; testcase( pC->nHdrParsed==p->iCol ); testcase( pC->nHdrParsed==p->iCol+1 ); if( type<12 ){ @@ -167,7 +170,7 @@ int sqlite3_blob_open( sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable); } #ifndef SQLITE_OMIT_VIEW - if( pTab && pTab->pSelect ){ + if( pTab && IsView(pTab) ){ pTab = 0; sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable); } @@ -187,7 +190,7 @@ int sqlite3_blob_open( /* Now search pTab for the exact column. */ for(iCol=0; iColnCol; iCol++) { - if( sqlite3StrICmp(pTab->aCol[iCol].zName, zColumn)==0 ){ + if( sqlite3StrICmp(pTab->aCol[iCol].zCnName, zColumn)==0 ){ break; } } @@ -212,7 +215,8 @@ int sqlite3_blob_open( ** key columns must be indexed. The check below will pick up this ** case. */ FKey *pFKey; - for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){ + assert( IsOrdinaryTable(pTab) ); + for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){ int j; for(j=0; jnCol; j++){ if( pFKey->aCol[j].iFrom==iCol ){ @@ -419,6 +423,8 @@ static int blobReadWrite( */ sqlite3_int64 iKey; iKey = sqlite3BtreeIntegerKey(p->pCsr); + assert( v->apCsr[0]!=0 ); + assert( v->apCsr[0]->eCurType==CURTYPE_BTREE ); sqlite3VdbePreUpdateHook( v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1, p->iCol ); diff --git a/src/vdbemem.c b/src/vdbemem.c index dc177161..570a2eb3 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -200,6 +200,7 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ #ifndef SQLITE_OMIT_UTF16 int rc; #endif + assert( pMem!=0 ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE || desiredEnc==SQLITE_UTF16BE ); @@ -332,6 +333,7 @@ static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){ ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. */ int sqlite3VdbeMemMakeWriteable(Mem *pMem){ + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){ @@ -356,6 +358,7 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){ #ifndef SQLITE_OMIT_INCRBLOB int sqlite3VdbeMemExpandBlob(Mem *pMem){ int nByte; + assert( pMem!=0 ); assert( pMem->flags & MEM_Zero ); assert( (pMem->flags&MEM_Blob)!=0 || MemNullNochng(pMem) ); testcase( sqlite3_value_nochange(pMem) ); @@ -371,6 +374,8 @@ int sqlite3VdbeMemExpandBlob(Mem *pMem){ if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){ return SQLITE_NOMEM_BKPT; } + assert( pMem->z!=0 ); + assert( sqlite3DbMallocSize(pMem->db,pMem->z) >= nByte ); memset(&pMem->z[pMem->n], 0, pMem->u.nZero); pMem->n += pMem->u.nZero; @@ -383,6 +388,7 @@ int sqlite3VdbeMemExpandBlob(Mem *pMem){ ** Make sure the given Mem is \u0000 terminated. */ int sqlite3VdbeMemNulTerminate(Mem *pMem){ + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); testcase( (pMem->flags & (MEM_Term|MEM_Str))==(MEM_Term|MEM_Str) ); testcase( (pMem->flags & (MEM_Term|MEM_Str))==0 ); @@ -410,6 +416,7 @@ int sqlite3VdbeMemNulTerminate(Mem *pMem){ int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ const int nByte = 32; + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !(pMem->flags&MEM_Zero) ); assert( !(pMem->flags&(MEM_Str|MEM_Blob)) ); @@ -445,6 +452,7 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){ sqlite3_context ctx; Mem t; assert( pFunc!=0 ); + assert( pMem!=0 ); assert( pFunc->xFinalize!=0 ); assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); @@ -595,6 +603,7 @@ static SQLITE_NOINLINE i64 memIntValue(Mem *pMem){ } i64 sqlite3VdbeIntValue(Mem *pMem){ int flags; + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); flags = pMem->flags; @@ -623,6 +632,7 @@ static SQLITE_NOINLINE double memRealValue(Mem *pMem){ return val; } double sqlite3VdbeRealValue(Mem *pMem){ + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); if( pMem->flags & MEM_Real ){ @@ -655,6 +665,7 @@ int sqlite3VdbeBooleanValue(Mem *pMem, int ifNull){ */ void sqlite3VdbeIntegerAffinity(Mem *pMem){ i64 ix; + assert( pMem!=0 ); assert( pMem->flags & MEM_Real ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); @@ -682,6 +693,7 @@ void sqlite3VdbeIntegerAffinity(Mem *pMem){ ** Convert pMem to type integer. Invalidate any prior representations. */ int sqlite3VdbeMemIntegerify(Mem *pMem){ + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); @@ -696,6 +708,7 @@ int sqlite3VdbeMemIntegerify(Mem *pMem){ ** Invalidate any prior representations. */ int sqlite3VdbeMemRealify(Mem *pMem){ + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); @@ -729,6 +742,7 @@ int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){ ** as much of the string as we can and ignore the rest. */ int sqlite3VdbeMemNumerify(Mem *pMem){ + assert( pMem!=0 ); testcase( pMem->flags & MEM_Int ); testcase( pMem->flags & MEM_Real ); testcase( pMem->flags & MEM_IntReal ); @@ -838,6 +852,7 @@ void sqlite3ValueSetNull(sqlite3_value *p){ ** Delete any previous value and set the value to be a BLOB of length ** n containing all zeros. */ +#ifndef SQLITE_OMIT_INCRBLOB void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ sqlite3VdbeMemRelease(pMem); pMem->flags = MEM_Blob|MEM_Zero; @@ -847,6 +862,21 @@ void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ pMem->enc = SQLITE_UTF8; pMem->z = 0; } +#else +int sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ + int nByte = n>0?n:1; + if( sqlite3VdbeMemGrow(pMem, nByte, 0) ){ + return SQLITE_NOMEM_BKPT; + } + assert( pMem->z!=0 ); + assert( sqlite3DbMallocSize(pMem->db, pMem->z)>=nByte ); + memset(pMem->z, 0, nByte); + pMem->n = n>0?n:0; + pMem->flags = MEM_Blob; + pMem->enc = SQLITE_UTF8; + return SQLITE_OK; +} +#endif /* ** The pMem is known to contain content that needs to be destroyed prior @@ -1080,6 +1110,7 @@ int sqlite3VdbeMemSetStr( int iLimit; /* Maximum allowed string or blob size */ u16 flags = 0; /* New value for pMem->flags */ + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); @@ -1388,7 +1419,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ #ifdef SQLITE_ENABLE_STAT4 static int valueFromFunction( sqlite3 *db, /* The database connection */ - Expr *p, /* The expression to evaluate */ + const Expr *p, /* The expression to evaluate */ u8 enc, /* Encoding to use */ u8 aff, /* Affinity to use */ sqlite3_value **ppVal, /* Write the new value here */ @@ -1405,8 +1436,10 @@ static int valueFromFunction( assert( pCtx!=0 ); assert( (p->flags & EP_TokenOnly)==0 ); + 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); assert( pFunc ); if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0 @@ -1482,7 +1515,7 @@ static int valueFromFunction( */ static int valueFromExpr( sqlite3 *db, /* The database connection */ - Expr *pExpr, /* The expression to evaluate */ + const Expr *pExpr, /* The expression to evaluate */ u8 enc, /* Encoding to use */ u8 affinity, /* Affinity to use */ sqlite3_value **ppVal, /* Write the new value here */ @@ -1510,7 +1543,9 @@ static int valueFromExpr( assert( (pExpr->flags & EP_TokenOnly)==0 || pCtx==0 ); if( op==TK_CAST ){ - u8 aff = sqlite3AffinityType(pExpr->u.zToken,0); + u8 aff; + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + aff = sqlite3AffinityType(pExpr->u.zToken,0); rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx); testcase( rc!=SQLITE_OK ); if( *ppVal ){ @@ -1583,6 +1618,7 @@ static int valueFromExpr( #ifndef SQLITE_OMIT_BLOB_LITERAL else if( op==TK_BLOB ){ int nVal; + assert( !ExprHasProperty(pExpr, EP_IntValue) ); assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' ); assert( pExpr->u.zToken[1]=='\'' ); pVal = valueNew(db, pCtx); @@ -1600,6 +1636,7 @@ static int valueFromExpr( } #endif else if( op==TK_TRUEFALSE ){ + assert( !ExprHasProperty(pExpr, EP_IntValue) ); pVal = valueNew(db, pCtx); if( pVal ){ pVal->flags = MEM_Int; @@ -1637,7 +1674,7 @@ no_mem: */ int sqlite3ValueFromExpr( sqlite3 *db, /* The database connection */ - Expr *pExpr, /* The expression to evaluate */ + const Expr *pExpr, /* The expression to evaluate */ u8 enc, /* Encoding to use */ u8 affinity, /* Affinity to use */ sqlite3_value **ppVal /* Write the new value here */ diff --git a/src/vdbesort.c b/src/vdbesort.c index 397935aa..8bf7b571 100644 --- a/src/vdbesort.c +++ b/src/vdbesort.c @@ -1289,7 +1289,7 @@ static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){ sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_CHUNK_SIZE, &chunksize); sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_SIZE_HINT, &nByte); sqlite3OsFetch(pFd, 0, (int)nByte, &p); - sqlite3OsUnfetch(pFd, 0, p); + if( p ) sqlite3OsUnfetch(pFd, 0, p); } } #else @@ -2007,6 +2007,7 @@ static int vdbeIncrMergerNew( vdbeMergeEngineFree(pMerger); rc = SQLITE_NOMEM_BKPT; } + assert( *ppOut!=0 || rc!=SQLITE_OK ); return rc; } diff --git a/src/vdbetrace.c b/src/vdbetrace.c index 1095e7f5..ae8ad311 100644 --- a/src/vdbetrace.c +++ b/src/vdbetrace.c @@ -84,11 +84,9 @@ char *sqlite3VdbeExpandSql( #ifndef SQLITE_OMIT_UTF16 Mem utf8; /* Used to convert UTF16 into UTF8 for display */ #endif - char zBase[100]; /* Initial working space */ db = p->db; - sqlite3StrAccumInit(&out, 0, zBase, sizeof(zBase), - db->aLimit[SQLITE_LIMIT_LENGTH]); + sqlite3StrAccumInit(&out, 0, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); if( db->nVdbeExec>1 ){ while( *zRawSql ){ const char *zStart = zRawSql; diff --git a/src/vtab.c b/src/vtab.c index c9dcadae..2c787c6c 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -192,7 +192,7 @@ void sqlite3VtabLock(VTable *pVTab){ VTable *sqlite3GetVTable(sqlite3 *db, Table *pTab){ VTable *pVtab; assert( IsVirtual(pTab) ); - for(pVtab=pTab->pVTable; pVtab && pVtab->db!=db; pVtab=pVtab->pNext); + for(pVtab=pTab->u.vtab.p; pVtab && pVtab->db!=db; pVtab=pVtab->pNext); return pVtab; } @@ -205,7 +205,8 @@ void sqlite3VtabUnlock(VTable *pVTab){ assert( db ); assert( pVTab->nRef>0 ); - assert( db->magic==SQLITE_MAGIC_OPEN || db->magic==SQLITE_MAGIC_ZOMBIE ); + assert( db->eOpenState==SQLITE_STATE_OPEN + || db->eOpenState==SQLITE_STATE_ZOMBIE ); pVTab->nRef--; if( pVTab->nRef==0 ){ @@ -220,21 +221,24 @@ void sqlite3VtabUnlock(VTable *pVTab){ /* ** Table p is a virtual table. This function moves all elements in the -** p->pVTable list to the sqlite3.pDisconnect lists of their associated +** p->u.vtab.p list to the sqlite3.pDisconnect lists of their associated ** database connections to be disconnected at the next opportunity. ** Except, if argument db is not NULL, then the entry associated with -** connection db is left in the p->pVTable list. +** connection db is left in the p->u.vtab.p list. */ static VTable *vtabDisconnectAll(sqlite3 *db, Table *p){ VTable *pRet = 0; - VTable *pVTable = p->pVTable; - p->pVTable = 0; + VTable *pVTable; + + assert( IsVirtual(p) ); + pVTable = p->u.vtab.p; + p->u.vtab.p = 0; /* Assert that the mutex (if any) associated with the BtShared database ** that contains table p is held by the caller. See header comments ** above function sqlite3VtabUnlockList() for an explanation of why ** this makes it safe to access the sqlite3.pDisconnect list of any - ** database connection that may have an entry in the p->pVTable list. + ** database connection that may have an entry in the p->u.vtab.p list. */ assert( db==0 || sqlite3SchemaMutexHeld(db, 0, p->pSchema) ); @@ -244,7 +248,7 @@ static VTable *vtabDisconnectAll(sqlite3 *db, Table *p){ assert( db2 ); if( db2==db ){ pRet = pVTable; - p->pVTable = pRet; + p->u.vtab.p = pRet; pRet->pNext = 0; }else{ pVTable->pNext = db2->pDisconnect; @@ -272,7 +276,7 @@ void sqlite3VtabDisconnect(sqlite3 *db, Table *p){ assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3_mutex_held(db->mutex) ); - for(ppVTab=&p->pVTable; *ppVTab; ppVTab=&(*ppVTab)->pNext){ + for(ppVTab=&p->u.vtab.p; *ppVTab; ppVTab=&(*ppVTab)->pNext){ if( (*ppVTab)->db==db ){ VTable *pVTab = *ppVTab; *ppVTab = pVTab->pNext; @@ -335,37 +339,41 @@ void sqlite3VtabUnlockList(sqlite3 *db){ ** database connection. */ void sqlite3VtabClear(sqlite3 *db, Table *p){ + assert( IsVirtual(p) ); if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p); - if( p->azModuleArg ){ + if( p->u.vtab.azArg ){ int i; - for(i=0; inModuleArg; i++){ - if( i!=1 ) sqlite3DbFree(db, p->azModuleArg[i]); + for(i=0; iu.vtab.nArg; i++){ + if( i!=1 ) sqlite3DbFree(db, p->u.vtab.azArg[i]); } - sqlite3DbFree(db, p->azModuleArg); + sqlite3DbFree(db, p->u.vtab.azArg); } } /* -** Add a new module argument to pTable->azModuleArg[]. +** Add a new module argument to pTable->u.vtab.azArg[]. ** The string is not copied - the pointer is stored. The ** string will be freed automatically when the table is ** deleted. */ static void addModuleArgument(Parse *pParse, Table *pTable, char *zArg){ - sqlite3_int64 nBytes = sizeof(char *)*(2+pTable->nModuleArg); + sqlite3_int64 nBytes; char **azModuleArg; sqlite3 *db = pParse->db; - if( pTable->nModuleArg+3>=db->aLimit[SQLITE_LIMIT_COLUMN] ){ + + assert( IsVirtual(pTable) ); + nBytes = sizeof(char *)*(2+pTable->u.vtab.nArg); + if( pTable->u.vtab.nArg+3>=db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many columns on %s", pTable->zName); } - azModuleArg = sqlite3DbRealloc(db, pTable->azModuleArg, nBytes); + azModuleArg = sqlite3DbRealloc(db, pTable->u.vtab.azArg, nBytes); if( azModuleArg==0 ){ sqlite3DbFree(db, zArg); }else{ - int i = pTable->nModuleArg++; + int i = pTable->u.vtab.nArg++; azModuleArg[i] = zArg; azModuleArg[i+1] = 0; - pTable->azModuleArg = azModuleArg; + pTable->u.vtab.azArg = azModuleArg; } } @@ -388,10 +396,11 @@ void sqlite3VtabBeginParse( pTable = pParse->pNewTable; if( pTable==0 ) return; assert( 0==pTable->pIndex ); + pTable->eTabType = TABTYP_VTAB; db = pParse->db; - assert( pTable->nModuleArg==0 ); + assert( pTable->u.vtab.nArg==0 ); addModuleArgument(pParse, pTable, sqlite3NameFromToken(db, pModuleName)); addModuleArgument(pParse, pTable, 0); addModuleArgument(pParse, pTable, sqlite3DbStrDup(db, pTable->zName)); @@ -408,11 +417,11 @@ void sqlite3VtabBeginParse( ** sqlite_schema table, has already been made by sqlite3StartTable(). ** The second call, to obtain permission to create the table, is made now. */ - if( pTable->azModuleArg ){ + if( pTable->u.vtab.azArg ){ int iDb = sqlite3SchemaToIndex(db, pTable->pSchema); assert( iDb>=0 ); /* The database the table is being created in */ sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName, - pTable->azModuleArg[0], pParse->db->aDb[iDb].zDbSName); + pTable->u.vtab.azArg[0], pParse->db->aDb[iDb].zDbSName); } #endif } @@ -440,9 +449,10 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ sqlite3 *db = pParse->db; /* The database connection */ if( pTab==0 ) return; + assert( IsVirtual(pTab) ); addArgumentToVtab(pParse); pParse->sArg.z = 0; - if( pTab->nModuleArg<1 ) return; + if( pTab->u.vtab.nArg<1 ) return; /* If the CREATE VIRTUAL TABLE statement is being entered for the ** first time (in other words if the virtual table is actually being @@ -475,7 +485,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); sqlite3NestedParse(pParse, - "UPDATE %Q." DFLT_SCHEMA_TABLE " " + "UPDATE %Q." LEGACY_SCHEMA_TABLE " " "SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q " "WHERE rowid=#%d", db->aDb[iDb].zDbSName, @@ -495,18 +505,14 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ iReg = ++pParse->nMem; sqlite3VdbeLoadString(v, iReg, pTab->zName); sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg); - } - - /* If we are rereading the sqlite_schema table create the in-memory - ** record of the table. The xConnect() method is not called until - ** the first time the virtual table is used in an SQL statement. This - ** allows a schema that contains virtual tables to be loaded before - ** the required virtual table implementations are registered. */ - else { + }else{ + /* If we are rereading the sqlite_schema table create the in-memory + ** record of the table. */ Table *pOld; Schema *pSchema = pTab->pSchema; const char *zName = pTab->zName; - assert( sqlite3SchemaMutexHeld(db, 0, pSchema) ); + assert( zName!=0 ); + sqlite3MarkAllShadowTablesOf(db, pTab); pOld = sqlite3HashInsert(&pSchema->tblHash, zName, pTab); if( pOld ){ sqlite3OomFault(db); @@ -557,13 +563,16 @@ static int vtabCallConstructor( VtabCtx sCtx; VTable *pVTable; int rc; - const char *const*azArg = (const char *const*)pTab->azModuleArg; - int nArg = pTab->nModuleArg; + const char *const*azArg; + int nArg = pTab->u.vtab.nArg; char *zErr = 0; char *zModuleName; int iDb; VtabCtx *pCtx; + assert( IsVirtual(pTab) ); + azArg = (const char *const*)pTab->u.vtab.azArg; + /* Check that the virtual-table is not already being initialized */ for(pCtx=db->pVtabCtx; pCtx; pCtx=pCtx->pPrior){ if( pCtx->pTab==pTab ){ @@ -590,7 +599,7 @@ static int vtabCallConstructor( pVTable->eVtabRisk = SQLITE_VTABRISK_Normal; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); - pTab->azModuleArg[1] = db->aDb[iDb].zDbSName; + pTab->u.vtab.azArg[1] = db->aDb[iDb].zDbSName; /* Invoke the virtual table constructor */ assert( &db->pVtabCtx ); @@ -629,12 +638,12 @@ static int vtabCallConstructor( int iCol; u16 oooHidden = 0; /* If everything went according to plan, link the new VTable structure - ** into the linked list headed by pTab->pVTable. Then loop through the + ** into the linked list headed by pTab->u.vtab.p. Then loop through the ** columns of the table to see if any of them contain the token "hidden". ** If so, set the Column COLFLAG_HIDDEN flag and remove the token from ** the type string. */ - pVTable->pNext = pTab->pVTable; - pTab->pVTable = pVTable; + pVTable->pNext = pTab->u.vtab.p; + pTab->u.vtab.p = pVTable; for(iCol=0; iColnCol; iCol++){ char *zType = sqlite3ColumnType(&pTab->aCol[iCol], ""); @@ -687,16 +696,17 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ int rc; assert( pTab ); - if( !IsVirtual(pTab) || sqlite3GetVTable(db, pTab) ){ + assert( IsVirtual(pTab) ); + if( sqlite3GetVTable(db, pTab) ){ return SQLITE_OK; } /* Locate the required virtual table module */ - zMod = pTab->azModuleArg[0]; + zMod = pTab->u.vtab.azArg[0]; pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); if( !pMod ){ - const char *zModule = pTab->azModuleArg[0]; + const char *zModule = pTab->u.vtab.azArg[0]; sqlite3ErrorMsg(pParse, "no such module: %s", zModule); rc = SQLITE_ERROR; }else{ @@ -759,10 +769,10 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){ const char *zMod; pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName); - assert( pTab && IsVirtual(pTab) && !pTab->pVTable ); + assert( pTab && IsVirtual(pTab) && !pTab->u.vtab.p ); /* Locate the required virtual table module */ - zMod = pTab->azModuleArg[0]; + zMod = pTab->u.vtab.azArg[0]; pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); /* If the module has been registered and includes a Create method, @@ -799,6 +809,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ Table *pTab; char *zErr = 0; Parse sParse; + int initBusy; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){ @@ -818,17 +829,23 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ memset(&sParse, 0, sizeof(sParse)); sParse.eParseMode = PARSE_MODE_DECLARE_VTAB; sParse.db = db; + /* We should never be able to reach this point while loading the + ** schema. Nevertheless, defend against that (turn off db->init.busy) + ** in case a bug arises. */ + assert( db->init.busy==0 ); + initBusy = db->init.busy; + db->init.busy = 0; sParse.nQueryLoop = 1; if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr) && sParse.pNewTable && !db->mallocFailed - && !sParse.pNewTable->pSelect - && !IsVirtual(sParse.pNewTable) + && IsOrdinaryTable(sParse.pNewTable) ){ if( !pTab->aCol ){ Table *pNew = sParse.pNewTable; Index *pIdx; pTab->aCol = pNew->aCol; + sqlite3ExprListDelete(db, pNew->u.tab.pDfltList); pTab->nNVCol = pTab->nCol = pNew->nCol; pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid); pNew->nCol = 0; @@ -864,6 +881,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ } sqlite3DeleteTable(db, sParse.pNewTable); sqlite3ParserReset(&sParse); + db->init.busy = initBusy; assert( (rc&0xff)==rc ); rc = sqlite3ApiExit(db, rc); @@ -883,10 +901,13 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){ Table *pTab; pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName); - if( pTab!=0 && ALWAYS(pTab->pVTable!=0) ){ + if( ALWAYS(pTab!=0) + && ALWAYS(IsVirtual(pTab)) + && ALWAYS(pTab->u.vtab.p!=0) + ){ VTable *p; int (*xDestroy)(sqlite3_vtab *); - for(p=pTab->pVTable; p; p=p->pNext){ + for(p=pTab->u.vtab.p; p; p=p->pNext){ assert( p->pVtab ); if( p->pVtab->nRef>0 ){ return SQLITE_LOCKED; @@ -900,9 +921,9 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){ rc = xDestroy(p->pVtab); /* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */ if( rc==SQLITE_OK ){ - assert( pTab->pVTable==p && p->pNext==0 ); + assert( pTab->u.vtab.p==p && p->pNext==0 ); p->pVtab = 0; - pTab->pVTable = 0; + pTab->u.vtab.p = 0; sqlite3VtabUnlock(p); } sqlite3DeleteTable(db, pTab); @@ -1116,6 +1137,7 @@ FuncDef *sqlite3VtabOverloadFunction( /* Check to see the left operand is a column in a virtual table */ if( NEVER(pExpr==0) ) return pDef; if( pExpr->op!=TK_COLUMN ) return pDef; + assert( ExprUseYTab(pExpr) ); pTab = pExpr->y.pTab; if( pTab==0 ) return pDef; if( !IsVirtual(pTab) ) return pDef; @@ -1190,8 +1212,9 @@ void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){ /* ** Check to see if virtual table module pMod can be have an eponymous ** virtual table instance. If it can, create one if one does not already -** exist. Return non-zero if the eponymous virtual table instance exists -** when this routine returns, and return zero if it does not exist. +** exist. Return non-zero if either the eponymous virtual table instance +** exists when this routine returns or if an attempt to create it failed +** and an error message was left in pParse. ** ** An eponymous virtual table instance is one that is named after its ** module, and more importantly, does not require a CREATE VIRTUAL TABLE @@ -1218,8 +1241,9 @@ int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){ } pMod->pEpoTab = pTab; pTab->nTabRef = 1; + pTab->eTabType = TABTYP_VTAB; pTab->pSchema = db->aDb[0].pSchema; - assert( pTab->nModuleArg==0 ); + assert( pTab->u.vtab.nArg==0 ); pTab->iPKey = -1; pTab->tabFlags |= TF_Eponymous; addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName)); @@ -1230,7 +1254,6 @@ int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){ sqlite3ErrorMsg(pParse, "%s", zErr); sqlite3DbFree(db, zErr); sqlite3VtabEponymousTableClear(db, pMod); - return 0; } return 1; } diff --git a/src/wal.c b/src/wal.c index c3f84dd2..a0ec9196 100644 --- a/src/wal.c +++ b/src/wal.c @@ -161,7 +161,10 @@ ** HASHTABLE_NPAGE_ONE frames. The values of HASHTABLE_NPAGE_ONE and ** HASHTABLE_NPAGE are selected so that together the wal-index header and ** first index block are the same size as all other index blocks in the -** wal-index. +** wal-index. The values are: +** +** HASHTABLE_NPAGE 4096 +** HASHTABLE_NPAGE_ONE 4062 ** ** Each index block contains two sections, a page-mapping that contains the ** database page number associated with each wal frame, and a hash-table @@ -397,6 +400,70 @@ struct WalCkptInfo { }; #define READMARK_NOT_USED 0xffffffff +/* +** This is a schematic view of the complete 136-byte header of the +** wal-index file (also known as the -shm file): +** +** +-----------------------------+ +** 0: | iVersion | \ +** +-----------------------------+ | +** 4: | (unused padding) | | +** +-----------------------------+ | +** 8: | iChange | | +** +-------+-------+-------------+ | +** 12: | bInit | bBig | szPage | | +** +-------+-------+-------------+ | +** 16: | mxFrame | | First copy of the +** +-----------------------------+ | WalIndexHdr object +** 20: | nPage | | +** +-----------------------------+ | +** 24: | aFrameCksum | | +** | | | +** +-----------------------------+ | +** 32: | aSalt | | +** | | | +** +-----------------------------+ | +** 40: | aCksum | | +** | | / +** +-----------------------------+ +** 48: | iVersion | \ +** +-----------------------------+ | +** 52: | (unused padding) | | +** +-----------------------------+ | +** 56: | iChange | | +** +-------+-------+-------------+ | +** 60: | bInit | bBig | szPage | | +** +-------+-------+-------------+ | Second copy of the +** 64: | mxFrame | | WalIndexHdr +** +-----------------------------+ | +** 68: | nPage | | +** +-----------------------------+ | +** 72: | aFrameCksum | | +** | | | +** +-----------------------------+ | +** 80: | aSalt | | +** | | | +** +-----------------------------+ | +** 88: | aCksum | | +** | | / +** +-----------------------------+ +** 96: | nBackfill | +** +-----------------------------+ +** 100: | 5 read marks | +** | | +** | | +** | | +** | | +** +-------+-------+------+------+ +** 120: | Write | Ckpt | Rcvr | Rd0 | \ +** +-------+-------+------+------+ ) 8 lock bytes +** | Read1 | Read2 | Rd3 | Rd4 | / +** +-------+-------+------+------+ +** 128: | nBackfillAttempted | +** +-----------------------------+ +** 132: | (unused padding) | +** +-----------------------------+ +*/ /* A block of WALINDEX_LOCK_RESERVED bytes beginning at ** WALINDEX_LOCK_OFFSET is reserved for locks. Since some systems @@ -553,9 +620,13 @@ struct WalIterator { ** so. It is safe to enlarge the wal-index if pWal->writeLock is true ** or pWal->exclusiveMode==WAL_HEAPMEMORY_MODE. ** -** If this call is successful, *ppPage is set to point to the wal-index -** page and SQLITE_OK is returned. If an error (an OOM or VFS error) occurs, -** then an SQLite error code is returned and *ppPage is set to 0. +** Three possible result scenarios: +** +** (1) rc==SQLITE_OK and *ppPage==Requested-Wal-Index-Page +** (2) rc>=SQLITE_ERROR and *ppPage==NULL +** (3) rc==SQLITE_OK and *ppPage==NULL // only if iPage==0 +** +** Scenario (3) can only occur when pWal->writeLock is false and iPage==0 */ static SQLITE_NOINLINE int walIndexPageRealloc( Wal *pWal, /* The WAL context */ @@ -588,7 +659,9 @@ static SQLITE_NOINLINE int walIndexPageRealloc( rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ, pWal->writeLock, (void volatile **)&pWal->apWiData[iPage] ); - assert( pWal->apWiData[iPage]!=0 || rc!=SQLITE_OK || pWal->writeLock==0 ); + assert( pWal->apWiData[iPage]!=0 + || rc!=SQLITE_OK + || (pWal->writeLock==0 && iPage==0) ); testcase( pWal->apWiData[iPage]==0 && rc==SQLITE_OK ); if( rc==SQLITE_OK ){ if( iPage>0 && sqlite3FaultSim(600) ) rc = SQLITE_NOMEM; @@ -927,8 +1000,8 @@ struct WalHashLoc { ** slot in the hash table is set to N, it refers to frame number ** (pLoc->iZero+N) in the log. ** -** Finally, set pLoc->aPgno so that pLoc->aPgno[1] is the page number of the -** first frame indexed by the hash table, frame (pLoc->iZero+1). +** Finally, set pLoc->aPgno so that pLoc->aPgno[0] is the page number of the +** first frame indexed by the hash table, frame (pLoc->iZero). */ static int walHashGet( Wal *pWal, /* WAL handle */ @@ -940,7 +1013,7 @@ static int walHashGet( rc = walIndexPage(pWal, iHash, &pLoc->aPgno); assert( rc==SQLITE_OK || iHash>0 ); - if( rc==SQLITE_OK ){ + if( pLoc->aPgno ){ pLoc->aHash = (volatile ht_slot *)&pLoc->aPgno[HASHTABLE_NPAGE]; if( iHash==0 ){ pLoc->aPgno = &pLoc->aPgno[WALINDEX_HDR_SIZE/sizeof(u32)]; @@ -948,7 +1021,8 @@ static int walHashGet( }else{ pLoc->iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE; } - pLoc->aPgno = &pLoc->aPgno[-1]; + }else if( NEVER(rc==SQLITE_OK) ){ + rc = SQLITE_ERROR; } return rc; } @@ -1030,8 +1104,9 @@ static void walCleanupHash(Wal *pWal){ /* Zero the entries in the aPgno array that correspond to frames with ** frame numbers greater than pWal->hdr.mxFrame. */ - nByte = (int)((char *)sLoc.aHash - (char *)&sLoc.aPgno[iLimit+1]); - memset((void *)&sLoc.aPgno[iLimit+1], 0, nByte); + nByte = (int)((char *)sLoc.aHash - (char *)&sLoc.aPgno[iLimit]); + assert( nByte>=0 ); + memset((void *)&sLoc.aPgno[iLimit], 0, nByte); #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT /* Verify that the every entry in the mapping region is still reachable @@ -1040,11 +1115,11 @@ static void walCleanupHash(Wal *pWal){ if( iLimit ){ int j; /* Loop counter */ int iKey; /* Hash key */ - for(j=1; j<=iLimit; j++){ + for(j=0; j=0 ); + memset((void*)sLoc.aPgno, 0, nByte); } /* If the entry in aPgno[] is already set, then the previous writer @@ -1087,9 +1162,9 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ ** Remove the remnants of that writers uncommitted transaction from ** the hash-table before writing any new entries. */ - if( sLoc.aPgno[idx] ){ + if( sLoc.aPgno[idx-1] ){ walCleanupHash(pWal); - assert( !sLoc.aPgno[idx] ); + assert( !sLoc.aPgno[idx-1] ); } /* Write the aPgno[] array entry and the hash-table slot. */ @@ -1097,7 +1172,7 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ for(iKey=walHash(iPage); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){ if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT; } - sLoc.aPgno[idx] = iPage; + sLoc.aPgno[idx-1] = iPage; AtomicStore(&sLoc.aHash[iKey], (ht_slot)idx); #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT @@ -1118,19 +1193,18 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ */ if( (idx&0x3ff)==0 ){ int i; /* Loop counter */ - for(i=1; i<=idx; i++){ + for(i=0; iapWiData[iPg] = aPrivate; for(iFrame=iFirst; iFrame<=iLast; iFrame++){ @@ -1410,14 +1485,43 @@ int sqlite3WalOpen( assert( zWalName && zWalName[0] ); assert( pDbFd ); + /* Verify the values of various constants. Any changes to the values + ** of these constants would result in an incompatible on-disk format + ** for the -shm file. Any change that causes one of these asserts to + ** fail is a backward compatibility problem, even if the change otherwise + ** works. + ** + ** This table also serves as a helpful cross-reference when trying to + ** interpret hex dumps of the -shm file. + */ + assert( 48 == sizeof(WalIndexHdr) ); + assert( 40 == sizeof(WalCkptInfo) ); + assert( 120 == WALINDEX_LOCK_OFFSET ); + assert( 136 == WALINDEX_HDR_SIZE ); + assert( 4096 == HASHTABLE_NPAGE ); + assert( 4062 == HASHTABLE_NPAGE_ONE ); + assert( 8192 == HASHTABLE_NSLOT ); + assert( 383 == HASHTABLE_HASH_1 ); + assert( 32768 == WALINDEX_PGSZ ); + assert( 8 == SQLITE_SHM_NLOCK ); + assert( 5 == WAL_NREADER ); + assert( 24 == WAL_FRAME_HDRSIZE ); + assert( 32 == WAL_HDRSIZE ); + assert( 120 == WALINDEX_LOCK_OFFSET + WAL_WRITE_LOCK ); + assert( 121 == WALINDEX_LOCK_OFFSET + WAL_CKPT_LOCK ); + assert( 122 == WALINDEX_LOCK_OFFSET + WAL_RECOVER_LOCK ); + assert( 123 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(0) ); + assert( 124 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(1) ); + assert( 125 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(2) ); + assert( 126 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(3) ); + assert( 127 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(4) ); + /* In the amalgamation, the os_unix.c and os_win.c source files come before ** this source file. Verify that the #defines of the locking byte offsets ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value. ** For that matter, if the lock offset ever changes from its initial design ** value of 120, we need to know that so there is an assert() to check it. */ - assert( 120==WALINDEX_LOCK_OFFSET ); - assert( 136==WALINDEX_HDR_SIZE ); #ifdef WIN_SHM_BASE assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET ); #endif @@ -1719,7 +1823,6 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){ int nEntry; /* Number of entries in this segment */ ht_slot *aIndex; /* Sorted index for this segment */ - sLoc.aPgno++; if( (i+1)==nSegment ){ nEntry = (int)(iLast - sLoc.iZero); }else{ @@ -2858,7 +2961,8 @@ int sqlite3WalSnapshotRecover(Wal *pWal){ rc = walHashGet(pWal, walFramePage(i), &sLoc); if( rc!=SQLITE_OK ) break; - pgno = sLoc.aPgno[i-sLoc.iZero]; + assert( i - sLoc.iZero - 1 >=0 ); + pgno = sLoc.aPgno[i-sLoc.iZero-1]; iDbOff = (i64)(pgno-1) * szPage; if( iDbOff+szPage<=szDb ){ @@ -3091,7 +3195,7 @@ int sqlite3WalFindFrame( iKey = walHash(pgno); while( (iH = AtomicLoad(&sLoc.aHash[iKey]))!=0 ){ u32 iFrame = iH + sLoc.iZero; - if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH]==pgno ){ + if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH-1]==pgno ){ assert( iFrame>iRead || CORRUPT_DB ); iRead = iFrame; } diff --git a/src/walker.c b/src/walker.c index 8c030847..f24c052d 100644 --- a/src/walker.c +++ b/src/walker.c @@ -75,7 +75,7 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){ assert( !ExprHasProperty(pExpr, EP_WinFunc) ); pExpr = pExpr->pRight; continue; - }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + }else if( ExprUseXSelect(pExpr) ){ assert( !ExprHasProperty(pExpr, EP_WinFunc) ); if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort; }else{ diff --git a/src/where.c b/src/where.c index 5315520d..7a834267 100644 --- a/src/where.c +++ b/src/where.c @@ -286,8 +286,10 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ iColumn = pScan->aiColumn[pScan->iEquiv-1]; iCur = pScan->aiCur[pScan->iEquiv-1]; assert( pWC!=0 ); + assert( iCur>=0 ); do{ for(pTerm=pWC->a+k; knTerm; k++, pTerm++){ + assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 || pTerm->leftCursor<0 ); if( pTerm->leftCursor==iCur && pTerm->u.x.leftColumn==iColumn && (iColumn!=XN_EXPR @@ -329,7 +331,8 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ } } if( (pTerm->eOperator & (WO_EQ|WO_IS))!=0 - && (pX = pTerm->pExpr->pRight)->op==TK_COLUMN + && (pX = pTerm->pExpr->pRight, ALWAYS(pX!=0)) + && pX->op==TK_COLUMN && pX->iTable==pScan->aiCur[0] && pX->iColumn==pScan->aiColumn[0] ){ @@ -726,6 +729,7 @@ static int termCanDriveIndex( return 0; } if( (pTerm->prereqRight & notReady)!=0 ) return 0; + assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); if( pTerm->u.x.leftColumn<0 ) return 0; aff = pSrc->pTab->aCol[pTerm->u.x.leftColumn].affinity; if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0; @@ -798,14 +802,17 @@ static void constructAutomaticIndex( sqlite3ExprDup(pParse->db, pExpr, 0)); } if( termCanDriveIndex(pTerm, pSrc, notReady) ){ - int iCol = pTerm->u.x.leftColumn; - Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); + int iCol; + Bitmask cMask; + assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); + iCol = pTerm->u.x.leftColumn; + cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); testcase( iCol==BMS ); testcase( iCol==BMS-1 ); if( !sentWarning ){ sqlite3_log(SQLITE_WARNING_AUTOINDEX, "automatic index on %s(%s)", pTable->zName, - pTable->aCol[iCol].zName); + pTable->aCol[iCol].zCnName); sentWarning = 1; } if( (idxCols & cMask)==0 ){ @@ -851,8 +858,11 @@ static void constructAutomaticIndex( idxCols = 0; for(pTerm=pWC->a; pTermu.x.leftColumn; - Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); + int iCol; + Bitmask cMask; + assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); + iCol = pTerm->u.x.leftColumn; + cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); testcase( iCol==BMS-1 ); testcase( iCol==BMS ); if( (idxCols & cMask)==0 ){ @@ -979,6 +989,7 @@ static sqlite3_index_info *allocateIndexInfo( testcase( pTerm->eOperator & WO_ALL ); if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; + assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); assert( pTerm->u.x.leftColumn>=(-1) ); nTerm++; } @@ -1039,6 +1050,7 @@ static sqlite3_index_info *allocateIndexInfo( ){ continue; } + assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); assert( pTerm->u.x.leftColumn>=(-1) ); pIdxCons[j].iColumn = pTerm->u.x.leftColumn; pIdxCons[j].iTermOffset = i; @@ -1802,6 +1814,7 @@ void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm){ if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L'; if( pTerm->wtFlags & TERM_CODED ) zType[3] = 'C'; if( pTerm->eOperator & WO_SINGLE ){ + assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); sqlite3_snprintf(sizeof(zLeft),zLeft,"left={%d:%d}", pTerm->leftCursor, pTerm->u.x.leftColumn); }else if( (pTerm->eOperator & WO_OR)!=0 && pTerm->u.pOrInfo!=0 ){ @@ -1819,7 +1832,7 @@ void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm){ sqlite3DebugPrintf(" prob=%-3d prereq=%llx,%llx", pTerm->truthProb, (u64)pTerm->prereqAll, (u64)pTerm->prereqRight); } - if( pTerm->u.x.iField ){ + if( (pTerm->eOperator & (WO_OR|WO_AND))==0 && pTerm->u.x.iField ){ sqlite3DebugPrintf(" iField=%d", pTerm->u.x.iField); } if( pTerm->iParent>=0 ){ @@ -1983,7 +1996,8 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ assert( pWInfo!=0 ); for(i=0; inLevel; i++){ WhereLevel *pLevel = &pWInfo->a[i]; - if( pLevel->pWLoop && (pLevel->pWLoop->wsFlags & WHERE_IN_ABLE) ){ + if( pLevel->pWLoop && (pLevel->pWLoop->wsFlags & WHERE_IN_ABLE)!=0 ){ + assert( (pLevel->pWLoop->wsFlags & WHERE_MULTI_OR)==0 ); sqlite3DbFree(db, pLevel->u.in.aInLoop); } } @@ -2011,7 +2025,8 @@ static void whereUndoExprMods(WhereInfo *pWInfo){ /* ** Return TRUE if all of the following are true: ** -** (1) X has the same or lower cost that Y +** (1) X has the same or lower cost, or returns the same or fewer rows, +** than Y. ** (2) X uses fewer WHERE clause terms than Y ** (3) Every WHERE clause term used by X is also used by Y ** (4) X skips at least as many columns as Y @@ -2034,11 +2049,8 @@ static int whereLoopCheaperProperSubset( if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){ return 0; /* X is not a subset of Y */ } + if( pX->rRun>pY->rRun && pX->nOut>pY->nOut ) return 0; if( pY->nSkip > pX->nSkip ) return 0; - if( pX->rRun >= pY->rRun ){ - if( pX->rRun > pY->rRun ) return 0; /* X costs more than Y */ - if( pX->nOut > pY->nOut ) return 0; /* X costs more than Y */ - } for(i=pX->nLTerm-1; i>=0; i--){ if( pX->aLTerm[i]==0 ) continue; for(j=pY->nLTerm-1; j>=0; j--){ @@ -2054,8 +2066,8 @@ static int whereLoopCheaperProperSubset( } /* -** Try to adjust the cost of WhereLoop pTemplate upwards or downwards so -** that: +** Try to adjust the cost and number of output rows of WhereLoop pTemplate +** upwards or downwards so that: ** ** (1) pTemplate costs less than any other WhereLoops that are a proper ** subset of pTemplate @@ -2076,16 +2088,20 @@ static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){ /* Adjust pTemplate cost downward so that it is cheaper than its ** subset p. */ WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n", - pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut-1)); - pTemplate->rRun = p->rRun; - pTemplate->nOut = p->nOut - 1; + pTemplate->rRun, pTemplate->nOut, + MIN(p->rRun, pTemplate->rRun), + MIN(p->nOut - 1, pTemplate->nOut))); + pTemplate->rRun = MIN(p->rRun, pTemplate->rRun); + pTemplate->nOut = MIN(p->nOut - 1, pTemplate->nOut); }else if( whereLoopCheaperProperSubset(pTemplate, p) ){ /* Adjust pTemplate cost upward so that it is costlier than p since ** pTemplate is a proper subset of p */ WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n", - pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut+1)); - pTemplate->rRun = p->rRun; - pTemplate->nOut = p->nOut + 1; + pTemplate->rRun, pTemplate->nOut, + MAX(p->rRun, pTemplate->rRun), + MAX(p->nOut + 1, pTemplate->nOut))); + pTemplate->rRun = MAX(p->rRun, pTemplate->rRun); + pTemplate->nOut = MAX(p->nOut + 1, pTemplate->nOut); } } } @@ -2416,9 +2432,12 @@ static int whereRangeVectorLen( char aff; /* Comparison affinity */ char idxaff = 0; /* Indexed columns affinity */ CollSeq *pColl; /* Comparison collation sequence */ - Expr *pLhs = pTerm->pExpr->pLeft->x.pList->a[i].pExpr; - Expr *pRhs = pTerm->pExpr->pRight; - if( pRhs->flags & EP_xIsSelect ){ + Expr *pLhs, *pRhs; + + assert( ExprUseXList(pTerm->pExpr->pLeft) ); + pLhs = pTerm->pExpr->pLeft->x.pList->a[i].pExpr; + pRhs = pTerm->pExpr->pRight; + if( ExprUseXSelect(pRhs) ){ pRhs = pRhs->x.pSelect->pEList->a[i].pExpr; }else{ pRhs = pRhs->x.pList->a[i].pExpr; @@ -2579,7 +2598,7 @@ static int whereLoopAddBtreeIndex( if( eOp & WO_IN ){ Expr *pExpr = pTerm->pExpr; - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( ExprUseXSelect(pExpr) ){ /* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */ int i; nIn = 46; assert( 46==sqlite3LogEst(25) ); @@ -2720,7 +2739,7 @@ static int whereLoopAddBtreeIndex( if( nInMul==0 && pProbe->nSample && ALWAYS(pNew->u.btree.nEq<=pProbe->nSampleCol) - && ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect)) + && ((eOp & WO_IN)==0 || ExprUseXList(pTerm->pExpr)) && OptimizationEnabled(db, SQLITE_Stat4) ){ Expr *pExpr = pTerm->pExpr; @@ -2984,7 +3003,6 @@ static int whereLoopAddBtree( int iSortIdx = 1; /* Index number */ int b; /* A boolean value */ LogEst rSize; /* number of rows in the table */ - LogEst rLogSize; /* Logarithm of the number of rows in the table */ WhereClause *pWC; /* The parsed WHERE clause */ Table *pTab; /* Table being queried */ @@ -2997,6 +3015,7 @@ static int whereLoopAddBtree( assert( !IsVirtual(pSrc->pTab) ); if( pSrc->fg.isIndexedBy ){ + assert( pSrc->fg.isCte==0 ); /* An INDEXED BY clause specifies a particular index to use */ pProbe = pSrc->u2.pIBIndex; }else if( !HasRowid(pTab) ){ @@ -3027,7 +3046,6 @@ static int whereLoopAddBtree( pProbe = &sPk; } rSize = pTab->nRowLogEst; - rLogSize = estLog(rSize); #ifndef SQLITE_OMIT_AUTOMATIC_INDEX /* Automatic indexes */ @@ -3041,8 +3059,10 @@ static int whereLoopAddBtree( && !pSrc->fg.isRecursive /* Not a recursive common table expression. */ ){ /* Generate auto-index WhereLoops */ + LogEst rLogSize; /* Logarithm of the number of rows in the table */ WhereTerm *pTerm; WhereTerm *pWCEnd = pWC->a + pWC->nTerm; + rLogSize = estLog(rSize); for(pTerm=pWC->a; rc==SQLITE_OK && pTermprereqRight & pNew->maskSelf ) continue; if( termCanDriveIndex(pTerm, pSrc, 0) ){ @@ -3060,7 +3080,7 @@ static int whereLoopAddBtree( ** those objects, since there is no opportunity to add schema ** indexes on subqueries and views. */ pNew->rSetup = rLogSize + rSize; - if( pTab->pSelect==0 && (pTab->tabFlags & TF_Ephemeral)==0 ){ + if( !IsView(pTab) && (pTab->tabFlags & TF_Ephemeral)==0 ){ pNew->rSetup += 28; }else{ pNew->rSetup -= 10; @@ -4082,7 +4102,7 @@ static i8 wherePathSatisfiesOrderBy( if( obSat==obDone ) return (i8)nOrderBy; if( !isOrderDistinct ){ for(i=nOrderBy-1; i>0; i--){ - Bitmask m = MASKBIT(i) - 1; + Bitmask m = ALWAYS(ipWInfo; if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0; @@ -4605,7 +4626,8 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ pLoop = pBuilder->pNew; pLoop->wsFlags = 0; pLoop->nSkip = 0; - pTerm = sqlite3WhereFindTerm(pWC, iCur, -1, 0, WO_EQ|WO_IS, 0); + pTerm = whereScanInit(&scan, pWC, iCur, -1, WO_EQ|WO_IS, 0); + while( pTerm && pTerm->prereqRight ) pTerm = whereScanNext(&scan); if( pTerm ){ testcase( pTerm->eOperator & WO_IS ); pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW; @@ -4624,7 +4646,8 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ ) continue; opMask = pIdx->uniqNotNull ? (WO_EQ|WO_IS) : WO_EQ; for(j=0; jnKeyCol; j++){ - pTerm = sqlite3WhereFindTerm(pWC, iCur, j, 0, opMask, pIdx); + pTerm = whereScanInit(&scan, pWC, iCur, j, opMask, pIdx); + while( pTerm && pTerm->prereqRight ) pTerm = whereScanNext(&scan); if( pTerm==0 ) break; testcase( pTerm->eOperator & WO_IS ); pLoop->aLTerm[j] = pTerm; @@ -4653,9 +4676,15 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } + if( scan.iEquiv>1 ) pLoop->wsFlags |= WHERE_TRANSCONS; #ifdef SQLITE_DEBUG pLoop->cId = '0'; #endif +#ifdef WHERETRACE_ENABLED + if( sqlite3WhereTrace ){ + sqlite3DebugPrintf("whereShortCut() used to compute solution\n"); + } +#endif return 1; } return 0; @@ -5211,7 +5240,7 @@ WhereInfo *sqlite3WhereBegin( pTab = pTabItem->pTab; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); pLoop = pLevel->pWLoop; - if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ){ + if( (pTab->tabFlags & TF_Ephemeral)!=0 || IsView(pTab) ){ /* Do nothing */ }else #ifndef SQLITE_OMIT_VIRTUALTABLE @@ -5336,6 +5365,7 @@ WhereInfo *sqlite3WhereBegin( for(ii=0; iinErr ) goto whereBeginError; pLevel = &pWInfo->a[ii]; wsFlags = pLevel->pWLoop->wsFlags; #ifndef SQLITE_OMIT_AUTOMATIC_INDEX @@ -5457,7 +5487,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ }else{ sqlite3VdbeResolveLabel(v, pLevel->addrCont); } - if( pLoop->wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){ + if( (pLoop->wsFlags & WHERE_IN_ABLE)!=0 && pLevel->u.in.nIn>0 ){ struct InLoop *pIn; int j; sqlite3VdbeResolveLabel(v, pLevel->addrNxt); @@ -5526,8 +5556,14 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur); } if( (ws & WHERE_INDEXED) - || ((ws & WHERE_MULTI_OR) && pLevel->u.pCovidx) + || ((ws & WHERE_MULTI_OR) && pLevel->u.pCoveringIdx) ){ + if( ws & WHERE_MULTI_OR ){ + Index *pIx = pLevel->u.pCoveringIdx; + int iDb = sqlite3SchemaToIndex(db, pIx->pSchema); + sqlite3VdbeAddOp3(v, OP_ReopenIdx, pLevel->iIdxCur, pIx->tnum, iDb); + sqlite3VdbeSetP4KeyInfo(pParse, pIx); + } sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iIdxCur); } if( pLevel->op==OP_Return ){ @@ -5574,7 +5610,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ ** created for the ONEPASS optimization. */ if( (pTab->tabFlags & TF_Ephemeral)==0 - && pTab->pSelect==0 + && !IsView(pTab) && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){ int ws = pLoop->wsFlags; @@ -5604,7 +5640,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ if( pLoop->wsFlags & (WHERE_INDEXED|WHERE_IDX_ONLY) ){ pIdx = pLoop->u.btree.pIndex; }else if( pLoop->wsFlags & WHERE_MULTI_OR ){ - pIdx = pLevel->u.pCovidx; + pIdx = pLevel->u.pCoveringIdx; } if( pIdx && !db->mallocFailed diff --git a/src/whereInt.h b/src/whereInt.h index c5dd83cc..f651e790 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -78,7 +78,7 @@ struct WhereLevel { u8 eEndLoopOp; /* IN Loop terminator. OP_Next or OP_Prev */ } *aInLoop; /* Information about each nested IN operator */ } in; /* Used when pWLoop->wsFlags&WHERE_IN_ABLE */ - Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */ + Index *pCoveringIdx; /* Possible covering index for WHERE_MULTI_OR */ } u; struct WhereLoop *pWLoop; /* The selected WhereLoop object */ Bitmask notReady; /* FROM entries not usable at this level */ diff --git a/src/wherecode.c b/src/wherecode.c index 84fa1a14..460ac4fe 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -29,7 +29,7 @@ static const char *explainIndexColumnName(Index *pIdx, int i){ i = pIdx->aiColumn[i]; if( i==XN_EXPR ) return ""; if( i==XN_ROWID ) return "rowid"; - return pIdx->pTable->aCol[i].zName; + return pIdx->pTable->aCol[i].zCnName; } /* @@ -416,16 +416,23 @@ static Expr *removeUnindexableInClauseTerms( Expr *pNew; pNew = sqlite3ExprDup(db, pX, 0); if( db->mallocFailed==0 ){ - ExprList *pOrigRhs = pNew->x.pSelect->pEList; /* Original unmodified RHS */ - ExprList *pOrigLhs = pNew->pLeft->x.pList; /* Original unmodified LHS */ + 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 = pLoop->aLTerm[i]->u.x.iField - 1; + 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; @@ -540,7 +547,7 @@ static int codeEqualityTerm( } iTab = 0; - if( (pX->flags & EP_xIsSelect)==0 || pX->x.pSelect->pEList->nExpr==1 ){ + if( !ExprUseXSelect(pX) || pX->x.pSelect->pEList->nExpr==1 ){ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0, &iTab); }else{ sqlite3 *db = pParse->db; @@ -562,8 +569,8 @@ static int codeEqualityTerm( sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0); VdbeCoverageIf(v, bRev); VdbeCoverageIf(v, !bRev); - assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 ); + assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 ); pLoop->wsFlags |= WHERE_IN_ABLE; if( pLevel->u.in.nIn==0 ){ pLevel->addrNxt = sqlite3VdbeMakeLabel(pParse); @@ -1105,7 +1112,7 @@ static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){ assert( nReg>0 ); if( p && sqlite3ExprIsVector(p) ){ #ifndef SQLITE_OMIT_SUBQUERY - if( (p->flags & EP_xIsSelect) ){ + if( ExprUseXSelect(p) ){ Vdbe *v = pParse->pVdbe; int iSelect; assert( p->op==TK_SELECT ); @@ -1115,7 +1122,9 @@ static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){ #endif { int i; - ExprList *pList = p->x.pList; + const ExprList *pList; + assert( ExprUseXList(p) ); + pList = p->x.pList; assert( nReg<=pList->nExpr ); for(i=0; ia[i].pExpr, iReg+i); @@ -1168,10 +1177,10 @@ static int whereIndexExprTransNode(Walker *p, Expr *pExpr){ pExpr->op = TK_COLUMN; pExpr->iTable = pX->iIdxCur; pExpr->iColumn = pX->iIdxCol; - pExpr->y.pTab = 0; testcase( ExprHasProperty(pExpr, EP_Skip) ); testcase( ExprHasProperty(pExpr, EP_Unlikely) ); - ExprClearProperty(pExpr, EP_Skip|EP_Unlikely); + ExprClearProperty(pExpr, EP_Skip|EP_Unlikely|EP_WinFunc|EP_Subrtn); + pExpr->y.pTab = 0; return WRC_Prune; }else{ return WRC_Continue; @@ -1186,7 +1195,7 @@ static int whereIndexExprTransColumn(Walker *p, Expr *pExpr){ if( pExpr->op==TK_COLUMN ){ IdxExprTrans *pX = p->u.pIdxTrans; if( pExpr->iTable==pX->iTabCur && pExpr->iColumn==pX->iTabCol ){ - assert( pExpr->y.pTab!=0 ); + assert( ExprUseYTab(pExpr) && pExpr->y.pTab!=0 ); preserveExpr(pX, pExpr); pExpr->affExpr = sqlite3TableColumnAffinity(pExpr->y.pTab,pExpr->iColumn); pExpr->iTable = pX->iIdxCur; @@ -1234,15 +1243,16 @@ static void whereIndexExprTrans( for(iIdxCol=0; iIdxColnColumn; iIdxCol++){ i16 iRef = pIdx->aiColumn[iIdxCol]; if( iRef==XN_EXPR ){ - assert( aColExpr->a[iIdxCol].pExpr!=0 ); + assert( aColExpr!=0 && aColExpr->a[iIdxCol].pExpr!=0 ); x.pIdxExpr = aColExpr->a[iIdxCol].pExpr; if( sqlite3ExprIsConstant(x.pIdxExpr) ) continue; w.xExprCallback = whereIndexExprTransNode; #ifndef SQLITE_OMIT_GENERATED_COLUMNS }else if( iRef>=0 && (pTab->aCol[iRef].colFlags & COLFLAG_VIRTUAL)!=0 - && (pTab->aCol[iRef].zColl==0 - || sqlite3StrICmp(pTab->aCol[iRef].zColl, sqlite3StrBINARY)==0) + && ((pTab->aCol[iRef].colFlags & COLFLAG_HASCOLL)==0 + || sqlite3StrICmp(sqlite3ColumnColl(&pTab->aCol[iRef]), + sqlite3StrBINARY)==0) ){ /* Check to see if there are direct references to generated columns ** that are contained in the index. Pulling the generated column @@ -1422,7 +1432,12 @@ Bitmask sqlite3WhereCodeOneLoopStart( pLevel->p1 = iCur; pLevel->op = pWInfo->eOnePass ? OP_Noop : OP_VNext; pLevel->p2 = sqlite3VdbeCurrentAddr(v); - iIn = pLevel->u.in.nIn; + assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 ); + if( pLoop->wsFlags & WHERE_IN_ABLE ){ + iIn = pLevel->u.in.nIn; + }else{ + iIn = 0; + } for(j=nConstraint-1; j>=0; j--){ pTerm = pLoop->aLTerm[j]; if( (pTerm->eOperator & WO_IN)!=0 ) iIn--; @@ -1499,9 +1514,6 @@ Bitmask sqlite3WhereCodeOneLoopStart( sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg); VdbeCoverage(v); pLevel->op = OP_Noop; - if( (pTerm->prereqAll & pLevel->notReady)==0 ){ - pTerm->wtFlags |= TERM_CODED; - } }else if( (pLoop->wsFlags & WHERE_IPK)!=0 && (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0 ){ @@ -1872,8 +1884,19 @@ Bitmask sqlite3WhereCodeOneLoopStart( ** range (if any). */ nConstraint = nEq; + assert( pLevel->p2==0 ); if( pRangeEnd ){ Expr *pRight = pRangeEnd->pExpr->pRight; + 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 @@ -1907,7 +1930,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( sqlite3DbFree(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 ){ @@ -2314,7 +2337,10 @@ Bitmask sqlite3WhereCodeOneLoopStart( } } ExplainQueryPlanPop(pParse); - pLevel->u.pCovidx = pCov; + assert( pLevel->pWLoop==pLoop ); + assert( (pLoop->wsFlags & WHERE_MULTI_OR)!=0 ); + assert( (pLoop->wsFlags & WHERE_IN_ABLE)==0 ); + pLevel->u.pCoveringIdx = pCov; if( pCov ) pLevel->iIdxCur = iCovCur; if( pAndExpr ){ pAndExpr->pLeft = 0; @@ -2458,12 +2484,13 @@ Bitmask sqlite3WhereCodeOneLoopStart( #endif assert( !ExprHasProperty(pE, EP_FromJoin) ); assert( (pTerm->prereqRight & pLevel->notReady)!=0 ); + assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.x.leftColumn, notReady, WO_EQ|WO_IN|WO_IS, 0); if( pAlt==0 ) continue; if( pAlt->wtFlags & (TERM_CODED) ) continue; if( (pAlt->eOperator & WO_IN) - && (pAlt->pExpr->flags & EP_xIsSelect) + && ExprUseXSelect(pAlt->pExpr) && (pAlt->pExpr->x.pSelect->pEList->nExpr>1) ){ continue; diff --git a/src/whereexpr.c b/src/whereexpr.c index 31f2ea43..53dd1403 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -195,6 +195,7 @@ static int isLikeOrGlob( #ifdef SQLITE_EBCDIC if( *pnoCase ) return 0; #endif + assert( ExprUseXList(pExpr) ); pList = pExpr->x.pList; pLeft = pList->a[1].pExpr; @@ -210,7 +211,8 @@ static int isLikeOrGlob( sqlite3VdbeSetVarmask(pParse->pVdbe, iCol); assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER ); }else if( op==TK_STRING ){ - z = (u8*)pRight->u.zToken; + assert( !ExprHasProperty(pRight, EP_IntValue) ); + z = (u8*)pRight->u.zToken; } if( z ){ @@ -239,7 +241,9 @@ static int isLikeOrGlob( pPrefix = sqlite3Expr(db, TK_STRING, (char*)z); if( pPrefix ){ int iFrom, iTo; - char *zNew = pPrefix->u.zToken; + char *zNew; + assert( !ExprHasProperty(pPrefix, EP_IntValue) ); + zNew = pPrefix->u.zToken; zNew[cnt] = 0; for(iFrom=iTo=0; iFromop!=TK_COLUMN || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT - || IsVirtual(pLeft->y.pTab) /* Value might be numeric */ + || (ALWAYS( ExprUseYTab(pLeft) ) + && pLeft->y.pTab + && IsVirtual(pLeft->y.pTab)) /* Might be numeric */ ){ int isNum; double rDummy; @@ -291,6 +297,7 @@ static int isLikeOrGlob( if( op==TK_VARIABLE ){ Vdbe *v = pParse->pVdbe; sqlite3VdbeSetVarmask(v, pRight->iColumn); + assert( !ExprHasProperty(pRight, EP_IntValue) ); if( *pisComplete && pRight->u.zToken[1] ){ /* If the rhs of the LIKE expression is a variable, and the current ** value of the variable means there is no need to invoke the LIKE @@ -364,6 +371,7 @@ static int isAuxiliaryVtabOperator( Expr *pCol; /* Column reference */ int i; + assert( ExprUseXList(pExpr) ); pList = pExpr->x.pList; if( pList==0 || pList->nExpr!=2 ){ return 0; @@ -377,9 +385,11 @@ static int isAuxiliaryVtabOperator( ** MATCH(expression,vtab_column) */ pCol = pList->a[1].pExpr; + assert( pCol->op!=TK_COLUMN || ExprUseYTab(pCol) ); testcase( pCol->op==TK_COLUMN && pCol->y.pTab==0 ); if( ExprIsVtab(pCol) ){ for(i=0; iu.zToken, aOp[i].zOp)==0 ){ *peOp2 = aOp[i].eOp2; *ppRight = pList->a[0].pExpr; @@ -400,6 +410,7 @@ static int isAuxiliaryVtabOperator( ** with function names in an arbitrary case. */ pCol = pList->a[0].pExpr; + assert( pCol->op!=TK_COLUMN || ExprUseYTab(pCol) ); testcase( pCol->op==TK_COLUMN && pCol->y.pTab==0 ); if( ExprIsVtab(pCol) ){ sqlite3_vtab *pVtab; @@ -409,7 +420,8 @@ static int isAuxiliaryVtabOperator( pVtab = sqlite3GetVTable(db, pCol->y.pTab)->pVtab; assert( pVtab!=0 ); assert( pVtab->pModule!=0 ); - pMod = (sqlite3_module *)pVtab->pModule; + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + pMod = (sqlite3_module *)pVtab->pModule; if( pMod->xFindFunction!=0 ){ i = pMod->xFindFunction(pVtab,2, pExpr->u.zToken, &xNotUsed, &pNotUsed); if( i>=SQLITE_INDEX_CONSTRAINT_FUNCTION ){ @@ -424,10 +436,12 @@ static int isAuxiliaryVtabOperator( int res = 0; Expr *pLeft = pExpr->pLeft; Expr *pRight = pExpr->pRight; + assert( pLeft->op!=TK_COLUMN || ExprUseYTab(pLeft) ); testcase( pLeft->op==TK_COLUMN && pLeft->y.pTab==0 ); if( ExprIsVtab(pLeft) ){ res++; } + assert( pRight==0 || pRight->op!=TK_COLUMN || ExprUseYTab(pRight) ); testcase( pRight && pRight->op==TK_COLUMN && pRight->y.pTab==0 ); if( pRight && ExprIsVtab(pRight) ){ res++; @@ -680,6 +694,7 @@ static void exprAnalyzeOrTerm( pOrTerm->u.pAndInfo = pAndInfo; pOrTerm->wtFlags |= TERM_ANDINFO; pOrTerm->eOperator = WO_AND; + pOrTerm->leftCursor = -1; pAndWC = &pAndInfo->wc; memset(pAndWC->aStatic, 0, sizeof(pAndWC->aStatic)); sqlite3WhereClauseInit(pAndWC, pWC->pWInfo); @@ -722,11 +737,10 @@ static void exprAnalyzeOrTerm( ** empty. */ pOrInfo->indexable = indexable; + pTerm->eOperator = WO_OR; + pTerm->leftCursor = -1; if( indexable ){ - pTerm->eOperator = WO_OR; pWC->hasOr = 1; - }else{ - pTerm->eOperator = WO_OR; } /* For a two-way OR, attempt to implementation case 2. @@ -799,6 +813,7 @@ static void exprAnalyzeOrTerm( assert( pOrTerm->wtFlags & (TERM_COPIED|TERM_VIRTUAL) ); continue; } + assert( (pOrTerm->eOperator & (WO_OR|WO_AND))==0 ); iColumn = pOrTerm->u.x.leftColumn; iCursor = pOrTerm->leftCursor; pLeft = pOrTerm->pExpr->pLeft; @@ -819,6 +834,7 @@ static void exprAnalyzeOrTerm( okToChngToIN = 1; for(; i>=0 && okToChngToIN; i--, pOrTerm++){ assert( pOrTerm->eOperator & WO_EQ ); + assert( (pOrTerm->eOperator & (WO_OR|WO_AND))==0 ); if( pOrTerm->leftCursor!=iCursor ){ pOrTerm->wtFlags &= ~TERM_OR_OK; }else if( pOrTerm->u.x.leftColumn!=iColumn || (iColumn==XN_EXPR @@ -855,6 +871,7 @@ static void exprAnalyzeOrTerm( for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){ if( (pOrTerm->wtFlags & TERM_OR_OK)==0 ) continue; assert( pOrTerm->eOperator & WO_EQ ); + assert( (pOrTerm->eOperator & (WO_OR|WO_AND))==0 ); assert( pOrTerm->leftCursor==iCursor ); assert( pOrTerm->u.x.leftColumn==iColumn ); pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0); @@ -867,7 +884,7 @@ static void exprAnalyzeOrTerm( if( pNew ){ int idxNew; transferJoinMarkings(pNew, pExpr); - assert( !ExprHasProperty(pNew, EP_xIsSelect) ); + assert( ExprUseXList(pNew) ); pNew->x.pList = pList; idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew==0 ); @@ -995,6 +1012,7 @@ static int exprMightBeIndexed( assert( TK_ISop==TK_VECTOR && (op>=TK_GT && ALWAYS(op<=TK_GE)) ){ + assert( ExprUseXList(pExpr) ); pExpr = pExpr->x.pList->a[0].pExpr; } @@ -1061,7 +1079,7 @@ static void exprAnalyze( if( op==TK_IN ){ assert( pExpr->pRight==0 ); if( sqlite3ExprCheckIN(pParse, pExpr) ) return; - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( ExprUseXSelect(pExpr) ){ pTerm->prereqRight = exprSelectUsage(pMaskSet, pExpr->x.pSelect); }else{ pTerm->prereqRight = sqlite3WhereExprListUsage(pMaskSet, pExpr->x.pList); @@ -1097,11 +1115,13 @@ static void exprAnalyze( if( pTerm->u.x.iField>0 ){ assert( op==TK_IN ); assert( pLeft->op==TK_VECTOR ); + assert( ExprUseXList(pLeft) ); pLeft = pLeft->x.pList->a[pTerm->u.x.iField-1].pExpr; } 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; } @@ -1139,12 +1159,18 @@ static void exprAnalyze( } pNew->wtFlags |= exprCommute(pParse, pDup); pNew->leftCursor = aiCurCol[0]; + assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); pNew->u.x.leftColumn = aiCurCol[1]; testcase( (prereqLeft | extraRight) != prereqLeft ); pNew->prereqRight = prereqLeft | extraRight; pNew->prereqAll = prereqAll; pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask; - }else if( op==TK_ISNULL && 0==sqlite3ExprCanBeNull(pLeft) ){ + }else + if( op==TK_ISNULL + && !ExprHasProperty(pExpr,EP_FromJoin) + && 0==sqlite3ExprCanBeNull(pLeft) + ){ + assert( !ExprHasProperty(pExpr, EP_IntValue) ); pExpr->op = TK_TRUEFALSE; pExpr->u.zToken = "false"; ExprSetProperty(pExpr, EP_IsFalse); @@ -1170,9 +1196,11 @@ static void exprAnalyze( ** BETWEEN term is skipped. */ else if( pExpr->op==TK_BETWEEN && pWC->op==TK_AND ){ - ExprList *pList = pExpr->x.pList; + ExprList *pList; int i; static const u8 ops[] = {TK_GE, TK_LE}; + assert( ExprUseXList(pExpr) ); + pList = pExpr->x.pList; assert( pList!=0 ); assert( pList->nExpr==2 ); for(i=0; i<2; i++){ @@ -1265,8 +1293,12 @@ static void exprAnalyze( const char *zCollSeqName; /* Name of collating sequence */ const u16 wtFlags = TERM_LIKEOPT | TERM_VIRTUAL | TERM_DYNAMIC; + assert( ExprUseXList(pExpr) ); pLeft = pExpr->x.pList->a[1].pExpr; pStr2 = sqlite3ExprDup(db, pStr1, 0); + assert( pStr1==0 || !ExprHasProperty(pStr1, EP_IntValue) ); + assert( pStr2==0 || !ExprHasProperty(pStr2, EP_IntValue) ); + /* Convert the lower bound to upper-case and the upper bound to ** lower-case (upper-case is less than lower-case in ASCII) so that @@ -1341,8 +1373,8 @@ static void exprAnalyze( for(i=0; ipLeft, i); - Expr *pRight = sqlite3ExprForVectorField(pParse, pExpr->pRight, i); + Expr *pLeft = sqlite3ExprForVectorField(pParse, pExpr->pLeft, i, nLeft); + Expr *pRight = sqlite3ExprForVectorField(pParse, pExpr->pRight, i, nLeft); pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight); transferJoinMarkings(pNew, pExpr); @@ -1366,6 +1398,7 @@ static void exprAnalyze( else if( pExpr->op==TK_IN && pTerm->u.x.iField==0 && pExpr->pLeft->op==TK_VECTOR + && ALWAYS( ExprUseXSelect(pExpr) ) && pExpr->x.pSelect->pPrior==0 #ifndef SQLITE_OMIT_WINDOWFUNC && pExpr->x.pSelect->pWin==0 @@ -1529,14 +1562,15 @@ Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){ if( p->pRight ){ mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pRight); assert( p->x.pList==0 ); - }else if( ExprHasProperty(p, EP_xIsSelect) ){ + }else if( ExprUseXSelect(p) ){ if( ExprHasProperty(p, EP_VarSelect) ) pMaskSet->bVarSelect = 1; mask |= exprSelectUsage(pMaskSet, p->x.pSelect); }else if( p->x.pList ){ mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList); } #ifndef SQLITE_OMIT_WINDOWFUNC - if( (p->op==TK_FUNCTION || p->op==TK_AGG_FUNCTION) && p->y.pWin ){ + if( (p->op==TK_FUNCTION || p->op==TK_AGG_FUNCTION) && ExprUseYWin(p) ){ + assert( p->y.pWin!=0 ); mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pPartition); mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pOrderBy); mask |= sqlite3WhereExprUsage(pMaskSet, p->y.pWin->pFilter); @@ -1611,6 +1645,7 @@ void sqlite3WhereTabFuncArgs( if( pColRef==0 ) return; pColRef->iTable = pItem->iCursor; pColRef->iColumn = k++; + assert( ExprUseYTab(pColRef) ); pColRef->y.pTab = pTab; pRhs = sqlite3PExpr(pParse, TK_UPLUS, sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0); diff --git a/src/window.c b/src/window.c index 2afa7c12..d7c412a3 100644 --- a/src/window.c +++ b/src/window.c @@ -581,7 +581,7 @@ static void noopValueFunc(sqlite3_context *p){ UNUSED_PARAMETER(p); /*no-op*/ } /* Window functions that use all window interfaces: xStep, xFinal, ** xValue, and xInverse */ #define WINDOWFUNCALL(name,nArg,extra) { \ - nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ + nArg, (SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ name ## StepFunc, name ## FinalizeFunc, name ## ValueFunc, \ name ## InvFunc, name ## Name, {0} \ } @@ -589,7 +589,7 @@ static void noopValueFunc(sqlite3_context *p){ UNUSED_PARAMETER(p); /*no-op*/ } /* Window functions that are implemented using bytecode and thus have ** no-op routines for their methods */ #define WINDOWFUNCNOOP(name,nArg,extra) { \ - nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ + nArg, (SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ noopStepFunc, noopValueFunc, noopValueFunc, \ noopStepFunc, name ## Name, {0} \ } @@ -598,7 +598,7 @@ static void noopValueFunc(sqlite3_context *p){ UNUSED_PARAMETER(p); /*no-op*/ } ** same routine for xFinalize and xValue and which never call ** xInverse. */ #define WINDOWFUNCX(name,nArg,extra) { \ - nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ + nArg, (SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ name ## StepFunc, name ## ValueFunc, name ## ValueFunc, \ noopStepFunc, name ## Name, {0} \ } @@ -908,9 +908,7 @@ static ExprList *exprListAppendList( if( bIntToNull ){ int iDummy; Expr *pSub; - for(pSub=pDup; ExprHasProperty(pSub, EP_Skip); pSub=pSub->pLeft){ - assert( pSub ); - } + pSub = sqlite3ExprSkipCollateAndLikely(pDup); if( sqlite3ExprIsInteger(pSub, &iDummy) ){ pSub->op = TK_NULL; pSub->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse); @@ -943,7 +941,8 @@ static int sqlite3WindowExtraAggFuncDepth(Walker *pWalker, Expr *pExpr){ static int disallowAggregatesInOrderByCb(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_AGG_FUNCTION && pExpr->pAggInfo==0 ){ - sqlite3ErrorMsg(pWalker->pParse, + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + sqlite3ErrorMsg(pWalker->pParse, "misuse of aggregate: %s()", pExpr->u.zToken); } return WRC_Continue; @@ -1031,7 +1030,9 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){ ** window function - one for the accumulator, another for interim ** results. */ for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ - ExprList *pArgs = pWin->pOwner->x.pList; + ExprList *pArgs; + assert( ExprUseXList(pWin->pOwner) ); + pArgs = pWin->pOwner->x.pList; if( pWin->pFunc->funcFlags & SQLITE_FUNC_SUBTYPE ){ selectWindowRewriteEList(pParse, pMWin, pSrc, pArgs, pTab, &pSublist); pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); @@ -1068,11 +1069,14 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){ ("New window-function subquery in FROM clause of (%u/%p)\n", p->selId, p)); p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); + assert( pSub!=0 || p->pSrc==0 ); /* Due to db->mallocFailed test inside + ** of sqlite3DbMallocRawNN() called from + ** sqlite3SrcListAppend() */ if( p->pSrc ){ Table *pTab2; p->pSrc->a[0].pSelect = pSub; sqlite3SrcListAssignCursors(pParse, p->pSrc); - pSub->selFlags |= SF_Expanded; + pSub->selFlags |= SF_Expanded|SF_OrderByReqd; pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE); pSub->selFlags |= (selFlags & SF_Aggregate); if( pTab2==0 ){ @@ -1095,7 +1099,11 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){ sqlite3SelectDelete(db, pSub); } if( db->mallocFailed ) rc = SQLITE_NOMEM; - sqlite3DbFree(db, pTab); + + /* Defer deleting the temporary table pTab because if an error occurred, + ** there could still be references to that table embedded in the + ** result-set or ORDER BY clause of the SELECT statement p. */ + sqlite3ParserAddCleanup(pParse, sqlite3DbFree, pTab); } if( rc ){ @@ -1344,7 +1352,12 @@ void sqlite3WindowLink(Select *pSel, Window *pWin){ ** different, or 2 if it cannot be determined if the objects are identical ** or not. Identical window objects can be processed in a single scan. */ -int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2, int bFilter){ +int sqlite3WindowCompare( + const Parse *pParse, + const Window *p1, + const Window *p2, + int bFilter +){ int res; if( NEVER(p1==0) || NEVER(p2==0) ) return 1; if( p1->eFrmType!=p2->eFrmType ) return 1; @@ -1416,8 +1429,11 @@ void sqlite3WindowCodeInit(Parse *pParse, Select *pSelect){ ** regApp+1: integer value used to ensure keys are unique ** regApp+2: output of MakeRecord */ - ExprList *pList = pWin->pOwner->x.pList; - KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pList, 0, 0); + ExprList *pList; + KeyInfo *pKeyInfo; + assert( ExprUseXList(pWin->pOwner) ); + pList = pWin->pOwner->x.pList; + pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pList, 0, 0); pWin->csrApp = pParse->nTab++; pWin->regApp = pParse->nMem+1; pParse->nMem += 3; @@ -1505,7 +1521,9 @@ static void windowCheckValue(Parse *pParse, int reg, int eCond){ ** with the object passed as the only argument to this function. */ static int windowArgCount(Window *pWin){ - ExprList *pList = pWin->pOwner->x.pList; + const ExprList *pList; + assert( ExprUseXList(pWin->pOwner) ); + pList = pWin->pOwner->x.pList; return (pList ? pList->nExpr : 0); } @@ -1690,6 +1708,7 @@ static void windowAggStep( int addrIf = 0; if( pWin->pFilter ){ int regTmp; + assert( ExprUseXList(pWin->pOwner) ); assert( pWin->bExprArgs || !nArg ||nArg==pWin->pOwner->x.pList->nExpr ); assert( pWin->bExprArgs || nArg ||pWin->pOwner->x.pList==0 ); regTmp = sqlite3GetTempReg(pParse); @@ -1703,6 +1722,7 @@ static void windowAggStep( int iOp = sqlite3VdbeCurrentAddr(v); int iEnd; + assert( ExprUseXList(pWin->pOwner) ); nArg = pWin->pOwner->x.pList->nExpr; regArg = sqlite3GetTempRange(pParse, nArg); sqlite3ExprCodeExprList(pParse, pWin->pOwner->x.pList, regArg, 0, 0); @@ -1717,6 +1737,7 @@ static void windowAggStep( if( pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ CollSeq *pColl; assert( nArg>0 ); + assert( ExprUseXList(pWin->pOwner) ); pColl = sqlite3ExprNNCollSeq(pParse, pWin->pOwner->x.pList->a[0].pExpr); sqlite3VdbeAddOp4(v, OP_CollSeq, 0,0,0, (const char*)pColl, P4_COLLSEQ); } @@ -1902,6 +1923,7 @@ static void windowReturnOneRow(WindowCodeArg *p){ for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ FuncDef *pFunc = pWin->pFunc; + assert( ExprUseXList(pWin->pOwner) ); if( pFunc->zName==nth_valueName || pFunc->zName==first_valueName ){ diff --git a/test/aggnested.test b/test/aggnested.test index dcb1f95c..35d5f1e3 100644 --- a/test/aggnested.test +++ b/test/aggnested.test @@ -306,6 +306,48 @@ do_execsql_test 5.5 { b, b; } +#------------------------------------------------------------------------- +# dbsqlfuzz a779227f721a834df95f4f42d0c31550a1f8b8a2 +# +reset_db +do_execsql_test 6.0 { + CREATE TABLE t1(a); + CREATE TABLE t2(b); + + INSERT INTO t1 VALUES('x'); + INSERT INTO t2 VALUES(1); +} + +do_execsql_test 6.1.1 { + SELECT ( + SELECT t2.b FROM (SELECT t2.b AS c FROM t1) GROUP BY 1 HAVING t2.b + ) + FROM t2 GROUP BY 'constant_string'; +} {1} +do_execsql_test 6.1.2 { + SELECT ( + SELECT c FROM (SELECT t2.b AS c FROM t1) GROUP BY c HAVING t2.b + ) + FROM t2 GROUP BY 'constant_string'; +} {1} + +do_execsql_test 6.2.0 { + UPDATE t2 SET b=0 +} +do_execsql_test 6.2.1 { + SELECT ( + SELECT t2.b FROM (SELECT t2.b AS c FROM t1) GROUP BY 1 HAVING t2.b + ) + FROM t2 GROUP BY 'constant_string'; +} {{}} +do_execsql_test 6.2.2 { + SELECT ( + SELECT c FROM (SELECT t2.b AS c FROM t1) GROUP BY c HAVING t2.b + ) + FROM t2 GROUP BY 'constant_string'; +} {{}} + + diff --git a/test/alter.test b/test/alter.test index 634e318e..0088858a 100644 --- a/test/alter.test +++ b/test/alter.test @@ -915,4 +915,24 @@ do_catchsql_test alter-18.1 { ALTER TABLE log RENAME COLUMN a TO x; } {1 {error in trigger tr1: no such table: main.logx}} +# 2021-10-13 dbsqlfuzz e89174cbfad2d904f06b5e24df0a22510b6a1c1e +reset_db +do_execsql_test alter-19.1 { + CREATE TABLE t1(x); + CREATE TABLE t2(c); + CREATE TRIGGER r1 AFTER INSERT ON t2 BEGIN + UPDATE t2 SET (c)=( + EXISTS(SELECT 1 WHERE (WITH cte1(a) AS (SELECT 1 FROM t1 WHERE (SELECT 1 WHERE (WITH cte2(b) AS (VALUES(1))SELECT b FROM cte2)))SELECT a FROM cte1)) + ); + END; + ALTER TABLE t2 RENAME TO t3; +} {} +do_execsql_test alter-19.2 { + SELECT name FROM sqlite_schema WHERE sql LIKE '%t2%'; +} {} +do_execsql_test alter-19.3 { + SELECT name FROM sqlite_schema WHERE sql LIKE '%t3%' ORDER BY name; +} {r1 t3} + + finish_test diff --git a/test/alter3.test b/test/alter3.test index 30bc1cbb..c6f26b0c 100644 --- a/test/alter3.test +++ b/test/alter3.test @@ -13,8 +13,6 @@ # file format change that may be used in the future to implement # "ALTER TABLE ... ADD COLUMN". # -# $Id: alter3.test,v 1.11 2008/03/19 00:21:31 drh Exp $ -# set testdir [file dirname $argv0] @@ -395,4 +393,51 @@ do_test alter3-8.2 { } } [list $::sql] +# 2021-07-20: Add support for detecting CHECK and NOT NULL constraint +# violations in ALTER TABLE ADD COLUMN +# +reset_db +do_execsql_test alter3-9.1 { + CREATE TABLE t1(a,b); + INSERT INTO t1 VALUES(1, 2), ('null!',NULL), (3,4); +} {} +do_catchsql_test alter3-9.2 { + ALTER TABLE t1 ADD COLUMN c CHECK(a!=1); +} {1 {CHECK constraint failed}} +do_catchsql_test alter3-9.3 { + ALTER TABLE t1 ADD COLUMN c CHECK(a!=3); +} {1 {CHECK constraint failed}} +do_catchsql_test alter3-9.4 { + ALTER TABLE t1 ADD COLUMN c CHECK(a!=2); +} {0 {}} +do_catchsql_test alter3-9.5 { + ALTER TABLE t1 ADD COLUMN d AS (b+1) NOT NULL; +} {1 {NOT NULL constraint failed}} +do_catchsql_test alter3-9.6 { + ALTER TABLE t1 ADD COLUMN d AS (b+1) NOT NULL CHECK(a!=1); +} {1 {CHECK constraint failed}} +do_catchsql_test alter3-9.7 { + ALTER TABLE t1 ADD COLUMN d AS (b+1) NOT NULL CHECK(a!=3); +} {1 {NOT NULL constraint failed}} + +do_execsql_test alter3-9.10 { + CREATE TEMP TABLE t0(m,n); + INSERT INTO t0 VALUES(1, 2), ('null!',NULL), (3,4); + ATTACH ':memory:' AS aux1; + CREATE TABLE aux1.t2(x,y); + INSERT INTO t2 VALUES(1, 2), ('null!',NULL), (3,4); +} {} +do_catchsql_test alter3-9.11 { + ALTER TABLE t0 ADD COLUMN xtra1 AS (n+1) NOT NULL CHECK(m!=1); +} {1 {CHECK constraint failed}} +do_catchsql_test alter3-9.12 { + ALTER TABLE t0 ADD COLUMN xtra1 AS (n+1) NOT NULL CHECK(m!=3); +} {1 {NOT NULL constraint failed}} +do_catchsql_test alter3-9.13 { + ALTER TABLE t2 ADD COLUMN xtra1 AS (y+1) NOT NULL CHECK(x!=1); +} {1 {CHECK constraint failed}} +do_catchsql_test alter3-9.14 { + ALTER TABLE t2 ADD COLUMN xtra1 AS (y+1) NOT NULL CHECK(x!=3); +} {1 {NOT NULL constraint failed}} + finish_test diff --git a/test/altercorrupt.test b/test/altercorrupt.test index 5c50fa4a..f24cb309 100644 --- a/test/altercorrupt.test +++ b/test/altercorrupt.test @@ -14,6 +14,12 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix altercorrupt +# If SQLITE_OMIT_ALTERTABLE is defined, omit this file. +ifcapable !altertable { + finish_test + return +} + database_may_be_corrupt #-------------------------------------------------------------------------- diff --git a/test/altermalloc3.test b/test/alterfault.test similarity index 53% copy from test/altermalloc3.test copy to test/alterfault.test index 5e4e7514..b6b42973 100644 --- a/test/altermalloc3.test +++ b/test/alterfault.test @@ -1,4 +1,4 @@ -# 2021 February 18 +# 2021 November 16 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: @@ -7,13 +7,13 @@ # 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. # set testdir [file dirname $argv0] source $testdir/tester.tcl -source $testdir/malloc_common.tcl -set testprefix altermalloc3 +set testprefix alterfault # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { @@ -22,26 +22,20 @@ ifcapable !altertable { } do_execsql_test 1.0 { - CREATE TABLE x1( - one, two, three, PRIMARY KEY(one), - CHECK (three!="xyz"), CHECK (two!="one") - ) WITHOUT ROWID; - CREATE INDEX x1i ON x1(one+"two"+"four") WHERE "five"; - CREATE TEMP TRIGGER AFTER INSERT ON x1 BEGIN - UPDATE x1 SET two=new.three || "new" WHERE one=new.one||""; - END; - CREATE TABLE t1(a, b, c, d, PRIMARY KEY(d, b)) WITHOUT ROWID; - INSERT INTO t1 VALUES(1, 2, 3, 4); + CREATE TABLE t1(a); } faultsim_save_and_close -do_faultsim_test 1 -prep { +do_faultsim_test 1.1 -faults oom* -prep { faultsim_restore_and_reopen } -body { - execsql { ALTER TABLE t1 DROP COLUMN c } + execsql { + ALTER TABLE t1 ADD COLUMN b CHECK (a!=1) + } } -test { faultsim_test_result {0 {}} } + finish_test diff --git a/test/altermalloc3.test b/test/altermalloc3.test index 5e4e7514..4c10f48f 100644 --- a/test/altermalloc3.test +++ b/test/altermalloc3.test @@ -43,5 +43,36 @@ do_faultsim_test 1 -prep { faultsim_test_result {0 {}} } +#------------------------------------------------------------------------- +# dbsqlfuzz e3dd84cda3848016a6a6024c7249d09bc2ef2615 +# +reset_db +do_execsql_test 2.0 { + CREATE TABLE t2(k,v); + CREATE TRIGGER r2 AFTER INSERT ON t2 BEGIN + UPDATE t2 SET (k,v)= ( + (WITH cte1(a) AS ( SELECT 1 FROM ( SELECT * FROM t2 ) ) + SELECT a FROM cte1 + ), 1); + END; +} + +faultsim_save_and_close +faultsim_restore_and_reopen + +do_execsql_test 2.1 { + ALTER TABLE t2 RENAME TO t2x; +} + +do_faultsim_test 2.2 -prep { + faultsim_restore_and_reopen + db eval { SELECT * FROM sqlite_master } +} -body { + execsql { + ALTER TABLE t2 RENAME TO t2x; + } +} -test { + faultsim_test_result {0 {}} +} finish_test diff --git a/test/alterqf.test b/test/alterqf.test index ce00f3b5..6a896418 100644 --- a/test/alterqf.test +++ b/test/alterqf.test @@ -17,6 +17,13 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix alterqf +# If SQLITE_OMIT_ALTERTABLE is defined, omit this file. +ifcapable !altertable { + finish_test + return +} + + sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db do_execsql_test 1.0 { diff --git a/test/altertab.test b/test/altertab.test index 079a382d..6d8347ec 100644 --- a/test/altertab.test +++ b/test/altertab.test @@ -540,6 +540,7 @@ ifcapable fts3 { do_execsql_test 16.0 { CREATE VIRTUAL TABLE y1 USING fts3; + VACUUM; } do_catchsql_test 16.10 { @@ -968,4 +969,16 @@ do_execsql_test 31.3 { ALTER TABLE t1x RENAME q TO x; } +# 2021-07-02 OSSFuzz https://oss-fuzz.com/testcase-detail/5517690440646656 +# Bad assert() statement +# +reset_db +do_catchsql_test 32.0 { + CREATE TABLE t1(x); + CREATE TRIGGER r1 BEFORE INSERT ON t1 BEGIN + UPDATE t1 SET x=x FROM (SELECT*); + END; + ALTER TABLE t1 RENAME TO x; +} {1 {error in trigger r1: no tables specified}} + finish_test diff --git a/test/altertab3.test b/test/altertab3.test index 1823b21e..2b9aac3e 100644 --- a/test/altertab3.test +++ b/test/altertab3.test @@ -648,4 +648,42 @@ do_catchsql_test 26.6 { } {1 {error in trigger xx: ambiguous column name: xx}} +#------------------------------------------------------------------------- +reset_db + +do_execsql_test 27.1 { + CREATE TABLE t1(a, b AS ((WITH w1 (xyz) AS ( SELECT t1.b FROM t1 ) SELECT 123) IN ()), c); +} + +do_execsql_test 27.2 { + ALTER TABLE t1 DROP COLUMN c; + SELECT sql FROM sqlite_schema WHERE name = 't1'; +} { + {CREATE TABLE t1(a, b AS ((WITH w1 (xyz) AS ( SELECT t1.b FROM t1 ) SELECT 123) IN ()))} +} + +do_execsql_test 27.3 { + CREATE TABLE t0(c0 , c1 AS (CASE TRUE NOT IN () WHEN NULL THEN CASE + 0xa ISNULL WHEN NOT + 0x9 THEN t0.c1 ELSE CURRENT_TIME LIKE CAST (t0.c1 REGEXP '-([1-9]\d*.\d*|0\.\d*[1-9]\d*)'ESCAPE (c1) COLLATE BINARY BETWEEN c1 AND c1 NOT IN (WITH t4 (c0) AS (WITH t3 (c0) AS NOT MATERIALIZED (WITH RECURSIVE t2 (c0) AS (WITH RECURSIVE t1 AS (VALUES (x'717171ff71717171' ) ) SELECT DISTINCT t0.c0 FROM t0 NOT INDEXED WHERE t0.c0 =t0.c0 GROUP BY 0x9 ) SELECT DISTINCT t0.c0 FROM t0 NOT INDEXED WHERE t0.c0 =t0.c1 ) SELECT DISTINCT t0.c0 FROM t0 NOT INDEXED WHERE t0.c0 =t0.c0 GROUP BY typeof(0x9 ) ) SELECT DISTINCT t0.c0 FROM t0 NOT INDEXED WHERE t0.c0 =t0.c0 GROUP BY typeof(typeof(0x9 ) ) ) IN t0 BETWEEN typeof(typeof(typeof(hex(*) FILTER (WHERE + x'5ccd1e68' ) ) ) ) AND 1 >0xa AS BLOB (+4.4E4 , -0xe ) ) END <> c1 IN () END ) VIRTUAL , c35 PRIMARY KEY , c60 , c64 NUMERIC (-6.8 , -0xE ) ) WITHOUT ROWID ; +} {} + +do_execsql_test 27.4 { + ALTER TABLE t0 DROP COLUMN c60; +} {} + +#------------------------------------------------------------------------- +reset_db +do_execsql_test 28.1 { + CREATE TABLE t1(a,b,c,d); + CREATE TRIGGER AFTER INSERT ON t1 BEGIN + UPDATE t1 SET (c,d)=(a,b); + END; + ALTER TABLE t1 RENAME TO t2; +} + +do_execsql_test 28.2 { + SELECT sql FROM sqlite_schema WHERE type='trigger' +} {{CREATE TRIGGER AFTER INSERT ON "t2" BEGIN + UPDATE "t2" SET (c,d)=(a,b); + END}} + finish_test diff --git a/test/analyze4.test b/test/analyze4.test index e3b0d23f..d4f1921e 100644 --- a/test/analyze4.test +++ b/test/analyze4.test @@ -20,6 +20,12 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +# If SQLITE_OMIT_ALTERTABLE is defined, omit this file. +ifcapable !altertable { + finish_test + return +} + do_test analyze4-1.0 { db eval { CREATE TABLE t1(a,b); diff --git a/test/atof1.test b/test/atof1.test index 0505fb22..a68266c9 100644 --- a/test/atof1.test +++ b/test/atof1.test @@ -19,6 +19,11 @@ if {$::longdouble_size<=8} { finish_test return } +if {![info exists tcl_platform(machine)] + || $::tcl_platform(machine)!="x86_64"} { + finish_test + return +} expr srand(1) for {set i 1} {$i<20000} {incr i} { diff --git a/test/auth3.test b/test/auth3.test index 4377bcdc..abc97343 100644 --- a/test/auth3.test +++ b/test/auth3.test @@ -115,18 +115,20 @@ do_test auth3-2.2 { # an authorizer failure during an ALTER TABLE. The solution (I think) is # to disable the authorizer during schema parsing. # -proc auth {code args} { - if {$code=="SQLITE_READ" && [regexp {DoNotRead} $args]} { - return SQLITE_DENY +ifcapable altertable { + proc auth {code args} { + if {$code=="SQLITE_READ" && [regexp {DoNotRead} $args]} { + return SQLITE_DENY + } + return SQLITE_OK } - return SQLITE_OK + do_execsql_test auth3-3.0 { + CREATE TEMPORARY TABLE TempTable ( + key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE, + value TEXT NOT NULL ON CONFLICT FAIL); + ALTER TABLE TempTable RENAME TO DoNotRead; + SELECT name FROM temp.sqlite_master; + } {DoNotRead sqlite_autoindex_DoNotRead_1} } -do_execsql_test auth3-3.0 { - CREATE TEMPORARY TABLE TempTable ( - key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE, - value TEXT NOT NULL ON CONFLICT FAIL); - ALTER TABLE TempTable RENAME TO DoNotRead; - SELECT name FROM temp.sqlite_master; -} {DoNotRead sqlite_autoindex_DoNotRead_1} finish_test diff --git a/test/autoindex5.test b/test/autoindex5.test index 36695d7f..aa8dec27 100644 --- a/test/autoindex5.test +++ b/test/autoindex5.test @@ -123,6 +123,10 @@ do_execsql_test 2.1 { SELECT sum(z) FROM vvv WHERE x='aaa' ) FROM one; } {8.0} + +# At one point the following was returning "no such column: rowid". This +# was incorrect - "rowid" matches against the rowid of table t1 in this +# query. do_catchsql_test 2.2 { DROP TABLE t1; CREATE TABLE t1(aaa); @@ -136,7 +140,7 @@ do_catchsql_test 2.2 { ) WHERE bbb = 1 ) ); -} {1 {no such column: rowid}} +} {0 9} # Ticket https://www.sqlite.org/src/info/787fa716be3a7f65 # Segfault due to multiple uses of the same subquery where the diff --git a/test/autovacuum.test b/test/autovacuum.test index 431c4b8a..245ea8b5 100644 --- a/test/autovacuum.test +++ b/test/autovacuum.test @@ -9,9 +9,8 @@ # #*********************************************************************** # This file implements regression tests for SQLite library. The -# focus of this file is testing the SELECT statement. +# focus of this file is testing the autovacuum feature. # -# $Id: autovacuum.test,v 1.29 2009/04/06 17:50:03 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl diff --git a/test/autovacuum2.test b/test/autovacuum2.test new file mode 100644 index 00000000..a3c40983 --- /dev/null +++ b/test/autovacuum2.test @@ -0,0 +1,87 @@ +# 2021-10-15 +# +# 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 file is testing the sqlite3_autovacuum_pages() interface +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# If this build of the library does not support auto-vacuum, omit this +# whole file. +ifcapable {!autovacuum || !pragma} { + finish_test + return +} + +# Demonstrate basic sqlite3_autovacuum_pages functionality +# +do_execsql_test autovacuum2-1.0 { + PRAGMA page_size=1024; + PRAGMA auto_vacuum=FULL; + CREATE TABLE t1(x); + VACUUM; + INSERT INTO t1(x) VALUES(zeroblob(10000)); + PRAGMA page_count; +} {12} +proc autovac_page_callback {schema filesize freesize pagesize} { + global autovac_callback_data + lappend autovac_callback_data $schema $filesize $freesize $pagesize + return [expr {$freesize/2}] +} +sqlite3_autovacuum_pages db autovac_page_callback +set autovac_callback_data {} +do_execsql_test autovacuum2-1.1 { + BEGIN; + DELETE FROM t1; + PRAGMA freelist_count; + PRAGMA page_count; +} {9 12} +do_execsql_test autovacuum2-1.2 { + COMMIT; +} {} +do_test autovacuum2-1.3 { + set autovac_callback_data +} {main 12 9 1024} +do_execsql_test autovacuum2-1.4 { + PRAGMA freelist_count; + PRAGMA page_count; +} {5 8} +do_execsql_test autovacuum2-1.5 { + PRAGMA integrity_check; +} {ok} + +# Disable the autovacuum-pages callback. Then do any transaction. +# The database should shrink to minimal size +# +sqlite3_autovacuum_pages db +do_execsql_test autovacuum2-1.10 { + CREATE TABLE t2(x); + PRAGMA freelist_count; +} {0} + +# Rig the autovacuum-pages callback to always return zero. No +# autovacuum will happen. +# +proc autovac_page_callback_off {schema filesize freesize pagesize} { + return 0 +} +sqlite3_autovacuum_pages db autovac_page_callback_off +do_execsql_test autovacuum2-1.20 { + BEGIN; + INSERT INTO t1(x) VALUES(zeroblob(10000)); + DELETE FROM t1; + PRAGMA freelist_count; + COMMIT; + PRAGMA freelist_count; +} {9 9} + +finish_test diff --git a/test/bestindex1.test b/test/bestindex1.test index 0d694699..e93d7349 100644 --- a/test/bestindex1.test +++ b/test/bestindex1.test @@ -323,5 +323,8 @@ do_test 4.1 { ] ] +do_catchsql_test 5.0 { + SELECT * FROM tcl('abc'); +} {1 {wrong number of arguments}} finish_test diff --git a/test/capi2.test b/test/capi2.test index 0680cf53..de47ab3d 100644 --- a/test/capi2.test +++ b/test/capi2.test @@ -64,13 +64,13 @@ do_test capi2-1.4 { } {t1 1} do_test capi2-1.5 { get_column_names $VM -} {name rowid text INTEGER} +} {name rowid TEXT INTEGER} do_test capi2-1.6 { sqlite3_step $VM } {SQLITE_DONE} do_test capi2-1.7 { list [sqlite3_column_count $VM] [get_row_values $VM] [get_column_names $VM] -} {2 {} {name rowid text INTEGER}} +} {2 {} {name rowid TEXT INTEGER}} # This used to be SQLITE_MISUSE. But now we automatically reset prepared # statements. @@ -91,7 +91,7 @@ ifcapable autoreset { do_test capi2-1.9 { sqlite3_reset $VM list [sqlite3_column_count $VM] [get_row_values $VM] [get_column_names $VM] -} {2 {} {name rowid text INTEGER}} +} {2 {} {name rowid TEXT INTEGER}} do_test capi2-1.10 { sqlite3_data_count $VM } {0} @@ -120,13 +120,13 @@ do_test capi2-2.2 { lappend r [sqlite3_column_count $VM] \ [get_row_values $VM] \ [get_column_names $VM] -} {SQLITE_ROW 2 {t1 1} {name rowid text INTEGER}} +} {SQLITE_ROW 2 {t1 1} {name rowid TEXT INTEGER}} do_test capi2-2.3 { set r [sqlite3_step $VM] lappend r [sqlite3_column_count $VM] \ [get_row_values $VM] \ [get_column_names $VM] -} {SQLITE_DONE 2 {} {name rowid text INTEGER}} +} {SQLITE_DONE 2 {} {name rowid TEXT INTEGER}} do_test capi2-2.4 { sqlite3_finalize $VM } {SQLITE_OK} @@ -141,7 +141,7 @@ do_test capi2-2.6 { lappend r [sqlite3_column_count $VM] \ [get_row_values $VM] \ [get_column_names $VM] -} {SQLITE_DONE 2 {} {name rowid text INTEGER}} +} {SQLITE_DONE 2 {} {name rowid TEXT INTEGER}} do_test capi2-2.7 { sqlite3_finalize $VM } {SQLITE_OK} diff --git a/test/carray01.test b/test/carray01.test index 6db4f5ea..d6243eb2 100644 --- a/test/carray01.test +++ b/test/carray01.test @@ -62,11 +62,35 @@ do_test 120 { sqlite3_carray_bind -int64 $STMT 3 1 2 3 4 5 6 7 run_stmt $STMT 0 } {1} +do_test 121 { + sqlite3_carray_bind -int64 -transient $STMT 3 1 2 3 4 5 6 7 + run_stmt $STMT 0 +} {1} +do_test 122 { + sqlite3_carray_bind -int64 -static $STMT 3 1 2 3 4 5 6 7 + run_stmt $STMT 0 +} {1} +do_test 123 { + sqlite3_carray_bind -int32 -transient $STMT 3 1 2 3 4 5 6 7 + run_stmt $STMT 0 +} {1} +do_test 124 { + sqlite3_carray_bind -int32 -static $STMT 3 1 2 3 4 5 6 7 + run_stmt $STMT 0 +} {1} +do_test 125 { + sqlite3_carray_bind -int32 $STMT 3 1 2 3 4 5 6 7 + run_stmt $STMT 0 +} {1} do_test 130 { sqlite3_carray_bind -int64 $STMT 3 1 2 3 4 6 7 run_stmt $STMT 0 } {0} do_test 131 { + sqlite3_carray_bind -int64 -transient $STMT 3 1 2 3 4 6 7 + run_stmt $STMT 0 +} {0} +do_test 131 { sqlite3_carray_bind -int64 -static $STMT 3 1 2 3 4 6 7 run_stmt $STMT 0 } {0} @@ -74,6 +98,14 @@ do_test 140 { sqlite3_carray_bind -double $STMT 3 1 2 3 4 5 6 7 run_stmt $STMT 0 } {1} +do_test 141 { + sqlite3_carray_bind -double -transient $STMT 3 1 2 3 4 5 6 7 + run_stmt $STMT 0 +} {1} +do_test 142 { + sqlite3_carray_bind -double -static $STMT 3 1 2 3 4 5 6 7 + run_stmt $STMT 0 +} {1} do_test 150 { sqlite3_carray_bind -double $STMT 3 1 2 3 4 6 7 run_stmt $STMT 0 diff --git a/test/changes.test b/test/changes.test new file mode 100644 index 00000000..21db075f --- /dev/null +++ b/test/changes.test @@ -0,0 +1,90 @@ +# 2021 June 22 +# +# 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. +# +#*********************************************************************** +# +# Tests for the sqlite3_changes() and sqlite3_total_changes() APIs. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix changes + +# To test that the change-counters do not suffer from 32-bit signed integer +# rollover, add the following line to the array of test cases below. The +# test will take will over an hour to run. +# +# 7 (1<<31)+10 "" +# + +foreach {tn nRow wor} { + 1 50 "" + 2 50 "WITHOUT ROWID" + + 3 5000 "" + 4 5000 "WITHOUT ROWID" + + 5 50000 "" + 6 50000 "WITHOUT ROWID" +} { + reset_db + set nBig [expr $nRow] + + do_execsql_test 1.$tn.0 " + PRAGMA journal_mode = off; + CREATE TABLE t1(x INTEGER PRIMARY KEY) $wor; + " {off} + + do_execsql_test 1.$tn.1 { + WITH s(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i < $nBig + ) + INSERT INTO t1 SELECT i FROM s; + } + + do_test 1.$tn.2 { + db changes + } [expr $nBig] + + do_test 1.$tn.3 { + db total_changes + } [expr $nBig] + + do_execsql_test 1.$tn.4 { + INSERT INTO t1 VALUES(-1) + } + + do_test 1.$tn.5 { + db changes + } [expr 1] + + do_test 1.$tn.6 { + db total_changes + } [expr {$nBig+1}] + + do_execsql_test 1.$tn.7a { + SELECT count(*) FROM t1 + } [expr {$nBig+1}] + + do_execsql_test 1.$tn.7 { + DELETE FROM t1 + } + + do_test 1.$tn.8 { + db changes + } [expr {$nBig+1}] + + do_test 1.$tn.9 { + db total_changes + } [expr {2*($nBig+1)}] +} + +finish_test + + diff --git a/test/columncount.test b/test/columncount.test index 669a35a7..d9956b40 100644 --- a/test/columncount.test +++ b/test/columncount.test @@ -16,6 +16,12 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix columncount +# If SQLITE_OMIT_ALTERTABLE is defined, omit this file. +ifcapable !altertable { + finish_test + return +} + proc do_ccsql_test {tn sql res} { uplevel [list do_test $tn [subst -nocommands { diff --git a/test/corruptL.test b/test/corruptL.test index 5ade7010..b7ff45d2 100644 --- a/test/corruptL.test +++ b/test/corruptL.test @@ -1179,9 +1179,12 @@ do_catchsql_test 14.1 { PRAGMA integrity_check; } {1 {database disk image is malformed}} -do_catchsql_test 14.2 { - ALTER TABLE t1 RENAME TO alkjalkjdfiiiwuer987lkjwer82mx97sf98788s9789s; -} {1 {database disk image is malformed}} +# If SQLITE_OMIT_ALTERTABLE is defined, omit this file. +ifcapable altertable { + do_catchsql_test 14.2 { + ALTER TABLE t1 RENAME TO alkjalkjdfiiiwuer987lkjwer82mx97sf98788s9789s; + } {1 {database disk image is malformed}} +} extra_schema_checks 1 #------------------------------------------------------------------------- diff --git a/test/corruptN.test b/test/corruptN.test index 8600e438..46857882 100644 --- a/test/corruptN.test +++ b/test/corruptN.test @@ -184,7 +184,7 @@ if {![info exists ::G(perm:presql)]} { do_catchsql_test 4.2 { PRAGMA writable_schema = 1; REPLACE INTO x1 VALUES(5, 2, 3); - } {1 {database disk image is malformed}} + } {0 {}} } @@ -224,5 +224,53 @@ ifcapable json1&&vtab { } }; # ifcapable json1&&vtab +#------------------------------------------------------------------------- +reset_db + +do_execsql_test 6.0 { + PRAGMA auto_vacuum = 0; + PRAGMA page_size=1024; + CREATE TABLE t1(a INTEGER PRIMARY KEY, b); + INSERT INTO t1(b) VALUES(zeroblob(300)),(zeroblob(300)),(zeroblob(300)),(zeroblob(300)); + CREATE TABLE t2(a); + CREATE TRIGGER t1tr BEFORE UPDATE ON t1 BEGIN DELETE FROM t2; END; + PRAGMA writable_schema=ON; + UPDATE sqlite_schema SET rootpage=3 WHERE rowid=2; + PRAGMA writable_schema=RESET; + INSERT INTO t2 VALUES('active'),('boomer'),('atom'),('atomic'), + ('alpha channel backup abandon test aback boomer atom alpha active'); +} +do_catchsql_test 6.1 { + UPDATE t1 SET b=zeroblob(299); +} {1 {database disk image is malformed}} + +reset_db +do_execsql_test 6.2 { + -- Make "t1" a large table. Large enough that the children of the root + -- node are interior nodes. + PRAGMA page_size = 1024; + PRAGMA auto_vacuum = 0; + CREATE TABLE t1(x); + WITH s(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<500 + ) + INSERT INTO t1 SELECT zeroblob(300) FROM s; + + CREATE TABLE t2(y); + CREATE TRIGGER tr BEFORE UPDATE ON t1 BEGIN + DELETE FROM t2; + END; + + -- Set the root of table t2 to 137 - the leftmost child of the root of t1. + PRAGMA writable_schema = ON; + UPDATE sqlite_schema SET rootpage = 137 WHERE name='t2'; + PRAGMA writable_schema = RESET; +} + +do_catchsql_test 6.3 { + -- Run an UPDATE on t1 that will hit a child of page 136. Have the trigger + -- clear page 136 and its children. Assert fails. + UPDATE t1 SET x='hello world' WHERE rowid=1; +} {1 {database disk image is malformed}} finish_test diff --git a/test/count.test b/test/count.test index 9769b765..fdcb21e8 100644 --- a/test/count.test +++ b/test/count.test @@ -233,5 +233,16 @@ do_eqp_test count-7.4 { `--SCAN t1 } +do_execsql_test count-8.0 { + CREATE TABLE t7(a INT,b TEXT,c BLOB,d REAL); + CREATE TABLE t8(a INT,b TEXT,c BLOB,d REAL); + CREATE INDEX t8a ON t8(a); +} +do_catchsql_test count-8.1 { + SELECT * FROM t8 WHERE (a, b) IN ( + SELECT count(t8.b), count(*) FROM t7 AS ra0 ORDER BY count(*) + ) AND t8.b=0; +} {1 {misuse of aggregate: count()}} + finish_test diff --git a/test/delete.test b/test/delete.test index c15ac53c..a448e52d 100644 --- a/test/delete.test +++ b/test/delete.test @@ -100,7 +100,7 @@ do_test delete-5.2.1 { } {200} do_test delete-5.2.2 { execsql {DELETE FROM table1} -} {202} +} {200} do_test delete-5.2.3 { execsql {BEGIN TRANSACTION} for {set i 1} {$i<=200} {incr i} { diff --git a/test/e_blobbytes.test b/test/e_blobbytes.test index d38f56bf..c24318c5 100644 --- a/test/e_blobbytes.test +++ b/test/e_blobbytes.test @@ -14,6 +14,11 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix e_blobbytes +ifcapable !incrblob { + finish_test + return +} + do_execsql_test 1.0 { CREATE TABLE q1(r INTEGER PRIMARY KEY, s TEXT); WITH d(a, b) AS ( diff --git a/test/e_blobclose.test b/test/e_blobclose.test index 26831978..40291cf0 100644 --- a/test/e_blobclose.test +++ b/test/e_blobclose.test @@ -14,6 +14,11 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix e_blobclose +ifcapable !incrblob { + finish_test + return +} + set dots [string repeat . 40] do_execsql_test 1.0 { CREATE TABLE x1(a INTEGER PRIMARY KEY, b DOTS); diff --git a/test/e_blobopen.test b/test/e_blobopen.test index a6168042..41fd13c6 100644 --- a/test/e_blobopen.test +++ b/test/e_blobopen.test @@ -14,6 +14,11 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix e_blobopen +ifcapable !incrblob { + finish_test + return +} + forcedelete test.db2 do_execsql_test 1.0 { diff --git a/test/e_blobwrite.test b/test/e_blobwrite.test index afcfc281..8d8588e6 100644 --- a/test/e_blobwrite.test +++ b/test/e_blobwrite.test @@ -14,6 +14,11 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix e_blobwrite +ifcapable !incrblob { + finish_test + return +} + #-------------------------------------------------------------------------- # EVIDENCE-OF: R-62898-22698 This function is used to write data into an # open BLOB handle from a caller-supplied buffer. N bytes of data are diff --git a/test/e_changes.test b/test/e_changes.test index a77e22a2..2eb77d31 100644 --- a/test/e_changes.test +++ b/test/e_changes.test @@ -25,10 +25,10 @@ proc do_changes_test {tn sql res} { #-------------------------------------------------------------------------- -# EVIDENCE-OF: R-15996-49369 This function returns the number of rows -# modified, inserted or deleted by the most recently completed INSERT, -# UPDATE or DELETE statement on the database connection specified by the -# only parameter. +# EVIDENCE-OF: R-58361-29089 The changes() function returns the number +# of database rows that were changed or inserted or deleted by the most +# recently completed INSERT, DELETE, or UPDATE statement, exclusive of +# statements in lower-level triggers. # do_execsql_test 1.0 { CREATE TABLE t1(a, b); @@ -108,7 +108,7 @@ foreach {tn schema} { #-------------------------------------------------------------------------- -# EVIDENCE-OF: R-44877-05564 Executing any other type of SQL statement +# X-EVIDENCE-OF: R-44877-05564 Executing any other type of SQL statement # does not modify the value returned by this function. # reset_db @@ -123,7 +123,9 @@ do_changes_test 2.2 { do_changes_test 2.3 { SELECT count(x) FROM t1 } {47 47} do_changes_test 2.4 { DROP TABLE t1 } 47 do_changes_test 2.5 { CREATE TABLE t1(x) } 47 -do_changes_test 2.6 { ALTER TABLE t1 ADD COLUMN b } 47 +ifcapable altertable { + do_changes_test 2.6 { ALTER TABLE t1 ADD COLUMN b } 47 +} #-------------------------------------------------------------------------- diff --git a/test/e_createtable.test b/test/e_createtable.test index c2cd1bc2..fa43d94b 100644 --- a/test/e_createtable.test +++ b/test/e_createtable.test @@ -1272,9 +1272,10 @@ do_createtable_tests 4.4 { 14 "INSERT INTO t2 VALUES(NULL, NULL)" {} } -# EVIDENCE-OF: R-35113-43214 Unless the column is an INTEGER PRIMARY KEY -# or the table is a WITHOUT ROWID table or the column is declared NOT -# NULL, SQLite allows NULL values in a PRIMARY KEY column. +# EVIDENCE-OF: R-40010-16873 Unless the column is an INTEGER PRIMARY KEY +# or the table is a WITHOUT ROWID table or a STRICT table or the column +# is declared NOT NULL, SQLite allows NULL values in a PRIMARY KEY +# column. # # If the column is an integer primary key, attempting to insert a NULL # into the column triggers the auto-increment behavior. Attempting @@ -1304,6 +1305,14 @@ do_catchsql_test 4.5.5 { CREATE TABLE t5(s, u INT PRIMARY KEY NOT NULL, v); INSERT INTO t5 VALUES(1, NULL, 2); } {1 {NOT NULL constraint failed: t5.u}} +do_catchsql_test 4.5.6 { + CREATE TABLE t6(s INT, u INT PRIMARY KEY, v INT) STRICT; + INSERT INTO t6 VALUES(1, NULL, 2); +} {1 {NOT NULL constraint failed: t6.u}} +do_catchsql_test 4.5.7 { + CREATE TABLE t7(s INT, u INT PRIMARY KEY NOT NULL, v INT) STRICT; + INSERT INTO t7 VALUES(1, NULL, 2); +} {1 {NOT NULL constraint failed: t7.u}} # EVIDENCE-OF: R-00227-21080 A UNIQUE constraint is similar to a PRIMARY # KEY constraint, except that a single table may have any number of diff --git a/test/e_expr.test b/test/e_expr.test index 242c503d..93ca0268 100644 --- a/test/e_expr.test +++ b/test/e_expr.test @@ -84,12 +84,12 @@ db func regexp -argcount 2 regexfunc # in the documentation exist and that the relative precedences of the # operators are also as the documentation suggests. # -# EVIDENCE-OF: R-15514-65163 SQLite understands the following binary +# X-EVIDENCE-OF: R-15514-65163 SQLite understands the following binary # operators, in order from highest to lowest precedence: || * / % + - # << >> & | < <= > >= = == != <> IS IS # NOT IN LIKE GLOB MATCH REGEXP AND OR # -# EVIDENCE-OF: R-38759-38789 Operators IS and IS NOT have the same +# X-EVIDENCE-OF: R-38759-38789 Operators IS and IS NOT have the same # precedence as =. # @@ -180,7 +180,7 @@ do_execsql_test e_expr-1.6 { # Check that the four unary prefix operators mentioned in the # documentation exist. # -# EVIDENCE-OF: R-13958-53419 Supported unary prefix operators are these: +# X-EVIDENCE-OF: R-13958-53419 Supported unary prefix operators are these: # - + ~ NOT # do_execsql_test e_expr-2.1 { SELECT - 10 } {-10} @@ -368,7 +368,7 @@ db collate reverse reverse_collate # EVIDENCE-OF: R-59577-33471 The COLLATE operator is a unary postfix # operator that assigns a collating sequence to an expression. # -# EVIDENCE-OF: R-36231-30731 The COLLATE operator has a higher +# X-EVIDENCE-OF: R-36231-30731 The COLLATE operator has a higher # precedence (binds more tightly) than any binary operator and any unary # prefix operator except "~". # @@ -860,7 +860,7 @@ foreach {tn x expr res nEval} { } [list $nEval $res] } -# EVIDENCE-OF: R-05155-34454 The precedence of the BETWEEN operator is +# X-EVIDENCE-OF: R-05155-34454 The precedence of the BETWEEN operator is # the same as the precedence as operators == and != and LIKE and groups # left to right. # diff --git a/test/e_fkey.test b/test/e_fkey.test index e5eb0d49..ab3c2903 100644 --- a/test/e_fkey.test +++ b/test/e_fkey.test @@ -2513,9 +2513,11 @@ proc test_efkey_6 {tn zAlter isError} { } -test_efkey_6 1 "ALTER TABLE tbl ADD COLUMN c REFERENCES xx" 0 -test_efkey_6 2 "ALTER TABLE tbl ADD COLUMN c DEFAULT NULL REFERENCES xx" 0 -test_efkey_6 3 "ALTER TABLE tbl ADD COLUMN c DEFAULT 0 REFERENCES xx" 1 +ifcapable altertable { + test_efkey_6 1 "ALTER TABLE tbl ADD COLUMN c REFERENCES xx" 0 + test_efkey_6 2 "ALTER TABLE tbl ADD COLUMN c DEFAULT NULL REFERENCES xx" 0 + test_efkey_6 3 "ALTER TABLE tbl ADD COLUMN c DEFAULT 0 REFERENCES xx" 1 +} #------------------------------------------------------------------------- # Test that ALTER TABLE adjusts REFERENCES clauses when the parent table @@ -2532,6 +2534,7 @@ test_efkey_6 3 "ALTER TABLE tbl ADD COLUMN c DEFAULT 0 REFERENCES xx" 1 # statement or statements stored in the sqlite_schema table are modified # to reflect the new parent table name. # +ifcapable altertable { do_test e_fkey-56.1 { drop_all_tables execsql { @@ -2569,6 +2572,7 @@ do_test e_fkey-56.4 { {CREATE TABLE c2(e, f, FOREIGN KEY(f) REFERENCES "p" ON UPDATE CASCADE)} \ {CREATE TABLE c3(e, 'f col 2', FOREIGN KEY('f col 2') REFERENCES "p" ON UPDATE CASCADE)} \ ] +} #------------------------------------------------------------------------- # Check that a DROP TABLE does an implicit DELETE FROM. Which does not @@ -2769,6 +2773,7 @@ do_test e_fkey-60.6 { # EVIDENCE-OF: R-54142-41346 The properties of the DROP TABLE and ALTER # TABLE commands described above only apply if foreign keys are enabled. # +ifcapable altertable { do_test e_fkey-61.1.1 { drop_all_tables execsql { CREATE TABLE t1(a, b) ; INSERT INTO t1 VALUES(1, 2) } @@ -2830,6 +2835,7 @@ do_test e_fkey-61.3.2 { do_test e_fkey-61.3.3 { execsql { PRAGMA foreign_keys = ON } } {} +} ########################################################################### ### SECTION 6: Limits and Unsupported Features diff --git a/test/e_totalchanges.test b/test/e_totalchanges.test index ee163c91..bb5cfba8 100644 --- a/test/e_totalchanges.test +++ b/test/e_totalchanges.test @@ -32,10 +32,9 @@ do_execsql_test 1.0 { #-------------------------------------------------------------------------- -# EVIDENCE-OF: R-65438-26258 This function returns the total number of -# rows inserted, modified or deleted by all INSERT, UPDATE or DELETE -# statements completed since the database connection was opened, -# including those executed as part of trigger programs. +# EVIDENCE-OF: R-38914-26427 The total_changes() function returns the +# number of row changes caused by INSERT, UPDATE or DELETE statements +# since the current database connection was opened. # # 1.1.*: different types of I/U/D statements, # 1.2.*: trigger programs. @@ -95,24 +94,26 @@ do_tc_test 1.2.2 { #-------------------------------------------------------------------------- # EVIDENCE-OF: R-61766-15253 Executing any other type of SQL statement # does not affect the value returned by sqlite3_total_changes(). -do_tc_test 2.1 { - INSERT INTO t1 VALUES(1, 2), (3, 4); - INSERT INTO t2 VALUES(1, 2), (3, 4); -} {15} -do_tc_test 2.2 { - SELECT count(*) FROM t1; -} {2 15} -do_tc_test 2.3 { - CREATE TABLE t4(a, b); - ALTER TABLE t4 ADD COLUMN c; - CREATE INDEX i4 ON t4(c); - ALTER TABLE t4 RENAME TO t5; - ANALYZE; - BEGIN; - DROP TABLE t2; - ROLLBACK; - VACUUM; -} {15} +ifcapable altertable { + do_tc_test 2.1 { + INSERT INTO t1 VALUES(1, 2), (3, 4); + INSERT INTO t2 VALUES(1, 2), (3, 4); + } {15} + do_tc_test 2.2 { + SELECT count(*) FROM t1; + } {2 15} + do_tc_test 2.3 { + CREATE TABLE t4(a, b); + ALTER TABLE t4 ADD COLUMN c; + CREATE INDEX i4 ON t4(c); + ALTER TABLE t4 RENAME TO t5; + ANALYZE; + BEGIN; + DROP TABLE t2; + ROLLBACK; + VACUUM; + } {15} +} #-------------------------------------------------------------------------- diff --git a/test/e_uri.test b/test/e_uri.test index dbcc6f3e..92a3df78 100644 --- a/test/e_uri.test +++ b/test/e_uri.test @@ -25,6 +25,7 @@ proc parse_uri {uri} { set ::uri_open [list] set DB [sqlite3_open_v2 $uri { SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE SQLITE_OPEN_WAL + SQLITE_OPEN_EXRESCODE } tvfs] set fileName [sqlite3_db_filename $DB main] sqlite3_close $DB diff --git a/test/fkey1.test b/test/fkey1.test index fa873358..db93be50 100644 --- a/test/fkey1.test +++ b/test/fkey1.test @@ -222,5 +222,54 @@ do_execsql_test 6.2 { INSERT INTO c1 VALUES(1); } {} +# 2021-07-03 https://sqlite.org/forum/forumpost/a6b0c05277 +# 2021-07-07 https://sqlite.org/forum/forumpost/79c9e4797d +# Failure to allocate enough registers in the VDBE for a +# PRAGMA foreign_key_check when the foreign key has more +# columns than the table. +# +reset_db +do_execsql_test 7.1 { + PRAGMA foreign_keys=OFF; + CREATE TABLE t1(a,b,c,FOREIGN KEY(a,a,a,a,a,a,a,a,a,a,a,a,a,a) REFERENCES t0); + INSERT INTO t1 VALUES(1,2,3); + PRAGMA foreign_key_check; +} {t1 1 t0 0} +do_execsql_test 7.2 { + DROP TABLE t1; + CREATE TABLE t1(a,b,c AS(1),d, FOREIGN KEY(c,d,b,a,b,d,b,c) REFERENCES t0); + PRAGMA foreign_key_check; +} {} + +# 2021-12-31 forum https://sqlite.org/forum/forumpost/24bd1fef7e9323ef +# Memory leak caused by sqlite3NestedParse() running on a corrupt system +# table. Discovered by Jingzhou Fu. +# +reset_db +do_execsql_test 8.1 { + PRAGMA writable_schema=ON; + PRAGMA foreign_keys = ON; + CREATE TABLE sqlite_stat1 (tbl INTEGER PRIMARY KEY DESC, idx UNIQUE DEFAULT NULL) WITHOUT ROWID; + PRAGMA writable_schema=OFF; + CREATE TABLE sqlsim4(stat PRIMARY KEY);; + CREATE TABLE t1(sqlsim7 REFERENCES sqlite_stat1 ON DELETE CASCADE); + DROP table "sqlsim4"; +} {} +# 2022-01-01 dbsqlfuzz 1c57440219f6f0aedf5e8f72a8ddd75f15aea381 +# Follow-up case to the above. Assertion is not true if the schema +# is corrupt. +reset_db +database_may_be_corrupt +do_execsql_test 8.2 { + CREATE TABLE t1(a REFERENCES sqlite_stat1 ON DELETE CASCADE); + CREATE TABLE t2(a TEXT PRIMARY KEY); + PRAGMA writable_schema=ON; + CREATE TABLE sqlite_stat1(tbl INTEGER PRIMARY KEY DESC, idx UNIQUE DEFAULT NULL) WITHOUT ROWID; + UPDATE sqlite_schema SET name='sqlite_autoindex_sqlite_stat1_1' WHERE name='sqlite_autoindex_sqlite_stat1_2'; + PRAGMA writable_schema=RESET; +} {} +do_catchsql_test 8.3 { + REINDEX; +} {1 {database disk image is malformed}} finish_test diff --git a/test/fts3corrupt4.test b/test/fts3corrupt4.test index 044fd4e6..f0b83a39 100644 --- a/test/fts3corrupt4.test +++ b/test/fts3corrupt4.test @@ -6805,7 +6805,428 @@ do_execsql_test 50.1 { {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} } +#------------------------------------------------------------------------- +# +reset_db +do_test 51.0 { + sqlite3 db {} + db deserialize [decode_hexdb { +.open --hexdb +| size 28672 pagesize 4096 filename crash-11cf359576eb28.db +| page 1 offset 0 +| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. +| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........ +| 32: 00 00 00 02 00 00 00 01 00 00 00 07 00 00 00 04 ................ +| 96: 00 00 00 00 0d 0e b1 00 06 0d a4 00 0f 8d 0f 21 ...............! +| 112: 0e b9 0d c8 0e 7e 0d a4 0d a4 00 00 00 00 00 00 .....~.......... +| 3488: 00 00 00 00 22 07 06 17 11 11 01 31 74 61 62 6c ...........1tabl +| 3504: 65 74 32 74 32 07 43 52 45 41 54 45 20 54 41 42 et2t2.CREATE TAB +| 3520: 4c 45 20 74 32 28 78 29 81 33 05 07 17 1f 1f 01 LE t2(x).3...... +| 3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 .5tablet1_segdir +| 3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45 t1_segdir.CREATE +| 3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 TABLE 't1_segdi +| 3584: 72 27 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 r'(level INTEGER +| 3600: 2c 69 64 78 20 49 4e 54 45 47 45 52 2c 73 74 61 ,idx INTEGER,sta +| 3616: 72 74 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 rt_block INTEGER +| 3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 ,leaves_end_bloc +| 3648: 6b 20 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c k INTEGER,end_bl +| 3664: 6f 63 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 ock INTEGER,root +| 3680: 20 42 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 BLOB,PRIMARY KE +| 3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 06 Y(level, idx))1. +| 3712: 06 17 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 ..E...indexsqlit +| 3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 e_autoindex_t1_s +| 3744: 65 67 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 egdir_1t1_segdir +| 3760: 06 0f c7 00 08 00 00 00 00 66 04 07 17 23 23 01 .........f...##. +| 3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e ..tablet1_segmen +| 3792: 74 73 74 31 5f 73 65 67 6d 65 6e 74 73 04 43 52 tst1_segments.CR +| 3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 EATE TABLE 't1_s +| 3824: 65 67 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 egments'(blockid +| 3840: 20 49 4e 54 45 47 45 52 20 50 51 49 4d 41 52 59 INTEGER PQIMARY +| 3856: 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 KEY, block BLOB +| 3872: 29 6a 03 07 17 21 21 01 81 1f 74 61 62 6c 65 74 )j...!!...tablet +| 3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 1_contentt1_cont +| 3904: 65 6e 74 03 43 52 45 41 54 45 20 54 41 42 4c 45 ent.CREATE TABLE +| 3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 't1_content'(do +| 3936: 63 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d cid INTEGER PRIM +| 3952: 41 52 59 20 4b 45 59 2c 20 27 63 30 61 27 2c 20 ARY KEY, 'c0a', +| 3968: 27 63 31 62 27 2c 20 27 63 32 63 27 29 38 02 06 'c1b', 'c2c')8.. +| 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR +| 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB +| 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33 LE t1 USING fts3 +| 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c)......... +| page 3 offset 8192 +| 0: 0d 00 00 00 25 0b 48 00 0f d8 0f af 0f 86 0f 74 ....%.H........t +| 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./.......... +| 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$...... +| 48: 0d bb 0d a0 0d 84 0d 68 0d 4f 0d 35 0d 1b 0c fb .......h.O.5.... +| 64: 0c da 0c b9 0c 99 0c 78 0c 57 0c 3e 0c 24 0c 0a .......x.W.>.$.. +| 80: 0b 48 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .H.............. +| 2880: 00 00 00 00 00 00 00 00 81 3f 25 06 00 82 7f 00 .........?%..... +| 2896: 00 43 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e .COMPILER=gcc-5. +| 2912: 34 2e 30 20 32 30 31 36 30 36 30 39 20 44 45 42 4.0 20160609 DEB +| 2928: 55 47 20 45 4e 41 42 4c 45 20 44 42 53 54 41 54 UG ENABLE DBSTAT +| 2944: 20 56 54 41 42 20 45 4e 41 42 4c 45 20 46 54 53 VTAB ENABLE FTS +| 2960: 34 20 45 4e 41 42 4c 45 20 46 54 53 35 20 45 4e 4 ENABLE FTS5 EN +| 2976: 41 42 4c 45 20 47 45 4f 59 0f 4c 59 20 45 4e 41 ABLE GEOY.LY ENA +| 2992: 42 4c 45 20 4a 53 4f 4e 31 20 45 4e 41 42 4c 45 BLE JSON1 ENABLE +| 3008: 20 4d 45 4d 53 59 53 35 20 45 4e 41 42 4c 45 20 MEMSYS5 ENABLE +| 3024: 52 54 52 45 45 20 4d 41 58 20 4d 45 4d 4f 52 59 RTREE MAX MEMORY +| 3040: 3d 35 30 30 30 30 30 30 30 20 4f 4d 49 54 20 4d =50000000 OMIT M +| 3056: 4f 41 44 20 45 58 54 45 4e 53 49 4f 4e 20 54 48 OAD EXTENSION TH +| 3072: 52 45 41 44 53 41 46 45 3d 30 18 24 05 00 25 0f READSAFE=0.$..%. +| 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI +| 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA +| 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE.. +| 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE= +| 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM +| 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO +| 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O +| 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI +| 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3.. +| 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS +| 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3.. +| 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000 +| 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3. +| 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000 +| 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3 +| 3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500 +| 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....% +| 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB +| 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB +| 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE. +| 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR +| 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E +| 3440: 4e 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 NABLE MEMSYS5XBI +| 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL +| 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE +| 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME +| 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....% +| 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB +| 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB +| 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE. +| 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO +| 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E +| 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49 NABLE GEOPOLYXBI +| 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL +| 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 45 E GEOPOLYXNOCASE +| 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE +| 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....# +| 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI +| 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL +| 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE... +| 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X +| 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB +| 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY.. +| 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4 +| 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN +| 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM. +| 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS +| 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY. +| 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS +| 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE. +| 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS +| 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM.. +| 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR +| 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO +| 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG +| 3968: 58 52 54 52 49 4d 27 03 05 00 43 10 19 43 4f 4d XRTRIM'...C..COM +| 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0 +| 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY' +| 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g +| 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060 +| 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 0f 17 43 9XNOCASE&...C..C +| 4064: 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e OMPILER=gcc-5.4. +| 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM +| page 4 offset 12288 +| 0: 0d 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 ................ +| page 5 offset 16384 +| 0: 0d 00 00 00 02 0b a0 00 0c ad 0b a0 00 00 00 00 ................ +| 2976: 82 0a 02 08 08 09 08 08 17 84 06 30 20 32 35 33 ...........0 253 +| 2992: 00 01 30 04 25 06 1b 00 00 08 32 30 31 36 30 36 ..0.%.....201606 +| 3008: 30 39 03 25 07 00 00 01 34 03 25 05 00 00 01 35 09.%....4.%....5 +| 3024: 03 25 04 00 01 07 30 30 30 30 30 30 30 03 25 1a .%....0000000.%. +| 3040: 00 00 08 63 6f 6d 70 69 6c 65 72 03 25 02 00 00 ...compiler.%... +| 3056: 06 64 62 73 74 61 74 03 25 0a 00 01 04 65 62 75 .dbstat.%....ebu +| 3072: 67 03 25 08 00 00 06 65 6e 61 62 6c 65 09 25 09 g.%....enable.%. +| 3088: 05 04 04 04 04 04 00 01 08 78 74 65 6e 73 69 6f .........xtensio +| 3104: 6e 03 25 1d 00 00 04 66 74 73 34 03 25 0d 00 03 n.%....fts4.%... +| 3120: 01 35 03 25 0f 00 00 03 67 63 63 03 25 03 00 01 .5.%....gcc.%... +| 3136: 06 65 6f 70 6f 6c 79 03 25 11 00 00 05 6a 73 6f .eopoly.%....jso +| 3152: 6e 31 03 25 13 00 00 04 6c 6f 61 64 03 25 1c 00 n1.%....load.%.. +| 3168: 00 03 6d 61 78 03 25 18 00 01 05 65 6d 6f 72 79 ..max.%....emory +| 3184: 03 25 19 00 03 04 73 79 73 35 03 25 15 00 00 04 .%....sys5.%.... +| 3200: 6f 6d 69 74 03 25 1b 00 00 05 72 74 72 65 65 03 omit.%....rtree. +| 3216: 25 17 00 00 0a 74 68 72 65 61 64 73 61 66 65 03 %....threadsafe. +| 3232: 25 1e 00 00 04 76 74 61 62 03 25 0b 00 86 50 01 %....vtab.%...P. +| 3248: 08 08 08 08 08 17 8d 12 30 20 38 33 35 00 01 30 ........0 835..0 +| 3264: 12 01 06 00 01 06 00 01 06 00 1f 03 00 01 03 00 ................ +| 3280: 01 03 00 00 08 32 30 31 36 30 36 30 39 09 01 07 .....20160609... +| 3296: 00 01 07 00 01 07 00 00 01 34 09 01 05 00 01 05 .........4...... +| 3312: 00 01 05 00 00 01 35 09 01 04 00 01 04 00 01 04 ......5......... +| 3328: 00 01 07 30 30 30 30 30 30 30 09 1c 04 00 01 04 ...0000000...... +| 3344: 00 01 04 00 00 06 62 69 6e 61 72 79 3c 03 01 02 ......binary<... +| 3360: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ +| 3376: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 5f ..............._ +| 3392: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 ................ +| 3408: 01 02 02 00 03 01 02 02 00 00 08 63 6f 6d 70 69 ...........compi +| 3424: 6c 65 72 09 01 02 00 01 02 00 01 02 00 00 06 64 ler............d +| 3440: 62 73 74 61 74 09 07 03 00 01 03 00 01 03 00 01 bstat........... +| 3456: 04 65 62 75 67 09 04 02 00 01 02 00 01 02 00 00 .ebug........... +| 3472: 06 65 6e 61 62 6c 65 3f 07 02 00 01 02 00 01 02 .enable?........ +| 3488: 00 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 ................ +| 3504: 01 02 00 01 02 00 01 02 00 01 02 00 01 02 00 01 ................ +| 3520: 02 00 01 01 00 01 02 00 01 02 00 01 02 00 01 02 ................ +| 3536: 00 01 02 00 01 02 00 01 08 78 74 65 6e 73 69 6f .........xtensio +| 3552: 6e 09 1f 04 00 01 04 00 01 04 00 00 04 66 74 73 n............fts +| 3568: 34 09 0a 03 00 01 03 00 01 03 00 03 01 35 09 0d 4............5.. +| 3584: 03 00 01 03 00 01 03 00 00 03 67 63 63 09 01 03 ..........gcc... +| 3600: 00 01 03 00 01 03 00 01 06 65 6f 70 6f 6c 79 09 .........eopoly. +| 3616: 10 03 00 01 03 00 01 03 00 00 05 6a 73 6f 6e 31 ...........json1 +| 3632: 09 13 03 00 01 03 00 01 03 00 00 04 6c 6f 61 64 ............load +| 3648: 09 1f 03 00 01 03 00 01 03 00 00 03 6d 61 78 09 ............max. +| 3664: 1c 02 00 01 02 00 01 02 00 01 05 65 6d 6f 72 79 ...........emory +| 3680: 09 1c 03 00 01 03 00 01 03 00 03 04 73 79 73 35 ............sys5 +| 3696: 09 16 03 00 01 03 00 01 03 00 00 06 6e 6f 63 61 ............noca +| 3712: 73 65 3c 02 01 02 02 00 03 01 02 02 00 03 01 02 se<............. +| 3728: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ +| 3744: 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 ................ +| 3760: 03 01 02 02 00 03 01 02 02 00 03 01 02 02 00 00 ................ +| 3776: 04 6f 6d 69 74 09 1f 02 00 01 02 00 01 02 00 00 .omit........... +| 3792: 05 72 74 72 65 65 09 19 03 00 01 03 00 01 03 00 .rtree.......... +| 3808: 03 02 69 6d 3c 01 01 02 02 00 03 01 02 02 00 03 ..im<........... +| 3824: 01 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 ................ +| 3840: 02 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 ................ +| 3856: 02 00 03 01 02 02 00 03 01 02 02 00 03 01 02 02 ................ +| 3872: 00 00 0a 74 68 72 65 61 64 73 61 66 65 09 22 02 ...threadsafe... +| 3888: 00 01 02 00 01 02 00 00 04 76 74 61 62 09 07 04 .........vtab... +| 3904: 00 01 04 00 01 04 00 00 01 78 b4 01 01 01 01 02 .........x...... +| 3920: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ +| 3936: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ +| 3952: 01 01 03 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ +| 3968: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ +| 3984: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ +| 4000: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ +| 4016: 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 ................ +| 4032: 01 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 ................ +| 4048: 01 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 ................ +| 4064: 02 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 ................ +| 4080: 00 01 01 01 02 00 01 01 01 02 00 01 01 01 02 00 ................ +| page 6 offset 20480 +| 0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 00 00 00 00 ................ +| 4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09 ................ +| page 7 offset 24576 +| 0: 0d 00 00 00 05 0f b8 00 0f f4 0f e9 0f d6 00 00 ................ +| 4016: 00 00 00 00 00 00 00 00 0d 05 02 23 61 75 74 6f ...........#auto +| 4032: 6d 65 72 67 65 3d 35 0d 04 02 23 6d 65 72 67 65 merge=5...#merge +| 4048: 3d 31 30 30 2c 38 11 03 02 2b 69 6e 74 65 67 72 =100,8...+integr +| 4064: 69 74 79 2d 63 68 65 63 6b 09 02 02 1b 72 65 62 ity-check....reb +| 4080: 75 69 6c 64 0a 01 02 1d 6f 70 74 69 6d 69 7a 65 uild....optimize +| end crash-11cf359576eb28.db +}]} {} + +set saved $sqlite_fts3_enable_parentheses +set sqlite_fts3_enable_parentheses 1 +do_catchsql_test 51.1 { + SELECT 'xyzzy',offsets(t1) FROM t1 WHERE t1 MATCH 'rtree OR json1''rtree NEAR "json1 enable"'; +} {1 {database disk image is malformed}} +set sqlite_fts3_enable_parentheses $saved + +#------------------------------------------------------------------------- +# +reset_db +do_test 52.0 { + sqlite3 db {} + db deserialize [decode_hexdb { +.open --hexdb +| size 28672 pagesize 4096 filename crash-fd33f4b1c8348b.db +| page 1 offset 0 +| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3. +| 16: 10 00 01 01 00 40 20 20 00 00 00 92 00 00 00 07 .....@ ........ +| 32: 00 00 00 00 00 00 00 00 00 00 00 07 00 00 00 04 ................ +| 96: 00 00 00 00 0d 0e ef 00 08 0d 13 00 0f bd 0f 5f ..............._ +| 112: 0e f7 0e 06 0e bc 0d a4 0d 4d 0d 13 00 00 00 00 .........M...... +| 3344: 00 00 00 38 08 06 17 11 11 08 5f 74 61 62 6c 65 ...8......_table +| 3360: 74 32 74 32 43 52 45 41 54 45 20 56 49 52 54 55 t2t2CREATE VIRTU +| 3376: 41 4c 20 54 41 42 4c 45 20 74 32 20 55 53 49 4e AL TABLE t2 USIN +| 3392: 47 20 66 74 73 34 61 75 78 28 74 31 29 55 07 07 G fts4aux(t1)U.. +| 3408: 17 1b 1b 01 81 01 74 61 62 6c 65 74 31 5f 73 74 ......tablet1_st +| 3424: 61 74 74 31 5f 73 74 61 74 07 43 52 45 41 54 45 att1_stat.CREATE +| 3440: 20 54 41 42 4c 45 20 27 74 31 5f 73 74 61 74 27 TABLE 't1_stat' +| 3456: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d (id INTEGER PRIM +| 3472: 41 52 59 20 4b 45 59 2c 20 76 61 6c 75 65 20 42 ARY KEY, value B +| 3488: 4c 4f 42 29 60 06 07 17 21 21 01 81 0b 74 61 62 LOB)`...!!...tab +| 3504: 6c 65 74 31 5f 64 6f 63 73 69 7a 65 74 31 5f 64 let1_docsizet1_d +| 3520: 6f 63 73 69 7a 65 06 43 52 45 41 54 45 20 54 41 ocsize.CREATE TA +| 3536: 42 4c 45 20 27 74 31 5f 64 6f 63 73 69 7a 65 27 BLE 't1_docsize' +| 3552: 28 64 6f 63 69 64 20 49 4e 54 45 47 45 52 20 50 (docid INTEGER P +| 3568: 52 49 4d 41 52 59 20 4b 45 59 2c 20 73 69 7a 65 RIMARY KEY, size +| 3584: 20 42 4c 4f 42 29 81 33 04 07 17 1f 1f 01 82 35 BLOB).3.......5 +| 3600: 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72 74 31 tablet1_segdirt1 +| 3616: 5f 73 65 67 64 69 72 04 43 52 45 41 54 45 20 54 _segdir.CREATE T +| 3632: 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69 72 27 ABLE 't1_segdir' +| 3648: 28 6c 65 76 65 6c 20 49 4e 54 45 47 45 52 2c 69 (level INTEGER,i +| 3664: 64 78 20 49 4e 64 45 47 45 52 2c 73 74 61 72 74 dx INdEGER,start +| 3680: 5f 62 6c 6f 63 6b 20 49 4e 54 45 47 45 52 2c 6c _block INTEGER,l +| 3696: 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63 6b 20 eaves_end_block +| 3712: 49 4e 54 45 47 45 52 2c 65 6e 64 5f 62 6c 6f 63 INTEGER,end_bloc +| 3728: 6b 20 49 4e 54 45 47 45 52 2c 72 6f 6f 74 20 42 k INTEGER,root B +| 3744: 4c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45 59 28 LOB,PRIMARY KEY( +| 3760: 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 05 06 17 level, idx))1... +| 3776: 45 1f 01 00 69 6e 64 65 78 73 71 6c 69 74 65 5f E...indexsqlite_ +| 3792: 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73 65 67 autoindex_t1_seg +| 3808: 64 69 72 5f 31 74 31 5f 73 65 67 64 69 72 05 00 dir_1t1_segdir.. +| 3824: 00 00 08 00 00 00 00 66 03 07 17 23 23 01 81 13 .......f...##... +| 3840: 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e 74 73 tablet1_segments +| 3856: 74 31 5f 73 65 67 6d 65 6e 74 73 03 43 52 45 41 t1_segments.CREA +| 3872: 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 TE TABLE 't1_seg +| 3888: 6d 65 6e 74 73 27 28 62 6c 6f 63 6b 69 64 20 49 ments'(blockid I +| 3904: 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b NTEGER PRIMARY K +| 3920: 45 59 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 5c EY, block BLOB). +| 3936: 02 07 17 21 21 01 81 03 74 61 62 6c 65 74 31 5f ...!!...tablet1_ +| 3952: 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74 65 6e contentt1_conten +| 3968: 74 02 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 t.CREATE TABLE ' +| 3984: 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f 63 69 t1_content'(doci +| 4000: 64 20 49 4e 54 45 47 45 52 e6 50 52 49 4d 41 52 d INTEGER.PRIMAR +| 4016: 59 20 4b 45 59 2c 20 27 63 30 61 27 29 41 01 06 Y KEY, 'c0a')A.. +| 4032: 17 11 11 08 71 74 61 62 6c 65 74 31 74 31 43 52 ....qtablet1t1CR +| 4048: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB +| 4064: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 34 LE t1 USING fts4 +| 4080: 28 61 2c 70 72 65 66 69 78 3d 27 31 2c 32 27 29 (a,prefix='1,2') +| page 2 offset 4096 +| 0: 0d 00 00 00 08 0e 22 00 0f c4 0f 00 00 00 00 00 ................ +| 3616: 00 00 42 08 04 00 81 09 73 75 6e 74 20 69 6e 20 ..B.....sunt in +| 3632: 63 75 6c 70 61 20 71 75 69 20 6f 66 66 69 63 69 culpa qui offici +| 3648: 61 20 64 65 73 65 72 75 6e 74 20 6d 6f 6c 6c 69 a deserunt molli +| 3664: 74 20 61 6e 69 6d 20 69 64 20 65 73 74 20 7c 61 t anim id est |a +| 3680: 62 6f 72 75 6d 2e 32 07 03 00 6b 45 78 63 65 70 borum.2...kExcep +| 3696: 74 65 75 72 20 73 69 6e 74 20 6f 63 63 61 65 63 teur sint occaec +| 3712: 61 74 20 63 75 70 69 64 61 74 61 74 20 6e 6f 6e at cupidatat non +| 3728: 20 70 72 6f 69 64 65 6e 74 2c 29 06 03 00 59 63 proident,)...Yc +| 3744: 69 6c 6c 75 6d 20 64 6f 6c 6f 72 65 20 65 20 66 illum dolore e f +| 3760: 75 67 69 61 74 20 6e 75 6c 6c 61 20 70 61 72 69 ugiat nulla pari +| 3776: 61 74 75 72 2e 42 05 04 00 81 09 44 75 69 73 20 atur.B.....Duis +| 3792: 61 75 74 65 20 69 72 75 72 65 20 64 6f 6c 6f 72 aute irure dolor +| 3808: 20 69 6e 20 72 65 60 72 65 68 65 6e 64 65 72 69 in re`rehenderi +| 3824: 74 20 69 6e 20 76 70 6c 75 70 74 61 74 65 20 76 t in vpluptate v +| 3840: 65 6c 69 72 c0 65 73 73 65 29 04 03 00 59 6e 69 elir.esse)...Yni +| 3856: 73 6a 20 75 74 20 61 6c 69 71 75 69 70 20 65 20 sj ut aliquip e +| 3872: 65 20 63 6f 6d 6d 6f 64 6f 20 63 6f 6e 73 65 71 e commodo conseq +| 3888: 75 61 74 2e 46 03 04 00 29 11 55 74 20 65 6e 69 uat.F...).Ut eni +| 3904: 6d 20 61 64 20 6d 69 6e 69 6d 20 76 65 6e 69 61 m ad minim venia +| 3920: 6d 2c 20 71 75 69 73 20 6e 6f 73 74 72 75 64 20 m, quis nostrud +| 3936: 65 78 65 72 63 69 7a 71 74 69 6f 6e 20 75 6c 6c exercizqtion ull +| 3952: 61 6d 63 6f 20 6c 61 62 6f 72 69 73 46 02 04 00 amco laborisF... +| 3968: 81 11 73 65 64 20 64 6f 20 65 69 75 73 6d 6f 64 ..sed do eiusmod +| 3984: 20 74 65 6d 70 6f 72 20 69 6e 63 69 64 69 64 75 tempor incididu +| 4000: 6e 74 20 75 74 20 6c 61 62 6f 72 65 20 65 74 20 nt ut labore et +| 4016: 64 6f 6c 6f 72 65 20 6d 61 67 6e 61 20 61 6c 69 dolore magna ali +| 4032: 71 75 61 2e 3a 01 03 00 7b 4c 6f 72 65 6d 20 69 qua.:....Lorem i +| 4048: 72 63 75 6d 20 64 6f 6c 6f 72 20 73 69 74 20 61 rcum dolor sit a +| 4064: 6d 65 74 2c 20 63 6f 6e 78 65 63 74 65 64 75 72 met, conxectedur +| 4080: 20 61 64 69 70 69 73 00 00 00 00 00 00 00 00 00 adipis......... +| page 4 offset 12288 +| 0: 0d 00 00 00 03 0a c1 00 0d 61 0c 54 0a c1 00 00 .........a.T.... +| 2752: 00 83 10 03 08 02 08 08 08 17 86 0e 08 00 30 20 ..............0 +| 2768: 33 38 35 00 02 61 64 06 01 08 00 02 04 00 01 01 385..ad......... +| 2784: 6c 06 02 0c 00 02 04 00 01 01 6d 03 01 06 10 01 l.........m..... +| 2800: 01 6e 03 08 09 00 01 01 75 03 05 03 00 00 02 63 .n......u......c +| 2816: 69 03 06 02 00 01 01 6f 07 01 07 00 03 07 03 00 i......o........ +| 2832: 01 01 75 06 75 05 00 01 04 00 00 02 64 65 03 08 ..u.u.......de.. +| 2848: 07 00 01 01 6f 0d 01 04 00 01 03 09 00 03 05 00 ....o........... +| 2864: 01 03 00 01 01 75 03 05 02 00 00 02 65 69 03 02 .....u......ei.. +| 2880: 04 00 01 01 6c 03 01 44 00 01 01 6e 03 03 03 00 ....l..D...n.... +| 2896: 01 01 73 06 05 0b 00 03 0b 00 01 01 74 03 02 09 ..s.........t... +| 2912: 00 01 01 78 06 03 09 00 04 02 00 00 02 66 75 03 ...x.........fu. +| 2928: 06 05 00 00 02 69 64 03 08 0a 00 01 01 6e 0a 02 .....id......n.. +| 2944: 06 00 03 06 04 00 03 03 00 01 01 70 03 01 03 00 ...........p.... +| 2960: 01 01 72 03 05 04 00 00 02 6c 61 09 02 08 00 01 ..r......la..... +| 2976: 0b 00 05 0c 00 01 01 6f 03 01 02 00 00 02 6d 61 .......o......ma +| 2992: 03 02 0b 00 01 01 69 03 03 05 00 01 01 6f 03 08 ......i......o.. +| 3008: 08 00 00 02 6e 69 03 04 02 00 01 01 6f 06 03 08 ....ni......o... +| 3024: 00 04 06 00 01 01 75 03 06 06 00 00 02 6f 63 03 ......u......oc. +| 3040: 07 04 00 01 01 66 03 08 06 00 00 02 70 61 03 06 .....f......pa.. +| 3056: 07 00 01 11 72 03 07 07 00 00 02 71 75 06 03 07 ....r......qu... +| 3072: 00 05 05 00 00 02 72 65 03 05 07 00 00 02 73 65 ......re......se +| 3088: 03 02 02 00 01 01 69 06 01 05 00 06 03 00 01 01 ......i......... +| 3104: 75 03 08 02 00 00 02 74 65 03 02 05 00 00 02 75 u......te......u +| 3120: 6c 13 03 0a 00 01 01 74 09 02 07 00 01 02 00 01 l......t........ +| 3136: 02 ff ff 02 76 65 06 03 06 00 02 0a 00 01 01 6f ....ve.........o +| 3152: 03 05 09 00 82 0a 02 08 02 08 08 08 17 84 02 04 ................ +| 3168: 00 30 20 32 35 31 00 01 61 13 01 06 04 00 01 0c .0 251..a....... +| 3184: 00 01 04 00 01 04 00 01 03 00 03 09 00 00 01 63 ...............c +| 3200: 10 01 07 00 03 07 03 00 02 02 00 01 05 00 01 04 ................ +| 3216: 00 00 01 64 11 01 04 00 01 03 09 00 03 02 05 00 ...d............ +| 3232: 01 03 00 02 07 00 00 01 65 1b 01 09 00 01 04 07 ........e....... +| 3248: 00 01 03 08 00 01 05 03 00 01 1c eb 01 04 00 01 ................ +| 3264: 0e 80 01 0b 00 00 01 66 03 06 05 00 00 01 69 0f .......f......i. +| 3280: 01 03 00 01 06 0b 23 04 04 04 00 03 03 09 00 00 ......#......... +| 3296: 01 6c 0c 01 02 00 01 08 00 01 0b 00 05 0c 00 00 .l.............. +| 3312: 01 6d 09 02 0b 00 01 05 00 05 08 00 00 01 6e 0c .m............n. +| 3328: 03 08 00 01 02 00 02 06 00 01 06 00 00 01 6f 06 ..............o. +| 3344: 07 04 00 01 06 00 00 01 70 06 06 07 00 01 07 00 ........p....... +| 3360: 00 01 71 06 03 07 00 05 05 00 00 01 72 03 05 07 ..q.........r... +| 3376: 00 00 02 73 0c 01 05 00 01 02 00 05 03 00 01 02 ...s............ +| 3392: 00 00 01 74 03 02 05 00 00 01 75 0a 02 07 00 01 ...t......u..... +| 3408: 02 0a 00 01 03 00 00 01 76 07 03 06 00 02 09 03 ........v....... +| 3424: 00 85 1c 01 08 08 08 08 08 17 8a 2a 30 20 36 35 ...........*0 65 +| 3440: 35 00 02 61 64 03 03 04 00 02 08 69 70 69 73 63 5..ad......ipisc +| 3456: 69 6e 67 03 01 08 00 01 05 6c 69 71 75 61 03 02 ing......liqua.. +| 3472: 0c 00 05 02 69 70 03 04 04 00 01 03 6d 65 74 03 ....ip......met. +| 3488: 01 06 00 01 03 6e 69 6d 03 08 09 00 01 03 75 74 .....nim......ut +| 3504: 65 03 05 03 00 00 06 63 69 6c 6c 75 6d 03 06 02 e......cillum... +| 3520: 00 01 06 6f 6d 6d 6f 64 6f 03 04 07 00 02 09 6e ...ommodo......n +| 3536: 73 65 63 74 65 74 75 72 03 01 07 00 05 04 71 75 sectetur......qu +| 3552: 61 73 03 04 08 00 01 04 75 6c 70 61 03 08 04 00 as......ulpa.... +| 3568: 02 07 70 69 64 61 74 61 74 03 07 05 00 00 08 64 ..pidatat......d +| 3584: 65 73 65 72 75 6e 74 03 08 07 00 01 01 6f 03 09 eserunt......o.. +| 3600: b3 00 02 03 6c 6f 72 06 01 04 00 04 05 00 05 01 ....lor......... +| 3616: 65 06 02 0a 00 04 03 00 01 03 75 69 73 03 05 02 e.........uis... +| 3632: 00 00 01 65 07 04 05 03 00 02 04 00 01 06 69 75 ...e..........iu +| 3648: 73 6d 6f 64 03 02 04 00 01 03 6c 69 74 03 01 09 smod......lit... +| 3664: 00 01 03 6e 69 6d 03 03 03 00 01 03 73 73 65 03 ...nim......sse. +| 3680: 05 0b 00 02 01 74 03 08 0b 00 01 01 74 03 02 09 .....t......t... +| 3696: 00 01 08 78 63 65 70 64 65 75 72 03 07 02 00 02 ...xcepdeur..... +| 3712: 0a 65 72 63 69 74 61 74 69 6f 6e 03 03 09 00 00 .ercitation..... +| 3728: 06 66 75 67 69 61 74 03 06 05 00 00 02 69 64 03 .fugiat......id. +| 3744: 08 0a 00 01 01 6e 07 05 06 04 00 03 03 00 02 08 .....n.......... +| 3760: 63 69 64 69 64 75 6e 74 03 02 06 00 01 04 70 73 cididunt......ps +| 3776: 75 6c f3 01 03 00 01 04 72 75 72 65 03 05 04 00 ul......rure.... +| 3792: 00 06 6c 61 62 6f 72 65 03 02 08 00 05 02 69 73 ..labore......is +| 3808: 03 03 0b 00 05 02 75 6d 03 08 0c 00 01 04 6f 72 ......um......or +| 3824: 65 6d 03 01 02 00 00 05 6d 61 67 6e 61 03 02 0b em......magna... +| 3840: 00 01 04 69 6e 69 6d 03 03 05 00 01 05 6f 6c 6c ...inim......oll +| 3856: 69 74 03 08 08 00 00 04 6e 69 73 69 03 04 02 00 it......nisi.... +| 3872: 01 02 6f 6e 03 07 06 00 02 05 73 74 72 75 64 03 ..on......strud. +| 3888: 03 08 00 01 04 75 6c 6c 61 03 06 06 00 00 08 6f .....ulla......o +| 3904: 63 63 61 65 63 61 74 03 07 04 00 01 06 66 66 69 ccaecat......ffi +| 3920: 63 69 61 03 08 06 00 00 08 70 61 72 69 61 74 75 cia......pariatu +| 3936: 72 03 06 07 00 01 07 72 6f 69 64 65 6e 74 03 07 r......roident.. +| 3952: 07 00 00 03 71 75 69 03 08 15 00 03 01 73 03 03 ....qui......s.. +| 3968: 07 00 00 0d 72 65 70 72 65 68 65 6e 64 65 72 69 ....reprehenderi +| 3984: 74 03 05 07 00 00 03 73 65 64 03 02 01 ff ff f0 t......sed...... +| 4000: b9 6e 74 03 07 03 00 02 01 74 03 01 05 00 01 03 .nt......t...... +| 4016: 75 6e 74 03 08 02 00 00 06 74 65 6d 70 6f 72 03 unt......tempor. +| 4032: 02 05 00 00 07 75 6c 6c 61 6d 63 6f 03 03 0a 00 .....ullamco.... +| 4048: 01 01 74 09 02 07 00 01 02 00 01 03 00 00 05 76 ..t............v +| 4064: 65 6c 69 74 03 05 0a 00 02 04 6e 69 61 6d 03 03 elit......niam.. +| 4080: 06 00 01 08 6f 6c 75 70 74 61 74 65 03 05 09 00 ....oluptate.... +| page 5 offset 16384 +| 0: 0a 00 00 00 03 0f eb 00 0f fb 0f f3 00 00 00 00 ................ +| 4064: 00 00 00 00 00 00 00 00 00 00 00 07 04 02 08 01 ................ +| 4080: 08 00 03 07 04 02 08 01 04 00 02 04 04 08 08 09 ................ +| page 6 offset 20480 +| 0: 0d 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 ................ +| 4048: 04 08 03 00 0e 0b 04 07 03 00 0e 06 04 06 03 00 ................ +| 4064: 0e 06 04 05 03 00 0e 0a 04 04 03 00 0e 07 04 03 ................ +| 4080: 03 00 0d fa 04 02 03 00 0e 0b 04 00 00 00 00 00 ................ +| page 7 offset 24576 +| 4080: 00 00 00 00 00 00 00 07 00 03 00 00 00 00 00 00 ................ +| end crash-fd33f4b1c8348b.db +}]} {} +do_catchsql_test 52.1 { + SELECT * FROM t1, t2; +} {1 {database disk image is malformed}} finish_test diff --git a/test/fts3f.test b/test/fts3f.test new file mode 100644 index 00000000..d9a57cbc --- /dev/null +++ b/test/fts3f.test @@ -0,0 +1,57 @@ +# 2006 September 9 +# +# 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 FTS3 module. +# +# $Id: fts3aa.test,v 1.1 2007/08/20 17:38:42 shess Exp $ +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix fts3f + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts3 { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE ft USING fts3(x); + BEGIN; + INSERT INTO ft VALUES('a one'), ('b one'), ('c one'); +} + +do_test 1.1 { + set ret [list] + db eval { SELECT docid FROM ft WHERE ft MATCH 'one' } { + if { $docid==2 } { + db eval COMMIT + } + lappend ret $docid + } + set ret +} {1 2 3} + +do_execsql_test 1.2 { + BEGIN; + INSERT INTO ft VALUES('a one'), ('b one'), ('c one'); +} + +do_execsql_test 1.3 { + SELECT docid, optimize(ft) FROM ft WHERE ft MATCH 'one' +} { + 1 {Index optimized} 2 {Index already optimal} 3 {Index already optimal} + 4 {Index already optimal} + 5 {Index already optimal} 6 {Index already optimal} +} + +finish_test diff --git a/test/fts3offsets.test b/test/fts3offsets.test index 4a1e63aa..24c339dc 100644 --- a/test/fts3offsets.test +++ b/test/fts3offsets.test @@ -118,6 +118,18 @@ do_execsql_test 1.4.1 { 1 {(A) (B) (C)} } +do_execsql_test 1.5.0 { + CREATE VIRTUAL TABLE x1 USING fts3(x); + INSERT INTO x1 VALUES('A A A'); + INSERT INTO x1 VALUES('A A A'); +} +do_execsql_test 1.5.1 { + SELECT offsets(x1) FROM x1 WHERE x1 MATCH 'a OR b AND c NEAR d' +} { + {0 0 0 1 0 0 2 1 0 0 4 1} + {0 0 0 1 0 0 2 1 0 0 4 1} +} + set sqlite_fts3_enable_parentheses 0 finish_test diff --git a/test/func.test b/test/func.test index 38c00377..ca1027f5 100644 --- a/test/func.test +++ b/test/func.test @@ -1459,12 +1459,15 @@ do_execsql_test func-33.10 { do_catchsql_test func-33.11 { INSERT INTO t33a VALUES(1,2); } {1 {unsafe use of testdirectonly()}} + +ifcapable altertable { do_execsql_test func-33.20 { ALTER TABLE t33a RENAME COLUMN a TO aaa; SELECT sql FROM sqlite_master WHERE name='r1'; } {{CREATE TRIGGER r1 AFTER INSERT ON t33a BEGIN INSERT INTO t33b(x,y) VALUES(testdirectonly(new.aaa),new.b); END}} +} # 2020-01-09 Yongheng fuzzer find # The bug is in the register-validity debug logic, not in the SQLite core diff --git a/test/func3.test b/test/func3.test index a535bae7..0221a0df 100644 --- a/test/func3.test +++ b/test/func3.test @@ -198,6 +198,14 @@ do_test func3-5.59 { } [db eval {EXPLAIN SELECT min(1.0+'2.0',4*11)}] +# Test the outcome of specifying NULL xStep and xFinal pointers (normally +# used to delete any existing function) and a non-NULL xDestroy when there +# is no existing function to destroy. +# +do_test func3-6.0 { + sqlite3_create_function_v2 db nofunc 1 utf8 +} {} + finish_test diff --git a/test/fuzzcheck.c b/test/fuzzcheck.c index 3020086a..f5a7b092 100644 --- a/test/fuzzcheck.c +++ b/test/fuzzcheck.c @@ -302,6 +302,108 @@ static VFile *createVFile(const char *zName, int sz, unsigned char *pData){ return pNew; } +/* Return true if the line is all zeros */ +static int allZero(unsigned char *aLine){ + int i; + for(i=0; i<16 && aLine[i]==0; i++){} + return i==16; +} + +/* +** Render a database and query as text that can be input into +** the CLI. +*/ +static void renderDbSqlForCLI( + FILE *out, /* Write to this file */ + const char *zFile, /* Name of the database file */ + unsigned char *aDb, /* Database content */ + int nDb, /* Number of bytes in aDb[] */ + unsigned char *zSql, /* SQL content */ + int nSql /* Bytes of SQL */ +){ + fprintf(out, ".print ******* %s *******\n", zFile); + if( nDb>100 ){ + int i, j; /* Loop counters */ + int pgsz; /* Size of each page */ + int lastPage = 0; /* Last page number shown */ + int iPage; /* Current page number */ + unsigned char *aLine; /* Single line to display */ + unsigned char buf[16]; /* Fake line */ + unsigned char bShow[256]; /* Characters ok to display */ + + memset(bShow, '.', sizeof(bShow)); + for(i=' '; i<='~'; i++){ + if( i!='{' && i!='}' && i!='"' && i!='\\' ) bShow[i] = i; + } + pgsz = (aDb[16]<<8) | aDb[17]; + if( pgsz==0 ) pgsz = 65536; + if( pgsz<512 || (pgsz&(pgsz-1))!=0 ) pgsz = 4096; + fprintf(out,".open --hexdb\n"); + fprintf(out,"| size %d pagesize %d filename %s\n",nDb,pgsz,zFile); + for(i=0; inDb ){ + memset(buf, 0, sizeof(buf)); + memcpy(buf, aDb+i, nDb-i); + aLine = buf; + }else{ + aLine = aDb + i; + } + if( allZero(aLine) ) continue; + iPage = i/pgsz + 1; + if( lastPage!=iPage ){ + fprintf(out,"| page %d offset %d\n", iPage, (iPage-1)*pgsz); + lastPage = iPage; + } + fprintf(out,"| %5d:", i-(iPage-1)*pgsz); + for(j=0; j<16; j++) fprintf(out," %02x", aLine[j]); + fprintf(out," "); + for(j=0; j<16; j++){ + unsigned char c = (unsigned char)aLine[j]; + fputc( bShow[c], stdout); + } + fputc('\n', stdout); + } + fprintf(out,"| end %s\n", zFile); + }else{ + fprintf(out,".open :memory:\n"); + } + fprintf(out,".testctrl prng_seed 1 db\n"); + fprintf(out,".testctrl internal_functions\n"); + fprintf(out,"%.*s", nSql, zSql); + if( nSql>0 && zSql[nSql-1]!='\n' ) fprintf(out, "\n"); +} + +/* +** Read the complete content of a file into memory. Add a 0x00 terminator +** and return a pointer to the result. +** +** The file content is held in memory obtained from sqlite_malloc64() which +** should be freed by the caller. +*/ +static char *readFile(const char *zFilename, long *sz){ + FILE *in; + long nIn; + unsigned char *pBuf; + + *sz = 0; + if( zFilename==0 ) return 0; + in = fopen(zFilename, "rb"); + if( in==0 ) return 0; + fseek(in, 0, SEEK_END); + *sz = nIn = ftell(in); + rewind(in); + pBuf = sqlite3_malloc64( nIn+1 ); + if( pBuf && 1==fread(pBuf, nIn, 1, in) ){ + pBuf[nIn] = 0; + fclose(in); + return (char*)pBuf; + } + sqlite3_free(pBuf); + *sz = 0; + fclose(in); + return 0; +} + /* ** Implementation of the "readfile(X)" SQL function. The entire content @@ -313,25 +415,15 @@ static void readfileFunc( int argc, sqlite3_value **argv ){ - const char *zName; - FILE *in; long nIn; void *pBuf; + const char *zName = (const char*)sqlite3_value_text(argv[0]); - zName = (const char*)sqlite3_value_text(argv[0]); if( zName==0 ) return; - in = fopen(zName, "rb"); - if( in==0 ) return; - fseek(in, 0, SEEK_END); - nIn = ftell(in); - rewind(in); - pBuf = sqlite3_malloc64( nIn ); - if( pBuf && 1==fread(pBuf, nIn, 1, in) ){ + pBuf = readFile(zName, &nIn); + if( pBuf ){ sqlite3_result_blob(context, pBuf, nIn, sqlite3_free); - }else{ - sqlite3_free(pBuf); } - fclose(in); } /* @@ -750,7 +842,11 @@ static int block_troublesome_sql( (void)zArg3; (void)zArg4; if( eCode==SQLITE_PRAGMA ){ - if( eVerbosity==0 ){ + if( sqlite3_stricmp("busy_timeout",zArg1)==0 + && (zArg2==0 || strtoll(zArg2,0,0)>100 || strtoll(zArg2,0,10)>100) + ){ + return SQLITE_DENY; + }else if( eVerbosity==0 ){ if( sqlite3_strnicmp("vdbe_", zArg1, 5)==0 || sqlite3_stricmp("parser_trace", zArg1)==0 || sqlite3_stricmp("temp_store_directory", zArg1)==0 @@ -762,9 +858,16 @@ static int block_troublesome_sql( oomCounter = atoi(zArg2); } }else if( eCode==SQLITE_ATTACH ){ - if( zArg1==0 || (zArg1[0]!=0 && strcmp(zArg1,":memory:")!=0) ){ - return SQLITE_DENY; + /* Deny the ATTACH if it is attaching anything other than an in-memory + ** database. */ + if( zArg1==0 ) return SQLITE_DENY; + if( strcmp(zArg1,":memory:")==0 ) return SQLITE_OK; + if( sqlite3_strglob("file:*[?]vfs=memdb", zArg1)==0 + && sqlite3_strglob("file:*[^/a-zA-Z0-9_.]*[?]vfs=memdb", zArg1)!=0 + ){ + return SQLITE_OK; } + return SQLITE_DENY; } return SQLITE_OK; } @@ -844,7 +947,13 @@ static int runDbSql(sqlite3 *db, const char *zSql){ } /* Invoke this routine to run a single test case */ -int runCombinedDbSqlInput(const uint8_t *aData, size_t nByte, int iTimeout){ +int runCombinedDbSqlInput( + const uint8_t *aData, /* Combined DB+SQL content */ + size_t nByte, /* Size of aData in bytes */ + int iTimeout, /* Use this timeout */ + int bScript, /* If true, just render CLI output */ + int iSqlId /* SQL identifier */ +){ int rc; /* SQLite API return value */ int iSql; /* Index in aData[] of start of SQL */ unsigned char *aDb = 0; /* Decoded database content */ @@ -870,6 +979,14 @@ int runCombinedDbSqlInput(const uint8_t *aData, size_t nByte, int iTimeout){ iSql = decodeDatabase((unsigned char*)aData, (int)nByte, &aDb, &nDb); if( iSql<0 ) return 0; nSql = (int)(nByte - iSql); + if( bScript ){ + char zName[100]; + sqlite3_snprintf(sizeof(zName),zName,"dbsql%06d.db",iSqlId); + renderDbSqlForCLI(stdout, zName, aDb, nDb, + (unsigned char*)(aData+iSql), nSql); + sqlite3_free(aDb); + return 0; + } if( eVerbosity>=3 ){ printf( "****** %d-byte input, %d-byte database, %d-byte script " @@ -973,7 +1090,7 @@ testrun_finished: if( rc!=SQLITE_OK ){ fprintf(stdout, "sqlite3_close() returns %d\n", rc); } - if( eVerbosity>=2 ){ + if( eVerbosity>=2 && !bScript ){ fprintf(stdout, "Peak memory usages: %f MB\n", sqlite3_memory_highwater(1) / 1000000.0); } @@ -1447,6 +1564,7 @@ static void showHelp(void){ " -q|--quiet Reduced output\n" " --rebuild Rebuild and vacuum the database file\n" " --result-trace Show the results of each SQL command\n" +" --script Output CLI script instead of running tests\n" " --skip N Skip the first N test cases\n" " --spinner Use a spinner to show progress\n" " --sqlid N Use only SQL where sqlid=N\n" @@ -1476,6 +1594,7 @@ int main(int argc, char **argv){ int vdbeLimitFlag = 0; /* --limit-vdbe */ int infoFlag = 0; /* --info */ int nSkip = 0; /* --skip */ + int bScript = 0; /* --script */ int bSpinner = 0; /* True for --spinner */ int timeoutTest = 0; /* undocumented --timeout-test flag */ int runFlags = 0; /* Flags sent to runSql() */ @@ -1503,6 +1622,7 @@ int main(int argc, char **argv){ int nV; /* How much to increase verbosity with -vvvv */ sqlite3_int64 tmStart; /* Start of each test */ + sqlite3_config(SQLITE_CONFIG_URI,1); registerOomSimulator(); sqlite3_initialize(); iBegin = timeOfDay(); @@ -1573,7 +1693,7 @@ int main(int argc, char **argv){ }else if( strcmp(z,"load-dbsql")==0 ){ zInsSql = "INSERT INTO xsql(sqltext)" - "VALUES(CAST(readtextfile(?1) AS text))"; + "VALUES(readfile(?1))"; iFirstInsArg = i+1; openFlags4Data = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; dbSqlOnly = 1; @@ -1609,6 +1729,9 @@ int main(int argc, char **argv){ if( strcmp(z,"result-trace")==0 ){ runFlags |= SQL_OUTPUT; }else + if( strcmp(z,"script")==0 ){ + bScript = 1; + }else if( strcmp(z,"skip")==0 ){ if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); nSkip = atoi(argv[++i]); @@ -1657,6 +1780,16 @@ int main(int argc, char **argv){ } return 0; }else + if( strcmp(z,"is-dbsql")==0 ){ + i++; + for(i++; izName); + if( rc==SQLITE_OK ){ + rc = sqlite3_exec(db, "SELECT count(*) FROM sqlite_schema", 0, 0, 0); + } if( rc ){ - fatalError("cannot open source database %s - %s", - azSrcDb[iSrcDb], sqlite3_errmsg(db)); + sqlite3_close(db); + zRawData = readFile(azSrcDb[iSrcDb], &nRawData); + if( zRawData==0 ){ + fatalError("input file \"%s\" is not recognized\n", azSrcDb[iSrcDb]); + } + sqlite3_open(":memory:", &db); } /* Print the description, if there is one */ @@ -1718,6 +1860,7 @@ int main(int argc, char **argv){ sqlite3_finalize(pStmt); printf("\n"); sqlite3_close(db); + sqlite3_free(zRawData); continue; } @@ -1742,6 +1885,21 @@ int main(int argc, char **argv){ sqlite3_free(zSql); if( rc ) fatalError("cannot change description: %s", sqlite3_errmsg(db)); } + if( zRawData ){ + zInsSql = "INSERT INTO xsql(sqltext) VALUES(?1)"; + rc = sqlite3_prepare_v2(db, zInsSql, -1, &pStmt, 0); + if( rc ) fatalError("cannot prepare statement [%s]: %s", + zInsSql, sqlite3_errmsg(db)); + sqlite3_bind_text(pStmt, 1, zRawData, nRawData, SQLITE_STATIC); + sqlite3_step(pStmt); + rc = sqlite3_reset(pStmt); + if( rc ) fatalError("insert failed for %s", argv[i]); + sqlite3_finalize(pStmt); + rebuild_database(db, dbSqlOnly); + zInsSql = 0; + sqlite3_free(zRawData); + zRawData = 0; + } ossFuzzThisDb = ossFuzz; /* If the CONFIG(name,value) table exists, read db-specific settings @@ -1785,7 +1943,7 @@ int main(int argc, char **argv){ while( rc==0 && fgets(zLine,sizeof(zLine),stdin)!=0 ){ size_t kk = strlen(zLine); while( kk>0 && zLine[kk-1]<=' ' ) kk--; - sqlite3_bind_text(pStmt, 1, zLine, kk, SQLITE_STATIC); + sqlite3_bind_text(pStmt, 1, zLine, (int)kk, SQLITE_STATIC); if( verboseFlag ) printf("loading %.*s\n", (int)kk, zLine); sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); @@ -1872,7 +2030,7 @@ int main(int argc, char **argv){ } /* Print the description, if there is one */ - if( !quietFlag ){ + if( !quietFlag && !bScript ){ zDbName = azSrcDb[iSrcDb]; i = (int)strlen(zDbName) - 1; while( i>0 && zDbName[i-1]!='/' && zDbName[i-1]!='\\' ){ i--; } @@ -1929,12 +2087,16 @@ int main(int argc, char **argv){ /* Run a test using each SQL script against each database. */ - if( !verboseFlag && !quietFlag && !bSpinner ) printf("%s:", zDbName); + if( !verboseFlag && !quietFlag && !bSpinner && !bScript ){ + printf("%s:", zDbName); + } for(pSql=g.pFirstSql; pSql; pSql=pSql->pNext){ tmStart = timeOfDay(); if( isDbSql(pSql->a, pSql->sz) ){ sqlite3_snprintf(sizeof(g.zTestName), g.zTestName, "sqlid=%d",pSql->id); - if( bSpinner ){ + if( bScript ){ + /* No progress output */ + }else if( bSpinner ){ int nTotal =g.nSql; int idx = pSql->seq; printf("\r%s: %d/%d ", zDbName, idx, nTotal); @@ -1955,10 +2117,10 @@ int main(int argc, char **argv){ if( nSkip>0 ){ nSkip--; }else{ - runCombinedDbSqlInput(pSql->a, pSql->sz, iTimeout); + runCombinedDbSqlInput(pSql->a, pSql->sz, iTimeout, bScript, pSql->id); } nTest++; - if( bTimer ){ + if( bTimer && !bScript ){ sqlite3_int64 tmEnd = timeOfDay(); printf("%lld %s\n", tmEnd - tmStart, g.zTestName); } @@ -1971,7 +2133,9 @@ int main(int argc, char **argv){ const char *zVfs = "inmem"; sqlite3_snprintf(sizeof(g.zTestName), g.zTestName, "sqlid=%d,dbid=%d", pSql->id, pDb->id); - if( bSpinner ){ + if( bScript ){ + /* No progress output */ + }else if( bSpinner ){ int nTotal = g.nDb*g.nSql; int idx = pSql->seq*g.nDb + pDb->id - 1; printf("\r%s: %d/%d ", zDbName, idx, nTotal); @@ -1993,6 +2157,14 @@ int main(int argc, char **argv){ nSkip--; continue; } + if( bScript ){ + char zName[100]; + sqlite3_snprintf(sizeof(zName), zName, "db%06d.db", + pDb->id>1 ? pDb->id : pSql->id); + renderDbSqlForCLI(stdout, zName, + pDb->a, pDb->sz, pSql->a, pSql->sz); + continue; + } createVFile("main.db", pDb->sz, pDb->a); sqlite3_randomness(0,0); if( ossFuzzThisDb ){ @@ -2065,7 +2237,9 @@ int main(int argc, char **argv){ } } } - if( bSpinner ){ + if( bScript ){ + /* No progress output */ + }else if( bSpinner ){ int nTotal = g.nDb*g.nSql; printf("\r%s: %d/%d \n", zDbName, nTotal, nTotal); }else if( !quietFlag && !verboseFlag ){ @@ -2081,7 +2255,7 @@ int main(int argc, char **argv){ } /* End loop over all source databases */ - if( !quietFlag ){ + if( !quietFlag && !bScript ){ sqlite3_int64 iElapse = timeOfDay() - iBegin; printf("fuzzcheck: 0 errors out of %d tests in %d.%03d seconds\n" "SQLite %s %s\n", diff --git a/test/fuzzdata8.db b/test/fuzzdata8.db index 86217e4b421375154ba0316867b7d9aa9514c191..966b73730c2c0c73069714e73127ecf2b056a306 100644 GIT binary patch delta 165725 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 delta 61690 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 diff --git a/test/gencol1.test b/test/gencol1.test index 43f48dff..ee0ebc53 100644 --- a/test/gencol1.test +++ b/test/gencol1.test @@ -585,5 +585,34 @@ do_execsql_test gencol1-20.2 { SELECT * FROM tab; } {2001-01-01 0 0 5 {}} +# 2021-07-30 forum https://sqlite.org/forum/forumpost/ff3ffe09251c105b?t=h +# +ifcapable vtab { +reset_db + do_execsql_test gencol1-21.1 { + CREATE TABLE t1( + a integer primary key, + b int generated always as (a+5), + c text GENERATED ALWAYS as (printf('%08x',a)), + d Generated + Always + AS ('xyzzy'), + e int Always default(5) + ); + INSERT INTO t1(a) VALUES(5); + SELECT name, type FROM pragma_table_xinfo('t1'); + } {a INTEGER b INT c TEXT d {} e INT} +} + +# 2021-09-07 forum https://sqlite.org/forum/forumpost/699b44b3ee +# +reset_db +do_execsql_test gencol1-22.1 { + CREATE TABLE t0(a PRIMARY KEY,b TEXT AS ('2') UNIQUE); + INSERT INTO t0(a) VALUES(2); + 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} finish_test diff --git a/test/hook.test b/test/hook.test index 1dba87f2..bb868df8 100644 --- a/test/hook.test +++ b/test/hook.test @@ -677,30 +677,32 @@ do_preupdate_test 7.4.2.3 { DELETE main t5 1 1 a 1 } -do_execsql_test 7.5.1.0 { - CREATE TABLE t7(a, b); - INSERT INTO t7 VALUES('one', 'two'); - INSERT INTO t7 VALUES('three', 'four'); - ALTER TABLE t7 ADD COLUMN c DEFAULT NULL; -} - -do_preupdate_test 7.5.1.1 { - DELETE FROM t7 WHERE a = 'one' -} { - DELETE main t7 1 1 one two {} -} - -do_preupdate_test 7.5.1.2 { - UPDATE t7 SET b = 'five' -} { - UPDATE main t7 2 2 three four {} three five {} -} - -do_execsql_test 7.5.2.0 { - CREATE TABLE t8(a, b); - INSERT INTO t8 VALUES('one', 'two'); - INSERT INTO t8 VALUES('three', 'four'); - ALTER TABLE t8 ADD COLUMN c DEFAULT 'xxx'; +ifcapable altertable { + do_execsql_test 7.5.1.0 { + CREATE TABLE t7(a, b); + INSERT INTO t7 VALUES('one', 'two'); + INSERT INTO t7 VALUES('three', 'four'); + ALTER TABLE t7 ADD COLUMN c DEFAULT NULL; + } + + do_preupdate_test 7.5.1.1 { + DELETE FROM t7 WHERE a = 'one' + } { + DELETE main t7 1 1 one two {} + } + + do_preupdate_test 7.5.1.2 { + UPDATE t7 SET b = 'five' + } { + UPDATE main t7 2 2 three four {} three five {} + } + + do_execsql_test 7.5.2.0 { + CREATE TABLE t8(a, b); + INSERT INTO t8 VALUES('one', 'two'); + INSERT INTO t8 VALUES('three', 'four'); + ALTER TABLE t8 ADD COLUMN c DEFAULT 'xxx'; + } } if 0 { @@ -848,48 +850,53 @@ do_preupdate_test 7.6.4 { } # No preupdate callbacks for modifying sqlite_master. -do_preupdate_test 8.1 { CREATE TABLE x1(x, y); } { } -do_preupdate_test 8.2 { ALTER TABLE x1 ADD COLUMN z } { } -do_preupdate_test 8.3 { ALTER TABLE x1 RENAME TO y1 } { } -do_preupdate_test 8.4 { CREATE INDEX y1x ON y1(x) } { } -do_preupdate_test 8.5 { CREATE VIEW v1 AS SELECT * FROM y1 } { } -do_preupdate_test 8.6 { DROP TABLE y1 } { } +ifcapable altertable { + do_preupdate_test 8.1 { CREATE TABLE x1(x, y); } { } + do_preupdate_test 8.2 { ALTER TABLE x1 ADD COLUMN z } { } + do_preupdate_test 8.3 { ALTER TABLE x1 RENAME TO y1 } { } + do_preupdate_test 8.4 { CREATE INDEX y1x ON y1(x) } { } + do_preupdate_test 8.5 { CREATE VIEW v1 AS SELECT * FROM y1 } { } + do_preupdate_test 8.6 { DROP TABLE y1 } { } +} #------------------------------------------------------------------------- reset_db db preupdate hook preupdate_hook -do_execsql_test 9.0 { - CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); - CREATE TABLE t2(a, b INTEGER PRIMARY KEY); -} -do_preupdate_test 9.1 { - INSERT INTO t1 VALUES(456, NULL, NULL); -} { - INSERT main t1 456 456 0 456 {} {} -} -do_execsql_test 9.2 { - ALTER TABLE t1 ADD COLUMN d; -} -do_preupdate_test 9.3 { - INSERT INTO t1(a, b, c) VALUES(457, NULL, NULL); -} { - INSERT main t1 457 457 0 457 {} {} {} -} -do_preupdate_test 9.4 { - DELETE FROM t1 WHERE a=456 -} { - DELETE main t1 456 456 0 456 {} {} {} + +ifcapable altertable { + do_execsql_test 9.0 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); + CREATE TABLE t2(a, b INTEGER PRIMARY KEY); + } + do_preupdate_test 9.1 { + INSERT INTO t1 VALUES(456, NULL, NULL); + } { + INSERT main t1 456 456 0 456 {} {} + } + do_execsql_test 9.2 { + ALTER TABLE t1 ADD COLUMN d; + } + do_preupdate_test 9.3 { + INSERT INTO t1(a, b, c) VALUES(457, NULL, NULL); + } { + INSERT main t1 457 457 0 457 {} {} {} + } + do_preupdate_test 9.4 { + DELETE FROM t1 WHERE a=456 + } { + DELETE main t1 456 456 0 456 {} {} {} + } + do_preupdate_test 9.5 { + INSERT INTO t2 DEFAULT VALUES; + } { + INSERT main t2 1 1 0 {} 1 + } + do_preupdate_test 9.6 { + INSERT INTO t1 DEFAULT VALUES; + } { + INSERT main t1 458 458 0 458 {} {} {} + } } -do_preupdate_test 9.5 { - INSERT INTO t2 DEFAULT VALUES; -} { - INSERT main t2 1 1 0 {} 1 -} -do_preupdate_test 9.6 { - INSERT INTO t1 DEFAULT VALUES; -} { - INSERT main t1 458 458 0 458 {} {} {} -} do_execsql_test 10.0 { diff --git a/test/in4.test b/test/in4.test index 07bd5477..a3fe22e7 100644 --- a/test/in4.test +++ b/test/in4.test @@ -470,4 +470,51 @@ do_execsql_test 11.2 { AND c BETWEEN 'abc' AND 'xyz'; } {/ SeekScan /} +# 2021-06-25 ticket 6dcbfd11cf666e21 +# Another problem with OP_SeekScan +# +reset_db +do_execsql_test 12.0 { + CREATE TABLE t1(a,b,c); + CREATE INDEX t1abc ON t1(a,b,c); + CREATE INDEX t1bca on t1(b,c,a); + INSERT INTO t1 VALUES(56,1119,1115); + INSERT INTO t1 VALUES(57,1147,1137); + INSERT INTO t1 VALUES(100,1050,1023); + INSERT INTO t1 VALUES(101,1050,1023); + ANALYZE sqlite_schema; + INSERT INTO sqlite_stat1 VALUES('t1','t1abc','358677 2 2 1'); + INSERT INTO sqlite_stat1 VALUES('t1','t1bca','358677 4 2 1'); + ANALYZE sqlite_schema; + SELECT * FROM t1 NOT INDEXED + WHERE (b = 1137 AND c IN (97, 98)) + OR (b = 1119 AND c IN (1115, 1023)); +} {56 1119 1115} +do_execsql_test 12.1 { + SELECT * FROM t1 + WHERE (b = 1137 AND c IN (97, 98)) + OR (b = 1119 AND c IN (1115, 1023)); +} {56 1119 1115} + +# 2021-11-02 ticket 5981a8c041a3c2f3 +# Another OP_SeekScan problem. +# +reset_db +do_execsql_test 13.0 { + CREATE TABLE t1(id INTEGER PRIMARY KEY, a INT, b INT, c INT); + INSERT INTO t1 VALUES(10,1,2,5); + INSERT INTO t1 VALUES(20,1,3,5); + INSERT INTO t1 VALUES(30,1,2,4); + INSERT INTO t1 VALUES(40,1,3,4); + ANALYZE sqlite_master; + INSERT INTO sqlite_stat1 VALUES('t1','t1x','84000 3 2 1'); + CREATE INDEX t1x ON t1(a,b,c); + PRAGMA writable_schema=RESET; + SELECT * FROM t1 + WHERE a=1 + AND b IN (2,3) + AND c BETWEEN 4 AND 5 + ORDER BY +id; +} {10 1 2 5 20 1 3 5 30 1 2 4 40 1 3 4} + finish_test diff --git a/test/incrblob3.test b/test/incrblob3.test index 5f2e860d..b2bc8f8e 100644 --- a/test/incrblob3.test +++ b/test/incrblob3.test @@ -14,6 +14,11 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +ifcapable !incrblob { + finish_test + return +} + sqlite3 db test.db sqlite3_db_config_lookaside db 0 0 0 diff --git a/test/incrblobfault.test b/test/incrblobfault.test index 10c2c8ec..d070babe 100644 --- a/test/incrblobfault.test +++ b/test/incrblobfault.test @@ -14,6 +14,11 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +ifcapable !incrblob { + finish_test + return +} + set testprefix incrblobfault do_execsql_test 1.0 { diff --git a/test/indexexpr1.test b/test/indexexpr1.test index a31b8769..92dfc868 100644 --- a/test/indexexpr1.test +++ b/test/indexexpr1.test @@ -75,18 +75,20 @@ do_execsql_test indexexpr1-150eqp { ORDER BY +rowid; } {/USING INDEX t1abx/} -do_execsql_test indexexpr1-160 { - ALTER TABLE t1 ADD COLUMN d; - UPDATE t1 SET d=length(a); - CREATE INDEX t1a2 ON t1(SUBSTR(a, 27, 3)) WHERE d>=29; - SELECT rowid, b, c FROM t1 - WHERE substr(a,27,3)=='ord' AND d>=29; -} {1 1 1} -do_execsql_test indexexpr1-160eqp { - EXPLAIN QUERY PLAN - SELECT rowid, b, c FROM t1 - WHERE substr(a,27,3)=='ord' AND d>=29; -} {/USING INDEX t1a2/} +ifcapable altertable { + do_execsql_test indexexpr1-160 { + ALTER TABLE t1 ADD COLUMN d; + UPDATE t1 SET d=length(a); + CREATE INDEX t1a2 ON t1(SUBSTR(a, 27, 3)) WHERE d>=29; + SELECT rowid, b, c FROM t1 + WHERE substr(a,27,3)=='ord' AND d>=29; + } {1 1 1} + do_execsql_test indexexpr1-160eqp { + EXPLAIN QUERY PLAN + SELECT rowid, b, c FROM t1 + WHERE substr(a,27,3)=='ord' AND d>=29; + } {/USING INDEX t1a2/} +} # ORDER BY using an indexed expression # @@ -166,18 +168,20 @@ do_execsql_test indexexpr1-250eqp { ORDER BY +id; } {/USING INDEX t1abx/} -do_execsql_test indexexpr1-260 { - ALTER TABLE t1 ADD COLUMN d; - UPDATE t1 SET d=length(a); - CREATE INDEX t1a2 ON t1(SUBSTR(a, 27, 3)) WHERE d>=29; - SELECT id, b, c FROM t1 - WHERE substr(a,27,3)=='ord' AND d>=29; -} {1 1 1} -do_execsql_test indexexpr1-260eqp { - EXPLAIN QUERY PLAN - SELECT id, b, c FROM t1 - WHERE substr(a,27,3)=='ord' AND d>=29; -} {/USING INDEX t1a2/} +ifcapable altertable { + do_execsql_test indexexpr1-260 { + ALTER TABLE t1 ADD COLUMN d; + UPDATE t1 SET d=length(a); + CREATE INDEX t1a2 ON t1(SUBSTR(a, 27, 3)) WHERE d>=29; + SELECT id, b, c FROM t1 + WHERE substr(a,27,3)=='ord' AND d>=29; + } {1 1 1} + do_execsql_test indexexpr1-260eqp { + EXPLAIN QUERY PLAN + SELECT id, b, c FROM t1 + WHERE substr(a,27,3)=='ord' AND d>=29; + } {/USING INDEX t1a2/} +} do_catchsql_test indexexpr1-300 { diff --git a/test/io.test b/test/io.test index e1af808a..dfadcd13 100644 --- a/test/io.test +++ b/test/io.test @@ -640,4 +640,6 @@ foreach {tn sql} { } sqlite3_simulate_device -char {} -sectorsize 0 +unregister_devsim + finish_test diff --git a/test/ioerr.test b/test/ioerr.test index f42beef5..29a3dede 100644 --- a/test/ioerr.test +++ b/test/ioerr.test @@ -334,6 +334,7 @@ do_ioerr_test ioerr-12 -ckrefcount true -erc 1 -tclprep { } sqlite3_simulate_device -char {} -sectorsize 0 catch {db close} +unregister_devsim do_ioerr_test ioerr-13 -ckrefcount true -erc 1 -sqlprep { PRAGMA auto_vacuum = incremental; diff --git a/test/istrue.test b/test/istrue.test index 13eccabc..f1ba6324 100644 --- a/test/istrue.test +++ b/test/istrue.test @@ -143,20 +143,22 @@ foreach {tn val} [list 1 NaN 2 -NaN 3 NaN0 4 -NaN0 5 Inf 6 -Inf] { } {0} } -do_execsql_test istrue-700 { - CREATE TABLE t7( - a INTEGER PRIMARY KEY, - b BOOLEAN DEFAULT false, - c BOOLEAN DEFAULT true - ); - INSERT INTO t7(a) VALUES(1); - INSERT INTO t7(a,b,c) VALUES(2,true,false); - ALTER TABLE t7 ADD COLUMN d BOOLEAN DEFAULT false; - ALTER TABLE t7 ADD COLUMN e BOOLEAN DEFAULT true; - INSERT INTO t7(a,b,c) VALUES(3,true,false); - INSERT INTO t7 VALUES(4,false,true,true,false); - SELECT *,'x' FROM t7 ORDER BY a; -} {1 0 1 0 1 x 2 1 0 0 1 x 3 1 0 0 1 x 4 0 1 1 0 x} +ifcapable altertable { + do_execsql_test istrue-700 { + CREATE TABLE t7( + a INTEGER PRIMARY KEY, + b BOOLEAN DEFAULT false, + c BOOLEAN DEFAULT true + ); + INSERT INTO t7(a) VALUES(1); + INSERT INTO t7(a,b,c) VALUES(2,true,false); + ALTER TABLE t7 ADD COLUMN d BOOLEAN DEFAULT false; + ALTER TABLE t7 ADD COLUMN e BOOLEAN DEFAULT true; + INSERT INTO t7(a,b,c) VALUES(3,true,false); + INSERT INTO t7 VALUES(4,false,true,true,false); + SELECT *,'x' FROM t7 ORDER BY a; + } {1 0 1 0 1 x 2 1 0 0 1 x 3 1 0 0 1 x 4 0 1 1 0 x} +} do_execsql_test istrue-710 { SELECT 0.5 IS TRUE COLLATE NOCASE; diff --git a/test/json104.test b/test/json104.test index e56e7ede..8d95e601 100644 --- a/test/json104.test +++ b/test/json104.test @@ -125,6 +125,9 @@ do_execsql_test json104-313 { do_execsql_test json104-314 { SELECT json_patch('{}','{"a":{"bb":{"ccc":null}}}'); } {{{"a":{"bb":{}}}}} +do_execsql_test json104-320 { + SELECT json_patch('{"x":{"one":1}}','{"x":{"two":2},"x":"three"}'); +} {{{"x":"three"}}} #------------------------------------------------------------------------- diff --git a/test/memdb1.test b/test/memdb1.test index ae2f5d50..5e219a4c 100644 --- a/test/memdb1.test +++ b/test/memdb1.test @@ -195,6 +195,22 @@ do_test 620 { lappend rc $msg } {1 {wrong # args: should be "db serialize ?DATABASE?"}} +# 2021-07-19 https://sqlite.org/forum/forumpost/e1cbb5f450b98aa6 +# The TEMP database cannot participate in serialization or +# deserialization. +# +reset_db +do_test 650 { + db eval { + CREATE TEMP TABLE t0(a); + CREATE TABLE t1(x); + WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1000) + INSERT INTO t1(x) SELECT random() FROM c; + } + set rc [catch {db deserialize temp [db serialize main]} err] + lappend rc err +} {1 err} + #------------------------------------------------------------------------- ifcapable vtab { reset_db @@ -213,4 +229,42 @@ ifcapable vtab { } {1 {table t1 already exists}} } + +#------------------------------------------------------------------------- +# dbsqlfuzz 0a13dfb474d4f2f11a48a2ea57075c96fb456dd7 +# +if {[wal_is_capable]} { + reset_db + do_execsql_test 800 { + PRAGMA auto_vacuum = 0; + PRAGMA page_size = 8192; + PRAGMA journal_mode = wal; + CREATE TABLE t1(x, y); + INSERT INTO t1 VALUES(1, 2); + CREATE TABLE t2(x, y); + } {wal} + db close + + set fd [open test.db] + fconfigure $fd -translation binary -encoding binary + set data [read $fd [expr 20*1024]] + + sqlite3 db "" + db deserialize $data + + do_execsql_test 810 { + PRAGMA locking_mode = exclusive; + SELECT * FROM t1 + } {exclusive 1 2} + + do_execsql_test 820 { + INSERT INTO t1 VALUES(3, 4); + SELECT * FROM t1; + } {1 2 3 4} + + do_catchsql_test 830 { + PRAGMA wal_checkpoint; + } {1 {database disk image is malformed}} +} + finish_test diff --git a/test/memjournal2.test b/test/memjournal2.test new file mode 100644 index 00000000..97d35a98 --- /dev/null +++ b/test/memjournal2.test @@ -0,0 +1,62 @@ +# 2022 Jan 01 +# +# 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. +# +#*********************************************************************** +# Tests focused on the in-memory journal. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/malloc_common.tcl +set testprefix memjournal2 + +do_execsql_test 1.0 { + PRAGMA journal_mode = memory; + CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE); +} {memory} + +set nRow [expr 2000] + +do_execsql_test 1.1 { + BEGIN; + WITH s(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<$nRow + ) + INSERT INTO t1 SELECT NULL, randomblob(700) FROM s; +} + +for {set jj 200} {$jj <= 300} {incr jj} { + do_execsql_test 1.2.$jj.1 { + SAVEPOINT one; + UPDATE t1 SET b=randomblob(700) WHERE a<=$jj; + } + do_execsql_test 1.2.$jj.2 { + SAVEPOINT two; + UPDATE t1 SET b=randomblob(700) WHERE a==1; + ROLLBACK TO two; + RELEASE two; + } + do_execsql_test 1.2.$jj.3 { + SAVEPOINT two; + UPDATE t1 SET b=randomblob(700) WHERE a==1; + ROLLBACK TO two; + RELEASE two; + } + + do_execsql_test 1.2.$jj.4 { + PRAGMA integrity_check; + ROLLBACK TO one; + RELEASE one; + } {ok} +} + + +finish_test + + diff --git a/test/minmax.test b/test/minmax.test index 295fac4e..81bd46db 100644 --- a/test/minmax.test +++ b/test/minmax.test @@ -646,6 +646,16 @@ do_execsql_test 14.2 { SELECT min(a) FROM t14 WHERE b='2' AND a>'50'; } {100} - +# 2021-08-21. https://sqlite.org/forum/forumpost/cfcb4b461d +# +reset_db +do_execsql_test 15.1 { + CREATE TABLE t1(a); + CREATE TABLE t2(b); + CREATE TABLE t3(c); + INSERT INTO t1 VALUES(0); + INSERT INTO t2 VALUES(5); + SELECT MIN((SELECT b FROM t2 UNION SELECT x FROM (SELECT x FROM (SELECT 1 AS x WHERE t1.a=1) UNION ALL SELECT c FROM t3))) FROM t1; +} {5} finish_test diff --git a/test/misc1.test b/test/misc1.test index c14a31eb..758d4082 100644 --- a/test/misc1.test +++ b/test/misc1.test @@ -728,7 +728,14 @@ do_execsql_test misc1-26.0 { # 2017-12-29 # # The following behaviors (duplicate column names on an INSERT or UPDATE) -# are undocumented. These tests are added to ensure that historical behavior +# are undocumented. <<--- Not so. There is a long-standing requirement +# in lang_update.in to say that when the columns to be updated appear more +# than once in an UPDATE statement that only the rightmost expression is used. +# See e_update-1.6.* for the tests. This is unfortunate, since omitting +# that requirement would greatly simplify the fix to the problem identified +# by forum post https://sqlite.org/forum/info/16ca0e9f32c38567 +# +# These tests are added to ensure that historical behavior # does not change accidentally. # # For duplication columns on an INSERT, the first value is used. diff --git a/test/mmap1.test b/test/mmap1.test index 7dcd1f8a..3362f718 100644 --- a/test/mmap1.test +++ b/test/mmap1.test @@ -12,7 +12,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -ifcapable !mmap { +ifcapable !mmap||!incrblob { finish_test return } diff --git a/test/multiplex.test b/test/multiplex.test index 6ea32890..2f1a02fb 100644 --- a/test/multiplex.test +++ b/test/multiplex.test @@ -182,6 +182,11 @@ do_test multiplex-2.1.3 { file size [multiplex_name test.x 0] } {4096} do_test multiplex-2.1.4 { execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } } {} +do_execsql_test multiplex-2.1.5 { + PRAGMA multiplex_enabled; + PRAGMA multiplex_filecount; + PRAGMA multiplex_chunksize; +} {1 1 2147418112} do_test multiplex-2.2.1 { execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } @@ -267,6 +272,18 @@ do_test multiplex-2.5.8 { do_test multiplex-2.5.9 { file size [multiplex_name test.x 0] } [list $g_chunk_size] do_test multiplex-2.5.10 { file size [multiplex_name test.x 1] } [list $g_chunk_size] +do_execsql_test multiplex-2.5.11 { + PRAGMA multiplex_enabled; + PRAGMA multiplex_filecount; + PRAGMA multiplex_chunksize; +} {1 3 65536} +sqlite3 db test.x +do_execsql_test multiplex-2.5.12 { + PRAGMA multiplex_filecount; + PRAGMA multiplex_chunksize; +} {3 65536} + + do_test multiplex-2.5.99 { db close diff --git a/test/notnull2.test b/test/notnull2.test index 75a519e9..12fffe28 100644 --- a/test/notnull2.test +++ b/test/notnull2.test @@ -109,4 +109,24 @@ do_execsql_test 3.1 { SELECT * FROM t0 WHERE ((c0 NOT NULL) AND 1) OR (c0 == NULL); } {0} +# 2021-07-22 https://sqlite.org/forum/forumpost/2078b7edd2 +# +reset_db +do_execsql_test 4.0 { + SELECT *, '/' + FROM ( + SELECT NULL val FROM (SELECT 1) + UNION ALL + SELECT 'missing' FROM (SELECT 1) + ) a + LEFT JOIN (SELECT 1) + ON a.val IS NULL; +} {{} 1 / missing {} /} +do_execsql_test 4.1 { + CREATE TABLE t1(a INT); + INSERT INTO t1(a) VALUES(1); + CREATE TABLE t2(b INT); + SELECT * FROM (SELECT 3 AS c FROM t1) AS t3 LEFT JOIN t2 ON c IS NULL; +} {3 {}} + finish_test diff --git a/test/pager1.test b/test/pager1.test index a1e06d15..ff7d3e40 100644 --- a/test/pager1.test +++ b/test/pager1.test @@ -21,6 +21,10 @@ if {[atomic_batch_write test.db]} { finish_test return } +ifcapable !incrblob { + finish_test + return +} # Do not use a codec for tests in this file, as the database file is # manipulated directly using tcl scripts (using the [hexio_write] command). @@ -1940,20 +1944,22 @@ do_test pager1-18.4 { } {1 {database disk image is malformed}} db2 close extra_schema_checks 0 -do_test pager1-18.5 { - sqlite3 db "" - sqlite3_db_config db DEFENSIVE 0 - execsql { - CREATE TABLE t1(a, b); - CREATE TABLE t2(a, b); - PRAGMA writable_schema = 1; - UPDATE sqlite_master SET rootpage=5 WHERE tbl_name = 't1'; - PRAGMA writable_schema = 0; - ALTER TABLE t1 RENAME TO x1; - } - catchsql { SELECT * FROM x1 } -} {1 {database disk image is malformed}} -db close +ifcapable altertable { + do_test pager1-18.5 { + sqlite3 db "" + sqlite3_db_config db DEFENSIVE 0 + execsql { + CREATE TABLE t1(a, b); + CREATE TABLE t2(a, b); + PRAGMA writable_schema = 1; + UPDATE sqlite_master SET rootpage=5 WHERE tbl_name = 't1'; + PRAGMA writable_schema = 0; + ALTER TABLE t1 RENAME TO x1; + } + catchsql { SELECT * FROM x1 } + } {1 {database disk image is malformed}} + db close +} extra_schema_checks 1 do_test pager1-18.6 { diff --git a/test/permutations.test b/test/permutations.test index b652f857..0987daeb 100644 --- a/test/permutations.test +++ b/test/permutations.test @@ -1138,7 +1138,14 @@ proc run_tests {name args} { set ::G(perm:dbconfig) $options(-dbconfig) set ::G(perm:presql) $options(-presql) - foreach file [lsort $options(-files)] { + set filelist [lsort $options(-files)] + if {[info exists ::env(TCLTEST_PART)]} { + regexp {^([0-9]*)/([0-9]*)$} $::env(TCLTEST_PART) -> A B + set nFile [expr {([llength $filelist]+$B-1)/$B}] + set filelist [lrange $filelist [expr ($A-1)*$nFile] [expr $A*$nFile-1]] + } + + foreach file $filelist { if {[file tail $file] == $file} { set file [file join $::testdir $file] } if {[info exists ::env(SQLITE_TEST_PATTERN_LIST)]} { @@ -1212,6 +1219,7 @@ if {[file tail $argv0] == "permutations.test"} { set S $::testspec($suite) set i 1 } else { + set suite default set S [list] set i 0 } @@ -1232,9 +1240,10 @@ if {[file tail $argv0] == "permutations.test"} { set extra [list -files $files] } - eval run_tests $suite $S $extra + eval [list run_tests $suite] $S $extra } } main $argv + set argv {} finish_test } diff --git a/test/pragma.test b/test/pragma.test index 04f5bd0f..ba61882d 100644 --- a/test/pragma.test +++ b/test/pragma.test @@ -532,29 +532,31 @@ Page 6 is never used} {row 1 missing from index i2}} # Verify that PRAGMA integrity_check catches UNIQUE and NOT NULL # constraint violations. # -sqlite3_db_config db DEFENSIVE 0 -do_execsql_test pragma-3.20 { - CREATE TABLE t1(a,b); - CREATE INDEX t1a ON t1(a); - INSERT INTO t1 VALUES(1,1),(2,2),(3,3),(2,4),(NULL,5),(NULL,6); - PRAGMA writable_schema=ON; - UPDATE sqlite_master SET sql='CREATE UNIQUE INDEX t1a ON t1(a)' - WHERE name='t1a'; - UPDATE sqlite_master SET sql='CREATE TABLE t1(a NOT NULL,b)' - WHERE name='t1'; - PRAGMA writable_schema=OFF; - ALTER TABLE t1 RENAME TO t1x; - PRAGMA integrity_check; -} {{non-unique entry in index t1a} {NULL value in t1x.a} {non-unique entry in index t1a} {NULL value in t1x.a}} -do_execsql_test pragma-3.21 { - PRAGMA integrity_check(3); -} {{non-unique entry in index t1a} {NULL value in t1x.a} {non-unique entry in index t1a}} -do_execsql_test pragma-3.22 { - PRAGMA integrity_check(2); -} {{non-unique entry in index t1a} {NULL value in t1x.a}} -do_execsql_test pragma-3.23 { - PRAGMA integrity_check(1); -} {{non-unique entry in index t1a}} +ifcapable altertable { + sqlite3_db_config db DEFENSIVE 0 + do_execsql_test pragma-3.20 { + CREATE TABLE t1(a,b); + CREATE INDEX t1a ON t1(a); + INSERT INTO t1 VALUES(1,1),(2,2),(3,3),(2,4),(NULL,5),(NULL,6); + PRAGMA writable_schema=ON; + UPDATE sqlite_master SET sql='CREATE UNIQUE INDEX t1a ON t1(a)' + WHERE name='t1a'; + UPDATE sqlite_master SET sql='CREATE TABLE t1(a NOT NULL,b)' + WHERE name='t1'; + PRAGMA writable_schema=OFF; + ALTER TABLE t1 RENAME TO t1x; + PRAGMA integrity_check; + } {{non-unique entry in index t1a} {NULL value in t1x.a} {non-unique entry in index t1a} {NULL value in t1x.a}} + do_execsql_test pragma-3.21 { + PRAGMA integrity_check(3); + } {{non-unique entry in index t1a} {NULL value in t1x.a} {non-unique entry in index t1a}} + do_execsql_test pragma-3.22 { + PRAGMA integrity_check(2); + } {{non-unique entry in index t1a} {NULL value in t1x.a}} + do_execsql_test pragma-3.23 { + PRAGMA integrity_check(1); + } {{non-unique entry in index t1a}} +} # PRAGMA integrity check (or more specifically the sqlite3BtreeCount() # interface) used to leave index cursors in an inconsistent state @@ -564,7 +566,7 @@ do_execsql_test pragma-3.23 { # that problem has been fixed. # do_test pragma-3.30 { - db close + catch { db close } delete_file test.db sqlite3 db test.db db eval { @@ -815,7 +817,7 @@ do_test pragma-6.7 { ORDER BY cid} } [concat \ {0 one INT 1 -1 0} \ - {1 two text 0 {} 0} \ + {1 two TEXT 0 {} 0} \ {2 three {VARCHAR(45, 65)} 0 'abcde' 0} \ {3 four REAL 0 X'abcdef' 0} \ {4 five {} 0 CURRENT_TIME 0} \ @@ -1957,14 +1959,16 @@ do_test 23.3 { capture_pragma db2 out {PRAGMA index_list(t1)} db2 eval {SELECT seq, name, "unique", origin, '|' FROM out ORDER BY seq} } {0 i3 0 c | 1 i2 0 c | 2 i2x 0 c | 3 i1 0 c |} -do_test 23.4 { - db eval { - ALTER TABLE t1 ADD COLUMN e; - } - db2 eval { - PRAGMA table_info(t1); - } -} {/4 e {} 0 {} 0/} +ifcapable altertable { + do_test 23.4 { + db eval { + ALTER TABLE t1 ADD COLUMN e; + } + db2 eval { + PRAGMA table_info(t1); + } + } {/4 e {} 0 {} 0/} +} do_test 23.5 { db eval { DROP TABLE t2; diff --git a/test/quote.test b/test/quote.test index 212885c0..9810a3ca 100644 --- a/test/quote.test +++ b/test/quote.test @@ -141,43 +141,45 @@ do_execsql_test 2.5 { # 2021-03-13 # ticket 1c24a659e6d7f3a1 -reset_db -do_catchsql_test 3.0 { - CREATE TABLE t1(a,b); - CREATE INDEX x1 on t1("b"); - ALTER TABLE t1 DROP COLUMN b; -} {1 {error in index x1 after drop column: no such column: b}} -do_catchsql_test 3.1 { - DROP TABLE t1; - CREATE TABLE t1(a,"b"); - CREATE INDEX x1 on t1("b"); - ALTER TABLE t1 DROP COLUMN b; -} {1 {error in index x1 after drop column: no such column: b}} -do_catchsql_test 3.2 { - DROP TABLE t1; - CREATE TABLE t1(a,'b'); - CREATE INDEX x1 on t1("b"); - ALTER TABLE t1 DROP COLUMN b; -} {1 {error in index x1 after drop column: no such column: b}} -do_catchsql_test 3.3 { - DROP TABLE t1; - CREATE TABLE t1(a,"b"); - CREATE INDEX x1 on t1('b'); - ALTER TABLE t1 DROP COLUMN b; -} {1 {error in index x1 after drop column: no such column: b}} -do_catchsql_test 3.4 { - DROP TABLE t1; - CREATE TABLE t1(a, b, c); - CREATE INDEX x1 ON t1("a"||"b"); - INSERT INTO t1 VALUES(1,2,3),(1,4,5); - ALTER TABLE t1 DROP COLUMN b; -} {1 {error in index x1 after drop column: no such column: b}} -do_catchsql_test 3.5 { - DROP TABLE t1; - CREATE TABLE t1(a, b, c); - CREATE INDEX x1 ON t1("a"||"x"); - INSERT INTO t1 VALUES(1,2,3),(1,4,5); - ALTER TABLE t1 DROP COLUMN b; -} {0 {}} +ifcapable altertable { + reset_db + do_catchsql_test 3.0 { + CREATE TABLE t1(a,b); + CREATE INDEX x1 on t1("b"); + ALTER TABLE t1 DROP COLUMN b; + } {1 {error in index x1 after drop column: no such column: b}} + do_catchsql_test 3.1 { + DROP TABLE t1; + CREATE TABLE t1(a,"b"); + CREATE INDEX x1 on t1("b"); + ALTER TABLE t1 DROP COLUMN b; + } {1 {error in index x1 after drop column: no such column: b}} + do_catchsql_test 3.2 { + DROP TABLE t1; + CREATE TABLE t1(a,'b'); + CREATE INDEX x1 on t1("b"); + ALTER TABLE t1 DROP COLUMN b; + } {1 {error in index x1 after drop column: no such column: b}} + do_catchsql_test 3.3 { + DROP TABLE t1; + CREATE TABLE t1(a,"b"); + CREATE INDEX x1 on t1('b'); + ALTER TABLE t1 DROP COLUMN b; + } {1 {error in index x1 after drop column: no such column: b}} + do_catchsql_test 3.4 { + DROP TABLE t1; + CREATE TABLE t1(a, b, c); + CREATE INDEX x1 ON t1("a"||"b"); + INSERT INTO t1 VALUES(1,2,3),(1,4,5); + ALTER TABLE t1 DROP COLUMN b; + } {1 {error in index x1 after drop column: no such column: b}} + do_catchsql_test 3.5 { + DROP TABLE t1; + CREATE TABLE t1(a, b, c); + CREATE INDEX x1 ON t1("a"||"x"); + INSERT INTO t1 VALUES(1,2,3),(1,4,5); + ALTER TABLE t1 DROP COLUMN b; + } {0 {}} +} finish_test diff --git a/test/releasetest.tcl b/test/releasetest.tcl deleted file mode 100755 index da6113a1..00000000 --- a/test/releasetest.tcl +++ /dev/null @@ -1,1100 +0,0 @@ -#!/usr/bin/tclsh -# -# Documentation for this script. This may be output to stderr -# if the script is invoked incorrectly. See the [process_options] -# proc below. -# -set ::USAGE_MESSAGE { -This Tcl script is used to test the various configurations required -before releasing a new version. Supported command line options (all -optional) are: - - --buildonly (Just build testfixture - do not run) - --config CONFIGNAME (Run only CONFIGNAME) - --dryrun (Print what would have happened) - -f|--force (Run even if uncommitted changes) - --info (Show diagnostic info) - --jobs N (Use N processes - default 1) - --keep (Delete no files after each test run) - --msvc (Use MSVC as the compiler) - --platform PLATFORM (see below) - --progress (Show progress messages) - --quick (Run "veryquick.test" only) - --veryquick (Run "make smoketest" only) - --with-tcl=DIR (Use TCL build at DIR) - -The script determines the default value for --platform using the -$tcl_platform(os) and $tcl_platform(machine) variables. Supported -platforms are "Linux-x86", "Linux-x86_64", "Darwin-i386", -"Darwin-x86_64", "Windows NT-intel", and "Windows NT-amd64". - -Every test begins with a fresh run of the configure script at the top -of the SQLite source tree. -} - -# Return a timestamp of the form HH:MM:SS -# -proc now {} { - return [clock format [clock seconds] -format %H:%M:%S] -} - -# Omit comments (text between # and \n) in a long multi-line string. -# -proc strip_comments {in} { - regsub -all {#[^\n]*\n} $in {} out - return $out -} - -array set ::Configs [strip_comments { - "Default" { - -O2 - --disable-amalgamation --disable-shared - --enable-session - } - "Sanitize" { - CC=clang -fsanitize=undefined - -DSQLITE_ENABLE_STAT4 - -DCONFIG_SLOWDOWN_FACTOR=5.0 - --enable-session - } - "Stdcall" { - -DUSE_STDCALL=1 - -O2 - } - "Have-Not" { - # The "Have-Not" configuration sets all possible -UHAVE_feature options - # in order to verify that the code works even on platforms that lack - # these support services. - -DHAVE_FDATASYNC=0 - -DHAVE_GMTIME_R=0 - -DHAVE_ISNAN=0 - -DHAVE_LOCALTIME_R=0 - -DHAVE_LOCALTIME_S=0 - -DHAVE_MALLOC_USABLE_SIZE=0 - -DHAVE_STRCHRNUL=0 - -DHAVE_USLEEP=0 - -DHAVE_UTIME=0 - } - "Unlock-Notify" { - -O2 - -DSQLITE_ENABLE_UNLOCK_NOTIFY - -DSQLITE_THREADSAFE - -DSQLITE_TCL_DEFAULT_FULLMUTEX=1 - } - "User-Auth" { - -O2 - -DSQLITE_USER_AUTHENTICATION=1 - } - "Secure-Delete" { - -O2 - -DSQLITE_SECURE_DELETE=1 - -DSQLITE_SOUNDEX=1 - } - "Update-Delete-Limit" { - -O2 - -DSQLITE_DEFAULT_FILE_FORMAT=4 - -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 - -DSQLITE_ENABLE_STMT_SCANSTATUS - -DSQLITE_LIKE_DOESNT_MATCH_BLOBS - -DSQLITE_ENABLE_CURSOR_HINTS - --enable-json1 - } - "Check-Symbols" { - -DSQLITE_MEMDEBUG=1 - -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 - -DSQLITE_ENABLE_FTS3=1 - -DSQLITE_ENABLE_RTREE=1 - -DSQLITE_ENABLE_MEMSYS5=1 - -DSQLITE_ENABLE_MEMSYS3=1 - -DSQLITE_ENABLE_COLUMN_METADATA=1 - -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 - -DSQLITE_SECURE_DELETE=1 - -DSQLITE_SOUNDEX=1 - -DSQLITE_ENABLE_ATOMIC_WRITE=1 - -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 - -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1 - -DSQLITE_ENABLE_STAT4 - -DSQLITE_ENABLE_STMT_SCANSTATUS - --enable-json1 --enable-fts5 --enable-session - } - "Debug-One" { - --disable-shared - -O2 -funsigned-char - -DSQLITE_DEBUG=1 - -DSQLITE_MEMDEBUG=1 - -DSQLITE_MUTEX_NOOP=1 - -DSQLITE_TCL_DEFAULT_FULLMUTEX=1 - -DSQLITE_ENABLE_FTS3=1 - -DSQLITE_ENABLE_RTREE=1 - -DSQLITE_ENABLE_MEMSYS5=1 - -DSQLITE_ENABLE_COLUMN_METADATA=1 - -DSQLITE_ENABLE_STAT4 - -DSQLITE_ENABLE_HIDDEN_COLUMNS - -DSQLITE_MAX_ATTACHED=125 - -DSQLITE_MUTATION_TEST - --enable-fts5 --enable-json1 - } - "Fast-One" { - -O6 - -DSQLITE_ENABLE_FTS4=1 - -DSQLITE_ENABLE_RTREE=1 - -DSQLITE_ENABLE_STAT4 - -DSQLITE_ENABLE_RBU - -DSQLITE_MAX_ATTACHED=125 - -DLONGDOUBLE_TYPE=double - --enable-session - } - "Device-One" { - -O2 - -DSQLITE_DEBUG=1 - -DSQLITE_DEFAULT_AUTOVACUUM=1 - -DSQLITE_DEFAULT_CACHE_SIZE=64 - -DSQLITE_DEFAULT_PAGE_SIZE=1024 - -DSQLITE_DEFAULT_TEMP_CACHE_SIZE=32 - -DSQLITE_DISABLE_LFS=1 - -DSQLITE_ENABLE_ATOMIC_WRITE=1 - -DSQLITE_ENABLE_IOTRACE=1 - -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 - -DSQLITE_MAX_PAGE_SIZE=4096 - -DSQLITE_OMIT_LOAD_EXTENSION=1 - -DSQLITE_OMIT_PROGRESS_CALLBACK=1 - -DSQLITE_OMIT_VIRTUALTABLE=1 - -DSQLITE_ENABLE_HIDDEN_COLUMNS - -DSQLITE_TEMP_STORE=3 - --enable-json1 - } - "Device-Two" { - -DSQLITE_4_BYTE_ALIGNED_MALLOC=1 - -DSQLITE_DEFAULT_AUTOVACUUM=1 - -DSQLITE_DEFAULT_CACHE_SIZE=1000 - -DSQLITE_DEFAULT_LOCKING_MODE=0 - -DSQLITE_DEFAULT_PAGE_SIZE=1024 - -DSQLITE_DEFAULT_TEMP_CACHE_SIZE=1000 - -DSQLITE_DISABLE_LFS=1 - -DSQLITE_ENABLE_FTS3=1 - -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 - -DSQLITE_ENABLE_RTREE=1 - -DSQLITE_MAX_COMPOUND_SELECT=50 - -DSQLITE_MAX_PAGE_SIZE=32768 - -DSQLITE_OMIT_TRACE=1 - -DSQLITE_TEMP_STORE=3 - -DSQLITE_THREADSAFE=2 - --enable-json1 --enable-fts5 --enable-session - } - "Locking-Style" { - -O2 - -DSQLITE_ENABLE_LOCKING_STYLE=1 - } - "Apple" { - -Os - -DHAVE_GMTIME_R=1 - -DHAVE_ISNAN=1 - -DHAVE_LOCALTIME_R=1 - -DHAVE_PREAD=1 - -DHAVE_PWRITE=1 - -DHAVE_USLEEP=1 - -DHAVE_USLEEP=1 - -DHAVE_UTIME=1 - -DSQLITE_DEFAULT_CACHE_SIZE=1000 - -DSQLITE_DEFAULT_CKPTFULLFSYNC=1 - -DSQLITE_DEFAULT_MEMSTATUS=1 - -DSQLITE_DEFAULT_PAGE_SIZE=1024 - -DSQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS=1 - -DSQLITE_ENABLE_API_ARMOR=1 - -DSQLITE_ENABLE_AUTO_PROFILE=1 - -DSQLITE_ENABLE_FLOCKTIMEOUT=1 - -DSQLITE_ENABLE_FTS3=1 - -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 - -DSQLITE_ENABLE_FTS3_TOKENIZER=1 - if:os=="Darwin" -DSQLITE_ENABLE_LOCKING_STYLE=1 - -DSQLITE_ENABLE_PERSIST_WAL=1 - -DSQLITE_ENABLE_PURGEABLE_PCACHE=1 - -DSQLITE_ENABLE_RTREE=1 - -DSQLITE_ENABLE_SNAPSHOT=1 - # -DSQLITE_ENABLE_SQLLOG=1 - -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 - -DSQLITE_MAX_LENGTH=2147483645 - -DSQLITE_MAX_VARIABLE_NUMBER=500000 - # -DSQLITE_MEMDEBUG=1 - -DSQLITE_NO_SYNC=1 - -DSQLITE_OMIT_AUTORESET=1 - -DSQLITE_OMIT_LOAD_EXTENSION=1 - -DSQLITE_PREFER_PROXY_LOCKING=1 - -DSQLITE_SERIES_CONSTRAINT_VERIFY=1 - -DSQLITE_THREADSAFE=2 - -DSQLITE_USE_URI=1 - -DSQLITE_WRITE_WALFRAME_PREBUFFERED=1 - -DUSE_GUARDED_FD=1 - -DUSE_PREAD=1 - --enable-json1 --enable-fts5 - } - "Extra-Robustness" { - -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1 - -DSQLITE_MAX_ATTACHED=62 - } - "Devkit" { - -DSQLITE_DEFAULT_FILE_FORMAT=4 - -DSQLITE_MAX_ATTACHED=30 - -DSQLITE_ENABLE_COLUMN_METADATA - -DSQLITE_ENABLE_FTS4 - -DSQLITE_ENABLE_FTS5 - -DSQLITE_ENABLE_FTS4_PARENTHESIS - -DSQLITE_DISABLE_FTS4_DEFERRED - -DSQLITE_ENABLE_RTREE - --enable-json1 --enable-fts5 - } - "No-lookaside" { - -DSQLITE_TEST_REALLOC_STRESS=1 - -DSQLITE_OMIT_LOOKASIDE=1 - -DHAVE_USLEEP=1 - } - "Valgrind" { - -DSQLITE_ENABLE_STAT4 - -DSQLITE_ENABLE_FTS4 - -DSQLITE_ENABLE_RTREE - -DSQLITE_ENABLE_HIDDEN_COLUMNS - -DCONFIG_SLOWDOWN_FACTOR=8.0 - --enable-json1 - } - - # The next group of configurations are used only by the - # Failure-Detection platform. They are all the same, but we need - # different names for them all so that they results appear in separate - # subdirectories. - # - Fail0 {-O0} - Fail2 {-O0} - Fail3 {-O0} - Fail4 {-O0} - FuzzFail1 {-O0} - FuzzFail2 {-O0} -}] - -array set ::Platforms [strip_comments { - Linux-x86_64 { - "Check-Symbols" checksymbols - "Fast-One" "fuzztest test" - "Debug-One" "mptest test" - "Have-Not" test - "Secure-Delete" test - "Unlock-Notify" "QUICKTEST_INCLUDE=notify2.test test" - "User-Auth" tcltest - "Update-Delete-Limit" test - "Extra-Robustness" test - "Device-Two" "threadtest test" - "No-lookaside" test - "Devkit" test - "Apple" test - "Sanitize" {QUICKTEST_OMIT=func4.test,nan.test test} - "Device-One" fulltest - "Default" "threadtest fulltest" - "Valgrind" valgrindtest - } - Linux-i686 { - "Devkit" test - "Have-Not" test - "Unlock-Notify" "QUICKTEST_INCLUDE=notify2.test test" - "Device-One" test - "Device-Two" test - "Default" "threadtest fulltest" - } - Darwin-i386 { - "Locking-Style" "mptest test" - "Have-Not" test - "Apple" "threadtest fulltest" - } - Darwin-x86_64 { - "Locking-Style" "mptest test" - "Have-Not" test - "Apple" "threadtest fulltest" - } - "Windows NT-intel" { - "Stdcall" test - "Have-Not" test - "Default" "mptest fulltestonly" - } - "Windows NT-amd64" { - "Stdcall" test - "Have-Not" test - "Default" "mptest fulltestonly" - } - - # The Failure-Detection platform runs various tests that deliberately - # fail. This is used as a test of this script to verify that this script - # correctly identifies failures. - # - Failure-Detection { - Fail0 "TEST_FAILURE=0 test" - Sanitize "TEST_FAILURE=1 test" - Fail2 "TEST_FAILURE=2 valgrindtest" - Fail3 "TEST_FAILURE=3 valgrindtest" - Fail4 "TEST_FAILURE=4 test" - FuzzFail1 "TEST_FAILURE=5 test" - FuzzFail2 "TEST_FAILURE=5 valgrindtest" - } -}] - - -# End of configuration section. -######################################################################### -######################################################################### - -# Configuration verification: Check that each entry in the list of configs -# specified for each platforms exists. -# -foreach {key value} [array get ::Platforms] { - foreach {v t} $value { - if {0==[info exists ::Configs($v)]} { - puts stderr "No such configuration: \"$v\"" - exit -1 - } - } -} - -# Output log. Disabled for slave interpreters. -# -if {[lindex $argv end]!="--slave"} { - set LOG [open releasetest-out.txt w] - proc PUTS {txt} { - puts $txt - puts $::LOG $txt - flush $::LOG - } - proc PUTSNNL {txt} { - puts -nonewline $txt - puts -nonewline $::LOG $txt - flush $::LOG - } - proc PUTSERR {txt} { - puts stderr $txt - puts $::LOG $txt - flush $::LOG - } - puts $LOG "$argv0 $argv" - set tm0 [clock format [clock seconds] -format {%Y-%m-%d %H:%M:%S} -gmt 1] - puts $LOG "start-time: $tm0 UTC" -} else { - proc PUTS {txt} { - puts $txt - } - proc PUTSNNL {txt} { - puts -nonewline $txt - } - proc PUTSERR {txt} { - puts stderr $txt - } -} - -# Open the file $logfile and look for a report on the number of errors -# and the number of test cases run. Add these values to the global -# $::NERRCASE and $::NTESTCASE variables. -# -# If any errors occur, then write into $errmsgVar the text of an appropriate -# one-line error message to show on the output. -# -proc count_tests_and_errors {logfile rcVar errmsgVar} { - if {$::DRYRUN} return - upvar 1 $rcVar rc $errmsgVar errmsg - set fd [open $logfile rb] - set seen 0 - while {![eof $fd]} { - set line [gets $fd] - if {[regexp {(\d+) errors out of (\d+) tests} $line all nerr ntest]} { - incr ::NERRCASE $nerr - incr ::NTESTCASE $ntest - set seen 1 - if {$nerr>0} { - set rc 1 - set errmsg $line - } - } - if {[regexp {runtime error: +(.*)} $line all msg]} { - # skip over "value is outside range" errors - if {[regexp {value .* is outside the range of representable} $line]} { - # noop - } elseif {[regexp {overflow: .* cannot be represented} $line]} { - # noop - } else { - incr ::NERRCASE - if {$rc==0} { - set rc 1 - set errmsg $msg - } - } - } - if {[regexp {fatal error +(.*)} $line all msg]} { - incr ::NERRCASE - if {$rc==0} { - set rc 1 - set errmsg $msg - } - } - if {[regexp {ERROR SUMMARY: (\d+) errors.*} $line all cnt] && $cnt>0} { - incr ::NERRCASE - if {$rc==0} { - set rc 1 - set errmsg $all - } - } - if {[regexp {^VERSION: 3\.\d+.\d+} $line]} { - set v [string range $line 9 end] - if {$::SQLITE_VERSION eq ""} { - set ::SQLITE_VERSION $v - } elseif {$::SQLITE_VERSION ne $v} { - set rc 1 - set errmsg "version conflict: {$::SQLITE_VERSION} vs. {$v}" - } - } - } - close $fd - if {$::BUILDONLY} { - incr ::NTESTCASE - if {$rc!=0} { - set errmsg "Build failed" - } - } elseif {!$seen} { - set rc 1 - set errmsg "Test did not complete" - if {[file readable core]} { - append errmsg " - core file exists" - } - } -} - -#-------------------------------------------------------------------------- -# This command is invoked as the [main] routine for scripts run with the -# "--slave" option. -# -# For each test (i.e. "configure && make test" execution), the master -# process spawns a process with the --slave option. It writes two lines -# to the slaves stdin. The first contains a single boolean value - the -# value of ::TRACE to use in the slave script. The second line contains a -# list in the same format as each element of the list passed to the -# [run_all_test_suites] command in the master process. -# -# The slave then runs the "configure && make test" commands specified. It -# exits successfully if the tests passes, or with a non-zero error code -# otherwise. -# -proc run_slave_test {} { - # Read global vars configuration from stdin. - set V [gets stdin] - foreach {::TRACE ::MSVC ::DRYRUN ::KEEPFILES} $V {} - - # Read the test-suite configuration from stdin. - set T [gets stdin] - foreach {title dir configOpts testtarget makeOpts cflags opts} $T {} - - # Create and switch to the test directory. - set normaldir [file normalize $dir] - set ::env(SQLITE_TMPDIR) $normaldir - trace_cmd file mkdir $dir - trace_cmd cd $dir - catch {file delete core} - catch {file delete test.log} - - # Run the "./configure && make" commands. - set rc 0 - set rc [catch [configureCommand $configOpts]] - if {!$rc} { - if {[info exists ::env(TCLSH_CMD)]} { - set savedEnv(TCLSH_CMD) $::env(TCLSH_CMD) - } else { - unset -nocomplain savedEnv(TCLSH_CMD) - } - set ::env(TCLSH_CMD) [file nativename [info nameofexecutable]] - - # Create a file called "makecommand.sh" containing the text of - # the make command line. - catch { - set cmd [makeCommand $testtarget $makeOpts $cflags $opts] - set fd [open makecommand.sh w] - foreach e $cmd { - if {[string first " " $e]>=0} { - puts -nonewline $fd "\"$e\"" - } else { - puts -nonewline $fd $e - } - puts -nonewline $fd " " - } - puts $fd "" - close $fd - } msg - - # Run the make command. - set rc [catch {trace_cmd exec {*}$cmd >>& test.log} msg] - if {[info exists savedEnv(TCLSH_CMD)]} { - set ::env(TCLSH_CMD) $savedEnv(TCLSH_CMD) - } else { - unset -nocomplain ::env(TCLSH_CMD) - } - } - - # Clean up lots of extra files if --keep was not specified. - if {$::KEEPFILES==0} { cleanup $normaldir } - - # Exis successfully if the test passed, or with a non-zero error code - # otherwise. - exit $rc -} - -# This command is invoked in the master process each time a slave -# file-descriptor is readable. -# -proc slave_fileevent {fd T tm1} { - global G - foreach {title dir configOpts testtarget makeOpts cflags opts} $T {} - - if {[eof $fd]} { - fconfigure $fd -blocking 1 - set rc [catch { close $fd }] - - set errmsg {} - set logfile [file join $dir test.log] - if {[file exists $logfile]} { - count_tests_and_errors [file join $dir test.log] rc errmsg - } elseif {$rc==0 && !$::DRYRUN} { - set rc 1 - set errmsg "no test.log file..." - } - - if {!$::TRACE} { - set tm2 [clock seconds] - set hours [expr {($tm2-$tm1)/3600}] - set minutes [expr {(($tm2-$tm1)/60)%60}] - set seconds [expr {($tm2-$tm1)%60}] - set tm [format (%02d:%02d:%02d) $hours $minutes $seconds] - - if {$rc} { - set status FAIL - incr ::NERR - } else { - set status Ok - } - - set n [string length $title] - if {$::PROGRESS_MSGS} { - PUTS "finished: ${title}[string repeat . [expr {53-$n}]] $status $tm" - } else { - PUTS "${title}[string repeat . [expr {63-$n}]] $status $tm" - } - if {$errmsg!=""} {PUTS " $errmsg"} - flush stdout - } - - incr G(nJob) -1 - } else { - set line [gets $fd] - if {[string trim $line] != ""} { - puts "Trace : $title - \"$line\"" - } - } -} - -#-------------------------------------------------------------------------- -# The only argument passed to this function is a list of test-suites to -# run. Each "test-suite" is itself a list consisting of the following -# elements: -# -# * Test title (for display). -# * The name of the directory to run the test in. -# * The argument for [configureCommand] -# * The first argument for [makeCommand] -# * The second argument for [makeCommand] -# * The third argument for [makeCommand] -# -proc run_all_test_suites {alltests} { - global G - set tests $alltests - - set G(nJob) 0 - - while {[llength $tests]>0 || $G(nJob)>0} { - if {$G(nJob)>=$::JOBS || [llength $tests]==0} { - vwait G(nJob) - } - - if {[llength $tests]>0} { - set T [lindex $tests 0] - set tests [lrange $tests 1 end] - foreach {title dir configOpts testtarget makeOpts cflags opts} $T {} - if {$::PROGRESS_MSGS && !$::TRACE} { - set n [string length $title] - PUTS "starting: ${title} at [now]" - flush stdout - } - - # Run the job. - # - set tm1 [clock seconds] - incr G(nJob) - set script [file normalize [info script]] - set fd [open "|[info nameofexecutable] $script --slave" r+] - fconfigure $fd -blocking 0 - fileevent $fd readable [list slave_fileevent $fd $T $tm1] - puts $fd [list $::TRACE $::MSVC $::DRYRUN $::KEEPFILES] - puts $fd [list {*}$T] - flush $fd - } - } -} - -proc add_test_suite {listvar name testtarget config} { - upvar $listvar alltests - - # Tcl variable $opts is used to build up the value used to set the - # OPTS Makefile variable. Variable $cflags holds the value for - # CFLAGS. The makefile will pass OPTS to both gcc and lemon, but - # CFLAGS is only passed to gcc. - # - set makeOpts "" - set cflags [expr {$::MSVC ? "-Zi" : "-g"}] - set opts "" - set title ${name}($testtarget) - set configOpts $::WITHTCL - set skip 0 - - regsub -all {#[^\n]*\n} $config \n config - foreach arg $config { - if {$skip} { - set skip 0 - continue - } - if {[regexp {^-[UD]} $arg]} { - lappend opts $arg - } elseif {[regexp {^[A-Z]+=} $arg]} { - lappend testtarget $arg - } elseif {[regexp {^if:([a-z]+)(.*)} $arg all key tail]} { - # Arguments of the form 'if:os=="Linux"' will cause the subsequent - # argument to be skipped if the $tcl_platform(os) is not "Linux", for - # example... - set skip [expr !(\$::tcl_platform($key)$tail)] - } elseif {[regexp {^--(enable|disable)-} $arg]} { - if {$::MSVC} { - if {$arg eq "--disable-amalgamation"} { - lappend makeOpts USE_AMALGAMATION=0 - continue - } - if {$arg eq "--disable-shared"} { - lappend makeOpts USE_CRT_DLL=0 DYNAMIC_SHELL=0 - continue - } - if {$arg eq "--enable-fts5"} { - lappend opts -DSQLITE_ENABLE_FTS5 - continue - } - if {$arg eq "--enable-json1"} { - lappend opts -DSQLITE_ENABLE_JSON1 - continue - } - if {$arg eq "--enable-shared"} { - lappend makeOpts USE_CRT_DLL=1 DYNAMIC_SHELL=1 - continue - } - } - lappend configOpts $arg - } else { - if {$::MSVC} { - if {$arg eq "-g"} { - lappend cflags -Zi - continue - } - if {[regexp -- {^-O(\d+)$} $arg all level]} then { - lappend makeOpts OPTIMIZATIONS=$level - continue - } - } - lappend cflags $arg - } - } - - # Disable sync to make testing faster. - # - lappend opts -DSQLITE_NO_SYNC=1 - - # Some configurations already set HAVE_USLEEP; in that case, skip it. - # - if {[lsearch -regexp $opts {^-DHAVE_USLEEP(?:=|$)}]==-1} { - lappend opts -DHAVE_USLEEP=1 - } - - # Add the define for this platform. - # - if {$::tcl_platform(platform)=="windows"} { - lappend opts -DSQLITE_OS_WIN=1 - } else { - lappend opts -DSQLITE_OS_UNIX=1 - } - - # Set the sub-directory to use. - # - set dir [string tolower [string map {- _ " " _} $name]] - - # Join option lists into strings, using space as delimiter. - # - set makeOpts [join $makeOpts " "] - set cflags [join $cflags " "] - set opts [join $opts " "] - - lappend alltests [list \ - $title $dir $configOpts $testtarget $makeOpts $cflags $opts] -} - -# The following procedure returns the "configure" command to be exectued for -# the current platform, which may be Windows (via MinGW, etc). -# -proc configureCommand {opts} { - if {$::MSVC} return [list]; # This is not needed for MSVC. - set result [list trace_cmd exec] - if {$::tcl_platform(platform)=="windows"} { - lappend result sh - } - lappend result $::SRCDIR/configure --enable-load-extension - foreach x $opts {lappend result $x} - lappend result >& test.log -} - -# The following procedure returns the "make" command to be executed for the -# specified targets, compiler flags, and options. -# -proc makeCommand { targets makeOpts cflags opts } { - set result [list] - if {$::MSVC} { - set nmakeDir [file nativename $::SRCDIR] - set nmakeFile [file nativename [file join $nmakeDir Makefile.msc]] - lappend result nmake /f $nmakeFile TOP=$nmakeDir - set tclDir [file nativename [file normalize \ - [file dirname [file dirname [info nameofexecutable]]]]] - lappend result "TCLDIR=$tclDir" - if {[regexp {USE_STDCALL=1} $cflags]} { - lappend result USE_STDCALL=1 - } - } else { - lappend result make - } - foreach makeOpt $makeOpts { - lappend result $makeOpt - } - lappend result clean - foreach target $targets { - lappend result $target - } - lappend result CFLAGS=$cflags OPTS=$opts -} - -# The following procedure prints its arguments if ::TRACE is true. -# And it executes the command of its arguments in the calling context -# if ::DRYRUN is false. -# -proc trace_cmd {args} { - if {$::TRACE} { - PUTS $args - } - set res "" - if {!$::DRYRUN} { - set res [uplevel 1 $args] - } - return $res -} - - -# This proc processes the command line options passed to this script. -# Currently the only option supported is "-makefile", default -# "releasetest.mk". Set the ::MAKEFILE variable to the value of this -# option. -# -proc process_options {argv} { - set ::SRCDIR [file normalize [file dirname [file dirname $::argv0]]] - set ::QUICK 0 - set ::MSVC 0 - set ::BUILDONLY 0 - set ::DRYRUN 0 - set ::TRACE 0 - set ::JOBS 1 - set ::PROGRESS_MSGS 0 - set ::WITHTCL {} - set ::FORCE 0 - set ::KEEPFILES 0 ;# Keep extra files after test run - set config {} - set platform $::tcl_platform(os)-$::tcl_platform(machine) - - for {set i 0} {$i < [llength $argv]} {incr i} { - set x [lindex $argv $i] - if {[regexp {^--[a-z]} $x]} {set x [string range $x 1 end]} - switch -glob -- $x { - -slave { - run_slave_test - exit - } - - # Undocumented legacy option: --srcdir DIRECTORY - # - # DIRECTORY is the root of the SQLite checkout. This sets the - # SRCDIR global variable. But that variable is already set - # automatically so there really is no reason to have this option. - # - -srcdir { - incr i - set ::SRCDIR [file normalize [lindex $argv $i]] - } - - -platform { - incr i - set platform [lindex $argv $i] - } - - -jobs { - incr i - set ::JOBS [lindex $argv $i] - } - - -progress { - set ::PROGRESS_MSGS 1 - } - - -quick { - set ::QUICK 1 - } - -veryquick { - set ::QUICK 2 - } - - -config { - incr i - set config [lindex $argv $i] - } - - -msvc { - set ::MSVC 1 - } - - -buildonly { - set ::BUILDONLY 1 - } - - -dryrun { - set ::DRYRUN 1 - } - - -force - - -f { - set ::FORCE 1 - } - - -trace { - set ::TRACE 1 - } - - -info { - PUTS "Command-line Options:" - PUTS " --srcdir $::SRCDIR" - PUTS " --platform [list $platform]" - PUTS " --config [list $config]" - if {$::QUICK} { - if {$::QUICK==1} {PUTS " --quick"} - if {$::QUICK==2} {PUTS " --veryquick"} - } - if {$::MSVC} {PUTS " --msvc"} - if {$::BUILDONLY} {PUTS " --buildonly"} - if {$::DRYRUN} {PUTS " --dryrun"} - if {$::TRACE} {PUTS " --trace"} - PUTS "\nAvailable --platform options:" - foreach y [lsort [array names ::Platforms]] { - PUTS " [list $y]" - } - PUTS "\nAvailable --config options:" - foreach y [lsort [array names ::Configs]] { - PUTS " [list $y]" - } - exit - } - - -g { - lappend ::EXTRACONFIG [lindex $argv $i] - } - - -keep { - set ::KEEPFILES 1 - } - - -with-tcl=* { - set ::WITHTCL -$x - } - - -D* - - -O* - - -enable-* - - -disable-* - - *=* { - lappend ::EXTRACONFIG [lindex $argv $i] - } - - default { - PUTSERR "" - PUTSERR [string trim $::USAGE_MESSAGE] - exit -1 - } - } - } - - if {0==[info exists ::Platforms($platform)]} { - PUTS "Unknown platform: $platform" - PUTSNNL "Set the -platform option to " - set print [list] - foreach p [array names ::Platforms] { - lappend print "\"$p\"" - } - lset print end "or [lindex $print end]" - PUTS "[join $print {, }]." - exit - } - - if {$config!=""} { - if {[llength $config]==1} {lappend config fulltest} - set ::CONFIGLIST $config - } else { - if {$::JOBS>1} { - set ::CONFIGLIST {} - foreach {target zConfig} [lreverse $::Platforms($platform)] { - append ::CONFIGLIST [format " %-25s %s\n" \ - [list $zConfig] [list $target]] - } - } else { - set ::CONFIGLIST $::Platforms($platform) - } - } - PUTS "Running the following test configurations for $platform:" - PUTS " [string trim $::CONFIGLIST]" - PUTSNNL "Flags:" - if {$::PROGRESS_MSGS} {PUTSNNL " --progress"} - if {$::DRYRUN} {PUTSNNL " --dryrun"} - if {$::BUILDONLY} {PUTSNNL " --buildonly"} - if {$::MSVC} {PUTSNNL " --msvc"} - switch -- $::QUICK { - 1 {PUTSNNL " --quick"} - 2 {PUTSNNL " --veryquick"} - } - if {$::JOBS>1} {PUTSNNL " --jobs $::JOBS"} - PUTS "" -} - -# Check to see if there are uncommitted changes in the SQLite source -# checkout. Exit if there are. Except: Do nothing if the --force -# flag is used. Also, ignore this test if the fossil binary is -# unavailable, or if the source tree is not a valid fossil checkout. -# -proc check_uncommitted {} { - if {$::FORCE} return - set pwd [pwd] - cd $::SRCDIR - if {[catch {exec fossil changes} res]==0 && [string trim $res]!=""} { - puts "ERROR: The check-out contains uncommitted changes:" - puts $res - puts "Use the -f or --force options to override" - exit 1 - } - cd $pwd -} - -# A test run has just finished in directory $dir. This command deletes all -# non-essential files from the directory. Specifically, everything except -# -# * The "testfixture" and "sqlite3" binaries, -# * The "test-out.log" and "test.log" log files. -# -proc cleanup {dir} { - set K(testfixture) 1 - set K(testfixture.exe) 1 - set K(sqlite3) 1 - set K(sqlite3.exe) 1 - set K(test-out.txt) 1 - set K(test.log) 1 - - foreach f [glob -nocomplain [file join $dir *]] { - set tail [file tail $f] - if {[info exists K($tail)]==0} { - file delete -force $f - } - } -} - - -# Main routine. -# -proc main {argv} { - - # Process any command line options. - set ::EXTRACONFIG {} - process_options $argv - if {!$::DRYRUN} check_uncommitted - PUTS [string repeat * 79] - - set ::NERR 0 - set ::NTEST 0 - set ::NTESTCASE 0 - set ::NERRCASE 0 - set ::SQLITE_VERSION {} - set STARTTIME [clock seconds] - foreach {zConfig target} $::CONFIGLIST { - if {$::MSVC && ($zConfig eq "Sanitize" || "checksymbols" in $target - || "valgrindtest" in $target)} { - PUTS "Skipping $zConfig / $target for MSVC..." - continue - } - if {$target ne "checksymbols"} { - switch -- $::QUICK { - 1 {set target quicktest} - 2 {set target smoketest} - } - if {$::BUILDONLY} { - set target testfixture - if {$::tcl_platform(platform)=="windows"} { - append target .exe - } - } - } - set config_options [concat $::Configs($zConfig) $::EXTRACONFIG] - - incr NTEST - add_test_suite all $zConfig $target $config_options - - # If the configuration included the SQLITE_DEBUG option, then remove - # it and run veryquick.test. If it did not include the SQLITE_DEBUG option - # add it and run veryquick.test. - if {$target!="checksymbols" && $target!="valgrindtest" - && $target!="fuzzoomtest" && !$::BUILDONLY && $::QUICK<2} { - set debug_idx [lsearch -glob $config_options -DSQLITE_DEBUG*] - set xtarget $target - regsub -all {fulltest[a-z]*} $xtarget test xtarget - regsub -all {fuzzoomtest} $xtarget fuzztest xtarget - if {$debug_idx < 0} { - incr NTEST - append config_options " -DSQLITE_DEBUG=1 -DSQLITE_EXTRA_IFNULLROW=1" - add_test_suite all "${zConfig}_debug" $xtarget $config_options - } else { - incr NTEST - regsub { *-DSQLITE_MEMDEBUG[^ ]* *} $config_options { } config_options - regsub { *-DSQLITE_DEBUG[^ ]* *} $config_options { } config_options - add_test_suite all "${zConfig}_ndebug" $xtarget $config_options - } - } - } - - run_all_test_suites $all - - set elapsetime [expr {[clock seconds]-$STARTTIME}] - set hr [expr {$elapsetime/3600}] - set min [expr {($elapsetime/60)%60}] - set sec [expr {$elapsetime%60}] - set etime [format (%02d:%02d:%02d) $hr $min $sec] - if {$::JOBS>1} {append etime " $::JOBS cores"} - if {[catch {exec hostname} HNAME]==0} {append etime " on $HNAME"} - PUTS [string repeat * 79] - incr ::NERRCASE $::NERR - PUTS "$::NERRCASE failures out of $::NTESTCASE tests in $etime" - if {$::SQLITE_VERSION ne ""} { - PUTS "SQLite $::SQLITE_VERSION" - } -} - -main $argv diff --git a/test/releasetest_data.tcl b/test/releasetest_data.tcl index 00be2022..45966fd2 100644 --- a/test/releasetest_data.tcl +++ b/test/releasetest_data.tcl @@ -22,14 +22,6 @@ # "fulltest"). The program may be invoked as follows: # set USAGE { -$argv0 platforms - List available platforms. - -$argv0 tests ?-nodebug? PLATFORM - List tests in a specified platform. If the -nodebug switch is - specified, synthetic debug/ndebug configurations are omitted. Each - test is a combination of a configuration and a makefile target. - $argv0 script ?-msvc? CONFIGURATION TARGET Given a configuration and make target, return a bash (or, if -msvc is specified, batch) script to execute the test. The first argument @@ -37,6 +29,14 @@ $argv0 script ?-msvc? CONFIGURATION TARGET $argv0 configurations List available configurations. + +$argv0 platforms + List available platforms. + +$argv0 tests ?-nodebug? PLATFORM + List tests in a specified platform. If the -nodebug switch is + specified, synthetic debug/ndebug configurations are omitted. Each + test is a combination of a configuration and a makefile target. } # Omit comments (text between # and \n) in a long multi-line string. @@ -149,6 +149,7 @@ array set ::Configs [strip_comments { -DSQLITE_ENABLE_RBU -DSQLITE_MAX_ATTACHED=125 -DSQLITE_MAX_MMAP_SIZE=12884901888 + -DSQLITE_ENABLE_SORTER_MMAP=1 -DLONGDOUBLE_TYPE=double --enable-session } @@ -288,56 +289,61 @@ if {$tcl_platform(os)=="Darwin"} { array set ::Platforms [strip_comments { Linux-x86_64 { - "Check-Symbols*" checksymbols - "Fast-One" "QUICKTEST_INCLUDE=rbu.test fuzztest test" - "Debug-One" "mptest test" - "Debug-Two" "test" - "Have-Not" test - "Secure-Delete" test - "Unlock-Notify" "QUICKTEST_INCLUDE=notify2.test test" - "User-Auth" tcltest - "Update-Delete-Limit" test - "Extra-Robustness" test - "Device-Two" "threadtest test" - "No-lookaside" test - "Devkit" test - "Apple" test - "Sanitize" test - "Device-One" fulltest - "Default" "threadtest fulltest" - "Valgrind*" valgrindtest + "Check-Symbols*" "" checksymbols + "Fast-One" QUICKTEST_INCLUDE=rbu.test "fuzztest test" + "Debug-One" "" "mptest test" + "Debug-Two" "" test + "Have-Not" "" test + "Secure-Delete" "" test + "Unlock-Notify" QUICKTEST_INCLUDE=notify2.test test + "User-Auth" "" tcltest + "Update-Delete-Limit" "" test + "Extra-Robustness" "" test + "Device-Two" "" "threadtest test" + "No-lookaside" "" test + "Devkit" "" test + "Apple" "" test + "Sanitize*" "" test + "Device-One" "" alltest + "Default" "" "threadtest fuzztest alltest" + "Valgrind*" "" valgrindtest } Linux-i686 { - "Devkit" test - "Have-Not" test - "Unlock-Notify" "QUICKTEST_INCLUDE=notify2.test test" - "Device-One" test - "Device-Two" test - "Default" "threadtest fulltest" + "Devkit" "" test + "Have-Not" "" test + "Unlock-Notify" QUICKTEST_INCLUDE=notify2.test test + "Device-One" "" test + "Device-Two" "" test + "Default" "" "threadtest fuzztest alltest" } Darwin-i386 { - "Locking-Style" "mptest test" - "Have-Not" test - "Apple" "threadtest fulltest" + "Locking-Style" "" "mptest test" + "Have-Not" "" test + "Apple" "" "threadtest fuzztest alltest" } Darwin-x86_64 { - "Locking-Style" "mptest test" - "Have-Not" test - "Apple" "threadtest fulltest" + "Locking-Style" "" "mptest test" + "Have-Not" "" test + "Apple" "" "threadtest fuzztest alltest" + } + Darwin-arm64 { + "Locking-Style" "" "mptest test" + "Have-Not" "" test + "Apple" "" "threadtest fuzztest alltest" } "Windows NT-intel" { - "Stdcall" test - "Have-Not" test - "Windows-Memdebug*" test - "Windows-Win32Heap*" test - "Default" "mptest fulltestonly" + "Stdcall" "" test + "Have-Not" "" test + "Windows-Memdebug*" "" test + "Windows-Win32Heap*" "" test + "Default" "" "mptest fulltestonly" } "Windows NT-amd64" { - "Stdcall" test - "Have-Not" test - "Windows-Memdebug*" test - "Windows-Win32Heap*" test - "Default" "mptest fulltestonly" + "Stdcall" "" test + "Have-Not" "" test + "Windows-Memdebug*" "" test + "Windows-Win32Heap*" "" test + "Default" "" "mptest fulltestonly" } # The Failure-Detection platform runs various tests that deliberately @@ -345,13 +351,13 @@ array set ::Platforms [strip_comments { # correctly identifies failures. # Failure-Detection { - Fail0* "TEST_FAILURE=0 test" - Sanitize* "TEST_FAILURE=1 test" - Fail2* "TEST_FAILURE=2 valgrindtest" - Fail3* "TEST_FAILURE=3 valgrindtest" - Fail4* "TEST_FAILURE=4 test" - FuzzFail1* "TEST_FAILURE=5 test" - FuzzFail2* "TEST_FAILURE=5 valgrindtest" + Fail0* "TEST_FAILURE=0" test + Sanitize* "TEST_FAILURE=1" test + Fail2* "TEST_FAILURE=2" valgrindtest + Fail3* "TEST_FAILURE=3" valgrindtest + Fail4* "TEST_FAILURE=4" test + FuzzFail1* "TEST_FAILURE=5" test + FuzzFail2* "TEST_FAILURE=5" valgrindtest } }] @@ -367,7 +373,7 @@ array set ::Platforms [strip_comments { # specified for each platforms exists. # foreach {key value} [array get ::Platforms] { - foreach {v t} $value { + foreach {v vars t} $value { if {[string range $v end end]=="*"} { set v [string range $v 0 end-1] } @@ -438,6 +444,7 @@ proc main_script {args} { lappend opts -DSQLITE_EXTRA_IFNULLROW set config [string range $config 0 end-6] } + regexp {^(.*)-[0-9]+} $config -> config # Ensure that the named configuration exists. # @@ -473,6 +480,7 @@ proc main_script {args} { if {$bRemoveDebug} { if {$param=="-DSQLITE_DEBUG" || $param=="-DSQLITE_DEBUG=1" || $param=="-DSQLITE_MEMDEBUG" || $param=="-DSQLITE_MEMDEBUG=1" + || $param=="--enable-debug" } { continue } @@ -585,32 +593,57 @@ proc main_tests {args} { exit 1 } - foreach {config target} $::Platforms($p) { - set bNosynthetic 0 + set lTest [list] + + foreach {config vars target} $::Platforms($p) { if {[string range $config end end]=="*"} { - set bNosynthetic 1 set config [string range $config 0 end-1] - } - puts "$config \"$target\"" - if {$bNodebug==0 && $bNosynthetic==0} { - set iHas [string first SQLITE_DEBUG $::Configs($config)] - set dtarget [list] - set iQTI [lsearch -glob $target QUICKTEST_*] - if {$iQTI>=0} { - lappend dtarget [lindex $target $iQTI] + } elseif {$bNodebug==0} { + set dtarget test + if {[lsearch $target fuzztest]<0 && [lsearch $target test]<0} { + set dtarget tcltest } - if {[lsearch $target tcltest]>=0} { - lappend dtarget tcltest + if {$vars!=""} { set dtarget "$vars $dtarget" } + + if {[string first SQLITE_DEBUG $::Configs($config)]>=0 + || [string first --enable-debug $::Configs($config)]>=0 + } { + lappend lTest "$config-ndebug \"$dtarget\"" } else { - lappend dtarget test + lappend lTest "$config-debug \"$dtarget\"" } - if {$iHas>=0} { - puts "$config-ndebug \"$dtarget\"" - } else { - puts "$config-debug \"$dtarget\"" + } + + if {[llength $target]==1 && ([string match "*TEST_FAILURE*" $vars] || ( + [lsearch $target "valgrindtest"]<0 + && [lsearch $target "alltest"]<0 + && [lsearch $target "fulltestonly"]<0 + && ![string match Sanitize* $config] + ))} { + if {$vars!=""} { set target "$vars $target" } + lappend lTest "$config \"$target\"" + } else { + set idir -1 + foreach t $target { + if {$t=="valgrindtest" || $t=="alltest" || $t=="fulltestonly" + || [string match Sanitize* $config] + } { + if {$vars!=""} { set t "$vars $t" } + for {set ii 1} {$ii<=4} {incr ii} { + lappend lTest "$config-[incr idir] \"TCLTEST_PART=$ii/4 $t\"" + } + } else { + if {$vars!=""} { set t "$vars $t" } + lappend lTest "$config-[incr idir] \"$t\"" + } } } } + + foreach l $lTest { + puts $l + } + } if {[llength $argv]==0} { usage } diff --git a/test/returning1.test b/test/returning1.test index dc465523..c64e72f7 100644 --- a/test/returning1.test +++ b/test/returning1.test @@ -318,4 +318,19 @@ do_test 12.4 { lsort [array names cname] } {{"x"+"y"} *} +ifcapable rtree { +#------------------------------------------------------------------------- +# Based on dbsqlfuzz find crash-ffbba524cac354b2a61bfd677cec9d2a4333f49a +reset_db +do_execsql_test 13.0 { + CREATE VIRTUAL TABLE t1 USING rtree(a, b, c); + CREATE TABLE t2(x); +} + +do_execsql_test 13.1 { + INSERT INTO t1(a,b,c) VALUES(1,2,3) + RETURNING (SELECT b FROM t2); +} {{}} +} ;# end ifcapable rtree + finish_test diff --git a/test/returningfault.test b/test/returningfault.test new file mode 100644 index 00000000..8bf6fbfe --- /dev/null +++ b/test/returningfault.test @@ -0,0 +1,36 @@ +# 2022 January 5 +# +# 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 +source $testdir/malloc_common.tcl + + +do_execsql_test 1.0 { + CREATE TABLE t1 (b); +} {} +faultsim_save_and_close + +do_faultsim_test pagerfault-1 -faults oom-t* -prep { + faultsim_restore_and_reopen +} -body { + execsql { + INSERT INTO t1(b) VALUES(65) RETURNING ( + SELECT * FROM sqlite_temp_schema + ) AS aaa; + } +} -test { + faultsim_test_result {1 {sub-select returns 5 columns - expected 1}} +} + + +finish_test diff --git a/test/rowid.test b/test/rowid.test index f4fa1ce8..4327004d 100644 --- a/test/rowid.test +++ b/test/rowid.test @@ -18,6 +18,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix rowid # Basic ROWID functionality tests. # @@ -786,5 +787,34 @@ do_execsql_test rowid-15.2 { ); } {1 {}} +#------------------------------------------------------------------------- +# Check that an unqualified "rowid" can be used in join queries so long +# as only one of the source objects has a rowid column. +# +reset_db +do_execsql_test 16.0 { + CREATE TABLE t1(x); + CREATE TABLE t2(y PRIMARY KEY) WITHOUT ROWID; + CREATE VIEW v1 AS SELECT x FROM t1; + CREATE TABLE t3(z); + + INSERT INTO t1(rowid, x) VALUES(1, 1); + INSERT INTO t2(y) VALUES(2); + INSERT INTO t3(rowid, z) VALUES(3, 3); +} + +do_execsql_test 16.1 { SELECT rowid FROM t1, t2; } {1} +do_execsql_test 16.2 { SELECT rowid FROM t1, v1; } {1} +do_execsql_test 16.3 { SELECT rowid FROM t3, v1; } {3} +do_execsql_test 16.4 { SELECT rowid FROM t3, (SELECT 123); } {3} + +do_execsql_test 16.5 { SELECT rowid FROM t2, t1; } {1} +do_execsql_test 16.6 { SELECT rowid FROM v1, t1; } {1} +do_execsql_test 16.7 { SELECT rowid FROM v1, t3; } {3} +do_execsql_test 16.8 { SELECT rowid FROM (SELECT 123), t3; } {3} + +do_catchsql_test 16.5 { SELECT rowid FROM t1, t3; } {1 {no such column: rowid}} + + finish_test diff --git a/test/rowvalueA.test b/test/rowvalueA.test new file mode 100644 index 00000000..dc5a7a01 --- /dev/null +++ b/test/rowvalueA.test @@ -0,0 +1,77 @@ +# 2021 July 6 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix rowvalueA + +do_execsql_test 1.0 { + SELECT (1, 2) IN ( (3, 4), (5, 6), (1, 3) ); +} {0} + +do_execsql_test 1.1 { + SELECT (1, 2) IN ( (3, 4), (5, 6), (1, 2) ); +} {1} + +do_execsql_test 1.2 { + SELECT (1, 2) IN ( (3, 2) ); +} {0} + +do_execsql_test 1.3 { + SELECT (1, 2) IN ( (1, 2) ); +} {1} + +do_execsql_test 1.4 { + SELECT (1, 2) IN ( ); +} {0} + +do_execsql_test 1.5 { + SELECT (1, 2) NOT IN ( ); +} {1} + +for {set ii 0} {$ii < 2000} {incr ii} { + lappend L "($ii, $ii)" +} + +do_execsql_test 1.6.1 " + SELECT (400,400) IN ( [join $L ,] ) +" 1 + +do_execsql_test 1.6.2 " + SELECT (1500,1500) IN ( [join $L ,] ) +" 1 + +do_execsql_test 1.6.2 " + SELECT (1500,1499) IN ( [join $L ,] ) +" 0 + +#------------------------------------------------------------------------- + +do_catchsql_test 2.0 { + SELECT (1, 2) IN ( (1, 2), (3, 4, 5), (5, 6) ) +} {1 {IN(...) element has 3 terms - expected 2}} + +do_catchsql_test 2.1 { + SELECT (1, 2) IN ( (1, 2), 4, (5, 6) ) +} {1 {IN(...) element has 1 term - expected 2}} + +do_catchsql_test 2.2 { + SELECT (1, 2, 3) IN ( (1, 2), (3, 4), (5, 6) ) +} {1 {IN(...) element has 2 terms - expected 3}} + +do_catchsql_test 2.3 { + SELECT 2 IN ( (1, 2), (3, 4), (5, 6) ) +} {1 {row value misused}} + +finish_test + diff --git a/test/rowvaluefault.test b/test/rowvaluefault.test index ac1b236b..a06ef886 100644 --- a/test/rowvaluefault.test +++ b/test/rowvaluefault.test @@ -68,4 +68,22 @@ do_faultsim_test 6 -faults oom* -body { faultsim_test_result {0 {2 3}} } +do_faultsim_test 7 -faults oom* -body { + execsql { + SELECT fou FROM xyz + WHERE (one, two, thr) IN ( ('a','b','c'), ('A','A','A'), (1,2,3) ); + } +} -test { + faultsim_test_result {0 1} +} + +do_faultsim_test 8 -faults oom* -body { + execsql { + SELECT fou FROM xyz + WHERE (two, one) IN ( ('a','b','c'), ('A','A','A'), (1,2,3) ); + } +} -test { + faultsim_test_result {1 {IN(...) element has 3 terms - expected 2}} +} + finish_test diff --git a/test/schema3.test b/test/schema3.test index ba7d745e..39d46323 100644 --- a/test/schema3.test +++ b/test/schema3.test @@ -16,6 +16,12 @@ source $testdir/tester.tcl source $testdir/malloc_common.tcl source $testdir/lock_common.tcl +# If SQLITE_OMIT_ALTERTABLE is defined, omit this file. +ifcapable !altertable { + finish_test + return +} + # This block tests that if one client modifies the database schema, a # second client updates its internal cache of the database schema before # executing any queries. Specifically, it does not return a "no such column" diff --git a/test/shell1.test b/test/shell1.test index 33027612..c4e2ceb8 100644 --- a/test/shell1.test +++ b/test/shell1.test @@ -18,6 +18,8 @@ # shell1-1.*: Basic command line option handling. # shell1-2.*: Basic "dot" command token parsing. # shell1-3.*: Basic test that "dot" command can be called. +# shell1-{4-8}.*: Test various "dot" commands's functionality. +# shell1-9.*: Basic test that "dot" commands and SQL intermix ok. # set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -51,7 +53,7 @@ do_test shell1-1.1.2 { # error on extra options do_test shell1-1.1.3 { catchcmd "test.db FOO test.db BAD" ".quit" -} {1 {Error: near "FOO": syntax error}} +} {1 {Error: in prepare, near "FOO": syntax error (1)}} # -help do_test shell1-1.2.1 { @@ -76,7 +78,7 @@ do_test shell1-1.3.2 { } {0 {}} do_test shell1-1.3.3 { catchcmd "-init FOO test.db BAD .quit" "" -} {1 {Error: near "BAD": syntax error}} +} {1 {Error: in prepare, near "BAD": syntax error (1)}} # -echo print commands before execution do_test shell1-1.4.1 { @@ -1224,4 +1226,22 @@ do_test shell1-8.4 { | 6683623321994527 | -47 | +------------------+-----+}} +#---------------------------------------------------------------------------- +# Test cases shell1-9.*: Basic test that "dot" commands and SQL intermix ok. +# +do_test shell1-9.1 { + catchcmd :memory: { +.mode csv +/* +x */ select 1,2; --x + -- .nada +; +.mode csv +--x +select 2,1; select 3,4; +} +} {0 {1,2 +2,1 +3,4}} + finish_test diff --git a/test/shell2.test b/test/shell2.test index 2de6bf75..6b4dff51 100644 --- a/test/shell2.test +++ b/test/shell2.test @@ -43,10 +43,10 @@ do_test shell2-1.1.1 { # Shell silently ignores extra parameters. # Ticket [f5cb008a65]. do_test shell2-1.2.1 { - set rc [catch { eval exec $CLI \":memory:\" \"select+3\" \"select+4\" } msg] - list $rc $msg + catchcmdex {:memory: "select+3" "select+4"} } {0 {3 -4}} +4 +}} # Test a problem reported on the mailing list. The shell was at one point # returning the generic SQLITE_ERROR message ("SQL error or missing database") @@ -63,7 +63,7 @@ do_test shell2-1.3 { UPDATE OR REPLACE t5 SET a = 4 WHERE a = 1; } -} {1 {Error: near line 9: too many levels of trigger recursion}} +} {1 {Error: near line 9: stepping, too many levels of trigger recursion (1)}} @@ -123,7 +123,7 @@ SELECT * FROM foo;} # NB. whitespace is important do_test shell2-1.4.5 { forcedelete foo.db - catchcmd "foo.db" {.echo ON + catchcmdex "foo.db" {.echo ON CREATE TABLE foo1(a); INSERT INTO foo1(a) VALUES(1); CREATE TABLE foo2(b); @@ -155,7 +155,7 @@ SELECT * FROM foo2; # NB. whitespace is important do_test shell2-1.4.6 { forcedelete foo.db - catchcmd "foo.db" {.echo ON + catchcmdex "foo.db" {.echo ON .headers ON CREATE TABLE foo1(a); INSERT INTO foo1(a) VALUES(1); diff --git a/test/shell3.test b/test/shell3.test index 63c30a26..243da976 100644 --- a/test/shell3.test +++ b/test/shell3.test @@ -18,6 +18,7 @@ # # shell3-1.*: Basic tests for running SQL statments from command line. # shell3-2.*: Basic tests for running SQL file from command line. +# shell3-3.*: Basic tests for processing odd SQL constructs. # set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -26,6 +27,7 @@ db close forcedelete test.db test.db-journal test.db-wal sqlite3 db test.db + # There are inconsistencies in command-line argument quoting on Windows. # In particular, individual applications are responsible for command-line # parsing in Windows, not the shell. Depending on whether the sqlite3.exe @@ -66,7 +68,7 @@ do_test shell3-1.6 { } {0 {}} do_test shell3-1.7 { catchcmd "foo.db \"CREATE TABLE\"" -} {1 {Error: incomplete input}} +} {1 {Error: in prepare, incomplete input (1)}} #---------------------------------------------------------------------------- # shell3-2.*: Basic tests for running SQL file from command line. @@ -96,6 +98,41 @@ do_test shell3-2.6 { } {0 {}} do_test shell3-2.7 { catchcmd "foo.db" "CREATE TABLE" -} {1 {Error: near line 1: incomplete input}} +} {1 {Error: near line 1: in prepare, incomplete input (1)}} + + +#---------------------------------------------------------------------------- +# shell3-3.*: Basic tests for processing odd SQL constructs. +# + +# Run combinations of odd identifiers, comments, semicolon placement +do_test shell3-3.1 { + forcedelete foo.db + set rc [ catchcmd "foo.db" {CREATE TABLE t1(" +a--. +" --x +); CREATE TABLE t2("a[""b""]"); +.header on +INSERT INTO t1 VALUES (' +x''y'); +INSERT INTO t2 VALUES (' +/*. +.*/ x +''y'); +SELECT * from t1 limit 1; +SELECT * from t2 limit 1; +} ] + set fexist [file exist foo.db] + list $rc $fexist +} {{0 { +a--. + + +x'y +a["b"] + +/*. +.*/ x +'y}} 1} finish_test diff --git a/test/shell5.test b/test/shell5.test index 8ec9a632..dc99a7ac 100644 --- a/test/shell5.test +++ b/test/shell5.test @@ -456,4 +456,19 @@ CREATE TABLE t7(a, b, c); db eval { SELECT * FROM t7 ORDER BY a } } {1 2 3 4 5 {} 6 7 8} +do_test shell5-4.3 { + forcedelete shell5.csv + set fd [open shell5.csv w] + puts $fd ",," + puts $fd "1,2,3" + close $fd + catchcmd test.db [string trim { +.mode csv +CREATE TABLE t8(a, b, c); +.import -skip 1 shell5.csv t8 +.nullvalue # + }] + db eval { SELECT * FROM t8 } +} {1 2 3} + finish_test diff --git a/test/shell8.test b/test/shell8.test index 3658a8ac..ddb4a47b 100644 --- a/test/shell8.test +++ b/test/shell8.test @@ -44,6 +44,10 @@ proc populate_dir {dirname spec} { } } +proc dir_content {dirname} { + lsort [glob -nocomplain $dirname/*] +} + proc dir_to_list {dirname {n -1}} { if {$n<0} {set n [llength [file split $dirname]]} @@ -170,8 +174,23 @@ foreach {tn tcl} { } } -finish_test - - +do_test 2.1.1 { + populate_dir ar2 { + file1 "abcd" + file2 "efgh" + junk1 "j1" + junk2 "j2" + dir1/file3 "ijkl" + } + populate_dir ar4 { + file2 "efgh" + } + catchcmd shell8.db {.ar -c} + catchcmd shell8.db {.ar -C ar2 -i .} + catchcmd shell8.db {.ar -r ./file2 ./dir1} + catchcmd shell8.db {.ar -g -r ./ju*2} + catchcmd shell8.db {.ar -C ar4 -x .} + regsub -all {ar4} [dir_content ar4] ar2 +} {ar2/file1 ar2/file2 ar2/junk1} finish_test diff --git a/test/shrink.test b/test/shrink.test index 7c9bed08..bc4a707b 100644 --- a/test/shrink.test +++ b/test/shrink.test @@ -24,7 +24,7 @@ do_test shrink-1.1 { CREATE TABLE t1(x,y); INSERT INTO t1 VALUES(randomblob(1000000),1); } - set ::baseline sqlite3_memory_used + set ::baseline [sqlite3_memory_used] # EVIDENCE-OF: R-58814-63508 The sqlite3_db_release_memory(D) interface # attempts to free as much heap memory as possible from database # connection D. diff --git a/test/skipscan2.test b/test/skipscan2.test index 47b2b3ff..aa870d45 100644 --- a/test/skipscan2.test +++ b/test/skipscan2.test @@ -157,7 +157,6 @@ do_execsql_test skipscan2-2.1 { CREATE INDEX peoplew_idx1 ON peoplew(role, height); INSERT INTO peoplew(name,role,height) SELECT name, role, height FROM people; - ALTER TABLE people RENAME TO old_people; SELECT name FROM peoplew WHERE height>=180 ORDER BY +name; } {David Jack Patrick Quiana Xavier} do_execsql_test skipscan2-2.2 { diff --git a/test/sorterref.test b/test/sorterref.test index 28445c6e..adf1cf53 100644 --- a/test/sorterref.test +++ b/test/sorterref.test @@ -14,6 +14,12 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix sorterref +# If SQLITE_OMIT_ALTERTABLE is defined, omit this file. +ifcapable !altertable { + finish_test + return +} + do_execsql_test 1.0 { CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES(1, 2, 3); diff --git a/test/speedtest1.c b/test/speedtest1.c index 9e8c3960..83c503c8 100644 --- a/test/speedtest1.c +++ b/test/speedtest1.c @@ -34,6 +34,7 @@ static const char zHelp[] = " --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" " --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" @@ -947,7 +948,7 @@ void testset_main(void){ speedtest1_begin_test(210, "ALTER TABLE ADD COLUMN, and query"); - speedtest1_exec("ALTER TABLE z2 ADD COLUMN d DEFAULT 123"); + speedtest1_exec("ALTER TABLE z2 ADD COLUMN d INT DEFAULT 123"); speedtest1_exec("SELECT sum(d) FROM z2"); speedtest1_end_test(); @@ -2317,8 +2318,22 @@ int main(int argc, char **argv){ if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); g.nReserve = atoi(argv[++i]); }else if( strcmp(z,"without-rowid")==0 ){ - g.zWR = "WITHOUT ROWID"; + if( strstr(g.zWR,"WITHOUT")!=0 ){ + /* no-op */ + }else if( strstr(g.zWR,"STRICT")!=0 ){ + g.zWR = "WITHOUT ROWID,STRICT"; + }else{ + g.zWR = "WITHOUT ROWID"; + } g.zPK = "PRIMARY KEY"; + }else if( strcmp(z,"strict")==0 ){ + if( strstr(g.zWR,"STRICT")!=0 ){ + /* no-op */ + }else if( strstr(g.zWR,"WITHOUT")!=0 ){ + g.zWR = "WITHOUT ROWID,STRICT"; + }else{ + g.zWR = "STRICT"; + } }else if( strcmp(z, "help")==0 || strcmp(z,"?")==0 ){ printf(zHelp, argv[0]); exit(0); diff --git a/test/sqldiff1.test b/test/sqldiff1.test index ea4e1f99..4ea5efbb 100644 --- a/test/sqldiff1.test +++ b/test/sqldiff1.test @@ -35,6 +35,10 @@ do_test sqldiff-1.0 { DELETE FROM x2.t2 WHERE a=48; INSERT INTO x2.t1(a,b) VALUES(1234,'hello'); INSERT INTO x2.t2(a,b) VALUES(50.5,'xyzzy'); + INSERT INTO x2.t2(a,b) VALUES(51.5,''); + INSERT INTO x2.t2(a,b) VALUES(52.5,''||X'0d0a'); + INSERT INTO x2.t2(a,b) VALUES(53.5,'one'||X'0a0d'); + INSERT INTO x2.t2(a,b) VALUES(54.5,'one'||X'0a'||'two'); CREATE TABLE x2.t3(a,b,c); INSERT INTO x2.t3 VALUES(111,222,333); CREATE TABLE main.t4(x,y,z); @@ -50,6 +54,11 @@ do_test sqldiff-1.1 { INSERT INTO t1(a,b) VALUES(1234,'hello'); DELETE FROM t2 WHERE a=48; INSERT INTO t2(a,b) VALUES(50.5,'xyzzy'); +INSERT INTO t2(a,b) VALUES(51.5,''); +INSERT INTO t2(a,b) VALUES(52.5,''||X'0d0a'); +INSERT INTO t2(a,b) VALUES(53.5,'one'||X'0a0d'); +INSERT INTO t2(a,b) VALUES(54.5,'one'||X'0a' +||'two'); CREATE TABLE t3(a,b,c); INSERT INTO t3(rowid,a,b,c) VALUES(1,111,222,333); DROP TABLE t4;} diff --git a/test/sqllimits1.test b/test/sqllimits1.test index 594c0615..6b7d7b60 100644 --- a/test/sqllimits1.test +++ b/test/sqllimits1.test @@ -293,8 +293,14 @@ do_test sqllimits1-5.9 { } {1 {string or blob too big}} do_test sqllimits1-5.10 { - set ::str [string repeat %J 2100] - catchsql { SELECT strftime($::str, '2003-10-31') } + # Prior to 3.37.0 strftime() allocated a large static buffer into + # which to format its output. Using that strategy, 2100 repeats was + # enough to exceed 100KiB and provoke the error. As of 3.37.0 strftime() + # uses the StrAccum functions, so it requires 12100 to fail. + # + # set ::str [string repeat %J 2100] + set ::str [string repeat %J 12100] + catchsql { SELECT length(strftime($::str, '2003-10-31')) } } {1 {string or blob too big}} do_test sqllimits1-5.11 { @@ -395,7 +401,7 @@ do_test sqllimits1-5.19 { unset blobvalue ifcapable datetime { - set strvalue [string repeat D [expr {$SQLITE_LIMIT_LENGTH-12}]] + set strvalue [string repeat D [expr {$SQLITE_LIMIT_LENGTH-11}]] do_test sqllimits1-5.20 { catchsql {SELECT strftime('%Y ' || $::strvalue, '2008-01-02')} } [list 0 [list "2008 $strvalue"]] @@ -863,16 +869,21 @@ do_test sqllimits1-15.2 { # This test case doesn't really belong with the other limits tests. # It is in this file because it is taxing to run, like the limits tests. # -do_test sqllimits1-16.1 { - set ::N [expr int(([expr pow(2,32)]/50) + 1)] - expr (($::N*50) & 0xffffffff)<55 -} {1} -do_test sqllimits1-16.2 { - set ::format "[string repeat A 60][string repeat "%J" $::N]" - catchsql { - SELECT strftime($::format, 1); - } -} {1 {string or blob too big}} +# Update for 3.37.0: strftime() used to allocate a large static buffer +# into which it would write its result. With that implementation, the +# following would trigger an SQLITE_TOOBIG error. But strftime() now +# uses the StrAccum functions, causing this test to fail. +# +#do_test sqllimits1-16.1 { +# set ::N [expr int(([expr pow(2,32)]/50) + 1)] +# expr (($::N*50) & 0xffffffff)<55 +#} {1} +#do_test sqllimits1-16.2 { +# set ::format "[string repeat A 60][string repeat "%J" $::N]" +# catchsql { +# SELECT strftime($::format, 1); +# } +#} {1 {string or blob too big}} do_catchsql_test sqllimits1.17.0 { SELECT *,*,*,*,*,*,*,* FROM ( diff --git a/test/stat.test b/test/stat.test index 5eb7d6f7..4705844c 100644 --- a/test/stat.test +++ b/test/stat.test @@ -36,8 +36,10 @@ do_execsql_test stat-0.0 { } {/0 name TEXT .* 1 path TEXT .* 9 pgsize INTEGER/} # Attempts to drop an eponymous virtual table are a no-op. -do_execsql_test stat-0.1 { +do_catchsql_test stat-0.1a { DROP TABLE dbstat; +} {1 {table dbstat may not be dropped}} +do_execsql_test stat-0.1b { PRAGMA table_info=dbstat; } {/0 name TEXT .* 1 path TEXT .* 9 pgsize INTEGER/} @@ -315,4 +317,12 @@ do_execsql_test 8.5 { SELECT * FROM st4 WHERE schema = NULL; } {} +#------------------------------------------------------------------------- +reset_db +breakpoint +do_catchsql_test 9.1 { + CREATE TABLE dbstat(x, y); + DROP TABLE nosuchdb.dbstat; +} {/1 {(no such table: nosuchdb.dbstat|table dbstat may not be dropped)}/} + finish_test diff --git a/test/statfault.test b/test/statfault.test index ce79e328..b5980d41 100644 --- a/test/statfault.test +++ b/test/statfault.test @@ -41,5 +41,15 @@ do_faultsim_test 1 -faults * -prep { faultsim_test_result {0 8} } +do_faultsim_test 2 -faults * -prep { + faultsim_restore_and_reopen + register_dbstat_vtab db + execsql { SELECT 1 FROM sqlite_master LIMIT 1 } +} -body { + db eval { SELECT * FROM sss } { db eval { SELECT randomblob(5000) } } +} -test { + faultsim_test_result {0 {}} +} finish_test + diff --git a/test/strict1.test b/test/strict1.test new file mode 100644 index 00000000..67483413 --- /dev/null +++ b/test/strict1.test @@ -0,0 +1,138 @@ +# 2021-08-18 +# +# 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 file is testing STRICT tables. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix strict1 + +# STRICT tables have on a limited number of allowed datatypes. +# +do_catchsql_test strict1-1.1 { + CREATE TABLE t1(a) STRICT; +} {1 {missing datatype for t1.a}} +do_catchsql_test strict1-1.2 { + CREATE TABLE t1(a PRIMARY KEY) STRICT, WITHOUT ROWID; +} {1 {missing datatype for t1.a}} +do_catchsql_test strict1-1.3 { + CREATE TABLE t1(a PRIMARY KEY) WITHOUT ROWID, STRICT; +} {1 {missing datatype for t1.a}} +do_catchsql_test strict1-1.4 { + CREATE TABLE t1(a BANJO PRIMARY KEY) WITHOUT ROWID, STRICT; +} {1 {unknown datatype for t1.a: "BANJO"}} +do_catchsql_test strict1-1.5 { + CREATE TABLE t1(a TEXT PRIMARY KEY, b INT, c INTEGER, d REAL, e BLOB, f DATE) strict; +} {1 {unknown datatype for t1.f: "DATE"}} +do_catchsql_test strict1-1.6 { + CREATE TABLE t1(a TEXT PRIMARY KEY, b INT, c INTEGER, d REAL, e BLOB, f TEXT(50)) WITHOUT ROWID, STRICT; +} {1 {unknown datatype for t1.f: "TEXT(50)"}} + +do_execsql_test strict1-2.0 { + CREATE TABLE t1( + a INT, + b INTEGER, + c BLOB, + d TEXT, + e REAL + ) STRICT; +} {} +ifcapable vtab { + do_execsql_test strict1-2.0a { + SELECT strict FROM pragma_table_list('t1'); + } {1} +} +do_catchsql_test strict1-2.1 { + INSERT INTO t1(a) VALUES('xyz'); +} {1 {cannot store TEXT value in INT column t1.a}} +do_catchsql_test strict1-2.2 { + INSERT INTO t1(b) VALUES('xyz'); +} {1 {cannot store TEXT value in INTEGER column t1.b}} +do_catchsql_test strict1-2.3 { + INSERT INTO t1(c) VALUES('xyz'); +} {1 {cannot store TEXT value in BLOB column t1.c}} +do_catchsql_test strict1-2.4 { + INSERT INTO t1(d) VALUES(x'3142536475'); +} {1 {cannot store BLOB value in TEXT column t1.d}} +do_catchsql_test strict1-2.5 { + INSERT INTO t1(e) VALUES('xyz'); +} {1 {cannot store TEXT value in REAL column t1.e}} + + +do_execsql_test strict1-3.1 { + INSERT INTO t1(a, b) VALUES(1,2),('3','4'),(5.0, 6.0),(null,null); + SELECT a, b, '|' FROM t1; +} {1 2 | 3 4 | 5 6 | {} {} |} +do_catchsql_test strict1-3.2 { + INSERT INTO t1(a) VALUES(1.2); +} {1 {cannot store REAL value in INT column t1.a}} +do_catchsql_test strict1-3.3 { + INSERT INTO t1(a) VALUES(x'313233'); +} {1 {cannot store BLOB value in INT column t1.a}} +do_catchsql_test strict1-3.4 { + INSERT INTO t1(b) VALUES(1.2); +} {1 {cannot store REAL value in INTEGER column t1.b}} +do_catchsql_test strict1-3.5 { + INSERT INTO t1(b) VALUES(x'313233'); +} {1 {cannot store BLOB value in INTEGER column t1.b}} + +do_execsql_test strict1-4.1 { + DELETE FROM t1; + INSERT INTO t1(c) VALUES(x'313233'), (NULL); + SELECT typeof(c), c FROM t1; +} {blob 123 null {}} +do_catchsql_test strict1-4.2 { + INSERT INTO t1(c) VALUES('456'); +} {1 {cannot store TEXT value in BLOB column t1.c}} + +do_execsql_test strict1-5.1 { + DELETE FROM t1; + INSERT INTO t1(d) VALUES('xyz'),(4),(5.5),(NULL); + SELECT typeof(d), d FROM t1; +} {text xyz text 4 text 5.5 null {}} +do_catchsql_test strict1-5.2 { + INSERT INTO t1(d) VALUES(x'4567'); +} {1 {cannot store BLOB value in TEXT column t1.d}} + +do_execsql_test strict1-6.1 { + DELETE FROM t1; + INSERT INTO t1(e) VALUES(1),(2.5),('3'),('4.5'),(6.0),(NULL); + SELECT typeof(e), e FROM t1; +} {real 1.0 real 2.5 real 3.0 real 4.5 real 6.0 null {}} +do_catchsql_test strict1-6.2 { + INSERT INTO t1(e) VALUES('xyz'); +} {1 {cannot store TEXT value in REAL column t1.e}} +do_catchsql_test strict1-6.3 { + INSERT INTO t1(e) VALUES(x'3456'); +} {1 {cannot store BLOB value in REAL column t1.e}} + +ifcapable altertable { + do_execsql_test strict1-7.1 { + DROP TABLE IF EXISTS t4; + CREATE TABLE t4( + a INT AS (b*2) VIRTUAL, + b INT AS (c*2) STORED, + c INT PRIMARY KEY + ) STRICT; + INSERT INTO t4(c) VALUES(1); + SELECT * FROM t4; + } {4 2 1} + do_catchsql_test strict1-7.2 { + ALTER TABLE t4 ADD COLUMN d VARCHAR; + } {1 {error in table t4 after add column: unknown datatype for t4.d: "VARCHAR"}} + do_catchsql_test strict1-7.3 { + ALTER TABLE t4 ADD COLUMN d; + } {1 {error in table t4 after add column: missing datatype for t4.d}} +} + +finish_test diff --git a/test/strict2.test b/test/strict2.test new file mode 100644 index 00000000..be595228 --- /dev/null +++ b/test/strict2.test @@ -0,0 +1,158 @@ +# 2021-08-19 +# +# 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 file is testing STRICT tables. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix strict2 + +# PRAGMA integrity_check on a STRICT table should verify that +# all of the values are of the correct type. +# +do_execsql_test strict2-1.1 { + CREATE TABLE t1( + a INT, + b INTEGER, + c TEXT, + d REAL, + e BLOB + ) STRICT; + CREATE TABLE t1nn( + a INT NOT NULL, + b INTEGER NOT NULL, + c TEXT NOT NULL, + d REAL NOT NULL, + e BLOB NOT NULL + ) STRICT; + CREATE TABLE t2(a,b,c,d,e); + INSERT INTO t1(a,b,c,d,e) VALUES(1,1,'one',1.0,x'b1'),(2,2,'two',2.25,x'b2b2b2'); + PRAGMA writable_schema=on; + UPDATE sqlite_schema SET rootpage=(SELECT rootpage FROM sqlite_schema WHERE name='t1'); +} {} +db close +sqlite3 db test.db +do_execsql_test strict2-1.2 { + PRAGMA quick_check('t1'); +} {ok} +do_execsql_test strict2-1.3 { + UPDATE t2 SET a=2.5 WHERE b=2; + PRAGMA quick_check('t1'); +} {{non-INT value in t1.a}} +do_execsql_test strict2-1.4 { + UPDATE t2 SET a='xyz' WHERE b=2; + PRAGMA quick_check('t1'); +} {{non-INT value in t1.a}} +do_execsql_test strict2-1.5 { + UPDATE t2 SET a=x'445566' WHERE b=2; + PRAGMA quick_check('t1'); +} {{non-INT value in t1.a}} +do_execsql_test strict2-1.6 { + UPDATE t2 SET a=2.5 WHERE b=2; + PRAGMA quick_check('t1nn'); +} {{non-INT value in t1nn.a}} +do_execsql_test strict2-1.7 { + UPDATE t2 SET a='xyz' WHERE b=2; + PRAGMA quick_check('t1nn'); +} {{non-INT value in t1nn.a}} +do_execsql_test strict2-1.8 { + UPDATE t2 SET a=x'445566' WHERE b=2; + PRAGMA quick_check('t1nn'); +} {{non-INT value in t1nn.a}} + +do_execsql_test strict2-1.13 { + UPDATE t2 SET a=2 WHERE b=2; + UPDATE t2 SET b=2.5 WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-INTEGER value in t1.b}} +do_execsql_test strict2-1.14 { + UPDATE t2 SET b='two' WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-INTEGER value in t1.b}} +do_execsql_test strict2-1.15 { + UPDATE t2 SET b=x'b0b1b2b3b4' WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-INTEGER value in t1.b}} +do_execsql_test strict2-1.16 { + UPDATE t2 SET b=NULL WHERE a=2; + PRAGMA quick_check('t1'); +} {ok} +do_execsql_test strict2-1.17 { + UPDATE t2 SET b=2.5 WHERE a=2; + PRAGMA quick_check('t1nn'); +} {{non-INTEGER value in t1nn.b}} +do_execsql_test strict2-1.18 { + UPDATE t2 SET b=NULL WHERE a=2; + PRAGMA quick_check('t1nn'); +} {{NULL value in t1nn.b}} + +do_execsql_test strict2-1.23 { + UPDATE t2 SET b=2 WHERE a=2; + UPDATE t2 SET c=9 WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-TEXT value in t1.c}} +do_execsql_test strict2-1.24 { + UPDATE t2 SET c=9.5 WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-TEXT value in t1.c}} +do_execsql_test strict2-1.25 { + UPDATE t2 SET c=x'b0b1b2b3b4' WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-TEXT value in t1.c}} + +do_execsql_test strict2-1.33 { + UPDATE t2 SET c='two' WHERE a=2; + UPDATE t2 SET d=9 WHERE a=2; + PRAGMA quick_check('t1'); +} {ok} +do_execsql_test strict2-1.34 { + UPDATE t2 SET d='nine' WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-REAL value in t1.d}} +do_execsql_test strict2-1.35 { + UPDATE t2 SET d=x'b0b1b2b3b4' WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-REAL value in t1.d}} + +do_execsql_test strict2-1.43 { + UPDATE t2 SET d=2.5 WHERE a=2; + UPDATE t2 SET e=9 WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-BLOB value in t1.e}} +do_execsql_test strict2-1.44 { + UPDATE t2 SET e=9.5 WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-BLOB value in t1.e}} +do_execsql_test strict2-1.45 { + UPDATE t2 SET e='hello' WHERE a=2; + PRAGMA quick_check('t1'); +} {{non-BLOB value in t1.e}} + +do_execsql_test strict2-2.0 { + DROP TABLE IF EXISTS t2; + CREATE TABLE t2(a INT, b ANY) STRICT; + INSERT INTO t2(a,b) VALUES(1,2),(3,4.5),(5,'six'),(7,x'8888'),(9,NULL); + PRAGMA integrity_check(t2); +} {ok} + +do_execsql_test strict2-3.0 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(id ANY PRIMARY KEY, x TEXT); + INSERT INTO t1 VALUES(1,2),('three','four'),(x'5555','six'),(NULL,'eight'); + PRAGMA writable_schema=ON; + UPDATE sqlite_schema SET sql=(sql||'STRICT') WHERE name='t1'; + PRAGMA writable_schema=RESET; + PRAGMA integrity_check(t1); +} {{NULL value in t1.id}} + +finish_test diff --git a/test/tabfunc01.test b/test/tabfunc01.test index 797267b3..d3d93792 100644 --- a/test/tabfunc01.test +++ b/test/tabfunc01.test @@ -32,8 +32,14 @@ do_execsql_test tabfunc01-1.1b { PRAGMA table_xinfo(generate_series); } {0 value {} 0 {} 0 0 1 start {} 0 {} 0 1 2 stop {} 0 {} 0 1 3 step {} 0 {} 0 1} do_execsql_test tabfunc01-1.2 { - SELECT *, '|' FROM generate_series LIMIT 5; + SELECT *, '|' FROM generate_series(0) LIMIT 5; } {0 | 1 | 2 | 3 | 4 |} +do_catchsql_test tabfunc01-1.2b { + SELECT *, '|' FROM generate_series LIMIT 5; +} {1 {first argument to "generate_series()" missing or unusable}} +do_catchsql_test tabfunc01-1.2c { + SELECT *, '|' FROM generate_series(value) LIMIT 5; +} {1 {first argument to "generate_series()" missing or unusable}} do_catchsql_test tabfunc01-1.3 { CREATE VIRTUAL TABLE t1 USING generate_series; } {1 {no such module: generate_series}} @@ -104,7 +110,7 @@ do_execsql_test tabfunc01-2.2 { } {2 1 | 2 2 | 3 1 | 3 2 | 3 3 |} do_execsql_test tabfunc01-2.50 { - SELECT * FROM generate_series() LIMIT 5; + SELECT * FROM generate_series(0) LIMIT 5; } {0 1 2 3 4} do_execsql_test tabfunc01-3.1 { diff --git a/test/tclsqlite.test b/test/tclsqlite.test index c111325b..c2fa522e 100644 --- a/test/tclsqlite.test +++ b/test/tclsqlite.test @@ -166,7 +166,7 @@ do_test tcl-2.1 { ifcapable schema_pragmas { do_test tcl-2.2 { execsql "PRAGMA table_info(t\u0123x)" - } "0 a int 0 {} 0 1 b\u1235 float 0 {} 0" + } "0 a INT 0 {} 0 1 b\u1235 float 0 {} 0" } do_test tcl-2.3 { execsql "INSERT INTO t\u0123x VALUES(1,2.3)" @@ -848,4 +848,40 @@ do_catchsql_test 19.911 { } {1 {invalid command name "bind_fallback_does_not_exist"}} db bind_fallback {} +#------------------------------------------------------------------------- +do_test 20.0 { + db transaction { + db close + } +} {} + +do_test 20.1 { + sqlite3 db test.db + set rc [catch { + db eval {SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3} { db close } + } msg] + list $rc $msg +} {1 {invalid command name "db"}} + + +proc closedb {} { + db close + return 10 +} +proc func1 {} { return 1 } + +sqlite3 db test.db +db func closedb closedb +db func func1 func1 + +do_test 20.2 { + set rc [catch { + db eval { + SELECT closedb(),func1() UNION ALL SELECT 20,30 UNION ALL SELECT 30,40 + } + } msg] + list $rc $msg +} {0 {10 1 20 30 30 40}} + finish_test + diff --git a/test/tester.tcl b/test/tester.tcl index 304808b6..bfcc831f 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -89,6 +89,9 @@ # verbose # +# Only run this script once. If sourced a second time, make it a no-op +if {[info exists ::tester_tcl_has_run]} return + # Set the precision of FP arithmatic used by the interpreter. And # configure SQLite to take database file locks on the page that begins # 64KB into the database file instead of the one 1GB in. This means @@ -1200,13 +1203,36 @@ proc speed_trial_summary {name} { } } -# Run this routine last +# Clear out left-over configuration setup from the end of a test # -proc finish_test {} { - catch {db close} +proc finish_test_precleanup {} { catch {db1 close} catch {db2 close} catch {db3 close} + catch {unregister_devsim} + catch {unregister_jt_vfs} + catch {unregister_demovfs} +} + +# Run this routine last +# +proc finish_test {} { + global argv + finish_test_precleanup + if {[llength $argv]>0} { + # If additional test scripts are specified on the command-line, + # run them also, before quitting. + proc finish_test {} { + finish_test_precleanup + return + } + foreach extra $argv { + puts "Running \"$extra\"" + db_delete_and_reopen + uplevel #0 source $extra + } + } + catch {db close} if {0==[info exists ::SLAVE]} { finalize_testing } } proc finalize_testing {} { @@ -1904,21 +1930,23 @@ proc do_ioerr_test {testname args} { set ::sqlite_io_error_hardhit 0 set r [catch $::ioerrorbody msg] set ::errseen $r - set rc [sqlite3_errcode $::DB] - if {$::ioerropts(-erc)} { - # If we are in extended result code mode, make sure all of the - # IOERRs we get back really do have their extended code values. - # If an extended result code is returned, the sqlite3_errcode - # TCLcommand will return a string of the form: SQLITE_IOERR+nnnn - # where nnnn is a number - if {[regexp {^SQLITE_IOERR} $rc] && ![regexp {IOERR\+\d} $rc]} { - return $rc - } - } else { - # If we are not in extended result code mode, make sure no - # extended error codes are returned. - if {[regexp {\+\d} $rc]} { - return $rc + if {[info commands db]!=""} { + set rc [sqlite3_errcode db] + if {$::ioerropts(-erc)} { + # If we are in extended result code mode, make sure all of the + # IOERRs we get back really do have their extended code values. + # If an extended result code is returned, the sqlite3_errcode + # TCLcommand will return a string of the form: SQLITE_IOERR+nnnn + # where nnnn is a number + if {[regexp {^SQLITE_IOERR} $rc] && ![regexp {IOERR\+\d} $rc]} { + return $rc + } + } else { + # If we are not in extended result code mode, make sure no + # extended error codes are returned. + if {[regexp {\+\d} $rc]} { + return $rc + } } } # The test repeats as long as $::go is non-zero. $::go starts out @@ -2495,3 +2523,5 @@ extra_schema_checks 1 source $testdir/thread_common.tcl source $testdir/malloc_common.tcl + +set tester_tcl_has_run 1 diff --git a/test/threadtest3.c b/test/threadtest3.c index 41c0fb9a..3a12c588 100644 --- a/test/threadtest3.c +++ b/test/threadtest3.c @@ -78,15 +78,31 @@ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include + +#ifdef _WIN32 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +# include + +# define O_BINARY 0 +#endif #include "test_multiplex.h" @@ -436,8 +452,13 @@ struct Thread { int iTid; /* Thread number within test */ void* pArg; /* Pointer argument passed by caller */ +#ifdef _WIN32 + uintptr_t winTid; /* Thread handle */ +#else pthread_t tid; /* Thread id */ +#endif char *(*xProc)(int, void*); /* Thread main proc */ + char *zRes; /* Value returned by xProc */ Thread *pNext; /* Next in this list of threads */ }; @@ -471,9 +492,13 @@ static void print_and_free_err(Error *p){ static void system_error(Error *pErr, int iSys){ pErr->rc = iSys; +#if _WIN32 + pErr->zErr = sqlite3_mprintf("%s", strerror(iSys)); +#else pErr->zErr = (char *)sqlite3_malloc(512); strerror_r(iSys, pErr->zErr, 512); pErr->zErr[511] = '\0'; +#endif } static void sqlite_error( @@ -512,7 +537,7 @@ static void clear_error_x( } static int busyhandler(void *pArg, int n){ - usleep(10*1000); + sqlite3_sleep(10); return 1; } @@ -749,10 +774,20 @@ static void integrity_check_x( } } +#ifdef _WIN32 +static unsigned __stdcall launch_thread_main(void *pArg){ + Thread *p = (Thread *)pArg; + p->zRes = p->xProc(p->iTid, p->pArg); + _endthreadex(0); + return 0; /* NOT REACHED */ +} +#else static void *launch_thread_main(void *pArg){ Thread *p = (Thread *)pArg; - return (void *)p->xProc(p->iTid, p->pArg); + p->zRes = p->xProc(p->iTid, p->pArg); + return 0; } +#endif static void launch_thread_x( Error *pErr, /* IN/OUT: Error code */ @@ -771,7 +806,13 @@ static void launch_thread_x( p->pArg = pArg; p->xProc = xProc; +#ifdef _WIN32 + rc = SQLITE_OK; + p->winTid = _beginthreadex(0, 0, launch_thread_main, (void*)p, 0, 0); + if( p->winTid==0 ) rc = errno ? errno : rc; +#else rc = pthread_create(&p->tid, NULL, launch_thread_main, (void *)p); +#endif if( rc!=0 ){ system_error(pErr, rc); sqlite3_free(p); @@ -789,29 +830,47 @@ static void join_all_threads_x( Thread *p; Thread *pNext; for(p=pThreads->pThread; p; p=pNext){ +#ifndef _WIN32 void *ret; - pNext = p->pNext; +#endif int rc; + pNext = p->pNext; + +#ifdef _WIN32 + do { + rc = WaitForSingleObjectEx((HANDLE)p->winTid, INFINITE, TRUE); + }while( rc==WAIT_IO_COMPLETION ); + CloseHandle((HANDLE)p->winTid); +#else rc = pthread_join(p->tid, &ret); +#endif + if( rc!=0 ){ if( pErr->rc==SQLITE_OK ) system_error(pErr, rc); }else{ - printf("Thread %d says: %s\n", p->iTid, (ret==0 ? "..." : (char *)ret)); + printf("Thread %d says: %s\n", p->iTid, (p->zRes==0 ? "..." : p->zRes)); fflush(stdout); } + sqlite3_free(p->zRes); sqlite3_free(p); } pThreads->pThread = 0; } +#ifdef _WIN32 +# define THREADTEST3_STAT _stat +#else +# define THREADTEST3_STAT stat +#endif + static i64 filesize_x( Error *pErr, const char *zFile ){ i64 iRet = 0; if( pErr->rc==SQLITE_OK ){ - struct stat sStat; - if( stat(zFile, &sStat) ){ + struct THREADTEST3_STAT sStat; + if( THREADTEST3_STAT(zFile, &sStat) ){ iRet = -1; }else{ iRet = sStat.st_size; @@ -836,12 +895,12 @@ static void filecopy_x( int fd2; unlink(zTo); - fd1 = open(zFrom, O_RDONLY); + fd1 = open(zFrom, O_RDONLY|O_BINARY); if( fd1<0 ){ system_error(pErr, errno); return; } - fd2 = open(zTo, O_RDWR|O_CREAT|O_EXCL, 0644); + fd2 = open(zTo, O_RDWR|O_CREAT|O_EXCL|O_BINARY, 0644); if( fd2<0 ){ system_error(pErr, errno); close(fd1); @@ -967,7 +1026,7 @@ static char *walthread1_ckpt_thread(int iTid, void *pArg){ opendb(&err, &db, "test.db", 0); while( !timetostop(&err) ){ - usleep(500*1000); + sqlite3_sleep(500); execsql(&err, &db, "PRAGMA wal_checkpoint"); if( err.rc==SQLITE_OK ) nCkpt++; clear_error(&err, SQLITE_BUSY); @@ -1415,7 +1474,7 @@ static void dynamic_triggers(int nMs){ launch_thread(&err, &threads, dynamic_triggers_2, 0); launch_thread(&err, &threads, dynamic_triggers_2, 0); - sleep(2); + sqlite3_sleep(2*1000); sqlite3_enable_shared_cache(0); launch_thread(&err, &threads, dynamic_triggers_2, 0); diff --git a/test/tkt-2d1a5c67d.test b/test/tkt-2d1a5c67d.test index 0d12a6ec..1f797686 100644 --- a/test/tkt-2d1a5c67d.test +++ b/test/tkt-2d1a5c67d.test @@ -19,7 +19,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix tkt-2d1a5c67d -ifcapable {!vtab} {finish_test; return} +ifcapable {!vtab || !incrblob} {finish_test; return} if {[wal_is_capable]==0} {finish_test; return} for {set ii 1} {$ii<=10} {incr ii} { diff --git a/test/tkt-8454a207b9.test b/test/tkt-8454a207b9.test index 88a8614f..20e14205 100644 --- a/test/tkt-8454a207b9.test +++ b/test/tkt-8454a207b9.test @@ -18,6 +18,12 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +# If SQLITE_OMIT_ALTERTABLE is defined, omit this file. +ifcapable !altertable { + finish_test + return +} + do_test tkt-8454a207b9.1 { db eval { CREATE TABLE t1(a); diff --git a/test/tkt-f67b41381a.test b/test/tkt-f67b41381a.test index 1ddec988..43e5cc7d 100644 --- a/test/tkt-f67b41381a.test +++ b/test/tkt-f67b41381a.test @@ -15,6 +15,11 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix tkt-f67b41381a +ifcapable !altertable { + finish_test + return +} + do_execsql_test 1.0 { CREATE TABLE t1(a); INSERT INTO t1 VALUES(1); diff --git a/test/transitive1.test b/test/transitive1.test index 87553384..80c53e8f 100644 --- a/test/transitive1.test +++ b/test/transitive1.test @@ -380,4 +380,50 @@ do_execsql_test transitive1-630 { SELECT ALL * FROM t1,t0 WHERE (likely(t1.c0=t0.c1) AND t1.c0=t0.c0); } {} +#------------------------------------------------------------------------- +# 2021-08-31 forum https://sqlite.org/forum/forumpost/8d1b58f112 +reset_db +do_execsql_test transitive1-700 { + CREATE TABLE t1(a INT PRIMARY KEY); + INSERT INTO t1(a) VALUES(1),(2),(3); + CREATE TABLE t2(x INTEGER PRIMARY KEY,y INT); + INSERT INTO t2(y) VALUES(2),(3); +} + +do_execsql_test transitive1-710 { + SELECT * FROM t1 CROSS JOIN t2 WHERE t2.y=t1.a AND t1.a=t2.x +} {} + +do_execsql_test transitive1-720 { + SELECT * FROM t1 CROSS JOIN t2 WHERE likely(t2.y=t1.a) AND unlikely(t1.a=t2.x) +} {} + +# 2021-10-04 forum https://sqlite.org/forum/forumpost/a65cacbf5e1c41ba +# +reset_db +do_execsql_test transitive1-800 { + CREATE TABLE t1(a INT); + INSERT INTO t1 VALUES(0),(3); + CREATE TABLE t2(b INT UNIQUE, c INT); + INSERT INTO t2 VALUES(1,4) ,(0,5); + SELECT * FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE c=a AND b IS a); + SELECT * FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE a=c AND a IS b); + SELECT * FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE a=c AND b IS a); + SELECT * FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE c=a AND a IS b); +} {} +do_execsql_test transitive1-810 { + CREATE TABLE t3(a INTEGER PRIMARY KEY,b); + INSERT INTO t3(a,b) VALUES(1,2),(5,5),(7,11); + SELECT * FROM t3 WHERE a=b AND a='5'; +} {5 5} +do_execsql_test transitive1-811 { + SELECT * FROM t3 WHERE a=b AND a='4'; +} {} +do_execsql_test transitive1-812 { + SELECT * FROM t3 WHERE a=b AND a='7'; +} {} +do_execsql_test transitive1-813 { + SELECT * FROM t3 WHERE a=b AND a='5x'; +} {} + finish_test diff --git a/test/tt3_checkpoint.c b/test/tt3_checkpoint.c index 060a6982..ec9d0727 100644 --- a/test/tt3_checkpoint.c +++ b/test/tt3_checkpoint.c @@ -75,7 +75,7 @@ static char *checkpoint_starvation_reader(int iTid, void *pArg){ i64 iCount1, iCount2; sql_script(&err, &db, "BEGIN"); iCount1 = execsql_i64(&err, &db, "SELECT count(x) FROM t1"); - usleep(CHECKPOINT_STARVATION_READMS*1000); + sqlite3_sleep(CHECKPOINT_STARVATION_READMS); iCount2 = execsql_i64(&err, &db, "SELECT count(x) FROM t1"); sql_script(&err, &db, "COMMIT"); @@ -107,7 +107,7 @@ static void checkpoint_starvation_main(int nMs, CheckpointStarvationCtx *p){ for(i=0; i<4; i++){ launch_thread(&err, &threads, checkpoint_starvation_reader, 0); - usleep(CHECKPOINT_STARVATION_READMS*1000/4); + sqlite3_sleep(CHECKPOINT_STARVATION_READMS/4); } sqlite3_wal_hook(db.db, checkpoint_starvation_walhook, (void *)p); diff --git a/test/tt3_vacuum.c b/test/tt3_vacuum.c index 023fdfd7..c41a6b48 100644 --- a/test/tt3_vacuum.c +++ b/test/tt3_vacuum.c @@ -23,9 +23,9 @@ static char *vacuum1_thread_writer(int iTid, void *pArg){ Error err = {0}; /* Error code and message */ Sqlite db = {0}; /* SQLite database connection */ - opendb(&err, &db, "test.db", 0); i64 i = 0; + opendb(&err, &db, "test.db", 0); while( !timetostop(&err) ){ i++; diff --git a/test/update.test b/test/update.test index dd96124b..7be36072 100644 --- a/test/update.test +++ b/test/update.test @@ -619,16 +619,18 @@ do_test update-14.4 { # Ticket [https://www.sqlite.org/src/tktview/43107840f1c02] on 2014-10-29 # An assertion fault on UPDATE # -do_execsql_test update-15.1 { - CREATE TABLE t15(a INTEGER PRIMARY KEY, b); - INSERT INTO t15(a,b) VALUES(10,'abc'),(20,'def'),(30,'ghi'); - ALTER TABLE t15 ADD COLUMN c; - CREATE INDEX t15c ON t15(c); - INSERT INTO t15(a,b) - VALUES(5,'zyx'),(15,'wvu'),(25,'tsr'),(35,'qpo'); - UPDATE t15 SET c=printf("y%d",a) WHERE c IS NULL; - SELECT a,b,c,'|' FROM t15 ORDER BY a; -} {5 zyx y5 | 10 abc y10 | 15 wvu y15 | 20 def y20 | 25 tsr y25 | 30 ghi y30 | 35 qpo y35 |} +ifcapable altertable { + do_execsql_test update-15.1 { + CREATE TABLE t15(a INTEGER PRIMARY KEY, b); + INSERT INTO t15(a,b) VALUES(10,'abc'),(20,'def'),(30,'ghi'); + ALTER TABLE t15 ADD COLUMN c; + CREATE INDEX t15c ON t15(c); + INSERT INTO t15(a,b) + VALUES(5,'zyx'),(15,'wvu'),(25,'tsr'),(35,'qpo'); + UPDATE t15 SET c=printf("y%d",a) WHERE c IS NULL; + SELECT a,b,c,'|' FROM t15 ORDER BY a; + } {5 zyx y5 | 10 abc y10 | 15 wvu y15 | 20 def y20 | 25 tsr y25 | 30 ghi y30 | 35 qpo y35 |} +} # Unreleased bug in UPDATE caused by the UPSERT changes. # Found by OSSFuzz as soon as the UPSERT changes landed on trunk. diff --git a/test/upfrom2.test b/test/upfrom2.test index 81c847a6..a1f00953 100644 --- a/test/upfrom2.test +++ b/test/upfrom2.test @@ -365,5 +365,21 @@ foreach {tn update nm} { "1 {target object/alias may not appear in FROM clause: $nm}" } +#-------------------------------------------------------------------------- +reset_db +do_execsql_test 6.0 { + CREATE TABLE t1(a); +} + +do_execsql_test 6.1 { + UPDATE t1 SET a = 1 FROM ( + SELECT * FROM t1 + ) +} {} +do_execsql_test 6.2 { + UPDATE t1 SET a = 1 FROM ( + SELECT * FROM t1 UNION ALL SELECT * FROM t1 + ) +} {} finish_test diff --git a/test/upsert1.test b/test/upsert1.test index 5250a5d2..a321d617 100644 --- a/test/upsert1.test +++ b/test/upsert1.test @@ -241,4 +241,18 @@ do_catchsql_test upsert1-1000 { ON CONFLICT(c2) DO UPDATE SET c1 = c0; } {1 {NOT NULL constraint failed: t0.c0}} +# 2021-12-29 forum post https://sqlite.org/forum/forumpost/06b16b8b29f8c8c3 +# By Jingzhou Fu. When there is both an INTEGER PRIMARY KEY ON CONFLICT REPLACE +# and an upsert on a constraint other than the INTEGER PRIMARY KEY, the +# constraint checking logic generates invalid bytecode which might result +# in a NULL pointer dereference. +# +reset_db +do_execsql_test upsert1-1100 { + CREATE TABLE t1(a INTEGER PRIMARY KEY ON CONFLICT REPLACE, b UNIQUE); + INSERT INTO t1(b) VALUES(22); + INSERT INTO t1 VALUES(2,22) ON CONFLICT (b) DO NOTHING; + SELECT * FROM t1; +} {1 22} + finish_test diff --git a/test/vacuum-into.test b/test/vacuum-into.test index cd1c57a2..a46d95cf 100644 --- a/test/vacuum-into.test +++ b/test/vacuum-into.test @@ -100,4 +100,37 @@ do_test vacuum-into-510 { db2 close db close +# Change the page-size on a VACUUM INTO even if the original +# database is in WAL mode. +# +if {[wal_is_capable]} { + forcedelete test.db + forcedelete test.db2 + do_test vacuum-into-600 { + sqlite3 db test.db + db eval { + PRAGMA page_size=4096; + PRAGMA journal_mode=WAL; + CREATE TABLE t1(a); + INSERT INTO t1 VALUES(19); + CREATE INDEX t1a ON t1(a); + PRAGMA integrity_check; + } + } {wal ok} + do_execsql_test vacuum-into-610 { + PRAGMA page_size; + } {4096} + do_execsql_test vacuum-into-620 { + PRAGMA page_size=1024; + VACUUM INTO 'test.db2'; + } {} + do_test vacuum-into-630 { + sqlite3 db test.db2 + db eval { + PRAGMA page_size; + PRAGMA integrity_check; + } + } {1024 ok} +} + finish_test diff --git a/test/vacuum3.test b/test/vacuum3.test index 484a7d44..e6a1c2b9 100644 --- a/test/vacuum3.test +++ b/test/vacuum3.test @@ -81,7 +81,17 @@ do_test vacuum3-2.1 { execsql { PRAGMA page_size = 1024; VACUUM; - ALTER TABLE t1 ADD COLUMN d; + } + ifcapable altertable { + execsql { ALTER TABLE t1 ADD COLUMN d; } + } else { + execsql { + DROP TABLE t1; + CREATE TABLE t1(a, b, c, d); + INSERT INTO t1 VALUES(1, 2, 3, NULL); + } + } + execsql { UPDATE t1 SET d = randomblob(1000); } file size test.db diff --git a/test/view.test b/test/view.test index b30d4162..85202d7d 100644 --- a/test/view.test +++ b/test/view.test @@ -55,6 +55,11 @@ do_test view-1.1.110 { SELECT * FROM v1temp ORDER BY a; } } {0 {1 2 4 5 7 8 1 2 4 5 7 8}} +ifcapable vtab { + do_execsql_test view-1.1.120 { + SELECT name, type FROM pragma_table_list('v1'); + } {v1 view} +} do_test view-1.2 { catchsql { ROLLBACK; diff --git a/test/vtab1.test b/test/vtab1.test index 3d2e2333..4b8fb9c7 100644 --- a/test/vtab1.test +++ b/test/vtab1.test @@ -1558,4 +1558,36 @@ ifcapable fts3 { } } +# 2021-07-04 https://sqlite.org/forum/forumpost/16ca0e9f32 +# Yu Liang crash involving UPDATE on a virtual table with +# a duplicate column in a vector changeset and invoking the +# query flattener for UNION ALL. +# +reset_db +register_echo_module db +do_catchsql_test 25.0 { + CREATE TABLE t0(a); + CREATE VIRTUAL TABLE t1 USING echo(t0); + WITH t3(a) AS (SELECT * FROM t1 UNION ALL SELECT * FROM t1) + UPDATE t1 SET (a,a) = (SELECT 1, 0) FROM t3; +} {0 {}} + +#-------------------------------------------------------------------------- +# +reset_db +load_static_extension db wholenumber +do_execsql_test 26.1 { + CREATE VIRTUAL TABLE t1 USING wholenumber; + CREATE TABLE tx(a, b, c); +} +do_test 26.2 { + sqlite3 db2 test.db + db2 eval { CREATE TABLE ty(x, y) } + db2 close +} {} +do_execsql_test 26.3 { + SELECT value FROM t1 WHERE value<5 +} {1 2 3 4} + + finish_test diff --git a/test/vtabA.test b/test/vtabA.test index eddaa70d..4c9beae0 100644 --- a/test/vtabA.test +++ b/test/vtabA.test @@ -128,7 +128,7 @@ proc analyse_parse {columns decltype_list} { do_test vtabA-2.1 { analyse_parse {(a text, b integer hidden, c hidden)} {a b c} -} {a text integer {}} +} {a TEXT integer {}} do_test vtabA-2.2 { analyse_parse {(a hidden , b integerhidden, c hidden1)} {a b c} diff --git a/test/vtabK.test b/test/vtabK.test new file mode 100644 index 00000000..07fe9c13 --- /dev/null +++ b/test/vtabK.test @@ -0,0 +1,83 @@ +# 2020-09-24 +# +# 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 a strange scenario discovered by +# dbsqlfuzz (0ad6d441f9bf3dfc32626a9900bc1700495b16f9) in which a +# virtual table is named "sqlite_stat1". +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix vtabK + +ifcapable !vtab||!rtree||!fts5 { + finish_test + return +} + +do_execsql_test 100 { + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(123); + PRAGMA writable_schema=ON; + CREATE VIRTUAL TABLE sqlite_stat1 USING fts5(a); + PRAGMA writable_schema=OFF; + CREATE VIRTUAL TABLE t3 USING fts5(b); + INSERT INTO t3 VALUES('this is a test'); +} +do_catchsql_test 110 { + CREATE VIRTUAL TABLE t2 USING rtree(id,x,y); +} {1 {no such column: stat}} +do_execsql_test 120 { + SELECT * FROM t1; +} {123} +do_execsql_test 130 { + INSERT INTO t3(b) VALUES('Four score and seven years ago'); + SELECT * FROM t3 WHERE t3 MATCH 'this'; +} {{this is a test}} +do_execsql_test 140 { + SELECT * FROM t3 WHERE t3 MATCH 'four seven'; +} {{Four score and seven years ago}} +do_execsql_test 150 { + INSERT INTO sqlite_stat1(a) + VALUES('We hold these truths to be self-evident...'); + SELECT * FROM sqlite_stat1; +} {{We hold these truths to be self-evident...}} +do_catchsql_test 160 { + ANALYZE; +} {1 {database disk image is malformed}} +do_execsql_test 170 { + PRAGMA integrity_check; +} {ok} + +# Follow-on dbsqlfuzz bc02a0cde82dee801a8d6f653d2831680f87dca1 +reset_db +do_execsql_test 200 { + CREATE TABLE t1(a); + INSERT INTO t1 VALUES('Ebed-malech'); + CREATE TABLE x(a); + PRAGMA writable_schema=ON; + CREATE VIRTUAL TABLE sqlite_stat1 USING fts5(a); +} {} +do_catchsql_test 210 { + CREATE VIRTUAL TABLE t2 USING rtree(id,x,y); +} {1 {no such column: stat}} +do_execsql_test 220 { + SELECT * FROM t1; +} {Ebed-malech} + +# Follow-on dbsqlfuzz a097eaad43c3c845b236126df92fb49b25449b0c +reset_db +do_catchsql_test 300 { + CREATE VIRTUAL TABLE t1 USING rtree(a,b,c); + CREATE TABLE t2(x); + ALTER TABLE t2 ADD d GENERATED ALWAYS AS (c IN (SELECT 1 FROM t1)) VIRTUAL; +} {1 {error in table t2 after add column: subqueries prohibited in generated columns}} + +finish_test diff --git a/test/where.test b/test/where.test index 298248a6..8ee57b8b 100644 --- a/test/where.test +++ b/test/where.test @@ -1571,4 +1571,27 @@ do_execsql_test where-26.8 { SELECT '-1'>=0 AND '-1'<=t1.c0 FROM t1; } {1} +# 2021-07-19 https://sqlite.org/forum/forumpost/2bdb86a068 +# Lose of precision when doing comparisons between integer and +# floating point values that are near 9223372036854775807 in the +# OP_SeekGE opcode (and similar). +# +# Valgrind documentation acknowledges that under valgrind, FP calculations +# may not be as accurate as on x86/amd64 hardware. This seems to be causing +# these tests to fail. +# +# https://valgrind.org/docs/manual/manual-core.html#manual-core.limits +# +if {[permutation]!="valgrind"} { + reset_db + do_execsql_test where-27.1 { + CREATE TABLE t1(a INTEGER PRIMARY KEY); + INSERT INTO t1(a) VALUES(9223372036854775807); + SELECT 1 FROM t1 WHERE a>=(9223372036854775807+1); + } {} + do_execsql_test where-27.2 { + SELECT a>=9223372036854775807+1 FROM t1; + } {0} +} + finish_test diff --git a/test/whereE.test b/test/whereE.test index 31086b24..cd9f81d5 100644 --- a/test/whereE.test +++ b/test/whereE.test @@ -18,6 +18,12 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix whereE +# If SQLITE_OMIT_ALTERTABLE is defined, omit this file. +ifcapable !altertable { + finish_test + return +} + do_execsql_test 1.1 { CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1,10), (2,20), (3,30), (2,22), (3, 33); diff --git a/test/window1.test b/test/window1.test index 886bf468..84331d11 100644 --- a/test/window1.test +++ b/test/window1.test @@ -1267,13 +1267,15 @@ do_catchsql_test 31.3 { } {1 {frame ending offset must be a non-negative integer}} # 2019-11-16 chromium issue 1025467 -db close -sqlite3 db :memory: -do_catchsql_test 32.10 { - CREATE VIEW a AS SELECT NULL INTERSECT SELECT NULL ORDER BY s() OVER R; - CREATE TABLE a0 AS SELECT 0; - ALTER TABLE a0 RENAME TO S; -} {1 {error in view a: 1st ORDER BY term does not match any column in the result set}} +ifcapable altertable { + db close + sqlite3 db :memory: + do_catchsql_test 32.10 { + CREATE VIEW a AS SELECT NULL INTERSECT SELECT NULL ORDER BY s() OVER R; + CREATE TABLE a0 AS SELECT 0; + ALTER TABLE a0 RENAME TO S; + } {1 {error in view a: 1st ORDER BY term does not match any column in the result set}} +} reset_db do_execsql_test 33.1 { @@ -2175,5 +2177,31 @@ do_catchsql_test 69.2 { SELECT * FROM t1 WHERE b <= (SELECT b FROM t1 ORDER BY lead(b) OVER () AND sum(a)); } {1 {misuse of aggregate: sum()}} +# 2021-06-23 +# Forum https://sqlite.org/forum/forumpost/31e0432608 +# +reset_db +do_execsql_test 70.0 { + CREATE TABLE t1(a); +} +do_execsql_test 70.1 { + SELECT substr(a,4,lag(a,7) OVER(PARTITION BY 'cf23' ORDER BY 2)) AS ca0 FROM t1 ORDER BY ca0; +} +do_execsql_test 70.2 { + SELECT substr(a,4,lag(a,7) OVER(PARTITION BY 'cf23' ORDER BY likely(2))) AS ca0 FROM t1 ORDER BY ca0; +} + +# 2021-11-07 +# Bug report from Wang Ke +# https://sqlite.org/forum/forumpost/9ba4f60ff8 +reset_db +do_catchsql_test 71.0 { + CREATE TABLE t0(a); + SELECT a FROM t0, (SELECT a AS b FROM t0) + WHERE (a,1)=(SELECT 2,2 UNION SELECT sum(b),max(b) OVER(ORDER BY b) ORDER BY 2) + AND b=4 + ORDER BY b; +} {/1 {.*}/} + finish_test diff --git a/test/windowB.test b/test/windowB.test index 30380aee..52221c44 100644 --- a/test/windowB.test +++ b/test/windowB.test @@ -9,6 +9,7 @@ # #*********************************************************************** # Test cases for RANGE BETWEEN and especially with NULLS LAST +# and for varying separator handling by group_concat(). # set testdir [file dirname $argv0] @@ -356,5 +357,12 @@ do_execsql_test 8.1 { FROM t1; } {111 660 938 979} +do_execsql_test 9.0 { + CREATE TABLE seps(x); + INSERT INTO seps(x) VALUES ('1'), ('22'), ('333'), ('4444'); + SELECT group_concat('-', x) + OVER ( ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING ) + FROM seps; +} {-22- -22-333- -333-4444- -4444-} finish_test diff --git a/test/windowC.test b/test/windowC.test new file mode 100644 index 00000000..013876f9 --- /dev/null +++ b/test/windowC.test @@ -0,0 +1,85 @@ +# 2021-09-29 +# +# 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 varying separator handling by group_concat(). +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix windowC + +ifcapable !windowfunc { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE TABLE x1(i INTEGER PRIMARY KEY, x); +} + +foreach {tn bBlob seps} { + 1 0 {a b c def g} + 2 0 {abcdefg {} {} abcdefg} + 3 0 {a bc def ghij klmno pqrstu} + 4 1 {a bc def ghij klmno pqrstu} + 5 1 {, , , , , , , , , , , , ....... , ,} +} { + foreach type {text blob} { + do_test 1.$type.$tn.1 { + execsql { DELETE FROM x1 } + foreach s $seps { + if {$type=="text"} { + execsql {INSERT INTO x1 VALUES(NULL, $s)} + } else { + execsql {INSERT INTO x1 VALUES(NULL, CAST ($s AS blob))} + } + } + } {} + + foreach {tn2 win} { + 1 "ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING" + 2 "ROWS BETWEEN 2 PRECEDING AND CURRENT ROW" + 3 "ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING" + } { + do_test 1.$type.$tn.2.$tn2 { + db eval " + SELECT group_concat('val', x) OVER ( ORDER BY i $win ) AS val FROM x1 + " { + if {[string range $val 0 2]!="val" + || [string range $val end-2 end]!="val" + } { + error "unexpected return value: $val" + } + } + } {} + } + } +} + +# 2021-10-12 dbsqlfuzz 6c31db077a14149a7b22a1069294bdb068be8a96 +# +reset_db +do_execsql_test 2.0 { + PRAGMA encoding=UTF16le; + WITH separator(x) AS (VALUES(',a,'),(',bc,')), + value(y) AS (VALUES(1),(x'5585d09013455178cd11ce4a')) + SELECT group_concat(y,x) OVER (ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) + FROM separator, value; +} {{} 1 蕕郐䔓硑ᇍ䫎 1} +reset_db +do_execsql_test 2.1 { + PRAGMA encoding=UTF16be; + WITH separator(x) AS (VALUES(',a,'),(',bc,')), + value(y) AS (VALUES(1),(x'5585d09013455178cd11ce4a')) + SELECT group_concat(y,x) OVER (ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) + FROM separator, value; +} {{} 1 喅킐ፅ典촑칊 1} + +finish_test diff --git a/test/windowfault.test b/test/windowfault.test index b5d74331..5340ce08 100644 --- a/test/windowfault.test +++ b/test/windowfault.test @@ -292,4 +292,43 @@ do_faultsim_test 12 -faults oom* -prep { faultsim_test_result {0 {}} } +#------------------------------------------------------------------------- +reset_db +do_execsql_test 13.0 { + CREATE TABLE t1(id INTEGER PRIMARY KEY, a, b); + INSERT INTO t1 VALUES(1, '1', 'a'); + INSERT INTO t1 VALUES(2, '22', 'b'); + INSERT INTO t1 VALUES(3, '333', 'c'); + INSERT INTO t1 VALUES(4, '4444', 'dddd'); + INSERT INTO t1 VALUES(5, '55555', 'e'); + INSERT INTO t1 VALUES(6, '666666', 'f'); + INSERT INTO t1 VALUES(7, '7777777', 'gggggggggg'); +} {} + +set queryres [list {*}{ + 1b22 + 1b22c333 + 22c333dddd4444 + 333dddd4444e55555 + 4444e55555f666666 + 55555f666666gggggggggg7777777 + 666666gggggggggg7777777 +}] +do_execsql_test 13.1 { + SELECT group_concat(a, b) OVER ( + ORDER BY id RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING + ) FROM t1 +} $queryres + +do_faultsim_test 13 -faults oom* -prep { +} -body { + execsql { + SELECT group_concat(a, b) OVER ( + ORDER BY id RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING + ) FROM t1 + } +} -test { + faultsim_test_result [list 0 $::queryres] +} + finish_test diff --git a/test/with2.test b/test/with2.test index 02f808ea..660df52b 100644 --- a/test/with2.test +++ b/test/with2.test @@ -552,63 +552,77 @@ do_execsql_test 10.1 { # 2021-05-21 # Forum post https://sqlite.org/forum/forumpost/aa4a7a3980 # +ifcapable altertable { reset_db -do_execsql_test 11.1 { - CREATE TABLE t1(a); - CREATE VIEW v2(c) AS - WITH x AS ( - WITH y AS ( - WITH z AS(SELECT * FROM t1) - SELECT * FROM v2 - ) SELECT a - ) SELECT * from t1; - ALTER TABLE t1 RENAME COLUMN a TO b; - SELECT sql FROM sqlite_schema WHERE name='t1'; -} {{CREATE TABLE t1(b)}} -do_catchsql_test 11.2 { - INSERT INTO t1 VALUES(55); - SELECT * FROM v2; -} {0 55} -do_catchsql_test 11.3 { - DROP VIEW v2; - CREATE VIEW v2(c) AS - WITH x AS ( - WITH y AS ( - WITH z AS(SELECT * FROM t1) - SELECT * FROM v2 - ) SELECT a - ) SELECT * from t1, x; - SELECT * FROM v2; -} {1 {no such column: a}} -do_catchsql_test 11.4 { - DROP VIEW v2; - CREATE VIEW v2(c) AS - WITH x AS ( - WITH y AS ( - WITH z AS(SELECT * FROM t1) - SELECT * FROM v2 - ) SELECT * - ) SELECT * from t1, x; - SELECT * FROM v2; -} {1 {no tables specified}} -do_catchsql_test 11.5 { - WITH x AS ( - WITH y AS ( - WITH z AS(SELECT * FROM t1) - SELECT * FROM no_such_table - ) SELECT a - ) SELECT * from t1; -} {0 55} + do_execsql_test 11.1 { + CREATE TABLE t1(a); + CREATE VIEW v2(c) AS + WITH x AS ( + WITH y AS ( + WITH z AS(SELECT * FROM t1) + SELECT * FROM v2 + ) SELECT a + ) SELECT * from t1; + ALTER TABLE t1 RENAME COLUMN a TO b; + SELECT sql FROM sqlite_schema WHERE name='t1'; + } {{CREATE TABLE t1(b)}} + do_catchsql_test 11.2 { + INSERT INTO t1 VALUES(55); + SELECT * FROM v2; + } {0 55} + do_catchsql_test 11.3 { + DROP VIEW v2; + CREATE VIEW v2(c) AS + WITH x AS ( + WITH y AS ( + WITH z AS(SELECT * FROM t1) + SELECT * FROM v2 + ) SELECT a + ) SELECT * from t1, x; + SELECT * FROM v2; + } {1 {no such column: a}} + do_catchsql_test 11.4 { + DROP VIEW v2; + CREATE VIEW v2(c) AS + WITH x AS ( + WITH y AS ( + WITH z AS(SELECT * FROM t1) + SELECT * FROM v2 + ) SELECT * + ) SELECT * from t1, x; + SELECT * FROM v2; + } {1 {no tables specified}} + do_catchsql_test 11.5 { + WITH x AS ( + WITH y AS ( + WITH z AS(SELECT * FROM t1) + SELECT * FROM no_such_table + ) SELECT a + ) SELECT * from t1; + } {0 55} +} # 2021-05-23 dbsqlfuzz 6b7a144674e215f06ddfeb9042c873d9ee956ac0 */ reset_db -do_execsql_test 12.1 { - CREATE TABLE t1(a); - INSERT INTO t1 VALUES(1),('hello'),(4.25),(NULL),(x'3c626c6f623e'); - CREATE VIEW v2(c) AS WITH x AS (WITH y AS (WITH z AS(SELECT * FROM t1) SELECT * FROM v2) SELECT a) SELECT * from t1; - CREATE VIEW v3(c) AS WITH x AS (WITH y AS (WITH z AS(SELECT * FROM v2) SELECT * FROM v3) SELECT a) SELECT * from t1; - ALTER TABLE t1 RENAME TO t1x; - SELECT quote(c) FROM v3; -} {1 'hello' 4.25 NULL X'3C626C6F623E'} +ifcapable altertable { + do_execsql_test 12.1 { + CREATE TABLE t1(a); + INSERT INTO t1 VALUES(1),('hello'),(4.25),(NULL),(x'3c626c6f623e'); + CREATE VIEW v2(c) AS WITH x AS (WITH y AS (WITH z AS(SELECT * FROM t1) SELECT * FROM v2) SELECT a) SELECT * from t1; + CREATE VIEW v3(c) AS WITH x AS (WITH y AS (WITH z AS(SELECT * FROM v2) SELECT * FROM v3) SELECT a) SELECT * from t1; + ALTER TABLE t1 RENAME TO t1x; + SELECT quote(c) FROM v3; + } {1 'hello' 4.25 NULL X'3C626C6F623E'} +} + +# 2021-08-11 https://sqlite.org/forum/forumpost/d496c3d29bc93736 +reset_db +do_execsql_test 13.1 { + WITH + t1(x) AS (SELECT 111), + t2(y) AS (SELECT 222), + t3(z) AS (SELECT * FROM t2 WHERE false UNION ALL SELECT * FROM t2) + SELECT * FROM t1, t3; +} {111 222} finish_test diff --git a/test/without_rowid1.test b/test/without_rowid1.test index e4e69eb7..11911155 100644 --- a/test/without_rowid1.test +++ b/test/without_rowid1.test @@ -38,6 +38,9 @@ integrity_check without_rowid1-1.0ic do_execsql_test_if_vtab without_rowid1-1.0ixi { SELECT name, key FROM pragma_index_xinfo('t1'); } {c 1 a 1 b 0 d 0} +do_execsql_test_if_vtab without_rowid1-1.0tl { + SELECT wr FROM pragma_table_list('t1'); +} {1} do_execsql_test without_rowid1-1.1 { SELECT *, '|' FROM t1 ORDER BY +c, a; @@ -455,15 +458,32 @@ do_execsql_test 13.10 { # 2021-05-13 https://sqlite.org/forum/forumpost/6c8960f545 reset_db -do_execsql_test 14.1 { - CREATE TABLE t1(a INT PRIMARY KEY) WITHOUT ROWID; - INSERT INTO t1(a) VALUES(10); - ALTER TABLE t1 ADD COLUMN b INT; - SELECT * FROM t1 WHERE a=20 OR (a=10 AND b=10); -} {} -do_execsql_test 14.2 { - CREATE TABLE dual AS SELECT 'X' AS dummy; - EXPLAIN QUERY PLAN SELECT * FROM dual, t1 WHERE a=10 AND b=10; -} {~/b=/} - +ifcapable altertable { + do_execsql_test 14.1 { + CREATE TABLE t1(a INT PRIMARY KEY) WITHOUT ROWID; + INSERT INTO t1(a) VALUES(10); + ALTER TABLE t1 ADD COLUMN b INT; + SELECT * FROM t1 WHERE a=20 OR (a=10 AND b=10); + } {} + do_execsql_test 14.2 { + CREATE TABLE dual AS SELECT 'X' AS dummy; + EXPLAIN QUERY PLAN SELECT * FROM dual, t1 WHERE a=10 AND b=10; + } {~/b=/} +} + +# 2022-01-01 https://sqlite.org/forum/forumpost/b03d86f951 PoC #1 +# Omit an assert() from 2013 that no longer serves any purpose and +# is no longer always true. +# +reset_db +do_execsql_test 15.1 { + PRAGMA writable_schema=ON; + CREATE TABLE sqlite_sequence (name PRIMARY KEY) WITHOUT ROWID; + PRAGMA writable_schema=OFF; + CREATE TABLE c1(x); + INSERT INTO sqlite_sequence(name) VALUES('c0'),('c1'),('c2'); + ALTER TABLE c1 RENAME TO a; + SELECT name FROM sqlite_sequence ORDER BY +name; +} {a c0 c2} + finish_test diff --git a/test/without_rowid5.test b/test/without_rowid5.test index 31a440ad..d1c49448 100644 --- a/test/without_rowid5.test +++ b/test/without_rowid5.test @@ -15,6 +15,10 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +ifcapable !incrblob { + finish_test + return +} # EVIDENCE-OF: R-36924-43758 By default, every row in SQLite has a # special column, usually called the "rowid", that uniquely identifies @@ -186,6 +190,87 @@ do_execsql_test without_rowid5-5.9 { SELECT count(*) FROM nnw; } {1} +# Ticket f2be158c57aaa8c6 (2021-08-18) +# NOT NULL ON CONFLICT clauses work on WITHOUT ROWID tables now. +# +do_test without_rowid5-5.100 { + db eval { + DROP TABLE IF EXISTS t5; + CREATE TABLE t5( + a INT NOT NULL ON CONFLICT ROLLBACK, + b TEXT, + c TEXT, + PRIMARY KEY(a,b) + ) WITHOUT ROWID; + BEGIN; + INSERT INTO t5(a,b,c) VALUES(1,2,3); + } + catch {db eval {INSERT INTO t5(a,b,c) VALUES(NULL,6,7);}} + db eval { + SELECT * FROM t5; + } +} {} +do_test without_rowid5-5.101 { + db eval { + DROP TABLE IF EXISTS t5; + CREATE TABLE t5( + a INT NOT NULL ON CONFLICT ABORT, + b TEXT, + c TEXT, + PRIMARY KEY(a,b) + ) WITHOUT ROWID; + BEGIN; + INSERT INTO t5(a,b,c) VALUES(1,2,3); + } + catch {db eval {INSERT INTO t5(a,b,c) VALUES(NULL,6,7);}} + db eval { + COMMIT; + SELECT * FROM t5; + } +} {1 2 3} +do_test without_rowid5-5.102 { + db eval { + DROP TABLE IF EXISTS t5; + CREATE TABLE t5( + a INT NOT NULL ON CONFLICT FAIL, + b TEXT, + c TEXT, + PRIMARY KEY(a,b) + ) WITHOUT ROWID; + } + catch {db eval {INSERT INTO t5(a,b,c) VALUES(1,2,3),(NULL,4,5),(6,7,8);}} + db eval { + SELECT * FROM t5; + } +} {1 2 3} +do_test without_rowid5-5.103 { + db eval { + DROP TABLE IF EXISTS t5; + CREATE TABLE t5( + a INT NOT NULL ON CONFLICT IGNORE, + b TEXT, + c TEXT, + PRIMARY KEY(a,b) + ) WITHOUT ROWID; + INSERT INTO t5(a,b,c) VALUES(1,2,3),(NULL,4,5),(6,7,8); + SELECT * FROM t5; + } +} {1 2 3 6 7 8} +do_test without_rowid5-5.104 { + db eval { + DROP TABLE IF EXISTS t5; + CREATE TABLE t5( + a INT NOT NULL ON CONFLICT REPLACE DEFAULT 3, + b TEXT, + c TEXT, + PRIMARY KEY(a,b) + ) WITHOUT ROWID; + INSERT INTO t5(a,b,c) VALUES(1,2,3),(NULL,4,5),(6,7,8); + SELECT * FROM t5; + } +} {1 2 3 3 4 5 6 7 8} + + # EVIDENCE-OF: R-12643-30541 The incremental blob I/O mechanism does not # work for WITHOUT ROWID tables. # diff --git a/test/zeroblob.test b/test/zeroblob.test index 9daa7d8d..df234eea 100644 --- a/test/zeroblob.test +++ b/test/zeroblob.test @@ -19,10 +19,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix zeroblob -ifcapable !incrblob { - finish_test - return -} +# ifcapable !incrblob { finish_test return } test_set_config_pagecache 0 0 @@ -42,12 +39,17 @@ do_test zeroblob-1.1 { execsql { INSERT INTO t1 VALUES(2,3,4,zeroblob(1000000)); } - set ::sqlite3_max_blobsize -} {10} +} {} + +ifcapable incrblob { + do_test zeroblob-1.1.1 { + set ::sqlite3_max_blobsize + } {10} + do_test zeroblob-1.1.2 { + expr {[sqlite3_memory_highwater]<$::memused+35000} + } {1} +} -do_test zeroblob-1.1.1 { - expr {[sqlite3_memory_highwater]<$::memused+35000} -} {1} do_test zeroblob-1.2 { execsql { SELECT length(d) FROM t1 @@ -78,8 +80,12 @@ do_test zeroblob-1.5 { execsql { INSERT INTO t1 VALUES(4,5,zeroblob(10000),zeroblob(10000)); } - set ::sqlite3_max_blobsize -} {11} +} {} +ifcapable incrblob { + do_test zeroblob-1.5.1 { + set ::sqlite3_max_blobsize + } {11} +} do_test zeroblob-1.6 { execsql { SELECT length(c), length(d) FROM t1 @@ -94,8 +100,12 @@ do_test zeroblob-1.7 { execsql { INSERT INTO t1 VALUES(5,zeroblob(10000),NULL,zeroblob(10000)); } - set ::sqlite3_max_blobsize -} {10} +} {} +ifcapable incrblob { + do_test zeroblob-1.7.1 { + set ::sqlite3_max_blobsize + } {10} +} do_test zeroblob-1.8 { execsql { SELECT length(b), length(d) FROM t1 WHERE a=5 @@ -214,12 +224,14 @@ do_test zeroblob-7.2 { do_test zeroblob-7.3 { sqlite3_finalize $::STMT } {SQLITE_OK} -do_test zeroblob-7.4 { - set ::sqlite3_max_blobsize -} {0} -do_test zeroblob-7.5 { - expr {[sqlite3_memory_highwater]<$::memused+10000} -} {1} +ifcapable incrblob { + do_test zeroblob-7.4 { + set ::sqlite3_max_blobsize + } {0} + do_test zeroblob-7.5 { + expr {[sqlite3_memory_highwater]<$::memused+10000} + } {1} +} # Test that MakeRecord can handle a value with some real content # and a zero-blob tail. diff --git a/test/zeroblobfault.test b/test/zeroblobfault.test new file mode 100644 index 00000000..0ae5beae --- /dev/null +++ b/test/zeroblobfault.test @@ -0,0 +1,28 @@ +# 2021 November 8 +# +# 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 zeroblobfault +set quoted_res [db one { SELECT quote(zeroblob(2000)) }] + +do_faultsim_test 1 -prep { + sqlite3 db test.db +} -body { + execsql { SELECT quote(zeroblob(2000)) } +} -test { + faultsim_test_result [list 0 $::quoted_res] +} + +finish_test diff --git a/tool/lemon.c b/tool/lemon.c index 75fc7aa2..d4e157a1 100644 --- a/tool/lemon.c +++ b/tool/lemon.c @@ -917,8 +917,11 @@ void FindStates(struct lemon *lemp) lemp->errorcnt++; sp = lemp->startRule->lhs; } - }else{ + }else if( lemp->startRule ){ sp = lemp->startRule->lhs; + }else{ + ErrorMsg(lemp->filename,0,"Internal error - no start rule\n"); + exit(1); } /* Make sure the start symbol doesn't occur on the right-hand side of @@ -1083,7 +1086,7 @@ void FindLinks(struct lemon *lemp) ** which the link is attached. */ for(i=0; instate; i++){ stp = lemp->sorted[i]; - for(cfp=stp->cfp; cfp; cfp=cfp->next){ + for(cfp=stp?stp->cfp:0; cfp; cfp=cfp->next){ cfp->stp = stp; } } @@ -1092,7 +1095,7 @@ void FindLinks(struct lemon *lemp) ** links are used in the follow-set computation. */ for(i=0; instate; i++){ stp = lemp->sorted[i]; - for(cfp=stp->cfp; cfp; cfp=cfp->next){ + for(cfp=stp?stp->cfp:0; cfp; cfp=cfp->next){ for(plp=cfp->bplp; plp; plp=plp->next){ other = plp->cfp; Plink_add(&other->fplp,cfp); @@ -1115,6 +1118,7 @@ void FindFollowSets(struct lemon *lemp) int change; for(i=0; instate; i++){ + assert( lemp->sorted[i]!=0 ); for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){ cfp->status = INCOMPLETE; } @@ -1123,6 +1127,7 @@ void FindFollowSets(struct lemon *lemp) do{ progress = 0; for(i=0; instate; i++){ + assert( lemp->sorted[i]!=0 ); for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){ if( cfp->status==COMPLETE ) continue; for(plp=cfp->fplp; plp; plp=plp->next){ @@ -1172,7 +1177,14 @@ void FindActions(struct lemon *lemp) /* Add the accepting token */ if( lemp->start ){ sp = Symbol_find(lemp->start); - if( sp==0 ) sp = lemp->startRule->lhs; + if( sp==0 ){ + if( lemp->startRule==0 ){ + fprintf(stderr, "internal error on source line %d: no start rule\n", + __LINE__); + exit(1); + } + sp = lemp->startRule->lhs; + } }else{ sp = lemp->startRule->lhs; } @@ -1299,21 +1311,7 @@ static struct config **basisend = 0; /* End of list of basis configs */ /* Return a pointer to a new configuration */ PRIVATE struct config *newconfig(void){ - struct config *newcfg; - if( freelist==0 ){ - int i; - int amt = 3; - freelist = (struct config *)calloc( amt, sizeof(struct config) ); - if( freelist==0 ){ - fprintf(stderr,"Unable to allocate memory for a new configuration."); - exit(1); - } - for(i=0; inext; - return newcfg; + return (struct config*)calloc(1, sizeof(struct config)); } /* The configuration "old" is no longer used */ @@ -1932,8 +1930,12 @@ static FILE *errstream; static void errline(int n, int k, FILE *err) { int spcnt, i; - if( g_argv[0] ) fprintf(err,"%s",g_argv[0]); - spcnt = lemonStrlen(g_argv[0]) + 1; + if( g_argv[0] ){ + fprintf(err,"%s",g_argv[0]); + spcnt = lemonStrlen(g_argv[0]) + 1; + }else{ + spcnt = 0; + } for(i=1; isp->index>=lemp->nterminal ){ + if( ap->sp->index>=lemp->nterminal + && (lemp->errsym==0 || ap->sp->index!=lemp->errsym->index) + ){ act = lemp->minReduce + ap->x.rp->iRule; }else{ act = lemp->minShiftReduce + ap->x.rp->iRule; @@ -4090,7 +4094,7 @@ void print_stack_union( int *plineno, /* Pointer to the line number */ int mhflag /* True if generating makeheaders output */ ){ - int lineno = *plineno; /* The line number of the output */ + int lineno; /* The line number of the output */ char **types; /* A hash table of datatypes */ int arraysize; /* Size of the "types" array */ int maxdtlength; /* Maximum length of any ".datatype" field. */ @@ -5337,7 +5341,8 @@ int Strsafe_insert(const char *data) newnp->from = &(array.ht[h]); array.ht[h] = newnp; } - free(x1a->tbl); + /* free(x1a->tbl); // This program was originally for 16-bit machines. + ** Don't worry about freeing memory on modern platforms. */ *x1a = array; } /* Insert the new data */ @@ -5505,7 +5510,9 @@ int Symbol_insert(struct symbol *data, const char *key) newnp->from = &(array.ht[h]); array.ht[h] = newnp; } - free(x2a->tbl); + /* free(x2a->tbl); // This program was originally written for 16-bit + ** machines. Don't worry about freeing this trivial amount of memory + ** on modern platforms. Just leak it. */ *x2a = array; } /* Insert the new data */ @@ -5841,7 +5848,9 @@ int Configtable_insert(struct config *data) newnp->from = &(array.ht[h]); array.ht[h] = newnp; } - free(x4a->tbl); + /* free(x4a->tbl); // This code was originall written for 16-bit machines. + ** on modern machines, don't worry about freeing this trival amount of + ** memory. */ *x4a = array; } /* Insert the new data */ diff --git a/tool/lempar.c b/tool/lempar.c index 35c3768b..8cc57897 100644 --- a/tool/lempar.c +++ b/tool/lempar.c @@ -223,9 +223,9 @@ struct yyParser { }; typedef struct yyParser yyParser; +#include #ifndef NDEBUG #include -#include static FILE *yyTraceFILE = 0; static char *yyTracePrompt = 0; #endif /* NDEBUG */ @@ -882,8 +882,8 @@ void Parse( yyact = yy_find_shift_action((YYCODETYPE)yymajor,yyact); if( yyact >= YY_MIN_REDUCE ){ unsigned int yyruleno = yyact - YY_MIN_REDUCE; /* Reduce by this rule */ - assert( yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ); #ifndef NDEBUG + assert( yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ); if( yyTraceFILE ){ int yysize = yyRuleInfoNRhs[yyruleno]; if( yysize ){ @@ -981,14 +981,13 @@ void Parse( yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion); yymajor = YYNOCODE; }else{ - while( yypParser->yytos >= yypParser->yystack - && (yyact = yy_find_reduce_action( - yypParser->yytos->stateno, - YYERRORSYMBOL)) > YY_MAX_SHIFTREDUCE - ){ + while( yypParser->yytos > yypParser->yystack ){ + yyact = yy_find_reduce_action(yypParser->yytos->stateno, + YYERRORSYMBOL); + if( yyact<=YY_MAX_SHIFTREDUCE ) break; yy_pop_parser_stack(yypParser); } - if( yypParser->yytos < yypParser->yystack || yymajor==0 ){ + if( yypParser->yytos <= yypParser->yystack || yymajor==0 ){ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); yy_parse_failed(yypParser); #ifndef YYNOERRORRECOVERY diff --git a/tool/logest.c b/tool/logest.c index e936e02c..8ed0b19e 100644 --- a/tool/logest.c +++ b/tool/logest.c @@ -75,6 +75,9 @@ static sqlite3_uint64 logEstToInt(LogEst x){ x /= 10; if( n>=5 ) n -= 2; else if( n>=1 ) n -= 1; + if( x>60 ){ + return (((sqlite3_uint64)0xffffffff)<<32)+(sqlite3_uint64)0xffffffff; + } if( x>=3 ) return (n+8)<<(x-3); return (n+8)>>(3-x); } diff --git a/tool/mkctimec.tcl b/tool/mkctimec.tcl index 2f15ac9f..62946094 100644 --- a/tool/mkctimec.tcl +++ b/tool/mkctimec.tcl @@ -120,7 +120,6 @@ set boolean_defnil_options { SQLITE_MUTEX_PTHREADS SQLITE_MUTEX_W32 SQLITE_NEED_ERR_NAME - SQLITE_NOINLINE SQLITE_NO_SYNC SQLITE_OMIT_ALTERTABLE SQLITE_OMIT_ANALYZE @@ -216,6 +215,7 @@ set value2_options { # and is a single scalar. # set value_options { + SQLITE_ATOMIC_INTRINSICS SQLITE_BITMASK_TYPE SQLITE_DEFAULT_CACHE_SIZE SQLITE_DEFAULT_FILE_FORMAT @@ -330,7 +330,7 @@ foreach name_defval $boolean_defnnz_options { foreach b $boolean_defnil_options { set name [trim_name $b] set options($name) [subst { -#if $b +#ifdef $b "$name", #endif }] diff --git a/tool/mkkeywordhash.c b/tool/mkkeywordhash.c index bbb0ccf2..fe25b5ab 100644 --- a/tool/mkkeywordhash.c +++ b/tool/mkkeywordhash.c @@ -52,7 +52,7 @@ struct Keyword { /* ** Define masks used to determine which keywords are allowed */ -#ifdef SQLITE_OMIT_ALTERTABLE +#if defined(SQLITE_OMIT_ALTERTABLE) || defined(SQLITE_OMIT_VIRTUALTABLE) # define ALTER 0 #else # define ALTER 0x00000001 @@ -513,6 +513,7 @@ int main(int argc, char **argv){ bestSize = nKeyword; bestCount = nKeyword*nKeyword; for(i=nKeyword/2; i<=2*nKeyword; i++){ + if( i<=0 ) continue; for(j=0; j