diff --git a/Makefile.in b/Makefile.in index 4d14084e03..e4dcbcd90c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -432,7 +432,7 @@ TESTSRC = \ $(TOP)/ext/fts3/fts3_term.c \ $(TOP)/ext/fts3/fts3_test.c \ $(TOP)/ext/session/test_session.c \ - $(TOP)/ext/rbu/test_rbu.c + $(TOP)/ext/rbu/test_rbu.c # Statically linked extensions # @@ -522,7 +522,8 @@ TESTSRC2 = \ $(TOP)/ext/fts3/fts3_write.c \ $(TOP)/ext/async/sqlite3async.c \ $(TOP)/ext/session/sqlite3session.c \ - $(TOP)/ext/misc/stmt.c + $(TOP)/ext/misc/stmt.c \ + fts5.c # Header files used by all library source files. # @@ -616,12 +617,10 @@ SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB SHELL_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC -SHELL_OPT += -DSQLITE_ENABLE_DESERIALIZE FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1 FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000 FUZZCHECK_OPT += -DSQLITE_PRINTF_PRECISION_LIMIT=1000 -FUZZCHECK_OPT += -DSQLITE_ENABLE_DESERIALIZE FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS4 FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS3_PARENTHESIS #FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS5 @@ -695,7 +694,6 @@ dbfuzz$(TEXE): $(TOP)/test/dbfuzz.c sqlite3.c sqlite3.h DBFUZZ2_OPTS = \ -DSQLITE_THREADSAFE=0 \ -DSQLITE_OMIT_LOAD_EXTENSION \ - -DSQLITE_ENABLE_DESERIALIZE \ -DSQLITE_DEBUG \ -DSQLITE_ENABLE_DBSTAT_VTAB \ -DSQLITE_ENABLE_BYTECODE_VTAB \ @@ -1235,7 +1233,6 @@ TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024 TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_BYTECODE_VTAB -TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DESERIALIZE TESTFIXTURE_FLAGS += -DSQLITE_CKSUMVFS_STATIC TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.la @@ -1431,6 +1428,9 @@ threadtest3$(TEXE): sqlite3.lo $(THREADTEST3_SRC) threadtest: threadtest3$(TEXE) ./threadtest3$(TEXE) +threadtest5: sqlite3.c $(TOP)/test/threadtest5.c + $(LTLINK) $(TOP)/test/threadtest5.c sqlite3.c -o $@ $(TLIBS) + releasetest: $(TCLSH_CMD) $(TOP)/test/releasetest.tcl @@ -1484,6 +1484,7 @@ clean: rm -f sqldiff sqldiff.exe rm -f dbhash dbhash.exe rm -f fts5.* fts5parse.* + rm -f threadtest5 distclean: clean rm -f config.h config.log config.status libtool Makefile sqlite3.pc diff --git a/Makefile.msc b/Makefile.msc index f9d4016a65..ff6618e30b 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -367,7 +367,6 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBSTAT_VTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1 -OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=1 !ENDIF OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1 !ENDIF @@ -1552,7 +1551,7 @@ TESTSRC = \ $(TOP)\ext\fts3\fts3_term.c \ $(TOP)\ext\fts3\fts3_test.c \ $(TOP)\ext\rbu\test_rbu.c \ - $(TOP)\ext\session\test_session.c + $(TOP)\ext\session\test_session.c # Statically linked extensions. # @@ -1586,7 +1585,8 @@ TESTEXT = \ $(TOP)\ext\misc\spellfix.c \ $(TOP)\ext\misc\totype.c \ $(TOP)\ext\misc\unionvtab.c \ - $(TOP)\ext\misc\wholenumber.c + $(TOP)\ext\misc\wholenumber.c \ + fts5.c # If use of zlib is enabled, add the "zipfile.c" source file. # @@ -1689,7 +1689,6 @@ FUZZDATA = \ SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1 -SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DESERIALIZE=1 !ENDIF # <> @@ -1698,7 +1697,6 @@ SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DESERIALIZE=1 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_DESERIALIZE FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_FTS4 FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_RTREE FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_GEOPOLY @@ -2392,7 +2390,6 @@ TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_JSON1=1 -TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_CKSUMVFS_STATIC=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) $(TEST_CCONV_OPTS) diff --git a/README.md b/README.md index c12b77c1b9..fb72ae8c28 100644 --- a/README.md +++ b/README.md @@ -55,11 +55,11 @@ a stand-alone program. To install, simply download or build the single executable file and put that file someplace on your $PATH.) Then run commands like this: - mkdir ~/sqlite + mkdir -p ~/sqlite ~/Fossils cd ~/sqlite - fossil clone https://www.sqlite.org/src sqlite.fossil - fossil open sqlite.fossil - + fossil clone https://www.sqlite.org/src ~/Fossils/sqlite.fossil + fossil open ~/Fossils/sqlite.fossil + After setting up a repository using the steps above, you can always update to the lastest version using: diff --git a/VERSION b/VERSION index 9775ea7450..0b477b458f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.35.3 +3.36.0 diff --git a/autoconf/Makefile.msc b/autoconf/Makefile.msc index 1f177557a2..40d0e8113d 100644 --- a/autoconf/Makefile.msc +++ b/autoconf/Makefile.msc @@ -290,7 +290,6 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBSTAT_VTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1 -OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=1 !ENDIF OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1 !ENDIF @@ -960,7 +959,6 @@ LIBRESOBJS = SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1 -SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DESERIALIZE=1 !ENDIF diff --git a/configure b/configure index eb21344ce5..5df1386305 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.35.3. +# Generated by GNU Autoconf 2.69 for sqlite 3.36.0. # # # 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.35.3' -PACKAGE_STRING='sqlite 3.35.3' +PACKAGE_VERSION='3.36.0' +PACKAGE_STRING='sqlite 3.36.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1467,7 +1467,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.35.3 to adapt to many kinds of systems. +\`configure' configures sqlite 3.36.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1532,7 +1532,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of sqlite 3.35.3:";; + short | recursive ) echo "Configuration of sqlite 3.36.0:";; esac cat <<\_ACEOF @@ -1660,7 +1660,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -sqlite configure 3.35.3 +sqlite configure 3.36.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2079,7 +2079,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.35.3, which was +It was created by sqlite $as_me 3.36.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -12378,7 +12378,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.35.3, which was +This file was extended by sqlite $as_me 3.36.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -12444,7 +12444,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.35.3 +sqlite config.status 3.36.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/doc/lemon.html b/doc/lemon.html index 457004627e..324b3f3319 100644 --- a/doc/lemon.html +++ b/doc/lemon.html @@ -697,6 +697,7 @@ other than that, the order of directives in Lemon is arbitrary.

  • %stack_size
  • %start_symbol
  • %syntax_error +
  • %token
  • %token_class
  • %token_destructor
  • %token_prefix @@ -1079,14 +1080,37 @@ can choose a different start symbol using the

    See Error Processing.

    + +

    4.4.20 The %token directive

    + +

    Tokens are normally created automatically, the first time they are used. +Any identifier that begins with an upper-case letter is a token. + +

    Sometimes it is useful to declare tokens in advance, however. The +integer values assigned to each token determined by the order in which +the tokens are seen. So by declaring tokens in advance, it is possible to +cause some tokens to have low-numbered values, which might be desirable in +some grammers, or to have sequential values assigned to a sequence of +related tokens. For this reason, the %token directive is provided to +declare tokens in advance. The syntax is as follows: + +

    +%token TOKEN TOKEN... . +

    + +

    The %token directive is followed by zero or more token symbols and +terminated by a single ".". Each token named is created if it does not +already exist. Tokens are created in order. + + -

    4.4.20 The %token_class directive

    +

    4.4.21 The %token_class directive

    Undocumented. Appears to be related to the MULTITERMINAL concept. Implementation.

    -

    4.4.21 The %token_destructor directive

    +

    4.4.22 The %token_destructor directive

    The %destructor directive assigns a destructor to a non-terminal symbol. (See the description of the @@ -1102,7 +1126,7 @@ Other than that, the token destructor works just like the non-terminal destructors.

    -

    4.4.22 The %token_prefix directive

    +

    4.4.23 The %token_prefix directive

    Lemon generates #defines that assign small integer constants to each terminal symbol in the grammar. If desired, Lemon will @@ -1129,7 +1153,7 @@ to each of the #defines it generates.

    -

    4.4.23 The %token_type and %type directives

    +

    4.4.24 The %token_type and %type directives

    These directives are used to specify the data types for values on the parser's stack associated with terminal and non-terminal @@ -1166,7 +1190,7 @@ entry parser stack will require 100K of heap space. If you are willing and able to pay that price, fine. You just need to know.

    -

    4.4.24 The %wildcard directive

    +

    4.4.25 The %wildcard directive

    The %wildcard directive is followed by a single token name and a period. This directive specifies that the identified token should diff --git a/ext/expert/expert1.test b/ext/expert/expert1.test index 0e6fc82604..3987d0c910 100644 --- a/ext/expert/expert1.test +++ b/ext/expert/expert1.test @@ -103,7 +103,7 @@ do_setup_rec_test $tn.1 { CREATE TABLE t1(a, b, c) } { SELECT * FROM t1 } { (no new indexes) - SCAN TABLE t1 + SCAN t1 } do_setup_rec_test $tn.2 { @@ -112,7 +112,7 @@ do_setup_rec_test $tn.2 { SELECT * FROM t1 WHERE b>?; } { CREATE INDEX t1_idx_00000062 ON t1(b); - SEARCH TABLE t1 USING INDEX t1_idx_00000062 (b>?) + SEARCH t1 USING INDEX t1_idx_00000062 (b>?) } do_setup_rec_test $tn.3 { @@ -121,7 +121,7 @@ do_setup_rec_test $tn.3 { SELECT * FROM t1 WHERE b COLLATE nocase BETWEEN ? AND ? } { CREATE INDEX t1_idx_3e094c27 ON t1(b COLLATE NOCASE); - SEARCH TABLE t1 USING INDEX t1_idx_3e094c27 (b>? AND b? AND b? AND b? AND b? } { (no new indexes) - SEARCH TABLE example USING INDEX sqlite_autoindex_example_1 (A=? AND B>?) + SEARCH example USING INDEX sqlite_autoindex_example_1 (A=? AND B>?) } do_setup_rec_test $tn.17.5 { CREATE TABLE example (A INTEGER, B INTEGER, C INTEGER, PRIMARY KEY (A,B)); @@ -365,7 +365,7 @@ do_setup_rec_test $tn.17.5 { SELECT * FROM example WHERE a>? AND b=? } { CREATE INDEX example_idx_0000cb3f ON example(B, A); - SEARCH TABLE example USING INDEX example_idx_0000cb3f (B=? AND A>?) + SEARCH example USING INDEX example_idx_0000cb3f (B=? AND A>?) } do_setup_rec_test $tn.18.0 { @@ -377,7 +377,7 @@ do_setup_rec_test $tn.18.0 { SELECT x FROM SomeObject; } { (no new indexes) - SCAN TABLE SomeObject + SCAN SomeObject } do_setup_rec_test $tn.18.1 { CREATE TABLE SomeObject ( @@ -388,7 +388,7 @@ do_setup_rec_test $tn.18.1 { SELECT * FROM SomeObject WHERE x=?; } { CREATE INDEX SomeObject_idx_00000078 ON SomeObject(x); - SEARCH TABLE SomeObject USING COVERING INDEX SomeObject_idx_00000078 (x=?) + SEARCH SomeObject USING COVERING INDEX SomeObject_idx_00000078 (x=?) } } @@ -455,4 +455,3 @@ do_execsql_test 5.3 { } finish_test - diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index 50fa88db8a..9c5703d3f1 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -326,7 +326,9 @@ int sqlite3Fts3Never(int b) { assert( !b ); return b; } ** assert() conditions in the fts3 code are activated - conditions that are ** only true if it is guaranteed that the fts3 database is not corrupt. */ +#ifdef SQLITE_DEBUG int sqlite3_fts3_may_be_corrupt = 1; +#endif /* ** Write a 64-bit variable-length integer to memory starting at p[0]. @@ -1897,7 +1899,7 @@ static int fts3ScanInteriorNode( char *zBuffer = 0; /* Buffer to load terms into */ i64 nAlloc = 0; /* Size of allocated buffer */ int isFirstTerm = 1; /* True when processing first term on page */ - sqlite3_int64 iChild; /* Block id of child node to descend to */ + u64 iChild; /* Block id of child node to descend to */ int nBuffer = 0; /* Total term size */ /* Skip over the 'height' varint that occurs at the start of every @@ -1913,8 +1915,8 @@ static int fts3ScanInteriorNode( ** table, then there are always 20 bytes of zeroed padding following the ** nNode bytes of content (see sqlite3Fts3ReadBlock() for details). */ - zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); - zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); + zCsr += sqlite3Fts3GetVarintU(zCsr, &iChild); + zCsr += sqlite3Fts3GetVarintU(zCsr, &iChild); if( zCsr>zEnd ){ return FTS_CORRUPT_VTAB; } @@ -1967,20 +1969,20 @@ static int fts3ScanInteriorNode( */ cmp = memcmp(zTerm, zBuffer, (nBuffer>nTerm ? nTerm : nBuffer)); if( piFirst && (cmp<0 || (cmp==0 && nBuffer>nTerm)) ){ - *piFirst = iChild; + *piFirst = (i64)iChild; piFirst = 0; } if( piLast && cmp<0 ){ - *piLast = iChild; + *piLast = (i64)iChild; piLast = 0; } iChild++; }; - if( piFirst ) *piFirst = iChild; - if( piLast ) *piLast = iChild; + if( piFirst ) *piFirst = (i64)iChild; + if( piLast ) *piLast = (i64)iChild; finish_scan: sqlite3_free(zBuffer); @@ -3586,14 +3588,20 @@ static int fts3SetHasStat(Fts3Table *p){ */ static int fts3BeginMethod(sqlite3_vtab *pVtab){ Fts3Table *p = (Fts3Table*)pVtab; + int rc; UNUSED_PARAMETER(pVtab); assert( p->pSegments==0 ); assert( p->nPendingData==0 ); assert( p->inTransaction!=1 ); - TESTONLY( p->inTransaction = 1 ); - TESTONLY( p->mxSavepoint = -1; ); p->nLeafAdd = 0; - return fts3SetHasStat(p); + rc = fts3SetHasStat(p); +#ifdef SQLITE_DEBUG + if( rc==SQLITE_OK ){ + p->inTransaction = 1; + p->mxSavepoint = -1; + } +#endif + return rc; } /* @@ -5122,16 +5130,15 @@ static int fts3EvalStart(Fts3Cursor *pCsr){ #ifndef SQLITE_DISABLE_FTS4_DEFERRED if( rc==SQLITE_OK && nToken>1 && pTab->bFts4 ){ Fts3TokenAndCost *aTC; - Fts3Expr **apOr; aTC = (Fts3TokenAndCost *)sqlite3_malloc64( sizeof(Fts3TokenAndCost) * nToken + sizeof(Fts3Expr *) * nOr * 2 ); - apOr = (Fts3Expr **)&aTC[nToken]; if( !aTC ){ rc = SQLITE_NOMEM; }else{ + Fts3Expr **apOr = (Fts3Expr **)&aTC[nToken]; int ii; Fts3TokenAndCost *pTC = aTC; Fts3Expr **ppOr = apOr; diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h index b3e0ec85fb..8c2579166d 100644 --- a/ext/fts3/fts3Int.h +++ b/ext/fts3/fts3Int.h @@ -134,7 +134,7 @@ SQLITE_EXTENSION_INIT3 ** is used for assert() conditions that are true only if it can be ** guranteed that the database is not corrupt. */ -#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) +#ifdef SQLITE_DEBUG extern int sqlite3_fts3_may_be_corrupt; # define assert_fts3_nc(x) assert(sqlite3_fts3_may_be_corrupt || (x)) #else diff --git a/ext/fts3/fts3_aux.c b/ext/fts3/fts3_aux.c index 08edc00f40..b6e651853b 100644 --- a/ext/fts3/fts3_aux.c +++ b/ext/fts3/fts3_aux.c @@ -406,6 +406,7 @@ static int fts3auxFilterMethod( sqlite3Fts3SegReaderFinish(&pCsr->csr); sqlite3_free((void *)pCsr->filter.zTerm); sqlite3_free(pCsr->aStat); + sqlite3_free(pCsr->zStop); memset(&pCsr->csr, 0, ((u8*)&pCsr[1]) - (u8*)&pCsr->csr); pCsr->filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY; diff --git a/ext/fts3/fts3_snippet.c b/ext/fts3/fts3_snippet.c index ebc771fd6a..613d3e5f16 100644 --- a/ext/fts3/fts3_snippet.c +++ b/ext/fts3/fts3_snippet.c @@ -17,6 +17,10 @@ #include #include +#ifndef SQLITE_AMALGAMATION +typedef sqlite3_int64 i64; +#endif + /* ** Characters that may appear in the second argument to matchinfo(). */ @@ -67,9 +71,9 @@ struct SnippetIter { struct SnippetPhrase { int nToken; /* Number of tokens in phrase */ char *pList; /* Pointer to start of phrase position list */ - int iHead; /* Next value in position list */ + i64 iHead; /* Next value in position list */ char *pHead; /* Position list data following iHead */ - int iTail; /* Next value in trailing position list */ + i64 iTail; /* Next value in trailing position list */ char *pTail; /* Position list data following iTail */ }; @@ -234,7 +238,7 @@ void sqlite3Fts3MIBufferFree(MatchinfoBuffer *p){ ** After it returns, *piPos contains the value of the next element of the ** list and *pp is advanced to the following varint. */ -static void fts3GetDeltaPosition(char **pp, int *piPos){ +static void fts3GetDeltaPosition(char **pp, i64 *piPos){ int iVal; *pp += fts3GetVarint32(*pp, &iVal); *piPos += (iVal-2); @@ -343,10 +347,10 @@ static int fts3ExprPhraseCount(Fts3Expr *pExpr){ ** arguments so that it points to the first element with a value greater ** than or equal to parameter iNext. */ -static void fts3SnippetAdvance(char **ppIter, int *piIter, int iNext){ +static void fts3SnippetAdvance(char **ppIter, i64 *piIter, int iNext){ char *pIter = *ppIter; if( pIter ){ - int iIter = *piIter; + i64 iIter = *piIter; while( iIteraPhrase[i]; if( pPhrase->pTail ){ char *pCsr = pPhrase->pTail; - int iCsr = pPhrase->iTail; + i64 iCsr = pPhrase->iTail; while( iCsr<(iStart+pIter->nSnippet) && iCsr>=iStart ){ int j; @@ -475,7 +479,7 @@ static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){ rc = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol, &pCsr); assert( rc==SQLITE_OK || pCsr==0 ); if( pCsr ){ - int iFirst = 0; + i64 iFirst = 0; pPhrase->pList = pCsr; fts3GetDeltaPosition(&pCsr, &iFirst); if( iFirst<0 ){ @@ -1539,8 +1543,8 @@ typedef struct TermOffsetCtx TermOffsetCtx; struct TermOffset { char *pList; /* Position-list */ - int iPos; /* Position just read from pList */ - int iOff; /* Offset of this term from read positions */ + i64 iPos; /* Position just read from pList */ + i64 iOff; /* Offset of this term from read positions */ }; struct TermOffsetCtx { @@ -1559,7 +1563,7 @@ static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){ int nTerm; /* Number of tokens in phrase */ int iTerm; /* For looping through nTerm phrase terms */ char *pList; /* Pointer to position list for phrase */ - int iPos = 0; /* First position in position-list */ + i64 iPos = 0; /* First position in position-list */ int rc; UNUSED_PARAMETER(iPhrase); diff --git a/ext/fts3/fts3_test.c b/ext/fts3/fts3_test.c index fa0f00a6ce..49a8476bf3 100644 --- a/ext/fts3/fts3_test.c +++ b/ext/fts3/fts3_test.c @@ -585,6 +585,7 @@ static int SQLITE_TCLAPI fts3_may_be_corrupt( int objc, Tcl_Obj *CONST objv[] ){ +#ifdef SQLITE_DEBUG int bOld = sqlite3_fts3_may_be_corrupt; if( objc!=2 && objc!=1 ){ @@ -598,6 +599,7 @@ static int SQLITE_TCLAPI fts3_may_be_corrupt( } Tcl_SetObjResult(interp, Tcl_NewIntObj(bOld)); +#endif return TCL_OK; } diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c index bc42fc3d63..544e23addd 100644 --- a/ext/fts3/fts3_write.c +++ b/ext/fts3/fts3_write.c @@ -1807,7 +1807,7 @@ static int fts3SegReaderCmp(Fts3SegReader *pLhs, Fts3SegReader *pRhs){ if( rc==0 ){ rc = pRhs->iIdx - pLhs->iIdx; } - assert( rc!=0 ); + assert_fts3_nc( rc!=0 ); return rc; } diff --git a/ext/fts5/fts5_config.c b/ext/fts5/fts5_config.c index 6c02d2b35f..32335c9374 100644 --- a/ext/fts5/fts5_config.c +++ b/ext/fts5/fts5_config.c @@ -537,7 +537,7 @@ int sqlite3Fts5ConfigParse( nByte = nArg * (sizeof(char*) + sizeof(u8)); pRet->azCol = (char**)sqlite3Fts5MallocZero(&rc, nByte); - pRet->abUnindexed = (u8*)&pRet->azCol[nArg]; + pRet->abUnindexed = pRet->azCol ? (u8*)&pRet->azCol[nArg] : 0; pRet->zDb = sqlite3Fts5Strndup(&rc, azArg[1], -1); pRet->zName = sqlite3Fts5Strndup(&rc, azArg[2], -1); pRet->bColumnsize = 1; diff --git a/ext/fts5/fts5_expr.c b/ext/fts5/fts5_expr.c index 088d8b8cae..f3cec00be8 100644 --- a/ext/fts5/fts5_expr.c +++ b/ext/fts5/fts5_expr.c @@ -2412,6 +2412,7 @@ Fts5ExprNode *sqlite3Fts5ParseImplicitAnd( return pRet; } +#ifdef SQLITE_TEST static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){ sqlite3_int64 nByte = 0; Fts5ExprTerm *p; @@ -2778,12 +2779,14 @@ static void fts5ExprFold( sqlite3_result_int(pCtx, sqlite3Fts5UnicodeFold(iCode, bRemoveDiacritics)); } } +#endif /* ifdef SQLITE_TEST */ /* ** This is called during initialization to register the fts5_expr() scalar ** UDF with the SQLite handle passed as the only argument. */ int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){ +#ifdef SQLITE_TEST struct Fts5ExprFunc { const char *z; void (*x)(sqlite3_context*,int,sqlite3_value**); @@ -2801,6 +2804,10 @@ int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){ struct Fts5ExprFunc *p = &aFunc[i]; rc = sqlite3_create_function(db, p->z, -1, SQLITE_UTF8, pCtx, p->x, 0, 0); } +#else + int rc = SQLITE_OK; + UNUSED_PARAM2(pGlobal,db); +#endif /* Avoid warnings indicating that sqlite3Fts5ParserTrace() and ** sqlite3Fts5ParserFallback() are unused */ diff --git a/ext/fts5/fts5_index.c b/ext/fts5/fts5_index.c index 7a9ad5d713..b66e9bece4 100644 --- a/ext/fts5/fts5_index.c +++ b/ext/fts5/fts5_index.c @@ -431,7 +431,7 @@ struct Fts5SegIter { int iLeafPgno; /* Current leaf page number */ Fts5Data *pLeaf; /* Current leaf data */ Fts5Data *pNextLeaf; /* Leaf page (iLeafPgno+1) */ - int iLeafOffset; /* Byte offset within current leaf */ + i64 iLeafOffset; /* Byte offset within current leaf */ /* Next method */ void (*xNext)(Fts5Index*, Fts5SegIter*, int*); @@ -1611,7 +1611,7 @@ static void fts5SegIterLoadNPos(Fts5Index *p, Fts5SegIter *pIter){ static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){ u8 *a = pIter->pLeaf->p; /* Buffer to read data from */ - int iOff = pIter->iLeafOffset; + i64 iOff = pIter->iLeafOffset; ASSERT_SZLEAF_OK(pIter->pLeaf); if( iOff>=pIter->pLeaf->szLeaf ){ @@ -1644,7 +1644,7 @@ static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){ */ static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){ u8 *a = pIter->pLeaf->p; /* Buffer to read data from */ - int iOff = pIter->iLeafOffset; /* Offset to read at */ + i64 iOff = pIter->iLeafOffset; /* Offset to read at */ int nNew; /* Bytes of new data */ iOff += fts5GetVarint32(&a[iOff], nNew); @@ -2072,7 +2072,6 @@ static void fts5SegIterNext( ** this block is particularly performance critical, so equivalent ** code is inlined. */ int nSz; - assert( p->rc==SQLITE_OK ); assert_nc( pIter->iLeafOffset<=pIter->pLeaf->nn ); fts5FastGetVarint32(pIter->pLeaf->p, pIter->iLeafOffset, nSz); pIter->bDel = (nSz & 0x0001); @@ -4541,14 +4540,14 @@ static void fts5FlushOneHash(Fts5Index *p){ fts5BufferSafeAppendBlob(pBuf, pDoclist, nDoclist); }else{ i64 iRowid = 0; - i64 iDelta = 0; + u64 iDelta = 0; int iOff = 0; /* The entire doclist will not fit on this leaf. The following ** loop iterates through the poslists that make up the current ** doclist. */ while( p->rc==SQLITE_OK && iOffiter.nPoslist - pHead->iOff; /* WRITEPOSLISTSIZE */ - assert( tmp.n+nTail<=nTmp ); + assert_nc( tmp.n+nTail<=nTmp ); + assert( tmp.n+nTail<=nTmp+nMerge*10 ); if( tmp.n+nTail>nTmp-FTS5_DATA_ZERO_PADDING ){ if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT; break; @@ -6226,6 +6226,7 @@ int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum){ ** function only. */ +#ifdef SQLITE_TEST /* ** Decode a segment-data rowid from the %_data table. This function is ** the opposite of macro FTS5_SEGMENT_ROWID(). @@ -6248,7 +6249,9 @@ static void fts5DecodeRowid( *piSegid = (int)(iRowid & (((i64)1 << FTS5_DATA_ID_B) - 1)); } +#endif /* SQLITE_TEST */ +#ifdef SQLITE_TEST static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){ int iSegid, iHeight, iPgno, bDlidx; /* Rowid compenents */ fts5DecodeRowid(iKey, &iSegid, &bDlidx, &iHeight, &iPgno); @@ -6266,7 +6269,9 @@ static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){ ); } } +#endif /* SQLITE_TEST */ +#ifdef SQLITE_TEST static void fts5DebugStructure( int *pRc, /* IN/OUT: error code */ Fts5Buffer *pBuf, @@ -6288,7 +6293,9 @@ static void fts5DebugStructure( sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "}"); } } +#endif /* SQLITE_TEST */ +#ifdef SQLITE_TEST /* ** This is part of the fts5_decode() debugging aid. ** @@ -6313,7 +6320,9 @@ static void fts5DecodeStructure( fts5DebugStructure(pRc, pBuf, p); fts5StructureRelease(p); } +#endif /* SQLITE_TEST */ +#ifdef SQLITE_TEST /* ** This is part of the fts5_decode() debugging aid. ** @@ -6336,7 +6345,9 @@ static void fts5DecodeAverages( zSpace = " "; } } +#endif /* SQLITE_TEST */ +#ifdef SQLITE_TEST /* ** Buffer (a/n) is assumed to contain a list of serialized varints. Read ** each varint and append its string representation to buffer pBuf. Return @@ -6353,7 +6364,9 @@ static int fts5DecodePoslist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){ } return iOff; } +#endif /* SQLITE_TEST */ +#ifdef SQLITE_TEST /* ** The start of buffer (a/n) contains the start of a doclist. The doclist ** may or may not finish within the buffer. This function appends a text @@ -6386,7 +6399,9 @@ static int fts5DecodeDoclist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){ return iOff; } +#endif /* SQLITE_TEST */ +#ifdef SQLITE_TEST /* ** This function is part of the fts5_decode() debugging function. It is ** only ever used with detail=none tables. @@ -6427,7 +6442,9 @@ static void fts5DecodeRowidList( sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %lld%s", iRowid, zApp); } } +#endif /* SQLITE_TEST */ +#ifdef SQLITE_TEST /* ** The implementation of user-defined scalar function fts5_decode(). */ @@ -6636,7 +6653,9 @@ static void fts5DecodeFunction( } fts5BufferFree(&s); } +#endif /* SQLITE_TEST */ +#ifdef SQLITE_TEST /* ** The implementation of user-defined scalar function fts5_rowid(). */ @@ -6670,6 +6689,7 @@ static void fts5RowidFunction( } } } +#endif /* SQLITE_TEST */ /* ** This is called as part of registering the FTS5 module with database @@ -6680,6 +6700,7 @@ static void fts5RowidFunction( ** SQLite error code is returned instead. */ int sqlite3Fts5IndexInit(sqlite3 *db){ +#ifdef SQLITE_TEST int rc = sqlite3_create_function( db, "fts5_decode", 2, SQLITE_UTF8, 0, fts5DecodeFunction, 0, 0 ); @@ -6697,6 +6718,10 @@ int sqlite3Fts5IndexInit(sqlite3 *db){ ); } return rc; +#else + return SQLITE_OK; + UNUSED_PARAM(db); +#endif } diff --git a/ext/fts5/fts5_main.c b/ext/fts5/fts5_main.c index 8a7af1894a..2dcdad9f87 100644 --- a/ext/fts5/fts5_main.c +++ b/ext/fts5/fts5_main.c @@ -22,7 +22,9 @@ ** assert() conditions in the fts5 code are activated - conditions that are ** only true if it is guaranteed that the fts5 database is not corrupt. */ +#ifdef SQLITE_DEBUG int sqlite3_fts5_may_be_corrupt = 1; +#endif typedef struct Fts5Auxdata Fts5Auxdata; diff --git a/ext/fts5/fts5_tcl.c b/ext/fts5/fts5_tcl.c index f33dcae033..80c600dbb1 100644 --- a/ext/fts5/fts5_tcl.c +++ b/ext/fts5/fts5_tcl.c @@ -29,7 +29,9 @@ #include #include +#ifdef SQLITE_DEBUG extern int sqlite3_fts5_may_be_corrupt; +#endif extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3*); extern int sqlite3Fts5TestRegisterTok(sqlite3*, fts5_api*); @@ -1011,6 +1013,7 @@ static int SQLITE_TCLAPI f5tMayBeCorrupt( int objc, Tcl_Obj *CONST objv[] ){ +#ifdef SQLITE_DEBUG int bOld = sqlite3_fts5_may_be_corrupt; if( objc!=2 && objc!=1 ){ @@ -1024,6 +1027,7 @@ static int SQLITE_TCLAPI f5tMayBeCorrupt( } Tcl_SetObjResult(interp, Tcl_NewIntObj(bOld)); +#endif return TCL_OK; } diff --git a/ext/fts5/test/fts5corrupt3.test b/ext/fts5/test/fts5corrupt3.test index 9b43f3e069..4796f2c489 100644 --- a/ext/fts5/test/fts5corrupt3.test +++ b/ext/fts5/test/fts5corrupt3.test @@ -14591,6 +14591,336 @@ do_catchsql_test 74.1 { SELECT rowid, quote(matchinfo(t1,'p�xyb t1.x } { QUERY PLAN - |--SCAN TABLE f1 VIRTUAL TABLE INDEX 0: - `--SCAN TABLE t1 + |--SCAN f1 VIRTUAL TABLE INDEX 0: + `--SCAN t1 } do_eqp_test 1.3 { SELECT * FROM f1 WHERE f1 MATCH ? ORDER BY ff } { QUERY PLAN - |--SCAN TABLE f1 VIRTUAL TABLE INDEX 0:M1 + |--SCAN f1 VIRTUAL TABLE INDEX 0:M1 `--USE TEMP B-TREE FOR ORDER BY } @@ -54,12 +54,12 @@ do_eqp_test 1.4 { SELECT * FROM f1 ORDER BY rank } { QUERY PLAN - |--SCAN TABLE f1 VIRTUAL TABLE INDEX 0: + |--SCAN f1 VIRTUAL TABLE INDEX 0: `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 1.5 { SELECT * FROM f1 WHERE rank MATCH ? -} {SCAN TABLE f1 VIRTUAL TABLE INDEX 0:r} +} {SCAN f1 VIRTUAL TABLE INDEX 0:r} finish_test diff --git a/ext/fts5/test/fts5trigram.test b/ext/fts5/test/fts5trigram.test index 26eb7ba8de..fb66efed68 100644 --- a/ext/fts5/test/fts5trigram.test +++ b/ext/fts5/test/fts5trigram.test @@ -192,10 +192,9 @@ do_eqp_test 6.2 { } {VIRTUAL TABLE INDEX 0:G0} do_eqp_test 6.3 { SELECT * FROM ci1 WHERE x LIKE ? -} {{SCAN TABLE ci1 VIRTUAL TABLE INDEX 0:}} +} {{SCAN ci1 VIRTUAL TABLE INDEX 0:}} do_eqp_test 6.4 { SELECT * FROM ci1 WHERE x GLOB ? } {VIRTUAL TABLE INDEX 0:G0} finish_test - diff --git a/ext/misc/appendvfs.c b/ext/misc/appendvfs.c index 4ea5b1c2cb..ba6cc2c0b8 100644 --- a/ext/misc/appendvfs.c +++ b/ext/misc/appendvfs.c @@ -530,9 +530,11 @@ static int apndOpen( rc = pBaseVfs->xOpen(pBaseVfs, zName, pBaseFile, flags, pOutFlags); if( rc==SQLITE_OK ){ rc = pBaseFile->pMethods->xFileSize(pBaseFile, &sz); + if( rc ){ + pBaseFile->pMethods->xClose(pBaseFile); + } } if( rc ){ - pBaseFile->pMethods->xClose(pBaseFile); pFile->pMethods = 0; return rc; } diff --git a/ext/misc/cksumvfs.c b/ext/misc/cksumvfs.c index 0f6b00f436..6994dc7760 100644 --- a/ext/misc/cksumvfs.c +++ b/ext/misc/cksumvfs.c @@ -579,6 +579,18 @@ static int cksmFileControl(sqlite3_file *pFile, int op, void *pArg){ }else if( op==SQLITE_FCNTL_CKPT_START || op==SQLITE_FCNTL_CKPT_DONE ){ p->inCkpt = op==SQLITE_FCNTL_CKPT_START; if( p->pPartner ) p->pPartner->inCkpt = p->inCkpt; + }else if( op==SQLITE_FCNTL_CKSM_FILE ){ + /* This VFS needs to obtain a pointer to the corresponding database + ** file handle from within xOpen() calls to open wal files. To do this, + ** it uses the sqlite3_database_file_object() API to obtain a pointer + ** to the file-handle used by SQLite to access the db file. This is + ** fine if cksmvfs happens to be the top-level VFS, but not if there + ** are one or more wrapper VFS. To handle this case, this file-control + ** is used to extract the cksmvfs file-handle from any wrapper file + ** handle. */ + sqlite3_file **ppFile = (sqlite3_file**)pArg; + *ppFile = (sqlite3_file*)p; + return SQLITE_OK; } rc = pFile->pMethods->xFileControl(pFile, op, pArg); if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){ @@ -688,6 +700,8 @@ static int cksmOpen( if( rc ) goto cksm_open_done; if( flags & SQLITE_OPEN_WAL ){ sqlite3_file *pDb = sqlite3_database_file_object(zName); + rc = pDb->pMethods->xFileControl(pDb, SQLITE_FCNTL_CKSM_FILE, (void*)&pDb); + assert( rc==SQLITE_OK ); p->pPartner = (CksmFile*)pDb; assert( p->pPartner->pPartner==0 ); p->pPartner->pPartner = p; diff --git a/ext/misc/decimal.c b/ext/misc/decimal.c index a8d68ac72f..37c6c2f52c 100644 --- a/ext/misc/decimal.c +++ b/ext/misc/decimal.c @@ -459,10 +459,11 @@ static void decimalSubFunc( Decimal *pA = decimal_new(context, argv[0], 0, 0); Decimal *pB = decimal_new(context, argv[1], 0, 0); UNUSED_PARAMETER(argc); - if( pB==0 ) return; - pB->sign = !pB->sign; - decimal_add(pA, pB); - decimal_result(context, pA); + if( pB ){ + pB->sign = !pB->sign; + decimal_add(pA, pB); + decimal_result(context, pA); + } decimal_free(pA); decimal_free(pB); } diff --git a/ext/misc/json1.c b/ext/misc/json1.c index 77641064d4..41ff01db49 100644 --- a/ext/misc/json1.c +++ b/ext/misc/json1.c @@ -299,7 +299,7 @@ static void jsonAppendSeparator(JsonString *p){ */ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){ u32 i; - if( (N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0 ) return; + if( zIn==0 || ((N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0) ) return; p->zBuf[p->nUsed++] = '"'; for(i=0; inUsed>1 ){ jsonAppendChar(pStr, ','); - pStr->pCtx = ctx; } + pStr->pCtx = ctx; jsonAppendValue(pStr, argv[0]); } } @@ -1959,11 +1959,7 @@ static void jsonGroupInverse( if( NEVER(!pStr) ) return; #endif z = pStr->zBuf; - for(i=1; (c = z[i])!=',' || inStr || nNest; i++){ - if( i>=pStr->nUsed ){ - pStr->nUsed = 1; - return; - } + for(i=1; inUsed && ((c = z[i])!=',' || inStr || nNest); i++){ if( c=='"' ){ inStr = !inStr; }else if( c=='\\' ){ @@ -1973,8 +1969,13 @@ static void jsonGroupInverse( if( c=='}' || c==']' ) nNest--; } } - pStr->nUsed -= i; - memmove(&z[1], &z[i+1], (size_t)pStr->nUsed-1); + if( inUsed ){ + pStr->nUsed -= i; + memmove(&z[1], &z[i+1], (size_t)pStr->nUsed-1); + z[pStr->nUsed] = 0; + }else{ + pStr->nUsed = 1; + } } #else # define jsonGroupInverse 0 diff --git a/ext/misc/zipfile.c b/ext/misc/zipfile.c index f9fbcfc0bd..86f7ba0f94 100644 --- a/ext/misc/zipfile.c +++ b/ext/misc/zipfile.c @@ -36,10 +36,24 @@ SQLITE_EXTENSION_INIT1 #ifndef SQLITE_AMALGAMATION +#ifndef UINT32_TYPE +# ifdef HAVE_UINT32_T +# define UINT32_TYPE uint32_t +# else +# define UINT32_TYPE unsigned int +# endif +#endif +#ifndef UINT16_TYPE +# ifdef HAVE_UINT16_T +# define UINT16_TYPE uint16_t +# else +# define UINT16_TYPE unsigned short int +# endif +#endif typedef sqlite3_int64 i64; typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned long u32; +typedef UINT32_TYPE u32; /* 4-byte unsigned integer */ +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) @@ -706,34 +720,24 @@ static int zipfileScanExtra(u8 *aExtra, int nExtra, u32 *pmTime){ ** https://msdn.microsoft.com/en-us/library/9kkf9tah.aspx */ static u32 zipfileMtime(ZipfileCDS *pCDS){ - int Y = (1980 + ((pCDS->mDate >> 9) & 0x7F)); - int M = ((pCDS->mDate >> 5) & 0x0F); - int D = (pCDS->mDate & 0x1F); - int B = -13; - - int sec = (pCDS->mTime & 0x1F)*2; - int min = (pCDS->mTime >> 5) & 0x3F; - int hr = (pCDS->mTime >> 11) & 0x1F; - i64 JD; - - /* JD = INT(365.25 * (Y+4716)) + INT(30.6001 * (M+1)) + D + B - 1524.5 */ - - /* Calculate the JD in seconds for noon on the day in question */ - if( M<3 ){ - Y = Y-1; - M = M+12; + int Y,M,D,X1,X2,A,B,sec,min,hr; + i64 JDsec; + Y = (1980 + ((pCDS->mDate >> 9) & 0x7F)); + M = ((pCDS->mDate >> 5) & 0x0F); + D = (pCDS->mDate & 0x1F); + sec = (pCDS->mTime & 0x1F)*2; + min = (pCDS->mTime >> 5) & 0x3F; + hr = (pCDS->mTime >> 11) & 0x1F; + if( M<=2 ){ + Y--; + M += 12; } - JD = (i64)(24*60*60) * ( - (int)(365.25 * (Y + 4716)) - + (int)(30.6001 * (M + 1)) - + D + B - 1524 - ); - - /* Correct the JD for the time within the day */ - JD += (hr-12) * 3600 + min * 60 + sec; - - /* Convert JD to unix timestamp (the JD epoch is 2440587.5) */ - return (u32)(JD - (i64)(24405875) * 24*60*6); + X1 = 36525*(Y+4716)/100; + X2 = 306001*(M+1)/10000; + A = Y/100; + B = 2 - A + (A/4); + JDsec = (i64)((X1 + X2 + D + B - 1524.5)*86400) + hr*3600 + min*60 + sec; + return (u32)(JDsec - (i64)24405875*(i64)8640); } /* @@ -2170,6 +2174,10 @@ static int zipfileRegister(sqlite3 *db){ zipfileStep, zipfileFinal ); } + assert( sizeof(i64)==8 ); + assert( sizeof(u32)==4 ); + assert( sizeof(u16)==2 ); + assert( sizeof(u8)==1 ); return rc; } #else /* SQLITE_OMIT_VIRTUALTABLE */ diff --git a/ext/rbu/rbu1.test b/ext/rbu/rbu1.test index 7ec075b7e0..9237dbcea7 100644 --- a/ext/rbu/rbu1.test +++ b/ext/rbu/rbu1.test @@ -132,6 +132,11 @@ foreach {tn3 create_vfs destroy_vfs} { } { sqlite3rbu_destroy_vfs myrbu } + 3 { + sqlite3_register_cksumvfs + } { + sqlite3_unregister_cksumvfs + } } { eval $create_vfs diff --git a/ext/rbu/sqlite3rbu.c b/ext/rbu/sqlite3rbu.c index c5f809848d..1a13b6c4ad 100644 --- a/ext/rbu/sqlite3rbu.c +++ b/ext/rbu/sqlite3rbu.c @@ -1620,7 +1620,9 @@ char *rbuVacuumIndexStart( zSep = ""; for(iCol=0; iColnCol; iCol++){ const char *zQuoted = (const char*)sqlite3_column_text(pSel, iCol); - if( zQuoted[0]=='N' ){ + if( zQuoted==0 ){ + p->rc = SQLITE_NOMEM; + }else if( zQuoted[0]=='N' ){ bFailed = 1; break; } @@ -4992,28 +4994,14 @@ static int rbuVfsOpen( rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName, 0); if( pDb ){ if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){ - /* This call is to open a *-wal file. Intead, open the *-oal. This - ** code ensures that the string passed to xOpen() is terminated by a - ** pair of '\0' bytes in case the VFS attempts to extract a URI - ** parameter from it. */ - const char *zBase = zName; - size_t nCopy; - char *zCopy; + /* This call is to open a *-wal file. Intead, open the *-oal. */ + size_t nOpen; if( rbuIsVacuum(pDb->pRbu) ){ - zBase = sqlite3_db_filename(pDb->pRbu->dbRbu, "main"); - zBase = sqlite3_filename_wal(zBase); - } - nCopy = strlen(zBase); - zCopy = sqlite3_malloc64(nCopy+2); - if( zCopy ){ - memcpy(zCopy, zBase, nCopy); - zCopy[nCopy-3] = 'o'; - zCopy[nCopy] = '\0'; - zCopy[nCopy+1] = '\0'; - zOpen = (const char*)(pFd->zDel = zCopy); - }else{ - rc = SQLITE_NOMEM; + zOpen = sqlite3_db_filename(pDb->pRbu->dbRbu, "main"); + zOpen = sqlite3_filename_wal(zOpen); } + nOpen = strlen(zOpen); + ((char*)zOpen)[nOpen-3] = 'o'; pFd->pRbu = pDb->pRbu; } pDb->pWalFd = pFd; diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c index b1cff38edf..b7759bbb51 100644 --- a/ext/rtree/geopoly.c +++ b/ext/rtree/geopoly.c @@ -310,6 +310,10 @@ static GeoPoly *geopolyFuncParam( ){ const unsigned char *a = sqlite3_value_blob(pVal); int nVertex; + if( a==0 ){ + sqlite3_result_error_nomem(pCtx); + return 0; + } nVertex = (a[1]<<16) + (a[2]<<8) + a[3]; if( (a[0]==0 || a[0]==1) && (nVertex*2*sizeof(GeoCoord) + 4)==(unsigned int)nByte @@ -683,7 +687,7 @@ static GeoPoly *geopolyBBox( aCoord[2].f = mnY; aCoord[3].f = mxY; } - }else{ + }else if( aCoord ){ memset(aCoord, 0, sizeof(RtreeCoord)*4); } return pOut; diff --git a/ext/rtree/rtree.c b/ext/rtree/rtree.c index f5b57a5e23..2151d5af04 100644 --- a/ext/rtree/rtree.c +++ b/ext/rtree/rtree.c @@ -3890,11 +3890,16 @@ static void rtreedepth(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){ UNUSED_PARAMETER(nArg); if( sqlite3_value_type(apArg[0])!=SQLITE_BLOB || sqlite3_value_bytes(apArg[0])<2 + ){ sqlite3_result_error(ctx, "Invalid argument to rtreedepth()", -1); }else{ u8 *zBlob = (u8 *)sqlite3_value_blob(apArg[0]); - sqlite3_result_int(ctx, readInt16(zBlob)); + if( zBlob ){ + sqlite3_result_int(ctx, readInt16(zBlob)); + }else{ + sqlite3_result_error_nomem(ctx); + } } } diff --git a/ext/rtree/rtree6.test b/ext/rtree/rtree6.test index bc9ff84298..b6dfe992a6 100644 --- a/ext/rtree/rtree6.test +++ b/ext/rtree/rtree6.test @@ -79,47 +79,47 @@ do_eqp_test rtree6.2.1 { SELECT * FROM t1,t2 WHERE k=+ii AND x1<10 } { QUERY PLAN - |--SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0 - `--SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?) + |--SCAN t1 VIRTUAL TABLE INDEX 2:C0 + `--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test rtree6.2.2 { SELECT * FROM t1,t2 WHERE k=ii AND x1<10 } { QUERY PLAN - |--SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0 - `--SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?) + |--SCAN t1 VIRTUAL TABLE INDEX 2:C0 + `--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test rtree6.2.3 { SELECT * FROM t1,t2 WHERE k=ii } { QUERY PLAN - |--SCAN TABLE t1 VIRTUAL TABLE INDEX 2: - `--SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?) + |--SCAN t1 VIRTUAL TABLE INDEX 2: + `--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test rtree6.2.4.1 { SELECT * FROM t1,t2 WHERE v=+ii and x1<10 and x2>10 } { QUERY PLAN - |--SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0E1 - `--SEARCH TABLE t2 USING AUTOMATIC COVERING INDEX (v=?) + |--SCAN t1 VIRTUAL TABLE INDEX 2:C0E1 + `--SEARCH t2 USING AUTOMATIC COVERING INDEX (v=?) } do_eqp_test rtree6.2.4.2 { SELECT * FROM t1,t2 WHERE v=10 and x1<10 and x2>10 } { QUERY PLAN - |--SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0E1 - `--SEARCH TABLE t2 USING AUTOMATIC PARTIAL COVERING INDEX (v=?) + |--SCAN t1 VIRTUAL TABLE INDEX 2:C0E1 + `--SEARCH t2 USING AUTOMATIC PARTIAL COVERING INDEX (v=?) } do_eqp_test rtree6.2.5 { SELECT * FROM t1,t2 WHERE k=ii AND x1=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { QUERY PLAN - |--SCAN TABLE t - `--SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 + |--SCAN t + `--SCAN r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 } do_eqp_test 1.2 { @@ -39,8 +39,8 @@ do_eqp_test 1.2 { WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { QUERY PLAN - |--SCAN TABLE t - `--SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 + |--SCAN t + `--SCAN r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 } do_eqp_test 1.3 { @@ -48,16 +48,16 @@ do_eqp_test 1.3 { WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND ?<=max_y } { QUERY PLAN - |--SCAN TABLE t - `--SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 + |--SCAN t + `--SCAN r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 } do_eqp_test 1.5 { SELECT * FROM t, r_tree } { QUERY PLAN - |--SCAN TABLE r_tree VIRTUAL TABLE INDEX 2: - `--SCAN TABLE t + |--SCAN r_tree VIRTUAL TABLE INDEX 2: + `--SCAN t } do_execsql_test 2.0 { @@ -87,8 +87,8 @@ do_eqp_test 2.1 { WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { QUERY PLAN - |--SCAN TABLE t - `--SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 + |--SCAN t + `--SCAN r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 } do_eqp_test 2.2 { @@ -96,8 +96,8 @@ do_eqp_test 2.2 { WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { QUERY PLAN - |--SCAN TABLE t - `--SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 + |--SCAN t + `--SCAN r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 } do_eqp_test 2.3 { @@ -105,16 +105,16 @@ do_eqp_test 2.3 { WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND ?<=max_y } { QUERY PLAN - |--SCAN TABLE t - `--SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 + |--SCAN t + `--SCAN r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 } do_eqp_test 2.5 { SELECT * FROM t, r_tree } { QUERY PLAN - |--SCAN TABLE r_tree VIRTUAL TABLE INDEX 2: - `--SCAN TABLE t + |--SCAN r_tree VIRTUAL TABLE INDEX 2: + `--SCAN t } #------------------------------------------------------------------------- @@ -128,24 +128,24 @@ do_execsql_test 3.1 { do_eqp_test 3.2.1 { SELECT * FROM t1 CROSS JOIN t2 } { QUERY PLAN - |--SCAN TABLE t1 - `--SCAN TABLE t2 + |--SCAN t1 + `--SCAN t2 } do_eqp_test 3.2.2 { SELECT * FROM t2 CROSS JOIN t1 } { QUERY PLAN - |--SCAN TABLE t2 - `--SCAN TABLE t1 + |--SCAN t2 + `--SCAN t1 } do_eqp_test 3.3.1 { SELECT * FROM t1 CROSS JOIN t3 } { QUERY PLAN - |--SCAN TABLE t1 - `--SCAN TABLE t3 VIRTUAL TABLE INDEX 2: + |--SCAN t1 + `--SCAN t3 VIRTUAL TABLE INDEX 2: } do_eqp_test 3.3.2 { SELECT * FROM t3 CROSS JOIN t1 } { QUERY PLAN - |--SCAN TABLE t3 VIRTUAL TABLE INDEX 2: - `--SCAN TABLE t1 + |--SCAN t3 VIRTUAL TABLE INDEX 2: + `--SCAN t1 } #-------------------------------------------------------------------- @@ -203,8 +203,8 @@ do_eqp_test 5.2 { SELECT * FROM t1, rt WHERE x==id; } { QUERY PLAN - |--SCAN TABLE t1 - `--SCAN TABLE rt VIRTUAL TABLE INDEX 1: + |--SCAN t1 + `--SCAN rt VIRTUAL TABLE INDEX 1: } # Now create enough ANALYZE data to tell SQLite that virtual table "rt" @@ -220,8 +220,8 @@ do_eqp_test 5.4 { SELECT * FROM t1, rt WHERE x==id; } { QUERY PLAN - |--SCAN TABLE rt VIRTUAL TABLE INDEX 2: - `--SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (x=?) + |--SCAN rt VIRTUAL TABLE INDEX 2: + `--SEARCH t1 USING INDEX sqlite_autoindex_t1_1 (x=?) } # Delete the ANALYZE data. "t1" should be the outer loop again. @@ -233,8 +233,8 @@ do_eqp_test 5.6 { SELECT * FROM t1, rt WHERE x==id; } { QUERY PLAN - |--SCAN TABLE t1 - `--SCAN TABLE rt VIRTUAL TABLE INDEX 1: + |--SCAN t1 + `--SCAN rt VIRTUAL TABLE INDEX 1: } # This time create and attach a database that contains ANALYZE data for @@ -258,8 +258,8 @@ do_eqp_test 5.8 { SELECT * FROM t1, rt WHERE x==id; } { QUERY PLAN - |--SCAN TABLE t1 - `--SCAN TABLE rt VIRTUAL TABLE INDEX 1: + |--SCAN t1 + `--SCAN rt VIRTUAL TABLE INDEX 1: } #-------------------------------------------------------------------- @@ -327,9 +327,9 @@ do_eqp_execsql_test 7.1 { WHERE (x1 BETWEEN xmin AND xmax); } { QUERY PLAN - |--SCAN TABLE xdir - |--SCAN TABLE ydir - `--SCAN TABLE rt VIRTUAL TABLE INDEX 2:B2D3B0D1 + |--SCAN xdir + |--SCAN ydir + `--SCAN rt VIRTUAL TABLE INDEX 2:B2D3B0D1 } { 2 4 } @@ -340,9 +340,9 @@ do_eqp_execsql_test 7.2 { WHERE (x1 BETWEEN xmin AND xmax); } { QUERY PLAN - |--SCAN TABLE xdir - |--SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1 - `--SCAN TABLE ydir + |--SCAN xdir + |--SCAN rt VIRTUAL TABLE INDEX 2:B0D1 + `--SCAN ydir } { 5 1 2 7 12 14 {} 5 2 2 7 8 12 10 @@ -355,9 +355,9 @@ do_eqp_execsql_test 7.3 { WHERE (x1 BETWEEN xmin AND xmax); } { QUERY PLAN - |--SCAN TABLE xdir - |--SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1 - `--SCAN TABLE ydir + |--SCAN xdir + |--SCAN rt VIRTUAL TABLE INDEX 2:B0D1 + `--SCAN ydir } { 2 4 } @@ -368,9 +368,9 @@ do_eqp_execsql_test 7.4 { WHERE (x1 BETWEEN xmin AND xmax); } { QUERY PLAN - |--SCAN TABLE xdir - |--SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1 - `--SCAN TABLE ydir + |--SCAN xdir + |--SCAN rt VIRTUAL TABLE INDEX 2:B0D1 + `--SCAN ydir } { 2 4 } diff --git a/ext/rtree/rtreefuzz001.test b/ext/rtree/rtreefuzz001.test index db9df205af..58fd179ab9 100644 --- a/ext/rtree/rtreefuzz001.test +++ b/ext/rtree/rtreefuzz001.test @@ -1045,5 +1045,167 @@ do_test rtreefuzz001-500 { catchsql {UPDATE t1 SET ex= ex ISNULL} } {1 {database disk image is malformed}} +do_test rtreefuzz001-600 { + sqlite3 db {} + db deserialize [decode_hexdb { +| size 20480 pagesize 4096 filename crash-7b37d80f000235.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 05 .....@ ........ +| 32: 00 00 00 00 00 00 00 00 00 00 10 06 00 00 00 04 ................ +| 96: 00 00 00 00 0d 00 00 00 05 0e 49 00 0f 99 0f 40 ..........I....@ +| 112: 0e da 0e 8f 0e 49 00 00 00 00 00 00 00 00 00 00 .....I.......... +| 3648: 00 00 00 00 00 00 00 00 00 44 05 06 17 15 15 08 .........D...... +| 3664: 6f 74 61 62 6c 65 67 65 6f 31 67 65 6f 31 43 52 otablegeo1geo1CR +| 3680: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB +| 3696: 4c 45 20 67 65 6f 31 20 55 53 49 4e 47 20 67 65 LE geo1 USING ge +| 3712: 6f 70 6f 6c 79 28 74 79 70 65 2c 63 6c 72 29 49 opoly(type,clr)I +| 3728: 04 06 17 1f 1f 01 63 74 61 62 6c 65 71 75 65 72 ......ctablequer +| 3744: 79 70 6f 6c 79 71 75 65 72 79 70 6f 6c 79 05 43 ypolyquerypoly.C +| 3760: 52 45 41 54 45 20 54 41 42 4c 45 20 71 75 65 72 REATE TABLE quer +| 3776: 79 70 6f 6c 79 28 70 6f 6c 79 20 4a 53 4f 4e 2c ypoly(poly JSON, +| 3792: 20 63 6c 72 20 54 45 58 54 29 64 03 07 17 23 23 clr TEXT)d...## +| 3808: 01 81 0f 74 61 62 6c 65 67 65 6f 31 5f 70 61 72 ...tablegeo1_par +| 3824: 65 6e 74 67 65 6f 31 5f 70 61 72 65 6e 74 04 43 entgeo1_parent.C +| 3840: 52 45 41 54 45 20 54 41 42 4c 45 20 22 67 65 6f REATE TABLE .geo +| 3856: 31 5f 70 61 72 65 6e 74 22 28 6e 6f 64 65 6e 6f 1_parent.(nodeno +| 3872: 20 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 INTEGER PRIMARY +| 3888: 20 4b 45 59 2c 70 61 72 65 6e 74 6e 6f 64 85 29 KEY,parentnod.) +| 3904: 57 02 06 17 1f 1f 01 7f 74 61 62 6c 65 67 65 6f W.......tablegeo +| 3920: 31 5f 6e 6f 64 65 67 65 6f 31 5f 6e 6f 64 65 03 1_nodegeo1_node. +| 3936: 43 52 45 41 54 45 20 54 41 42 4c 45 20 22 67 65 CREATE TABLE .ge +| 3952: 6f 31 5f 6e 6f 64 65 22 28 6e 6f 64 65 6e 6f 20 o1_node.(nodeno +| 3968: 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 INTEGER PRIMARY +| 3984: 4b 45 59 2c 64 61 74 61 29 65 01 07 17 21 21 01 KEY,data)e...!!. +| 4000: 81 15 74 61 62 6c 65 67 65 6f 31 5f 72 6f 77 69 ..tablegeo1_rowi +| 4016: 64 67 65 6f 31 5f 72 6f 77 69 64 02 43 52 45 41 dgeo1_rowid.CREA +| 4032: 54 45 20 54 41 42 4c 45 20 22 67 65 6f 31 5f 72 TE TABLE .geo1_r +| 4048: 6f 77 69 64 22 28 72 6f 77 69 64 20 49 4e 54 45 owid.(rowid INTE +| 4064: 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c GER PRIMARY KEY, +| 4080: 6e 6f 64 65 6e 6f 2c 61 30 2c 61 31 2c 61 32 29 nodeno,a0,a1,a2) +| page 2 offset 4096 +| 0: 0d 00 00 00 0a 0d ab 00 0f c9 0f 88 0f 48 0f 00 .............H.. +| 3488: 00 00 00 00 00 00 00 00 00 00 00 45 82 0a 06 00 ...........E.... +| 3504: 09 74 1d 13 01 00 00 06 00 80 b5 43 00 80 ac 43 .t.........C...C +| 3520: 00 00 bd 43 8f 82 9f 43 71 fd c9 43 8f 02 a7 43 ...C...Cq..C...C +| 3536: 71 fd c8 43 e4 bd a8 43 64 bb bd 43 f4 3d a2 43 q..C...Cd..C.=.C +| 3552: 64 3b b7 43 00 80 ad 43 61 6e 67 6c 65 2d 33 30 d;.C...Cangle-30 +| 3568: 72 65 64 32 81 4e 06 00 09 44 23 17 01 00 00 03 red2.N...D#..... +| 3584: 00 40 3f 44 00 c0 20 44 00 c0 46 44 00 c0 20 44 .@?D.. D..FD.. D +| 3600: 00 00 43 44 00 40 28 44 74 72 69 61 6e 67 6c 65 ..CD.@(Dtriangle +| 3616: 2d 33 30 62 6c 61 63 6b 35 82 3e 06 00 09 54 1d -30black5.>...T. +| 3632: 13 01 00 00 04 00 40 54 44 00 80 1d 44 9a c9 5c ......@TD...D... +| 3648: 44 66 36 1b 44 33 13 5f 44 00 c0 23 44 9a 89 5b Df6.D3._D..#D..[ +| 3664: 44 a4 60 1d 44 61 72 72 6f 77 2d 35 30 72 65 64 D.`.Darrow-50red +| 3680: 36 74 06 00 09 54 1b 17 01 00 00 04 00 80 0d 44 6t...T.........D +| 3696: 00 00 f2 42 0a d7 04 44 00 00 ca 42 0a 77 05 44 ...B...D...B.w.D +| 3712: 0a 57 c1 42 00 20 0e 44 0a 57 e9 42 6c 69 6e 65 .W.B. .D.W.Bline +| 3728: 2d 34 30 67 72 65 65 6e 36 72 06 00 09 54 1b 17 -40green6r...T.. +| 3744: 01 00 00 04 00 00 7b 43 00 00 ea 42 29 5c 58 43 .......C...B).XC +| 3760: 00 00 c2 42 29 dc 5a 43 0a 57 b9 42 00 80 7d 43 ...B).ZC.W.B...C +| 3776: 0a 57 e1 42 6c 69 6e 65 2d 34 30 67 72 65 65 6e .W.Bline-40green +| 3792: 36 54 06 00 09 54 1b 17 01 00 00 04 00 00 a2 43 6T...T.........C +| 3808: 00 00 24 44 00 00 b6 43 00 00 24 44 00 00 b6 43 ..$D...C..$D...C +| 3824: 00 40 25 44 00 00 a2 43 00 40 25 44 6c 69 6e 65 .@%D...C.@%Dline +| 3840: 2d 34 30 62 6c 61 63 6b 3e 37 06 00 09 64 1d 15 -40black>7...d.. +| 3856: 01 00 00 05 00 80 f0 43 00 00 54 43 66 16 01 44 .......C..TCf..D +| 3872: 66 a6 30 43 cd ec 09 44 00 00 54 43 8f 0a 09 44 f.0C...D..TC...D +| 3888: a4 d0 73 43 66 16 01 44 9a 59 77 43 68 6f 75 73 ..sCf..D.YwChous +| 3904: 65 2d 37 30 62 6c 75 65 3e 35 06 00 09 64 1d 15 e-70blue>5...d.. +| 3920: 01 00 00 05 00 00 a2 43 00 00 5a 43 cd ac b3 43 .......C..ZC...C +| 3936: 66 a6 36 43 9a 59 c5 43 00 00 5a 43 1f 95 c3 43 f.6C.Y.C..ZC...C +| 3952: a4 d0 79 43 cd ac b3 43 9a 59 7d 43 68 6f 75 73 ..yC...C.Y.Chous +| 3968: 65 2d 37 30 62 6c 75 65 3f 2c 06 00 09 64 1d 17 e-70blue?,...d.. +| 3984: 01 00 00 05 00 00 f5 43 00 00 2f 43 00 00 07 44 .......C../C...D +| 4000: 00 00 2f 43 00 00 07 44 00 00 61 43 00 c0 00 44 ../C...D..aC...D +| 4016: 00 00 75 43 00 00 f5 43 00 00 61 43 68 6f 75 73 ..uC...C..aChous +| 4032: 65 2d 37 30 62 6c 61 63 6b 35 1f 06 10 09 54 19 e-70black5....T. +| 4048: 17 01 00 00 04 00 00 9b 43 00 00 67 43 0a 57 92 ........C..gC.W. +| 4064: 43 00 00 5d 43 0a 57 97 43 14 ae 4b 42 ff ff a0 C..]C.W.C..KB... +| 4080: 43 14 ae 55 43 62 6f 78 2d 32 30 67 72 65 65 6e C..UCbox-20green +| page 3 offset 8192 +| 0: 0d 00 00 00 01 0b 2d 00 0b 2e 00 00 00 00 00 00 ......-......... +| 2848: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 89 50 ...............P +| 2864: 01 04 00 93 24 00 00 00 0a 00 00 00 00 00 00 01 ....$........... +| 2880: 0a 43 b5 80 00 43 c9 fd 71 43 9f 82 8f 43 ad 80 .C...C..qC...C.. +| 2896: 00 00 00 00 00 00 00 00 72 43 58 5c 29 43 7d 80 ........rCX.)C.. +| 2912: 00 42 b9 57 0a 42 ea 00 00 00 00 00 00 00 00 00 .B.W.B.......... +| 2928: 35 43 a2 00 00 43 c5 59 9a 43 36 a6 66 43 7d 59 5C...C.Y.C6.fC.Y +| 2944: 9a 00 00 00 00 00 00 00 1f 43 92 57 0a 43 a0 00 .........C.W.C.. +| 2960: 00 43 4b ae 14 43 67 00 00 00 00 00 00 00 00 00 .CK..Cg......... +| 2976: 37 43 f0 80 00 44 09 ec cd 43 30 a6 66 43 77 59 7C...D...C0.fCwY +| 2992: 9a 00 00 00 00 00 00 00 2c 43 f5 00 00 44 07 00 ........,C...D.. +| 3008: 00 43 2f 00 00 43 75 00 00 00 00 00 00 00 00 00 .C/..Cu......... +| 3024: 74 44 04 d7 0a 44 0e 20 00 42 c1 57 0a 42 f2 00 tD...D. .B.W.B.. +| 3040: 00 00 00 00 00 00 00 00 ce 44 3f 40 00 44 46 c0 .........D?@.DF. +| 3056: 00 44 20 c0 00 44 28 40 00 00 00 00 00 00 00 00 .D ..D(@........ +| 3072: be 44 54 40 00 44 5f 13 33 44 1b 36 66 44 23 c0 .DT@.D_.3D.6fD#. +| 3088: 00 00 00 00 00 00 00 00 54 43 a2 00 00 43 b6 00 ........TC...C.. +| 3104: 00 44 24 00 00 44 25 40 00 00 00 00 00 00 00 00 .D$..D%@........ +| 3120: 54 43 a2 00 00 43 b6 00 00 44 24 00 00 44 25 40 TC...C...D$..D%@ +| 3136: 00 00 00 00 00 00 00 00 54 43 a2 00 00 43 b6 00 ........TC...C.. +| 3152: 00 44 24 00 00 44 25 40 00 00 00 00 00 00 00 00 .D$..D%@........ +| 3168: 54 43 a2 00 00 43 b6 00 00 44 24 00 00 44 25 40 TC...C...D$..D%@ +| 3184: 00 00 00 00 00 00 00 00 54 43 a2 00 00 43 b6 00 ........TC...C.. +| 3200: 00 44 24 00 00 44 25 40 00 00 00 00 00 00 00 00 .D$..D%@........ +| 3216: 54 43 a2 00 00 43 b6 00 00 44 24 00 00 44 25 40 TC...C...D$..D%@ +| 3232: 00 00 00 00 00 00 00 00 54 43 a2 00 00 43 b6 00 ........TC...C.. +| 3248: 00 44 24 00 00 44 25 40 00 00 00 00 00 00 00 00 .D$..D%@........ +| 3264: 54 43 a2 00 00 43 b6 00 00 44 24 00 00 44 25 40 TC...C...D$..D%@ +| 3280: 00 00 00 00 00 00 00 00 54 43 a2 00 00 43 b6 00 ........TC...C.. +| 3296: 00 44 24 00 00 44 25 40 00 00 00 00 00 00 00 00 .D$..D%@........ +| 3312: 54 43 a2 00 00 43 b6 00 00 44 24 00 00 44 25 40 TC...C...D$..D%@ +| 3328: 00 00 00 00 00 00 00 00 54 43 a2 00 00 43 b6 00 ........TC...C.. +| 3344: 00 44 24 00 00 44 25 40 00 00 00 00 00 00 00 01 .D$..D%@........ +| 3360: 36 44 53 e0 00 44 56 bb 64 43 71 34 bc 43 7d 00 6DS..DV.dCq4.C.. +| 3376: 00 00 00 00 00 00 00 01 36 44 53 e0 00 44 56 bb ........6DS..DV. +| 3392: 64 43 71 34 bc 43 7d 00 00 00 00 00 00 00 00 01 dCq4.C.......... +| 3408: 36 44 53 e0 00 44 56 bb 64 43 71 34 bc 43 7d 00 6DS..DV.dCq4.C.. +| 3424: 00 00 00 00 00 00 00 01 36 44 53 e0 00 44 56 bb ........6DS..DV. +| 3440: 64 43 71 34 bc 43 7d 00 00 00 00 00 00 00 00 01 dCq4.C.......... +| 3456: 36 44 53 e0 00 44 56 bb 64 43 71 34 bc 43 7d 00 6DS..DV.dCq4.C.. +| 3472: 00 00 00 00 00 00 00 01 36 44 53 e0 00 44 56 bb ........6DS..DV. +| 3488: 64 43 71 34 bc 43 7d 00 00 00 00 00 00 00 00 01 dCq4.C.......... +| 3504: 36 44 53 e0 00 44 56 bb 64 43 71 34 bc 43 7d 00 6DS..DV.dCq4.C.. +| 3520: 00 00 00 00 00 00 00 01 36 44 53 e0 00 44 56 bb ........6DS..DV. +| 3536: 64 43 71 34 bc 43 7d 00 00 00 00 00 00 00 00 01 dCq4.C.......... +| 3552: 36 44 53 e0 00 44 56 bb 64 43 71 34 bc 43 7d 00 6DS..DV.dCq4.C.. +| 3568: 00 00 00 00 00 00 00 01 36 44 53 e0 00 44 56 bb ........6DS..DV. +| 3584: 64 43 71 34 bc 43 7d 00 00 00 00 00 00 00 00 01 dCq4.C.......... +| 3600: 36 44 53 e0 00 44 56 bb 64 43 71 34 bc 43 7d 00 6DS..DV.dCq4.C.. +| 3616: 00 00 00 00 00 00 00 01 36 44 53 e0 00 44 56 bb ........6DS..DV. +| 3632: 64 43 71 34 bc 43 7d 00 00 00 00 00 00 00 00 01 dCq4.C.......... +| 3648: 36 44 53 e0 00 44 56 bb 64 43 71 34 bc 43 7d 00 6DS..DV.dCq4.C.. +| 3664: 00 00 00 00 00 00 00 01 36 44 53 e0 00 44 56 bb ........6DS..DV. +| 3680: 64 43 71 34 bc 43 7d 00 00 00 00 00 00 00 00 01 dCq4.C.......... +| 3696: 36 44 53 e0 00 44 56 bb 64 43 71 34 bc 43 7d 00 6DS..DV.dCq4.C.. +| 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 01 0f 8f 00 00 00 00 00 00 00 00 00 ................ +| 3968: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6f ...............o +| 3984: 01 04 81 57 19 5b 5b 33 30 30 2c 33 30 30 5d 2c ...W.[[300,300], +| 4000: 5b 34 30 30 2c 33 35 30 5d 2c 5b 35 30 30 2c 32 [400,350],[500,2 +| 4016: 35 30 5d 2c 5b 34 38 30 2c 35 30 30 5d 2c 5b 34 50],[480,500],[4 +| 4032: 30 30 2c 34 38 30 5d 2c 5c 33 30 30 2c 35 35 30 00,480],.300,550 +| 4048: 5d 2c 5b 32 38 30 2c 34 35 30 5d 2c 5b 33 32 30 ],[280,450],[320 +| 4064: 2c 34 30 30 5d 2c 5b 32 38 30 2c 33 35 30 5d 2c ,400],[280,350], +| 4080: 5b 33 30 30 2c 33 30 00 00 00 00 00 00 00 00 00 [300,30......... +| end crash-7b37d80f000235.db +}]} {} + +ifcapable geopoly { + +do_catchsql_test rtreefuzz001-601 { + SAVEPOINT one; + UPDATE geo1 SET clr=CASE WHEN rowid IN ( SELECT geo1.rowid FROM geo1, querypoly ) THEN 'e' ELSE 'blue' END; +} {1 {database disk image is malformed}} + +do_catchsql_test rtreefuzz001-602 { + SELECT geopoly_svg(_shape, printf('j',geo1.clr)) + FROM geo1, querypoly WHERE geopoly_overlap(_shape, poly); +} {1 {database disk image is malformed}} + +} ;# ifcapable geopoly finish_test diff --git a/ext/session/sessionsize.test b/ext/session/sessionsize.test new file mode 100644 index 0000000000..04d05514db --- /dev/null +++ b/ext/session/sessionsize.test @@ -0,0 +1,131 @@ +# 2021 April 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. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# + +if {![info exists testdir]} { + set testdir [file join [file dirname [info script]] .. .. test] +} +source [file join [file dirname [info script]] session_common.tcl] +source $testdir/tester.tcl +ifcapable !session {finish_test; return} + +set testprefix sessionsize + +proc do_changeset_size_test {tn sql} { + sqlite3session S db main + S attach * + db eval $sql + + set sz [S changeset_size] + set C [S changeset] + set szC [string length $C] + S delete + + do_test $tn "expr $sz" $szC +} + +do_execsql_test 1.0 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); + INSERT INTO t1 VALUES(1, 'abc', 'def'); + INSERT INTO t1 VALUES(2, 'ghi', 'jkl'); +} + +do_changeset_size_test 1.1 { + INSERT INTO t1 VALUES(3, 'hello', 'world'); +} + +do_changeset_size_test 1.2 { + DELETE FROM t1 WHERE a=2; +} + +do_changeset_size_test 1.3 { + DELETE FROM t1 WHERE a=3; + INSERT INTO t1 VALUES(3, 1, 2); +} + +do_changeset_size_test 1.4 { + UPDATE t1 SET c='hello world' WHERE a=3; +} + +#------------------------------------------------------------------------- + +do_execsql_test 2.0 { + CREATE TABlE t2(a, b, c, d, PRIMARY KEY(a, b)) WITHOUT ROWID; + CREATE TABlE t3(a, b, c, d PRIMARY KEY); +} + +do_changeset_size_test 2.1 { + WITH s(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<50 + ) + INSERT INTO t2 SELECT i, i+1, i+2, i+3 FROM s; + + UPDATE t2 SET c=randomblob(a) WHERE a>10 +} + +do_changeset_size_test 2.2 { + DELETE FROM t2 WHERE a=1; + INSERT INTO t2 VALUES(1, 4, 3, 4); +} + +do_changeset_size_test 2.2 { + UPDATE t2 SET b=4 WHERE a=2 +} + +do_changeset_size_test 2.3 { + INSERT INTO t2 VALUES('a', 'b', 'c', 'd'); + UPDATE t2 SET c='qwertyuiop' WHERE a='a'; +} + +do_changeset_size_test 2.4 { + DELETE FROM t2 WHERE a='a'; + INSERT INTO t2 VALUES('a', 'b', 'c', 'd'); +} + +do_changeset_size_test 2.5 { + UPDATE t2 SET a='aa', b='bb' WHERE (a, b) = ('a', 'b'); +} + +do_changeset_size_test 2.6 { + UPDATE t2 SET a='a', b='b' WHERE (a, b) = ('aa', 'bb'); +} + +do_changeset_size_test 2.7 { + INSERT INTO t3 DEFAULT VALUES; + INSERT INTO t3 VALUES(1,2,3,4); +} + +#------------------------------------------------------------------------- +reset_db + +do_execsql_test 3.0 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b); +} + +do_test 3.1 { + sqlite3session S db main + S object_config_size -1 +} 1 + +do_test 3.2.1 { S object_config_size 0 } 0 +do_test 3.2.2 { S object_config_size -1 } 0 +do_test 3.2.3 { S object_config_size 1 } 1 +do_test 3.2.4 { S object_config_size -1 } 1 + +do_test 3.3 { S attach t1 } {} +do_test 3.4 { S object_config_size 1 } {SQLITE_MISUSE} +do_test 3.4 { S object_config_size -1 } {1} + +S delete + +finish_test + diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c index f069a42e1f..e2f997393f 100644 --- a/ext/session/sqlite3session.c +++ b/ext/session/sqlite3session.c @@ -49,6 +49,7 @@ struct SessionHook { struct sqlite3_session { sqlite3 *db; /* Database handle session is attached to */ char *zDb; /* Name of database session is attached to */ + int bEnableSize; /* True if changeset_size() enabled */ int bEnable; /* True if currently recording */ int bIndirect; /* True if all changes are indirect */ int bAutoAttach; /* True to auto-attach tables */ @@ -56,6 +57,7 @@ struct sqlite3_session { void *pFilterCtx; /* First argument to pass to xTableFilter */ int (*xTableFilter)(void *pCtx, const char *zTab); i64 nMalloc; /* Number of bytes of data allocated */ + i64 nMaxChangesetSize; sqlite3_value *pZeroBlob; /* Value containing X'' */ sqlite3_session *pNext; /* Next session object on same db. */ SessionTable *pTable; /* List of attached tables */ @@ -298,8 +300,9 @@ struct SessionTable { ** this structure stored in a SessionTable.aChange[] hash table. */ struct SessionChange { - int op; /* One of UPDATE, DELETE, INSERT */ - int bIndirect; /* True if this change is "indirect" */ + u8 op; /* One of UPDATE, DELETE, INSERT */ + u8 bIndirect; /* True if this change is "indirect" */ + int nMaxSize; /* Max size of eventual changeset record */ int nRecord; /* Number of bytes in buffer aRecord[] */ u8 *aRecord; /* Buffer containing old.* record */ SessionChange *pNext; /* For hash-table collisions */ @@ -1128,6 +1131,12 @@ static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){ if( 0==sqlite3_stricmp("sqlite_stat1", pTab->zName) ){ pTab->bStat1 = 1; } + + if( pSession->bEnableSize ){ + pSession->nMaxChangesetSize += ( + 1 + sessionVarintLen(pTab->nCol) + pTab->nCol + strlen(pTab->zName)+1 + ); + } } } return (pSession->rc || pTab->abPK==0); @@ -1173,6 +1182,103 @@ static int sessionStat1Depth(void *pCtx){ return p->hook.xDepth(p->hook.pCtx); } +static int sessionUpdateMaxSize( + int op, + sqlite3_session *pSession, /* Session object pTab is attached to */ + SessionTable *pTab, /* Table that change applies to */ + SessionChange *pC /* Update pC->nMaxSize */ +){ + i64 nNew = 2; + if( pC->op==SQLITE_INSERT ){ + if( op!=SQLITE_DELETE ){ + int ii; + for(ii=0; iinCol; ii++){ + sqlite3_value *p = 0; + pSession->hook.xNew(pSession->hook.pCtx, ii, &p); + sessionSerializeValue(0, p, &nNew); + } + } + }else if( op==SQLITE_DELETE ){ + nNew += pC->nRecord; + if( sqlite3_preupdate_blobwrite(pSession->db)>=0 ){ + nNew += pC->nRecord; + } + }else{ + int ii; + u8 *pCsr = pC->aRecord; + for(ii=0; iinCol; ii++){ + int bChanged = 1; + int nOld = 0; + int eType; + sqlite3_value *p = 0; + pSession->hook.xNew(pSession->hook.pCtx, ii, &p); + if( p==0 ){ + return SQLITE_NOMEM; + } + + eType = *pCsr++; + switch( eType ){ + case SQLITE_NULL: + bChanged = sqlite3_value_type(p)!=SQLITE_NULL; + break; + + case SQLITE_FLOAT: + case SQLITE_INTEGER: { + if( eType==sqlite3_value_type(p) ){ + sqlite3_int64 iVal = sessionGetI64(pCsr); + if( eType==SQLITE_INTEGER ){ + bChanged = (iVal!=sqlite3_value_int64(p)); + }else{ + double dVal; + memcpy(&dVal, &iVal, 8); + bChanged = (dVal!=sqlite3_value_double(p)); + } + } + nOld = 8; + pCsr += 8; + break; + } + + default: { + int nByte; + nOld = sessionVarintGet(pCsr, &nByte); + pCsr += nOld; + nOld += nByte; + assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB ); + if( eType==sqlite3_value_type(p) + && nByte==sqlite3_value_bytes(p) + && (nByte==0 || 0==memcmp(pCsr, sqlite3_value_blob(p), nByte)) + ){ + bChanged = 0; + } + pCsr += nByte; + break; + } + } + + if( bChanged && pTab->abPK[ii] ){ + nNew = pC->nRecord + 2; + break; + } + + if( bChanged ){ + nNew += 1 + nOld; + sessionSerializeValue(0, p, &nNew); + }else if( pTab->abPK[ii] ){ + nNew += 2 + nOld; + }else{ + nNew += 2; + } + } + } + + if( nNew>pC->nMaxSize ){ + int nIncr = nNew - pC->nMaxSize; + pC->nMaxSize = nNew; + pSession->nMaxChangesetSize += nIncr; + } + return SQLITE_OK; +} /* ** This function is only called from with a pre-update-hook reporting a @@ -1246,7 +1352,6 @@ static void sessionPreupdateOneChange( /* Create a new change object containing all the old values (if ** this is an SQLITE_UPDATE or SQLITE_DELETE), or just the PK ** values (if this is an INSERT). */ - SessionChange *pChange; /* New change object */ sqlite3_int64 nByte; /* Number of bytes to allocate */ int i; /* Used to iterate through columns */ @@ -1272,13 +1377,13 @@ static void sessionPreupdateOneChange( } /* Allocate the change object */ - pChange = (SessionChange *)sessionMalloc64(pSession, nByte); - if( !pChange ){ + pC = (SessionChange *)sessionMalloc64(pSession, nByte); + if( !pC ){ rc = SQLITE_NOMEM; goto error_out; }else{ - memset(pChange, 0, sizeof(SessionChange)); - pChange->aRecord = (u8 *)&pChange[1]; + memset(pC, 0, sizeof(SessionChange)); + pC->aRecord = (u8 *)&pC[1]; } /* Populate the change object. None of the preupdate_old(), @@ -1293,17 +1398,17 @@ static void sessionPreupdateOneChange( }else if( pTab->abPK[i] ){ pSession->hook.xNew(pSession->hook.pCtx, i, &p); } - sessionSerializeValue(&pChange->aRecord[nByte], p, &nByte); + sessionSerializeValue(&pC->aRecord[nByte], p, &nByte); } /* Add the change to the hash-table */ if( pSession->bIndirect || pSession->hook.xDepth(pSession->hook.pCtx) ){ - pChange->bIndirect = 1; + pC->bIndirect = 1; } - pChange->nRecord = nByte; - pChange->op = op; - pChange->pNext = pTab->apChange[iHash]; - pTab->apChange[iHash] = pChange; + pC->nRecord = nByte; + pC->op = op; + pC->pNext = pTab->apChange[iHash]; + pTab->apChange[iHash] = pC; }else if( pC->bIndirect ){ /* If the existing change is considered "indirect", but this current @@ -1314,8 +1419,14 @@ static void sessionPreupdateOneChange( pC->bIndirect = 0; } } + + assert( rc==SQLITE_OK ); + if( pSession->bEnableSize ){ + rc = sessionUpdateMaxSize(op, pSession, pTab, pC); + } } + /* If an error has occurred, mark the session object as failed. */ error_out: if( pTab->bStat1 ){ @@ -2527,8 +2638,12 @@ int sqlite3session_changeset( int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ void **ppChangeset /* OUT: Buffer containing changeset */ ){ - return sessionGenerateChangeset( + int rc = sessionGenerateChangeset( pSession, SESSIONS_CHANGESET, 0, 0, pnChangeset, ppChangeset); + assert( rc || pnChangeset==0 + || pSession->bEnableSize==0 || *pnChangeset<=pSession->nMaxChangesetSize + ); + return rc; } /* @@ -2633,6 +2748,39 @@ sqlite3_int64 sqlite3session_memory_used(sqlite3_session *pSession){ return pSession->nMalloc; } +/* +** Configure the session object passed as the first argument. +*/ +int sqlite3session_object_config(sqlite3_session *pSession, int op, void *pArg){ + int rc = SQLITE_OK; + switch( op ){ + case SQLITE_SESSION_OBJCONFIG_SIZE: { + int iArg = *(int*)pArg; + if( iArg>=0 ){ + if( pSession->pTable ){ + rc = SQLITE_MISUSE; + }else{ + pSession->bEnableSize = (iArg!=0); + } + } + *(int*)pArg = pSession->bEnableSize; + break; + } + + default: + rc = SQLITE_MISUSE; + } + + return rc; +} + +/* +** Return the maximum size of sqlite3session_changeset() output. +*/ +sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession){ + return pSession->nMaxChangesetSize; +} + /* ** Do the work for either sqlite3changeset_start() or start_strm(). */ diff --git a/ext/session/sqlite3session.h b/ext/session/sqlite3session.h index 107bcfb6a9..0090f67d76 100644 --- a/ext/session/sqlite3session.h +++ b/ext/session/sqlite3session.h @@ -79,6 +79,38 @@ int sqlite3session_create( */ void sqlite3session_delete(sqlite3_session *pSession); +/* +** CAPIREF: Conigure a Session Object +** METHOD: sqlite3_session +** +** This method is used to configure a session object after it has been +** created. At present the only valid value for the second parameter is +** [SQLITE_SESSION_OBJCONFIG_SIZE]. +** +** Arguments for sqlite3session_object_config() +** +** The following values may passed as the the 4th parameter to +** sqlite3session_object_config(). +** +**

    SQLITE_SESSION_OBJCONFIG_SIZE
    +** This option is used to set, clear or query the flag that enables +** the [sqlite3session_changeset_size()] API. Because it imposes some +** computational overhead, this API is disabled by default. Argument +** pArg must point to a value of type (int). If the value is initially +** 0, then the sqlite3session_changeset_size() API is disabled. If it +** is greater than 0, then the same API is enabled. Or, if the initial +** value is less than zero, no change is made. In all cases the (int) +** variable is set to 1 if the sqlite3session_changeset_size() API is +** enabled following the current call, or 0 otherwise. +** +** It is an error (SQLITE_MISUSE) to attempt to modify this setting after +** the first table has been attached to the session object. +*/ +int sqlite3session_object_config(sqlite3_session*, int op, void *pArg); + +/* +*/ +#define SQLITE_SESSION_OBJCONFIG_SIZE 1 /* ** CAPI3REF: Enable Or Disable A Session Object @@ -349,6 +381,22 @@ int sqlite3session_fullchangeset( void **ppChangeset /* OUT: Buffer containing changeset */ ); +/* +** CAPI3REF: Return An Upper-limit For The Size Of The Changeset +** METHOD: sqlite3_session +** +** By default, this function always returns 0. For it to return +** a useful result, the sqlite3_session object must have been configured +** to enable this API using sqlite3session_object_config() with the +** SQLITE_SESSION_OBJCONFIG_SIZE verb. +** +** When enabled, this function returns an upper limit, in bytes, for the size +** of the changeset that might be produced if sqlite3session_changeset() were +** called. The final changeset size might be equal to or smaller than the +** size in bytes returned by this function. +*/ +sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession); + /* ** CAPI3REF: Load The Difference Between Tables Into A Session ** METHOD: sqlite3_session diff --git a/ext/session/test_session.c b/ext/session/test_session.c index d968699e02..009f2990d0 100644 --- a/ext/session/test_session.c +++ b/ext/session/test_session.c @@ -247,6 +247,8 @@ static int SQLITE_TCLAPI test_session_cmd( { "diff", 2, "FROMDB TBL" }, /* 8 */ { "fullchangeset",0, "" }, /* 9 */ { "memory_used", 0, "", }, /* 10 */ + { "changeset_size", 0, "", }, /* 11 */ + { "object_config_size", 1, "INTEGER", }, /* 12 */ { 0 } }; int iSub; @@ -362,6 +364,29 @@ static int SQLITE_TCLAPI test_session_cmd( Tcl_SetObjResult(interp, Tcl_NewWideIntObj(nMalloc)); break; } + + case 11: { + sqlite3_int64 nSize = sqlite3session_changeset_size(pSession); + Tcl_SetObjResult(interp, Tcl_NewWideIntObj(nSize)); + break; + } + case 12: { + int rc; + int iArg; + if( Tcl_GetIntFromObj(interp, objv[2], &iArg) ){ + return TCL_ERROR; + } + rc = sqlite3session_object_config( + pSession, SQLITE_SESSION_OBJCONFIG_SIZE, &iArg + ); + if( rc!=SQLITE_OK ){ + extern const char *sqlite3ErrName(int); + Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); + }else{ + Tcl_SetObjResult(interp, Tcl_NewIntObj(iArg)); + } + break; + } } return TCL_OK; @@ -387,6 +412,7 @@ static int SQLITE_TCLAPI test_sqlite3session( Tcl_CmdInfo info; int rc; /* sqlite3session_create() return code */ TestSession *p; /* New wrapper object */ + int iArg = -1; if( objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "CMD DB-HANDLE DB-NAME"); @@ -407,6 +433,13 @@ static int SQLITE_TCLAPI test_sqlite3session( return test_session_error(interp, rc, 0); } + /* Query the SQLITE_SESSION_OBJCONFIG_SIZE option to ensure that it + ** is clear by default. Then set it. */ + sqlite3session_object_config(p->pSession,SQLITE_SESSION_OBJCONFIG_SIZE,&iArg); + assert( iArg==0 ); + iArg = 1; + sqlite3session_object_config(p->pSession,SQLITE_SESSION_OBJCONFIG_SIZE,&iArg); + Tcl_CreateObjCommand( interp, Tcl_GetString(objv[1]), test_session_cmd, (ClientData)p, test_session_del diff --git a/main.mk b/main.mk index 1aabb4d965..2a085a3163 100644 --- a/main.mk +++ b/main.mk @@ -441,7 +441,8 @@ TESTSRC2 = \ $(TOP)/ext/misc/stmt.c \ $(TOP)/ext/session/sqlite3session.c \ $(TOP)/ext/session/sqlite3changebatch.c \ - $(TOP)/ext/session/test_session.c + $(TOP)/ext/session/test_session.c \ + fts5.c # Header files used by all library source files. # @@ -540,7 +541,6 @@ FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1 FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000 FUZZCHECK_OPT += -DSQLITE_PRINTF_PRECISION_LIMIT=1000 -FUZZCHECK_OPT += -DSQLITE_ENABLE_DESERIALIZE FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS4 FUZZCHECK_OPT += -DSQLITE_ENABLE_RTREE FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY @@ -593,7 +593,6 @@ dbfuzz$(EXE): $(TOP)/test/dbfuzz.c sqlite3.c sqlite3.h DBFUZZ2_OPTS = \ -DSQLITE_THREADSAFE=0 \ -DSQLITE_OMIT_LOAD_EXTENSION \ - -DSQLITE_ENABLE_DESERIALIZE \ -DSQLITE_DEBUG \ -DSQLITE_ENABLE_DBSTAT_VTAB \ -DSQLITE_ENABLE_BYTECODE_VTAB \ @@ -1085,6 +1084,9 @@ rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.o loadfts: $(TOP)/tool/loadfts.c libsqlite3.a $(TCC) $(TOP)/tool/loadfts.c libsqlite3.a -o loadfts $(THREADLIB) +threadtest5: $(TOP)/test/threadtest5.c libsqlite3.a + $(TCC) $(TOP)/test/threadtest5.c libsqlite3.a -o threadtest5 $(THREADLIB) + # This target will fail if the SQLite amalgamation contains any exported # symbols that do not begin with "sqlite3_". It is run as part of the # releasetest.tcl script. @@ -1147,3 +1149,4 @@ clean: rm -f sqldiff sqldiff.exe rm -f fts5.* fts5parse.* rm -f lsm.h lsm1.c + rm -f threadtest5 diff --git a/manifest b/manifest index 801dddf141..c04ab4523f 100644 --- a/manifest +++ b/manifest @@ -1,13 +1,13 @@ -C Merge\sup\sall\sthe\s3.35.3\schanges\sinto\sthe\sbegin-concurrent-pnu-wal2\sbranch. -D 2021-03-26T14:04:34.993 +C Merge\slatest\schanges\sfrom\swal2\sinto\sthis\sbranch. +D 2021-05-21T17:31:04.357 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 -F Makefile.in 39bea9c761b58790b94369abfb9257baa459e74fb226c5a44176a62d265944a5 +F Makefile.in 5d28a7a46c2700c518469b9c5720b22d386293ecdd44f148a9a6c69d191e7c3e F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241 -F Makefile.msc 670a8d12f5ddf61c38217a011e63065cbb2ae4585c0b5844137e9c3d384dedb0 -F README.md 1514a365ffca3c138e00c5cc839906108a01011a6b082bad19b09781e3aa498a -F VERSION 75575cade3e93b31a84ffcb0d40de856a49bd3e4c1028dff52432bfae9806adb +F Makefile.msc 264c5fe9c681611178d163e61d38f98cea592914e92d0b98b5538c617199243a +F README.md 2a71913f398ecac5f3e10945fcf438aed425c2e9ed9874de561156ba77fb7023 +F VERSION 8c392f6d70d82e513a0eac622bdf23c43df3e084cb630288beba8cef3012c812 F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2 F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90 @@ -15,7 +15,7 @@ F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2 F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903 F autoconf/Makefile.am a8d1d24affe52ebf8d7ddcf91aa973fa0316618ab95bb68c87cabf8faf527dc8 F autoconf/Makefile.fallback 22fe523eb36dfce31e0f6349f782eb084e86a5620b2b0b4f84a2d6133f53f5ac -F autoconf/Makefile.msc ebe7e66edbb2f453593cbde186d1a0fa0dcd8cae9977febcae27aef1dab5678d +F autoconf/Makefile.msc d146a08ebbdf7f881ba600a49cd8dce40c4c807addcdb4b9b6a507e4b40ce837 F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7 F autoconf/README.txt 4f04b0819303aabaa35fff5f7b257fb0c1ef95f1 F autoconf/configure.ac a8ba2a9e61216f5093d44f3b7d2cb8fe1890d6b7dc330a02f802d8efaa1fdc79 @@ -34,12 +34,12 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63 F config.guess 883205ddf25b46f10c181818bf42c09da9888884af96f79e1719264345053bd6 F config.h.in 6376abec766e9a0785178b1823b5a587e9f1ccbc F config.sub c2d0260f17f3e4bc0b6808fccf1b291cb5e9126c14fc5890efc77b9fd0175559 -F configure 174eed3b99edc1c897fe32638c5b4068d4abfb282dc545ccc3ee92a472f73d7a x +F configure c658869fc056a2460a2212fb2960e410cd24e3fb9c55640fbc78d15b48810936 x F configure.ac 4e4b58b32f88c8da9914a2f2c3158f80e69907eccc019fcc7e3ba14ffd91c640 F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd F doc/begin_concurrent.md 4bee2c3990d1eb800f1ce3726a911292a8e4b889300b2ffd4b08d357370db299 -F doc/lemon.html 1bb72ece6271df0d901d233551dd985f2c6ba30d09382cf2d321ed951ab57491 +F doc/lemon.html efc0cd2345d66905505d98f862e1c571512def0ceb5b016cb658fd4918eb76a3 F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710 F doc/trusted-schema.md 33625008620e879c7bcfbbfa079587612c434fa094d338b08242288d358c3e8a F doc/vdbesort-memory.md 4da2639c14cd24a31e0af694b1a8dd37eaf277aff3867e9a8cc14046bc49df56 @@ -52,7 +52,7 @@ 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 63d778d964e55ef2d1a723043d91c59e7dc6ef1649d91c78c0bef00f9c6f1427 +F ext/expert/expert1.test 6703fd74711daf8230240680b0a348d0720e28819b602701adfbd32457fdcddd F ext/expert/sqlite3expert.c de51b187c629a4c4264d5de0b77862641e11426f7a963a92abf2d4077085fc8c F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72 @@ -86,25 +86,25 @@ 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 7b449348226a91cc851fe969f5c1932d4f00c359a32fd17f2afea92bf875147b +F ext/fts3/fts3.c 95f55e24550c01c2a325d09c9ea8fdff61e923a4675f8545b28bf3c470e57dfb F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe -F ext/fts3/fts3Int.h 045179f538c478ced266ca14327269cde8ad8d573c5be902230a5ebaa5636c59 -F ext/fts3/fts3_aux.c 96708c8b3a7d9b8ca1b68ea2b7e503e283f20e95f145becadedfad096dbd0f34 +F ext/fts3/fts3Int.h bde280294d56ff50ee29d03e5140f0b6953b44d1c969bb5831e8ae85e3e76715 +F ext/fts3/fts3_aux.c 1af58af8f2b00a49f4fb1c2602f8da2054ad60076f46c8ebf85c5410eccccb65 F ext/fts3/fts3_expr.c 5853cd7a35a79d193614add9b4c461b2d56f465d90899ca4309f05d9d1536558 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 86e7e947a176f0f005720b3ca17631aca2fd2f9daa6729d4adbf2d16ab1b9613 +F ext/fts3/fts3_snippet.c 57e1965906f3ecfcb5251a14aea98ac2d2dd1868a123bcd5a569601719ab9ead F ext/fts3/fts3_term.c f45a1e7c6ef464abb1231245d123dae12266b69e05cc56e14045b76591ae92d1 -F ext/fts3/fts3_test.c 73b16e229e517c1b1f0fb8e1046182a4e5dbc8dbe6eea8a5d4353fcce7dbbf39 +F ext/fts3/fts3_test.c d8d7b2734f894e8a489987447658e374cdd3a3bc8575c401decf1911cb7c6454 F ext/fts3/fts3_tokenize_vtab.c 8d15b148e7d88a4280389a200b26e8d52abda4c4ec2e9a35e9d7a1fa50e5aa03 F ext/fts3/fts3_tokenizer.c 6d8fc150c48238955d5182bf661498db0dd473c8a2a80e00c16994a646fa96e7 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 a5159accfd88f85fd3fc2298286d7a9427a02d1ea9a52b7c79730cff7a0bc03f +F ext/fts3/fts3_write.c aa751c4559a0d1b885206c5f4421c5b34a8ec7ea3d3d04127b7747a5a83a2f4e F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100 F ext/fts3/tool/fts3cov.sh c331d006359456cf6f8f953e37f2b9c7d568f3863f00bb5f7eb87fea4ac01b73 @@ -118,13 +118,13 @@ F ext/fts5/fts5.h c132a9323f22a972c4c93a8d5a3d901113a6e612faf30ca8e695788438c5ca F ext/fts5/fts5Int.h 26c74dd5776f798436fbf604a0bf0e8de263b35b5060b05c15f9085845d9fda2 F ext/fts5/fts5_aux.c f558e1fb9f0f86a4f7489e258c162e1f947de5ff2709087fbb465fddb7092f98 F ext/fts5/fts5_buffer.c 5a5fe0159752c0fb0a5a93c722e9db2662822709490769d482b76a6dc8aaca70 -F ext/fts5/fts5_config.c be54f44fca491e96c6923a4b9a736f2da2b13811600eb6e38d1bcc91c4ea2e61 -F ext/fts5/fts5_expr.c 016bd06030679bd31b0f07ef87d62c42031e5da25cb3174a84e5b0f6ef4b47b0 +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 df5e18b705ac601e826576298a5ce23ef1e5d417fbfdb3feb5f702f89e5f6f41 -F ext/fts5/fts5_main.c d77648a52b8d73d13887306149912e420f7e0b2d7b3d7da2f54152bfa140ac02 +F ext/fts5/fts5_index.c 222b5e56f51139ca5400985e26ea9971165901c7a45a2c17499bd2be3695c697 +F ext/fts5/fts5_main.c f497ca97cb2802311ec93733b595762dc5b044ce3c6c8ce5fb3e871dd3fccd5d F ext/fts5/fts5_storage.c 58ba71e6cd3d43a5735815e7956ee167babb4d2cbfe206905174792af4d09d75 -F ext/fts5/fts5_tcl.c 39bcbae507f594aad778172fa914cad0f585bf92fd3b078c686e249282db0d95 +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 @@ -162,13 +162,13 @@ 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 1cad09897fc69084a904c921dee7f777e1c866964ee2ec2cc7a8a69cc3f1ab68 +F ext/fts5/test/fts5corrupt3.test 7748c28d0a0c8f00e7741a097df7c76eed207b5443908621dd1ce1dd23b84a07 F ext/fts5/test/fts5corrupt4.test f4c08e2182a48d8b70975fd869ee5391855c06d8a0ff87b6a2529e7c5a88a1d3 F ext/fts5/test/fts5delete.test 619295b20dbc1d840b403ee07c878f52378849c3c02e44f2ee143b3e978a0aa7 F ext/fts5/test/fts5detail.test 31b240dbf6d44ac3507e2f8b65f29fdc12465ffd531212378c7ce1066766f54e F ext/fts5/test/fts5determin.test 1b77879b2ae818b5b71c859e534ee334dac088b7cf3ff3bf76a2c82b1c788d11 F ext/fts5/test/fts5dlidx.test b90852c55881b29dbac6380b274de27beae623ac4b6d567c6c8fb9cdc315a86e -F ext/fts5/test/fts5doclist.test e39a6001495f1dc68e20323586ac965787986c2bf6f515b9b0285627b089d9e6 +F ext/fts5/test/fts5doclist.test faa9e9cc3c0645fa6203667cb5f007c359447c6ee66753f71a58175c2497cacd F ext/fts5/test/fts5ea.test b01e3a18cdfabbff8104a96a5242a06a68a998a0 F ext/fts5/test/fts5eb.test 239bb2f02571f8cccfc7018d08f502df1cd8cc6a69b65ed1dde5f6a070e3f669 F ext/fts5/test/fts5fault1.test d28a65caee75db6897c3cf1358c5230d3bb2a3bf7fb31062c19c7e5382b3d2bd @@ -202,7 +202,7 @@ F ext/fts5/test/fts5near.test 211477940142d733ac04fad97cb24095513ab2507073a99c27 F ext/fts5/test/fts5onepass.test f9b7d9b2c334900c6542a869760290e2ab5382af8fbd618834bf1fcc3e7b84da F ext/fts5/test/fts5optimize.test 36a752d24c818792032e4ff502936fc9cc5ef938721696396fdc79214b2717f1 F ext/fts5/test/fts5phrase.test 13e5d8e9083077b3d9c74315b3c92ec723cc6eb37c8155e0bfe1bba00559f07b -F ext/fts5/test/fts5plan.test 79d35b5e83bbdcba48d946a7f008df161f6b0ede1a966892d0aa6c8dd0b6e773 +F ext/fts5/test/fts5plan.test b65cfcca9ddd6fdaa118c61e17aeec8e8433bc5b6bb307abd116514f79c49c5a F ext/fts5/test/fts5porter.test 8d08010c28527db66bc3feebd2b8767504aaeb9b101a986342fa7833d49d0d15 F ext/fts5/test/fts5porter2.test 0d251a673f02fa13ca7f011654873b3add20745f7402f108600a23e52d8c7457 F ext/fts5/test/fts5prefix.test a0fa67b06650f2deaa7bf27745899d94e0fb547ad9ecbd08bfad98c04912c056 @@ -221,7 +221,7 @@ F ext/fts5/test/fts5synonym2.test b54cce5c34ec08ed616f646635538ae82e34a0e28f947e F ext/fts5/test/fts5tok1.test 1f7817499f5971450d8c4a652114b3d833393c8134e32422d0af27884ffe9cef F ext/fts5/test/fts5tok2.test dcacb32d4a2a3f0dd3215d4a3987f78ae4be21a2 F ext/fts5/test/fts5tokenizer.test ac3c9112b263a639fb0508ae73a3ee886bf4866d2153771a8e8a20c721305a43 -F ext/fts5/test/fts5trigram.test e2ce256fd0ccd6707e740aa3596206aedb0d5834b100c0cb49e344dcd1d8463c +F ext/fts5/test/fts5trigram.test 5b4feb53a4d5aca70c841f6919c8719b5a9c805474727dda99285fccdd2e9cce F ext/fts5/test/fts5umlaut.test a42fe2fe6387c40c49ab27ccbd070e1ae38e07f38d05926482cc0bccac9ad602 F ext/fts5/test/fts5unicode.test 17056f4efe6b0a5d4f41fdf7a7dc9af2873004562eaa899d40633b93dc95f5a9 F ext/fts5/test/fts5unicode2.test 9b3df486de05fb4bde4aa7ee8de2e6dae1df6eb90e3f2e242c9383b95d314e3e @@ -288,27 +288,27 @@ F ext/lsm1/tool/mklsm1c.tcl f31561bbee5349f0a554d1ad7236ac1991fc09176626f529f607 F ext/misc/README.md d6dd0fe1d8af77040216798a6a2b0c46c73054d2f0ea544fbbcdccf6f238c240 F ext/misc/amatch.c e3ad5532799cee9a97647f483f67f43b38796b84b5a8c60594fe782a4338f358 F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb -F ext/misc/appendvfs.c bdc9de0a0e61c21327e975da178b4fd6f57de9c46123044aa6ee3a20798c5db2 +F ext/misc/appendvfs.c 500fef0736caafc629ca1dbae348a121367eaa4ed8c385c291cb9ad65ea790fb F ext/misc/bgckpt.c 49ae19aa03e6da393db5d17da256374d4c4d36889fdd89d6e4bc93aca2b752e6 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/cksumvfs.c 8dc4e1b718e374bed3a9b5c0a08da2922438002e33267311697768e06217b983 +F ext/misc/cksumvfs.c 2c6b07714f3be6c1200671c53aa781a86d2c472c0fcb2fff520375362eb94303 F ext/misc/closure.c dbfd8543b2a017ae6b1a5843986b22ddf99ff126ec9634a2f4047cd14c85c243 F ext/misc/completion.c 6dafd7f4348eecc7be9e920d4b419d1fb2af75d938cd9c59a20cfe8beb2f22b9 F ext/misc/compress.c 3354c77a7c8e86e07d849916000cdac451ed96500bfb5bd83b20eb61eee012c9 F ext/misc/csv.c 53b3338d4fa812eda51a2637df30233a4dae16b964ee5666e2051b9672ed8bb4 F ext/misc/dbdata.c e316fba936571584e55abd5b974a32a191727a6b746053a0c9d439bd2cf93940 F ext/misc/dbdump.c b8592f6f2da292c62991a13864a60d6c573c47a9cc58362131b9e6a64f823e01 -F ext/misc/decimal.c 3ddbf8162015be4d5ec2395dee4538f1e638bb517174bb148274b132df6e1d08 +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/fossildelta.c 1240b2d3e52eab1d50c160c7fe1902a9bd210e052dc209200a750bbf885402d5 F ext/misc/fuzzer.c eae560134f66333e9e1ca4c8ffea75df42056e2ce8456734565dbe1c2a92bf3d F ext/misc/ieee754.c cd6ab89f85fda8a020559b3f4d03001a8a62dd856beda5af3f558621d12be913 -F ext/misc/json1.c f31e89171f932d1821c91f10d2cb4979fc0447030030a8bce70420cd43d074c0 +F ext/misc/json1.c 2c5c0dbc7fa303f0213f008e5878db9f0e5875fe8ff59a7c2d9f235b18e323a7 F ext/misc/memstat.c 3017a0832c645c0f8c773435620d663855f04690172316bd127270d1a7523d4d F ext/misc/memtrace.c 7c0d115d2ef716ad0ba632c91e05bd119cb16c1aedf3bec9f06196ead2d5537b F ext/misc/memvfs.c ab36f49e02ebcdf85a1e08dc4d8599ea8f343e073ac9e0bca18a98b7e1ec9567 @@ -340,10 +340,10 @@ F ext/misc/vfsstat.c 389ea13983d3af926504c314f06a83cc858d5adc24b40af74aaed1fece0 F ext/misc/vtablog.c 5538acd0c8ddaae372331bee11608d76973436b77d6a91e8635cfc9432fba5ae F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd F ext/misc/wholenumber.c a838d1bea913c514ff316c69695efbb49ea3b8cb37d22afc57f73b6b010b4546 -F ext/misc/zipfile.c e35e035bc2765b1ccdcb15f9815c2112843fcbc8f36aa071f0e5935df7072228 +F ext/misc/zipfile.c acbad31bd9c9ec3540fa72b2e3fcd6f757eb33117d51528c0e13d0da5c836908 F ext/misc/zorder.c b0ff58fa643afa1d846786d51ea8d5c4b6b35aa0254ab5a82617db92f3adda64 F ext/rbu/rbu.c b880ca5cb857d6d6f52e72eb7397813058ef48c78c5402cd04ff2b6b5437f622 -F ext/rbu/rbu1.test 221d9c18a5e600ac9ac6b1810d99d9f99163a7909ba61597876ab6e4d4beb3d6 +F ext/rbu/rbu1.test c62904bd9526dcdc3496a21199aaf14ae191bbadbf67f076bf16be6b3f2115c2 F ext/rbu/rbu10.test 0a201c32202143f23c81c0144503da339786fc20acb7a2fda11601b65659f314 F ext/rbu/rbu11.test 5c834cf491086b45e071eabf71f708febc143e86a384a92de69e0b1a4cace144 F ext/rbu/rbu12.test 29f8b2118f6c96fac3755bd6d2b55c2db24f878b1f11fbfbe294f3a230a3dcdc @@ -382,7 +382,7 @@ F ext/rbu/rbuvacuum.test 55e101e90168c2b31df6c9638fe73dc7f7cc666b6142266d1563697 F ext/rbu/rbuvacuum2.test b8e5b51dc8b2c0153373d024c0936be3f66f9234acbd6d0baab0869d56b14e6b F ext/rbu/rbuvacuum3.test 8addd82e4b83b4c93fa47428eae4fd0dbf410f8512c186f38e348feb49ba03dc F ext/rbu/rbuvacuum4.test a78898e438a44803eb2bc897ba3323373c9f277418e2d6d76e90f2f1dbccfd10 -F ext/rbu/sqlite3rbu.c e6531884442b72f9e0ba47036fb5c4641ea817ff659a642b3984c10b8535b0fd +F ext/rbu/sqlite3rbu.c badb52388467f58e67ef104c5276d1ac68b316a30f8ccb2f74eac733625ae236 F ext/rbu/sqlite3rbu.h 1dc88ab7bd32d0f15890ea08d23476c4198d3da3056985403991f8c9cd389812 F ext/rbu/test_rbu.c 03f6f177096a5f822d68d8e4069ad8907fe572c62ff2d19b141f59742821828a F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15 @@ -395,21 +395,21 @@ 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 1b1ddecb79877b12331d35de9f393b80bbb731e0bf6db6c572f23191987ea803 -F ext/rtree/rtree.c 60f6f1675134201974be4189dbd219494c13e1ed30e80bd92ae0dcc86df1b035 +F ext/rtree/geopoly.c 98d45533989e908bf65b43f36ff6eaad95a9ffe6f3b6b8658fbd47d45c58b10b +F ext/rtree/rtree.c f1ce6a86f7cbff634900653bec2dfeba732dd4450eec921c0ac3851d41f462b9 F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412 F ext/rtree/rtree1.test 00792b030a4e188ff1b22e8530e8aa0452bb5dd81c2b18cb004afc7dc63e040e F ext/rtree/rtree2.test 9d9deddbb16fd0c30c36e6b4fdc3ee3132d765567f0f9432ee71e1303d32603d F ext/rtree/rtree3.test 4ee5d7df86040efe3d8d84f141f2962a7745452200a7cba1db06f86d97050499 F ext/rtree/rtree4.test 304de65d484540111b896827e4261815e5dca4ce28eeecd58be648cd73452c4b F ext/rtree/rtree5.test 49c9041d713d54560b315c2c7ef7207ee287eba1b20f8266968a06f2e55d3142 -F ext/rtree/rtree6.test 1252a0439da01d2f1f5cbbdeeb80455a2d68b9bae2a9787937b167a5e3957828 +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/rtreeB.test 4cec297f8e5c588654bbf3c6ed0903f10612be8a2878055dd25faf8c71758bc9 -F ext/rtree/rtreeC.test 6aa87eba4d9a3003b941a1ba77db259c5cabc3fd92fc5a6360f5369520eb9a4d +F ext/rtree/rtreeC.test c4bfa9a61c6788c03e4a9ce40ab2cfc6100982559effd9842d1b658e1d47aa5f F ext/rtree/rtreeD.test fe46aa7f012e137bd58294409b16c0d43976c3bb92c8f710481e577c4a1100dc F ext/rtree/rtreeE.test e65d3fc625da1800b412fc8785817327d43ccfec5f5973912d8c9e471928caa9 F ext/rtree/rtreeF.test 81ffa7ef51c4e4618d497a57328c265bf576990c7070633b623b23cd450ed331 @@ -421,7 +421,7 @@ 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/rtreefuzz001.test eef1ed593bb15886cd5d5367a2f2492f81e315848896cdf7afb6e21454978827 +F ext/rtree/rtreefuzz001.test 0fc793f67897c250c5fde96cefee455a5e2fb92f4feeabde5b85ea02040790ee F ext/rtree/sqlite3rtree.h 03c8db3261e435fbddcfc961471795cbf12b24e03001d0015b2636b0f3881373 F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de F ext/rtree/util/randomshape.tcl 54ee03d0d4a1c621806f7f44d5b78d2db8fac26e0e8687c36c4bd0203b27dbff @@ -458,20 +458,21 @@ F ext/session/sessioninvert.test 04075517a9497a80d39c495ba6b44f3982c7371129b89e2 F ext/session/sessionmem.test f2a735db84a3e9e19f571033b725b0b2daf847f3f28b1da55a0c1a4e74f1de09 F ext/session/sessionnoop.test a9366a36a95ef85f8a3687856ebef46983df399541174cb1ede2ee53b8011bc7 F ext/session/sessionrebase.test ccfa716b23bd1d3b03217ee58cfd90c78d4b99f53e6a9a2f05e82363b9142810 +F ext/session/sessionsize.test 6f644aff31c7f1e4871e9ff3542766e18da68fc7e587b83a347ea9820a002dd8 F ext/session/sessionstat1.test 218d351cf9fcd6648f125a26b607b140310160184723c2666091b54450a68fb5 F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc F ext/session/sqlite3changebatch.c d5553b79e012ee2cb06c0a96bdf9dfe19e66354390ea0036cc46c4953142d517 F ext/session/sqlite3changebatch.h e72016998c9a22d439ddfd547b69e1ebac810c24 -F ext/session/sqlite3session.c 5eb3a3cb490912376c5720d24eb256753e4a29a2a62f39ac708a084d854b4fea -F ext/session/sqlite3session.h cae11f96e40915220076acf4d7b3e4eb26f817d92064bd5983d47f9fe7f31ec6 -F ext/session/test_session.c 18372dfe254a219705f89bc95c5ef26744236c4dbac5cdfbe71959290afc928d +F ext/session/sqlite3session.c 381b2437cd5607193b5bf4c07b7f6026adfd7a3258435af1ee8f833eaf935b99 +F ext/session/sqlite3session.h 01807bb8c8f531c23052032e9d531eec49af79b7394f8213cf5a49784325b6a8 +F ext/session/test_session.c 226461035031632255c8098f3bcfa4ea27f0b051efd88857a2a36bcea5c294b9 F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3 F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04 F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 -F main.mk 884bf69d5658fdb71862a7e4bab17bdd7fd3c6782992f6879d2ea95d7c024af5 +F main.mk 026b21dfd84fccc01479857995685246ddabc6f7d28e9079cdd5ca89874912cd F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504 @@ -483,44 +484,44 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a -F src/alter.c 2d631213818b654faaf08755f26e934134c4769757ae9286981401cd6b571081 +F src/alter.c df53c39fd4f32528fc7ad8188b3bf2b506e1a8b3bb975b14f16a1bc6e901950f F src/analyze.c 01c6c6765cb4d40b473b71d85535093730770bb186f2f473abac25f07fcdee5c -F src/attach.c 9cbe761e464025694df8e6f6ee4d9f41432c3a255ca9443ccbb4130eeb87cf72 +F src/attach.c a514e81758ba7b3a3a0501faf70af6cfc509de8810235db726cfc9f25165e929 F src/auth.c 08954fdc4cc2da5264ba5b75cfd90b67a6fc7d1710a02ccf917c38eadec77853 F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d F src/bitvec.c 8433d9e98dd6f2ea3286e0d2fe5d65de1bfc18a706486eb2026b01be066b5806 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c 0ee2ae302a6e6985f655f3ebcf0e7fc61d0963da66c512780b0bf0709372d8e6 +F src/btree.c 8869176dd073fef60c2fab8074ea84fafd3edfdec21a60cbe3e91832e0d4dde0 F src/btree.h ccdc64bd1eee7ba79d4c0b2af22b6df1e5ededdbf9606f45f4fca4738dd6fa0b F src/btreeInt.h 1e9f10107a4ec5d2940ae5b859242ae83b81402986724bed08b8491a5ea64a4d -F src/build.c 9f06854962aad6b5d465c38f9f6e8c307028fbb4efa9fccb0531f0874bd088df +F src/build.c b470cd22b984fcb9c35ae24855b2a167a83098f56fbad744291df421570ec5cc F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e -F src/ctime.c 2a322b9a3d75771fb4d99e0702851f4f68dda982507a0f798eefb0712969a410 +F src/ctime.c 3052b6b05ed9ef547a3dd66b8e01bfa9d582e78752ad6ed327da84652641e038 F src/date.c e0632f335952b32401482d099321bbf12716b29d6e72836b53ae49683ebae4bf F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a F src/dbstat.c 3aa79fc3aed7ce906e4ea6c10e85d657299e304f6049861fe300053ac57de36c F src/delete.c 73f57a9a183532c344a3135cf8f2a5589376e39183e0b5f562d6b61b2af0f4d8 -F src/expr.c d681f0b48b1e16173ad8e1e8f7323cda120a0c517cb7a3d5b329c4e2c57f18bd +F src/expr.c c56c74d40d1ca5359177f1425d2eb2aa050c30da0b49e014da1f109aa38ece0f F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c e9063648396c58778f77583a678342fe4a9bc82436bf23c5f9f444f2df0fdaa4 -F src/func.c e701e9a1cbc2e1814d381ce781925c2e8776cdf994e7c17f53578ec3cc7af40a -F src/global.c ed55af196a9b66e198aaeda3f5454c3aa7d7d050c6c938181fd044b70d180a81 +F src/func.c 0e97ea309f882c4045a73d25219d816e60d2baf3c60068bb5d74f801a46355a9 +F src/global.c 25ba4d58476f6be29bba9d9d14f7f146b78476d3a4d75ebb8c3b736328afe0f9 F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c e36be69e3810902eaf7e171260c885bc9547b1d41616c868f1cc46e6a0a3b7fd +F src/insert.c 2189e0e596010a0dc5405d9f14f78db1ee2fa71138c931f5b6ea96610b95bfc1 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067 -F src/main.c 5becd80bb8369fe73cea609ac830dd43453d0a356c56ef361fd74698988484a0 +F src/main.c 28f45be66f575edf05465a2bc91ec50ebff6bb49099ef884f4dd506d83fd7769 F src/malloc.c c1af4ac5a463648cd2953fd4ac679b3ba9022ce5ec794a60806150ad69dfd33a F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de F src/mem2.c b93b8762ab999a29ae7751532dadf0a1ac78040308a5fb1d17fcc365171d67eb F src/mem3.c 30301196cace2a085cbedee1326a49f4b26deff0af68774ca82c1f7c06fda4f6 F src/mem5.c 9bf955937b07f8c32541c8a9991f33ce3173d944 -F src/memdb.c ab0632d42407e866d2b616bd19d4211ac0ad1b430f04c4e187d60005b8700b98 +F src/memdb.c f6ce717b26cd51a24cda62fce611b4b72b3db367113374aa498e489a69470715 F src/memjournal.c 431c70a111223a8a6e2e7e9f014afc6c88d818d357d866afc563195f2277d50e F src/msvc.h 3a15918220367a8876be3fa4f2abe423a861491e84b864fb2b7426bf022a28f8 F src/mutex.c 5e3409715552348732e97b9194abe92fdfcd934cfb681df4ba0ab87ac6c18d25 @@ -529,44 +530,44 @@ 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 2d6e646370b1aa78942c68d7edf124e518963adf4a90bce87f365a5a5495529a +F src/os.c 6e94cd64b134c9317e52ad534117578e3df66ec180d70dbf4b1d7eb1db8e5a5d F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432 F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85 F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586 -F src/os_unix.c f0d42250fcded6615ff81af94c7b3005dc2a52d67467b4d7ca2b29427019e2b1 +F src/os_unix.c 430266b3c1fcd3868c2db04a504a78b9a71de82092fc511e968919a0d661f7eb F src/os_win.c 77d39873836f1831a9b0b91894fec45ab0e9ca8e067dc8c549e1d1eca1566fe9 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a -F src/pager.c 964ebfc5105bdfe1b85fcdcd8b79fc3b971c994d2eaffa8a9dde288d3091e356 +F src/pager.c 08f6583f5463ea4e0d1a584455a321bbf66475fa33e740ea5731751558e77ae2 F src/pager.h 034a193e53d6649bdb641aa996e38094dbb7cbe365d8c10eba871a38a0f5ebb3 -F src/parse.y 3a7f2156485e377a637b4217b797001cf2ed9228e501f8d34fd06a9f46a40a73 +F src/parse.y 68f3bdc6ab07f5660944cde812318eab6007416fd1ea008422a96f1675c75ff2 F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177 F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c 388304fd2d91c39591080b5e0f3c62cfba87db20370e7e0554062bfb29740e9f F src/pragma.c 4577091a839722cd74e5492f10dc238a93751f4bcc0c8c9ee572d7592f3936be F src/pragma.h b93fd693bd38cefeaf8e2c7e8c929717f7799a9770104cdd2bae8df2a84e2da7 -F src/prepare.c e21b54489b5c73b06ada15e6fc79b5c6f64b06701924a6ca98944ae59e06256f -F src/printf.c 2b03a80d7c11bb422115dca175a18bf430e9c9dbaa0eee63b758f0c022f8f34f +F src/prepare.c d778af9986f3b0107c5b255dcfe2696e8e99e00fb77c5115bbfea4e92c3302e7 +F src/printf.c 78fabb49b9ac9a12dd1c89d744abdc9b67fd3205e62967e158f78b965a29ec4b F src/random.c f27af4099afaea7284ade5c206224dcfdb2334cfd119d018b470d46356b3f27d -F src/resolve.c dd47248c2c914feb0d4428c27d782e2723971d32cfa5536f49306d080df4d45a +F src/resolve.c 40e216d9a72e52841a9c8e0aec7d367bade8e2df17b804653b539b20c1ab5660 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c bdcfed8ae9cb311f145fd204be32e3d03f7bf359c796159900d1eec0b557991b -F src/shell.c.in aa28256887d049badaf93aa30ab5c76a2ec88143a674d685c0e739056702e5c3 -F src/sqlite.h.in 71ba363afc97d615d43ab4d1c6992036e82efb799852fe96106b79c94bb87f7f +F src/select.c 52ed98f39e1629ccf568b372f29b376ca6007158a46cdd956dbdcf8cab05fc89 +F src/shell.c.in 1b32ba2918ede13b68df47c7b92b72ba0d06e68d384e78bb9d7456527271d400 +F src/sqlite.h.in a5d8462d3c5a45240a258e6ed401b6fc14b7f4d2e00e94b864c31fc019151ce1 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e -F src/sqliteInt.h c4fd0becfa9115e307446ed62228c8c6007ddd03d84b9376ab1bba09ea28a9c3 +F src/sqliteInt.h 00259853d647cd714b93834ffef171d242077629e8fa905c9f19de3995c046c8 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 -F src/tclsqlite.c 986b6391f02cd9b53c1d688be55899f6ffddeb8e8014cd83c1b73ff912579a71 -F src/test1.c 6de6fac373fbf2533e8e772543398cb826d09e6aa38e199a496e09e2a4d1c75d +F src/tclsqlite.c 97645e4a15dde6a6ad6de8d81057ff9869413b866015a89e208fedacd709493e +F src/test1.c bb6fe83c5a0e255930c14cc6f0b29414410661839fcdd95015abed823df636b4 F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5 F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644 F src/test4.c 7c4420e01c577b5c4add2cb03119743b1a357543d347773b9e717195ea967159 F src/test5.c 328aae2c010c57a9829d255dc099d6899311672d F src/test6.c ae73a3a42bbc982fb9e301b84d30bda65a307be48c6dff20aba1461e17a9b0ce F src/test7.c 5612e9aecf934d6df7bba6ce861fdf5ba5456010 -F src/test8.c 7fb971777c2c79c734bb52757191d68d4af659b8de9b4a071be3f527a9d19a02 +F src/test8.c 0c856d6ff6b0d2ff6696addc467a15ed17c6910f14475302cd5b3b4e54406161 F src/test9.c 12e5ba554d2d1cbe0158f6ab3f7ffcd7a86ee4e5 F src/test_async.c 195ab49da082053fdb0f949c114b806a49ca770a F src/test_autoext.c 915d245e736652a219a907909bb6710f0d587871 @@ -574,7 +575,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 21aa5fc3e6bb11c60ba7f9a33b73951af8cb7a2042355f07469146b7e5e36765 +F src/test_config.c 7768197f40225aacf0ab4a325b0c30c0dd6ebdf2c64f62da90ad5d4989b42bf5 F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf9f8f F src/test_demovfs.c 86142ba864d4297d54c5b2e972e74f3141ae4b30f05b3a95824184ed2d3d7f91 F src/test_devsym.c aff2255ea290d7718da08af30cdf18e470ff7325a5eff63e0057b1496ed66593 @@ -613,34 +614,34 @@ 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 0b9c82fa628b5adce93e2bcaf935a24d43eb83344fb51551f7835526d0693fc4 -F src/treeview.c c6260e1fa5f41c361b2409edc9b0050bcaef5bc4d6abc467fbc45f0d7ccf3d84 -F src/trigger.c 861c3ec2c5b0fc830bdf82470454a9324fad70cbaa96d2e208fb54577c9e8d28 -F src/update.c 254aa78e23a18767a5d55b9d7efb6d808b1fcfd52124c774fa7868546f2ca2af +F src/tokenize.c bae853ad129d1129c063de8630a3e99e306283bc40146f359b1bb91be2c08f1e +F src/treeview.c e483aeedf6f207000db1f90eb6abd816350493314c30e8749d319bdb9ab3b08c +F src/trigger.c e0fd347b2571a2d956318cdc6d011ccca7ce862d10a0ca04188a37920ef5440c +F src/update.c e94570c89b2e339a7ae3e9f7f031ec69487112983e86608d93a8b1171be8b7da F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c 41c7a72da1df47864faa378a1c720b38adb288c6838cb6be5594511b6287a048 F src/vacuum.c 9d6ac090ff36d80f0a2c5bfc63994b714c464bfc44efa5056c457a6a4163dc99 -F src/vdbe.c cb96a5890cab40cf01511296b61c1720df5b421e426ca3e7358d183dad906468 +F src/vdbe.c 52918feb4b91ac67b45990105101818a0c1887a9ba2ad000345f7bdca0fb4bc1 F src/vdbe.h 25dabb25c7e157b84e59260cfb5b466c3ac103ede9f36f4db371332c47601abe -F src/vdbeInt.h 000d9ab1ea4cb55a80de15e28f3f595645b4fddef34bca4347fb3db8031d9041 -F src/vdbeapi.c 4a43e303ec3354c785f453e881521969378e85628278ab74ba4a9df790c0d93b -F src/vdbeaux.c cf79a11bff51f6b99fc898d10117f4ec289edd92858fae313a3ff8c4f0c60f0f -F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1 -F src/vdbemem.c 947f2a65910edb4014dc981d33e414a68c51f169f9df8c4c493a0ba840b6eb1f +F src/vdbeInt.h 58980223a32495ad059d10581b83e133abdc77248b1bab85c080cab8a13bd819 +F src/vdbeapi.c d9e99daf59fec928986838b3389a7337e82fec6b3b5de30206cb99fb4661b94e +F src/vdbeaux.c 708f3479a4b1f895f654e29b4fa597ee4c2927ecde3a27ed07dda964a3a12b3a +F src/vdbeblob.c c6b8db50b227f66fb404215732068df76485b5b433e5f9d4d9ac27410b218193 +F src/vdbemem.c 175c73ced03edbb0f6567a41c8032afaeb83372090fa7bddfc88a67e28da2b8a F src/vdbesort.c f5b5e473a7cee44e47a94817b042fd7172cf3aa2c0a7928a8339d612bcfdec5a F src/vdbetrace.c 666c6fd9f1b62be6999e072a45b913e3c2c3518bc60dfd4d54fe304130acb724 F src/vdbevtab.c f99b275366c5fc5e2d99f734729880994ab9500bdafde7fae3b02d562b9d323c -F src/vtab.c 032a0165c147fda16927e6a3230e90c068d4af93f887ce94e26f678fe48e5e4c +F src/vtab.c b928405ccb66040fc6c3a11eaa93ddb02cbf20f9ab6860b301b222b9b50dc089 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 -F src/wal.c 14561b22781dbf67ec97dddce537e31c1419f94e06d548d2d26cb5c44552ecda +F src/wal.c 24068dd5d1c25d55d4fb6e362edc2fa680a85ced86a9650d88ab3edaecb1035d F src/wal.h 7a733af13b966ecb81872ce397e862116b3575ea53245b90b139a2873ee87825 -F src/walker.c d42d6c80ea363ef689a462e65eefcfe87deab924c50de5baa37ecb6af7d7ddaa -F src/where.c 10d06b16670a1d2a992d52a9f08e49426d38a08fb0a7ae5f7f62fd023d560e1e -F src/whereInt.h 446e5e8018f83358ef917cf32d8e6a86dc8430113d0b17e720f1839d3faa44c4 -F src/wherecode.c e57a8690311a75d06e723e8d379f9831de04aba300e07174d236e32a7f9c7a13 -F src/whereexpr.c 53452fe2fb07be2f4cb17f55cc721416fae0092c00717f106faf289c990b6494 -F src/window.c 7e89ac4b6cd6bb9b7772234a625d19c39b530f4ac06e43688a8b7e6a1ab512a2 +F src/walker.c 7342becedf3f8a26f9817f08436bdf8b56ad69af83705f6b9320a0ad3092c2ac +F src/where.c 32f41c3c93c6785e0077e3a2cdc669c3ccfe70173787847be77f294c18fc7dc3 +F src/whereInt.h 9248161dd004f625ce5d3841ca9b99fed3fc8d61522cf76340fc5217dbe1375b +F src/wherecode.c 110ed13049e0f1dc27e9dd942eb870417b36480cb7819302f5804cbcf9330b0e +F src/whereexpr.c 5a9c9f5d2dac4bcdcaae3035034b4667523f731df228e0bb1d4efc669efa9da5 +F src/window.c ce5e73ab88a8527d268673906bf89cbe58c61bca8d54d38ed8c33c3220a276ee F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 F test/affinity3.test eecb0dabee4b7765a8465439d5e99429279ffba23ca74a7eae270a452799f9e7 @@ -651,34 +652,35 @@ F test/all.test 2ecb8bbd52416642e41c9081182a8df05d42c75637afd4488aace78cc4b69e13 F test/alter.test f53d8a4ecd35f051c07e54a36beec5d0a30d30a9d98bc723f6cde6afbfb3c5ca F test/alter2.test a966ccfcddf9ce0a4e0e6ff1aca9e6e7948e0e242cd7e43fc091948521807687 F test/alter3.test e487958dec7932453e0b83baf21d6b1e71d5e7d9a55bc20eadfa62a51ddffc29 -F test/alter4.test dfd6086faf461b27ca2d2999848dcd207edf23352fc1592d0005c0844f3f08cf +F test/alter4.test 716caa071dd8a3c6d57225778d15d3c3cbf5e34b2e84ae44199aeb2bbf50a707 F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256bafc959 -F test/alterauth2.test 794ac5cef251819fe364b4fe20f12f86e9c5d68070513c7fd26c17cb244c89af -F test/altercol.test 3456f7cc4196ef8f7d82d245d6e91940eb12bc95c36c91ac4b512f6b5c9a4fa9 +F test/alterauth2.test 381b1ab603c9ef96314a3158528ea17f7964449385a28eeaf8191120b2e24a8d +F test/altercol.test b11fa1b131e80ab5b6ecfb3b725fb0419c14ca6efba5adb57aeabfc9baa0c8f3 F test/altercorrupt.test 584d707a80e106952d6382790c8919bcf9f0db678ed3a1c09fd98b7f9d1d3a10 -F test/alterdropcol.test 596623cb8a72d9570bfb8417b0f302810efe007873796f03c17a9e9ff28dade1 +F test/alterdropcol.test a653a3945f964d26845ec0cd0a8e74189f46de3119a984c5bc45457da392612e F test/alterdropcol2.test 527fce683b200d620f560f666c44ae33e22728e990a10a48a543280dfd4b4d41 F test/alterlegacy.test f38c6d06cda39e1f7b955bbce57f2e3ef5b7cb566d3d1234502093e228c15811 F test/altermalloc.test 167a47de41b5c638f5f5c6efb59784002b196fff70f98d9b4ed3cd74a3fb80c9 F test/altermalloc2.test fa7b1c1139ea39b8dec407cf1feb032ca8e0076bd429574969b619175ad0174b -F test/altermalloc3.test 2c7bbd8cf3e9c4a91e28675bb62bcc2ef70f227967fa74349f03d9f4642f0615 -F test/altertab.test 7691872aadfe00a94b459af9086504bcf399dd936336e486da1b182930744b77 +F test/altermalloc3.test 059841a3de6b6780efd9f0b30bf1d9b4443c555f68d39975cbcac2583167b239 +F test/alterqf.test 67568ad152db8c1187b15633b801242cf960f1beafc51261a3d1725d910baeb2 +F test/altertab.test c7966d92e4da535050b911e1e9972ecb3a5befb0b2d22026b132cf5003d43dec F test/altertab2.test b0d62f323ca5dab42b0bc028c52e310ebdd13e655e8fac070fe622bad7852c2b F test/altertab3.test 2b82fa2236a3a91553d53ae5555d8e723c7eec174c41f1fa62ff497355398479 F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f F test/analyze.test 547bb700f903107b38611b014ca645d6b5bb819f5210d7bf39c40802aafeb7d7 -F test/analyze3.test fca2a9de0017becfdcc201647f03b1cfd5ba0e7b5b5c852936e4ec62780cde49 -F test/analyze4.test cdf88f3f72b0f0643a1ff6c730fc5af1e42464d47478d9fbac84c333f72c014e +F test/analyze3.test 4440c4932247adb2b4e0c838f657c19dc7af4f56859255436dc4e855f39b9324 +F test/analyze4.test 293ec8ea21525f3435beaf9d6b1efb29e719415f03a0cd2a70589d59098e8464 F test/analyze5.test fa5131952303ac4146aba101b116b9c8cb89e2637531c334a6df7f7d19dddc0d -F test/analyze6.test 6c3f7df2996cb6872f355a6ac1eb6d5de00a5a9288214bad7ef25c97d9cc72dc -F test/analyze7.test 6ef0b12369f61ddeadc7d8a705c40e6b52cb29f63de3a4c56581b510b46b5783 -F test/analyze8.test 36ce54947710bd44e4f9484e1ad07e725ef01a9d7078b417c1bc884356febe4d -F test/analyze9.test 9fbf0e0101eef4f5dc149769aa14e10b76ee06e7c28598264b32173cd1999a54 -F test/analyzeC.test 489fe2ea3be3f17548e8dd895f1b41c9669b52de1b0861f5bffe6eec46eac710 -F test/analyzeD.test e50cd0b3e6063216cc0c88a1776e8645dc0bd65a6bb275769cbee33b7fd8d90c -F test/analyzeE.test 8684e8ac5722fb97c251887ad97e5d496a98af1d -F test/analyzeF.test 9e1a0537949eb5483642b1140a5c39e5b4025939024b935398471fa552f4dabb -F test/analyzeG.test a48c0f324dd14de9a40d52abe5ca2637f682b9a791d2523dd619f6efa14e345b +F test/analyze6.test 028f5bdfc9e5b5294768fa9a7185b8cd1d019aa7aab5b2f8ee42d7271d9a3b28 +F test/analyze7.test 079d17c495e396bdbd6cc6a083112788a6fbfb3b95c42e760e4270a53c9ead8f +F test/analyze8.test 29ef237d8a59b39cc31c3310134fefe96a690b195e3deed5ecb652839089f15c +F test/analyze9.test 162cd40d713310fbe7a63a5ecff5d3a013777d86809618838177d9b2af4dd09c +F test/analyzeC.test 1111830ad355d29a294a5dda654dd5f6a8622c6a223a4f7b7b3d091df7a7a42b +F test/analyzeD.test 485f621cfd2ef0a8f8ac79672586651bfa495bd899db50461bb4b558400ab3c1 +F test/analyzeE.test 69d130f9ba78c9853dcd5a18317e81f462a72d704cec0c4c30afb220213acd29 +F test/analyzeF.test 40b5cc3ad7b10e81020d7ca86f1417647ecfae7477cfd88acc5aa7ae1068f949 +F test/analyzeG.test 623be33038c49648872746c8dd8b23b5792c08fef173c55e82f1b12fca259852 F test/analyzer1.test 459fa02c445ddbf0101a3bad47b34290a35f2e49 F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b @@ -692,18 +694,18 @@ F test/atrc.c c388fac43dbba05c804432a7135ae688b32e8f25818e9994ffba4b64cf60c27c F test/attach.test 54f8e49e88d0de48f6428267a678465863d2b8f72320612f35bd5c02e240bc2f F test/attach2.test 256bd240da1835fb8408dd59fb7ef71f8358c7a756c46662434d11d07ba3a0ce F test/attach3.test c59d92791070c59272e00183b7353eeb94915976 -F test/attach4.test aa05b1d8218b24eba5a7cccf4f224f514ba57ba705c9267f09d2bb63fed0eea1 +F test/attach4.test 00e754484859998d124d144de6d114d920f2ed6ca2f961e6a7f4183c714f885e F test/attachmalloc.test 12c4f028e570acf9e0a4b0b7fe6f536e21f3d5ebddcece423603d0569beaf438 F test/auth.test 2154625c05bc79f0e0ea72cb2358395a8041243caa0fd7ce7617d50da4331794 F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1 F test/auth3.test db21405b95257c24d29273b6b31d0efc59e1d337e3d5804ba2d1fd4897b1ae49 F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec F test/autoinc.test 997d6f185f138229dc4251583a1d04816423dddc2fc034871a01aeb1d728cb39 -F test/autoindex1.test 96185415f5faacd5b8d7a7f505efddd5abb1f111d58338e9c0b1dc40b87cd3cc +F test/autoindex1.test fe27af92eaf884bd9c38f94be3e8afa04ec494e5eefb189902026181a6175f5e F test/autoindex2.test 12ef578928102baaa0dc23ad397601a2f4ecb0df -F test/autoindex3.test 2dd997d6590438b53e4f715f9278aa91c9299cf3f81246a0915269c35beb790e +F test/autoindex3.test 2d13958a5617e987624a428d7aed91bf51f322b49b476e3573fadec697ce6da5 F test/autoindex4.test 49d3cd791a9baa16fb461d7ea3de80d019a819cf -F test/autoindex5.test a5d72fe8c217cc0ea356dc6fa06a282a8a3fc53aa807709d79dba07a8f248102 +F test/autoindex5.test ee0aa95e3f44190347a29a672c3d4ecf042e3f33c5fa3dc29f0ab6be057bbded F test/autovacuum.test 0831cd34e14695d297187f7f6519265e3121c5b0a1720e548e86829e796129e9 F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4 F test/avfs.test 0c3a38e03cccb0fc3127838462dc05dc3f4c1480d770c084b388304c25de3652 @@ -719,17 +721,17 @@ F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f F test/badutf2.test f310fd3b24a491b6b77bccdf14923b85d6ebcce751068c180d93a6b8ff854399 F test/bc_common.tcl b5e42d80305be95697e6370e015af571e5333a1c F test/bc_test1.c e0a092579552e066ed4ce7bcdaecfa69c4aacc8d -F test/bestindex1.test 705b57d7f51d53ee5fd043dd9666236e1fc18f4d59abf51da0ea5ea1b4804947 -F test/bestindex2.test 9a0ccd320b6525eec3a706aae6cdab7e1b7b5abca75027e39f39f755e76e5928 -F test/bestindex3.test 7622e792ff2da16d262d3cea6ad914591ac4806d57ed128e6c940b7920b47b84 -F test/bestindex4.test 038e3d0789332f3f1d61474f9bbc9c6d08c6bd1783a978f31f38ad82688de601 +F test/bestindex1.test 2e92e046148b3f8a2be62af9c0f307413547a33677af0df159c0fcc76e5134a2 +F test/bestindex2.test 60266e2854055788459cbfd86cef575601eabe74a2c61faba72601739fea4398 +F test/bestindex3.test e061a6ed0f519beee037ba7e7a4c37f80c8a7e4a303e2559ed1f760e4b0235eb +F test/bestindex4.test 82250e7dcc6d5b15244edc9d6554b1760583af1b8548c2a255a1c4f28e744c0e F test/bestindex5.test 67c1166131bb59f9e47c00118f7d432ca5491e6cae6ca3f87ca9db20103a78f9 F test/bestindex6.test d856a9bb63d927493575823eed44053bc36251e241aa364e54d0f2a2d302e1d4 -F test/bestindex7.test f36ada201973d3022cf7afffffe08de9e58341996020e7a2df9a1d2f2be20132 -F test/between.test 68137a6e941c221417c15b6fe2d55f27bb1b6ab48bdf9e2aa51efdd85bc53802 +F test/bestindex7.test a11348824aed0de2bb9030f092636929000cd72882bdf919adacc3792f67ccbd +F test/between.test b9a65fb065391980119e8a781a7409d3fcf059d89968279c750e190a9a1d5263 F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59 F test/bigfile2.test 1b489a3a39ae90c7f027b79110d6b4e1dbc71bfc -F test/bigmmap.test e906cf9729d7c362270ffe9fa6471f4c39c28ba83f0f77fb795e1b4d38a22ba0 +F test/bigmmap.test b820c234daa56d24bc3bf006e3ac7aa9d9623c8ac656a38f59063b444a2d65d1 F test/bigrow.test f0aeb7573dcb8caaafea76454be3ade29b7fc747 F test/bigsort.test 8299fa9298f4f1e02fc7d2712e8b77d6cd60e5a2 F test/bind.test 1e136709b306f7ed3192d349c2930d89df6ab621654ad6f1a72381d3fe76f483 @@ -748,7 +750,7 @@ F test/btree01.test e08b3613540145b353f20c81cb18ead54ff12e0f F test/btree02.test 7555a5440453d900410160a52554fe6478af4faf53098f7235f1f443d5a1d6cc F test/btreefault.test c2bcb542685eea44621275cfedbd8a13f65201e3 F test/busy.test 510dc6daaad18bcbbc085bcc6217d6dc418def5e73f72ce1475eea0cb7834727 -F test/busy2.test 0a1633fef7987fc8ea25ed5838f7eef2f08fc6d2a3dcc77d23e6402e53946a7a +F test/busy2.test dbfb61b3265e7a962d3bcd32cd542bbe3d7801edbda6438d35af5aa707cae981 F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de F test/cacheflush.test af25bb1509df04c1da10e38d8f322d66eceedf61 F test/cachespill.test 895997f84a25b323b166aecb69baab2d6380ea98f9e0bcc688c4493c535cfab9 @@ -780,7 +782,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 eff33d402a7b0fde0a52a1920d238af200ca573327021e0ce3b7e5688de41449 +F test/columncount.test d86fb6307261186370698962790ad2088ed419e4a4e823512b502f17d443b1b7 F test/concfault.test 500f17c3fcfe7705114422bcc6ddd3c740001a43 F test/concfault2.test 34b3fd258836aa305475d00e804c7450ade92f0de0bf9fa620e701446669bb12 F test/concurrent.test a0248ec6e3e79a5948453649cf86b5b359175cba55ea636b15426d6f0fa6c3da @@ -798,7 +800,7 @@ F test/contrib01.test 2a1cbc0f2f48955d7d073f725765da6fbceda6b4 F test/corrupt.test d7cb0300e4a297147b6a05e92a1684bc8973635c3bcaa3d66e983c9cbdbf47a3 F test/corrupt2.test bb50042cf9a1f1023d73af325d47eb02a6bb11e3c52f8812644b220c5d4bca35 F test/corrupt3.test 2520432b1fbf99994841e69804a3c59fb828183f4d09b85a1631bc7adca17e31 -F test/corrupt4.test 8d1d86b850fcc43e417450454f2044e52d55778a +F test/corrupt4.test b5ae41607e8d17d9c1f3e94fdb572ce061ed3beeebdb46fb3a348181b8c8a097 F test/corrupt5.test 387be3250795e2a86e6234745558b80efb248a357d0cd8e53bce75c7463f545d F test/corrupt6.test fc6a891716139665dae0073b6945e3670bf92568 F test/corrupt7.test b036f94bda4b0b23a2919bf717046ce9ecca4543 @@ -815,13 +817,13 @@ F test/corruptH.test 79801d97ec5c2f9f3c87739aa1ec2eb786f96454 F test/corruptI.test a17bbf54fdde78d43cf3cc34b0057719fd4a173a3d824285b67dc5257c064c7b F test/corruptJ.test 4d5ccc4bf959464229a836d60142831ef76a5aa4 F test/corruptK.test 5b4212fe346699831c5ad559a62c54e11c0611bdde1ea8423a091f9c01aa32af -F test/corruptL.test 22589f503602cc5984e80f27f46c4de2134f24f1515ba2440513c377cb692258 +F test/corruptL.test df132ba9ffd6fa15038380b4154998b9904ab8f1ea78400d7da53c920cb3b13d F test/corruptM.test 7d574320e08c1b36caa3e47262061f186367d593a7e305d35f15289cc2c3e067 -F test/corruptN.test 781c5f26a2d8918f03d45ac4968a738031eeb113a4b153c7588756d9b09c7b04 -F test/cost.test 1d156ce9858780a966c062694687afe0343a0ed12d081d071fb57027e726bafc -F test/count.test e0699a15712bc2a4679d60e408921c2cce7f6365a30340e790c98e0f334a9c77 +F test/corruptN.test 187d14093c333ddc705ea6c4aef8355febf260d5174d1b7cbc31c1ac8867951d +F test/cost.test b11cdbf9f11ffe8ef99c9881bf390e61fe92baf2182bad1dbe6de59a7295c576 +F test/count.test 5364003488249957750a5f15ee42ca1cd7b100b1131c2dc71fff266a1250bf55 F test/countofview.test e17d6e6688cf74f22783c9ec6e788c0790ee4fbbaee713affd00b1ac0bb39b86 -F test/coveridxscan.test 5ec98719a2e2914e8908dc75f7247d9b54a26df04625f846ac7900d5483f7296 +F test/coveridxscan.test f35c7208dedc4f98e471c569df64c0f95a49f6e072d8dc7c8f99bdee2697de1b F test/crash.test fb9dc4a02dcba30d4aa5c2c226f98b220b2b959f F test/crash2.test 5b14d4eb58b880e231361d3b609b216acda86651 F test/crash3.test 8f5de9d32ab9ab95475a9efe7f47a940aa889418 @@ -845,7 +847,7 @@ F test/dbdata.test 042f49acff3438f940eeba5868d3af080ae64ddf26ae78f80c92bec3ca7d8 F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e F test/dbfuzz001.test 55e1a3504f8dea84155e09912fe3b1c3ad77e0b1a938ec42ca03b8e51b321e30 F test/dbfuzz2-seed1.db e6225c6f3d7b63f9c5b6867146a5f329d997ab105bee64644dc2b3a2f2aebaee -F test/dbfuzz2.c db2a1710c0d30d38e1352ee1b52b717fcb224c8caacc6f10909ef540f73cc9e8 +F test/dbfuzz2.c 4b3c12de4d98b1b2d908ab03d217d4619e47c8b23d5e67f8a6f2b1bdee7cae23 F test/dbpage.test 650234ba683b9d82b899c6c51439819787e7609f17a0cc40e0080a7b6443bc38 F test/dbstatus.test 4a4221a883025ffd39696b3d1b3910b928fb097d77e671351acb35f3aed42759 F test/dbstatus2.test f5fe0afed3fa45e57cfa70d1147606c20d2ba23feac78e9a172f2fe8ab5b78ef @@ -860,20 +862,20 @@ F test/descidx1.test edc8adee58d491b06c7157c50364eaf1c3605c9c19f8093cb1ea2b6184f F test/descidx2.test a0ba347037ff3b811f4c6ceca5fd0f9d5d72e74e59f2d9de346a9d2f6ad78298 F test/descidx3.test 953c831df7ea219c73826dfbf2f6ee02d95040725aa88ccb4fa43d1a1999b926 F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e -F test/distinct.test e7d0cf371944dd0cbedff86420744e2f1ea2b528156451c97eb6ff41a99b9236 +F test/distinct.test 3e4210ef9cd1985aeec44939ad912c4621fbea9bb4a9c565696cebfe184b2ec5 F test/distinct2.test cd1d15a4a2abf579298f7161e821ed50c0119136fe0424db85c52cf0adc230d1 -F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376 +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 7107f5deda2324ea12dbf105044dc9265195401e9dbb3eead6a2c1a3da4bb5b7 +F test/e_createtable.test 7997c0106c181243e0ac7db7ba8b9ae7233d0bfb0188605650322a7a02ea326e 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 a2907f749cccd0b2c30d8576b673002eebdcc1fc9964bae61e5117b1d54733e2 +F test/e_fkey.test 351c7b989e5aefcc339ef5fc78dc4738442bd247a392cd67d81c2881000c369e F test/e_fts3.test 17ba7c373aba4d4f5696ba147ee23fd1a1ef70782af050e03e262ca187c5ee07 F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e F test/e_reindex.test 2b0e29344497d9a8a999453a003cb476b6b1d2eef2d6c120f83c2d3a429f3164 @@ -893,18 +895,18 @@ F test/enc.test 9a7be5479da985381d740b15f432800f65e2c87029ee57a318f42cb2eb43763a F test/enc2.test 848bf05f15b011719f478dddb7b5e9aea35e39e457493cba4c4eef75d849a5ec F test/enc3.test 6807f7a7740a00361ca8d0ccd66bc60c8dc5f2b6 F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020 -F test/eqp.test 84879b63e3110552bf8ce648a3507dc3ceb72109ecec83c2aef0db37a27f6382 +F test/eqp.test bfe979eb1f4b8ab7a3bd7db6d16c2e6c6be0e5a3aada2227716f3fd3a9d76b69 F test/errmsg.test eae9f091eb39ce7e20305de45d8e5d115b68fa856fba4ea6757b6ca3705ff7f9 F test/eval.test a64c9105d6ff163df7cf09d6ac29cdad5922078c F test/exclusive.test 7ff63be7503990921838d5c9f77f6e33e68e48ed1a9d48cd28745bf650bf0747 F test/exclusive2.test 984090e8e9d1b331d2e8111daf6e5d61dda0bef7 F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7 F test/exists.test 79a75323c78f02bbe9c251ea502a092f9ef63dac -F test/exists2.test 3e5726d6a67ebd4bd3466db58be424c09156c1f276c7594abb260cbf6ad494d3 -F test/existsfault.test 74f7edc713f5a335e7ff47adf503067bf05c6f8630f88b2a19c24f0fa5486ab8 F test/expr.test 26cd01e8485bc48c8aa6a1add598e9ce1e706b4eb4f3f554e0b0223022e8c2cf F test/expr2.test c27327ae9c017a7ff6280123f67aff496f912da74d78c888926d68b46ec75fd8 +F test/exprfault.test 497cc0b8fe6a677f49b55cb485e040f709ec2834b84f25912fe9c2dfeeda33db F test/extension01.test 00d13cec817f331a687a243e0e5a2d87b0e358c9 +F test/external_reader.test c7d34694f1b25c32d866f56ac80c1e29edddc42b4ef90cad589263ffac2cde0c F test/extraquick.test cb254400bd42bfb777ff675356aabf3287978f79 F test/fallocate.test 37a62e396a68eeede8f8d2ecf23573a80faceb630788d314d0a073d862616717 F test/filectrl.test 6e871c2d35dead1d9a88e176e8d2ca094fec6bb3 @@ -978,7 +980,7 @@ F test/fts3an.test a49ccadc07a2f7d646ec1b81bc09da2d85a85b18 F test/fts3ao.test 266989148fec6d9f1bb6c5382f7aa3dcea0e9cd444576e28dd2b9287ac7dd220 F test/fts3atoken.test dc2078ce464914efe3a8dfc545dd034a0fc14f2ab425c240471d5a5f1c721400 F test/fts3auto.test 649aa4c198d7acc5cd6355e19ee073d051c40d9e88a43fc3d88af46bdf3e99d5 -F test/fts3aux1.test 7a170e172afdbceb67f5baa05941fd4fbf56af42f61daa3d140f4b4bf4cb68f6 +F test/fts3aux1.test 1880eaa75c586cd10f53080479a2b819b3915ae7ce55c4e0ba8f1fe05ac0a6a7 F test/fts3aux2.test 2459e7fa3e22734aed237d1e2ae192f5541c4d8b218956ad2d90754977bf907f F test/fts3b.test c15c4a9d04e210d0be67e54ce6a87b927168fbf9c1e3faec8c1a732c366fd491 F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958 @@ -987,9 +989,9 @@ F test/fts3conf.test c84bbaec81281c1788aa545ac6e78a6bd6cde2bdbbce2da261690e3659f F test/fts3corrupt.test 79a32ffdcd5254e2f7fa121d9656e61949ad049c3c6554229911b7ceac37c9c6 F test/fts3corrupt2.test e318f0676e5e78d5a4b702637e2bb25265954c08a1b1e4aaf93c7880bb0c67d0 F test/fts3corrupt3.test 0d5b69a0998b4adf868cc301fc78f3d0707745f1d984ce044c205cdb764b491f -F test/fts3corrupt4.test b71512ec391d39da96d60d01959e4e9f20d4237a964a94abcf5f5a2ad28378c1 +F test/fts3corrupt4.test 2b61991318db59b3c569d630660c4df0f22b0b2fe59f3bfbc111863b3bda6f14 F test/fts3corrupt5.test 0549f85ec4bd22e992f645f13c59b99d652f2f5e643dac75568bfd23a6db7ed5 -F test/fts3corrupt6.test d5896a8d389bd824457772dc1e2d2023cd5c5cf8e42733607b5d632103018d8b +F test/fts3corrupt6.test d274f139ec173392002c768631f404fefc007ae02ffa1b03d8cbd096c3fc00f9 F test/fts3cov.test 7eacdbefd756cfa4dc2241974e3db2834e9b372ca215880e00032222f32194cf F test/fts3d.test 2bd8c97bcb9975f2334147173b4872505b6a41359a4f9068960a36afe07a679f F test/fts3defer.test f4c20e4c7153d20a98ee49ee5f3faef624fefc9a067f8d8d629db380c4d9f1de @@ -1006,7 +1008,7 @@ F test/fts3fault.test 798e45af84be7978ca33d5bdc94246eb44724db24174b5d8e9b1ac46c5 F test/fts3fault2.test 6a17a11d8034b1c4eca9f3091649273d56c49ff049e2173df8060f94341e9da0 F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641 F test/fts3fuzz001.test e3c7b0ce9b04cc02281dcc96812a277f02df03cd7dc082055d87e11eb18aaf56 -F test/fts3join.test 949b4f5ae3ae9cc2423cb865d711e32476bdb205ab2be923fdf48246e4a44166 +F test/fts3join.test b285c919559af5b093c51abb2c07ce7ec0156dbc9573f444b78dabd9f3040db2 F test/fts3malloc.test b0e4c133b8d61d4f6d112d8110f8320e9e453ef6 F test/fts3matchinfo.test aa66cc50615578b30f6df9984819ae5b702511cf8a94251ec7c594096a703a4a F test/fts3matchinfo2.test 00144e841704b8debfcdf6097969cd9f2a1cf759e2203cda42583648f2e6bf58 @@ -1015,12 +1017,12 @@ F test/fts3near.test 7e3354d46f155a822b59c0e957fd2a70c1d7e905 F test/fts3offsets.test b85fd382abdc78ebce721d8117bd552dfb75094c F test/fts3prefix.test fa794eaab0bdae466494947b0b153d7844478ab2 F test/fts3prefix2.test e1f0a822ca661dced7f12ce392e14eaf65609dce -F test/fts3query.test ca033ff2ebcc22c69d89032fb0bc1850997d31e7e60ecd26440796ba1654e78f +F test/fts3query.test 45806a302921b245a9dba5d85c9d51fb98b3f137eea6e6bf6eae4883e041ab72 F test/fts3rank.test cd99bc83a3c923c8d52afd90d86979cf05fc41849f892faeac3988055ef37b99 F test/fts3rnd.test 1320d8826a845e38a96e769562bf83d7a92a15d0 F test/fts3shared.test 57e26a801f21027b7530da77db54286a6fe4997e F test/fts3snippet.test 0887196d67cffbe365edde535b95ecc642a532ce8551ccd9a73aab5999c3ffae -F test/fts3snippet2.test 2dabb5889eda4c9980aad325e688b470781f97ce7c0fca0db125616fae0a2cdd +F test/fts3snippet2.test e79afeb1f673713f96d7fc5655726081975399d11e659d15553207be43301dc4 F test/fts3sort.test ed34c716a11cc2009a35210e84ad5f9c102362ca F test/fts3tok1.test a663f4cac22a9505400bc22aacb818d7055240409c28729669ea7d4cc2120d15 F test/fts3tok_err.test 52273cd193b9036282f7bacb43da78c6be87418d @@ -1047,7 +1049,7 @@ F test/fts4record.test a48508f69a84c9287c8019d3a1ae712f5730d8335ffaf8e2101e691d0 F test/fts4rename.test 2e0565ffd92b2c51f1a757df0b8f2ca30537197106fec09e943919801d173692 F test/fts4umlaut.test fcaca4471de7e78c9d1f7e8976e3e8704d7d8ad979d57a739d00f3f757380429 F test/fts4unicode.test 82a9c16b68ba2f358a856226bb2ee02f81583797bc4744061c54401bf1a0f4c9 -F test/fts4upfrom.test 8df5acb6e10ad73f393d1add082b042ab1db72567888847d098152121e507b34 +F test/fts4upfrom.test f25835162c989dffd5e2ef91ec24c4848cc9973093e2d492d1c7b32afac1b49d F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d F test/func.test f673822636fb8ed618dd2b80230d16e495d19c8f2e2e7d6c22e93e2b3de097ad F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f @@ -1063,7 +1065,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 772110a59c6f839f95e49a9fd3e5f855bd9cbb90e9d366a6ccd15cb3616fc631 +F test/fuzzcheck.c c51cdb34e926d0a6551624aa1f04c456c29317b5457855d64391917d9b4c2aff F test/fuzzdata1.db d36e88741b4f23bcbaaf55b006290669d03c6c891cf13c7b3a53bc1b097b693f F test/fuzzdata2.db 128b3feeb78918d075c9b14b48610145a0dd4c8d6f1ca7c2870c7e425f5bf31f F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba @@ -1071,7 +1073,7 @@ F test/fuzzdata4.db b502c7d5498261715812dd8b3c2005bad08b3a26e6489414bd13926cd3e4 F test/fuzzdata5.db e35f64af17ec48926481cfaf3b3855e436bd40d1cfe2d59a9474cb4b748a52a5 F test/fuzzdata6.db 92a80e4afc172c24f662a10a612d188fb272de4a9bd19e017927c95f737de6d7 F test/fuzzdata7.db 0166b56fd7a6b9636a1d60ef0a060f86ddaecf99400a666bb6e5bbd7199ad1f2 -F test/fuzzdata8.db c8325de6fbdd24d030cd3a01384a2ff325dda5d5e3ff5d531a26ada3d9d7e010 +F test/fuzzdata8.db 5e616432bbdd9b27014463545cae06797790645021fbc650d28c994b4f02a6f5 F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8 F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14 F test/fuzzerfault.test f64c4aef4c9e9edf1d6dc0d3f1e65dcc81e67c996403c88d14f09b74807a42bc @@ -1081,7 +1083,7 @@ F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98 F test/having.test a89236dd8d55aa50c4805f82ac9daf64d477a44d712d8209c118978d0ca21ec9 F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751 F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711 -F test/hook.test fa54fa8afc842ae375f10c1f9fc0014fa59789052fc30c9eae19811fa3afa009 +F test/hook.test 55b6d605d06dadbb04416eae8ad79889aea3521d119c87f04353c25f9c1450a4 F test/hook2.test b9ff3b8c6519fb67f33192f1afe86e7782ee4ac8 F test/icu.test 716a6b89fbabe5cc63e0cd4c260befb08fd7b9d761f04d43669233292f0753b1 F test/ieee754.test b0945d12be7d255f3dfa18e2511b17ca37e0edd2b803231c52d05b86c04ab26e @@ -1089,9 +1091,9 @@ F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8 F test/in.test 688ed2011d922d83141a45af431601738674a4c0bdde34b6351f688b82a169b3 F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75 F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0 -F test/in4.test 64ac9c767ac5af562f066a40163d4202f8fa3be05d264ec65d6258e74606b30c +F test/in4.test cd08375ba470b248c3dc4ab30fd5dbcb682deafe3862d8249ba0ad6a11dd25ea F test/in5.test b32ce7f4a93f44c5dee94af16886d922cc16ebe33c8e1765c73d4049d0f4b40f -F test/in6.test 8562d0945195cab3cc4ab3794e9118e72cb44c43f785c2b04d48a9d06ca6b4ec +F test/in6.test f5f40d6816a8bb7c784424b58a10ac38efb76ab29127a2c17399e0cbeeda0e4b F test/incrblob.test c9b96afc292aeff43d6687bcb09b0280aa599822 F test/incrblob2.test a494c9e848560039a23974b9119cfc2cf3ad3bd15cc2694ee6367ae537ef8f1f F test/incrblob3.test d8d036fde015d4a159cd3cbae9d29003b37227a4 @@ -1099,7 +1101,7 @@ F test/incrblob4.test 21a52a6843a56cdcce968c6a86b72a7066d0e6ba F test/incrblob_err.test 89372a28f1d98254f03fed705f9efcd34ef61a674df16d2dbb4726944a2de5e9 F test/incrblobfault.test 74dd8ac108304cea0b4a0df6df63a1567e558758 F test/incrcorrupt.test 6c567fbf870aa9e91866fe52ce6f200cd548939a -F test/incrvacuum.test 2aaee202b1f230e55779f70d155f6ba67bbdff8481d650214d256ab0f97d4a2b +F test/incrvacuum.test 3fa6145f5e71f603554fd7b8ec3da4290b1341029682313285cb5f9e1893d6ba F test/incrvacuum2.test 7d26cfda66c7e55898d196de54ac4ec7d86a4e3d F test/incrvacuum3.test 75256fb1377e7c39ef2de62bfc42bbff67be295a F test/incrvacuum_ioerr.test 6ae2f783424e47a0033304808fe27789cf93e635 @@ -1108,13 +1110,13 @@ F test/index2.test f835d5e13ca163bd78c4459ca15fd2e4ed487407 F test/index3.test 51685f39345462b84fcf77eb8537af847fdf438cc96b05c45d6aaca4e473ade0 F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6 F test/index5.test 8621491915800ec274609e42e02a97d67e9b13e7 -F test/index6.test f172653b35b20233e59200e8b92a76db61bf7285437bf777b93b306ba26a47e7 -F test/index7.test b8a0ba2110fd517bb48c4e76d26d60f1ab2ed9e257b18d71f820d7e71e9f8570 -F test/index8.test bc2e3db70e8e62459aaa1bd7e4a9b39664f8f9d7 +F test/index6.test 880858a65d8686120fe9a8971a4d82b429cc206fe7fd525b8b2b55451c74d82d +F test/index7.test b238344318e0b4e42126717f6554f0e7dfd0b39cecad4b736039b43e1e3b6eb3 +F test/index8.test caa097735c91dbc23d8a402f5e63a2a03c83840ba3928733ed7f9a03f8a912a3 F test/index9.test 0aa3e509dddf81f93380396e40e9bb386904c1054924ba8fa9bcdfe85a8e7721 -F test/indexedby.test a3ca11f0819a9279619099f36b624bcaa315f7a1ed65c3ed2219c2a944683d2c -F test/indexexpr1.test 284e119999d132cc8bf37735a928c9859b28e8e295d02b7a6a4f93977c7f9ba5 -F test/indexexpr2.test dba11dbb0a58fcba4cd694f46b4004976123b81b0501f525d43c9be59f0207b1 +F test/indexedby.test f21eca4f7a6ffe14c8500a7ad6cd53166666c99e5ccd311842a28bc94a195fe0 +F test/indexexpr1.test 7e0e7a33acb4d9b3524398e6ce90cc05c26603fabbaf3062083a036c8874bc12 +F test/indexexpr2.test 2c7abe3c48f8aaa5a448615ab4d13df3662185d28419c00999670834a3f0b484 F test/indexfault.test 98d78a8ff1f5335628b62f886a1cb7c7dac1ef6d48fa39c51ec871c87dce9811 F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7 F test/insert.test 4e3f0de67aac3c5be1f4aaedbcea11638f1b5cdc9a3115be14d19aa9db7623c6 @@ -1128,7 +1130,7 @@ F test/instrfault.test 95e28efade652e6d51ae11b377088fe523a581a07ec428009e152a4dd F test/intarray.test bb976b0b3df0ebb6a2eddfb61768280440e672beba5460ed49679ea984ccf440 F test/interrupt.test 16ea879ec728cb76414c148c5f24afd5d1f91054 F test/interrupt2.test e4408ca770a6feafbadb0801e54a0dcd1a8d108d -F test/intpkey.test ac71107a49a06492b69b82aafaf225400598d3c8 +F test/intpkey.test aee694afed1a65c86c4e69ad030224b3fc268113d00685234d40079fca16bad3 F test/intreal.test 2a87e85a5949bd55e41ef04c58f5800587c5380bdbc559ff1c79b614b0e6a533 F test/io.test f95bca1783b01ea7761671560d023360d2dfa4cc F test/ioerr.test 470fcc78e9cd352d162baf782fe301ea807d764241f58a48fc58109c2dfcdb6b @@ -1139,10 +1141,10 @@ F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4 F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b F test/istrue.test 9619a2d77580f676048aaff7a16a0bcfea2b96c6c660dfaded2e53c873418899 F test/join.test 25da4f53523a4aa17c893134b47fba6aa4799bb33350517b157785878290e238 -F test/join2.test 21fc30e54ab35ed66bf51b89cec18729205497f5cc43c83bc042f96a73721593 +F test/join2.test 9bdc615841b91c97a16d68bad9508aea11fa0c6b34e5689847bcc4dac70e4990 F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 -F test/join5.test 3a96dc62f0b45402d7207e22d1993fe0c2fce1c57644a11439891dd62b990eb7 +F test/join5.test f418fccdfefa41f1659663463aa517431ddcf3e30ccbb80e64173b7d615a03f4 F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4 @@ -1160,9 +1162,9 @@ F test/kvtest.c feb4358fb022da8ebd098c45811f2f6507688bb6c43aa72b3e840df19026317b F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63 F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200 F test/lemon-test01.y 58b764610fd934e189ffbb0bbfa33d171b9cb06019b55bdc04d090d6767e11d7 -F test/like.test 0b7b4765ca59d95a1f92dfab9e4d810c9fb8280b5edd6332a01340a20db9e0ed +F test/like.test 5fe0bc37f307aef0a453ce2de4632bdfc0759448f0421c39f6d53caefe905fac F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da -F test/like3.test 03d1bdf848483b78d2cfd1db283d75c4ec2e37c8b8eccc006813f3978d78fbbd +F test/like3.test a76e5938fadbe6d32807284c796bafd869974a961057bc5fc5a28e06de98745c F test/limit.test 350f5d03c29e7dff9a2cde016f84f8d368d40bcd02fa2b2a52fa10c4bf3cbfaf F test/limit2.test 9409b033284642a859fafc95f29a5a6a557bd57c1f0d7c3f554bd64ed69df77e F test/loadext.test faa4f6eed07a5aac35d57fdd7bc07f8fc82464cfd327567c10cf0ba3c86cde04 @@ -1197,7 +1199,7 @@ F test/mallocG.test 0ff91b65c50bdaba680fb75d87fe4ad35bb7934f F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb F test/mallocI.test 6c23a71df077fa5d387be90e7e669c5b368ca38a F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e -F test/mallocK.test 1f4b5efbf61715ab79b20b38739ff4b3d110ceb53f54e5db6da1f01c083707ab +F test/mallocK.test 25897506da0098cea09b302ff432b0fb6d8002773c1e0fc9732aa8b444bfd455 F test/mallocL.test fb311ff80afddf3b1a75e52289081f4754d901dc F test/mallocM.test 78bbe9d3da84a5c679123cdb40d7b2010b18fc46e13897e4f253c6ba6fbff134 F test/malloc_common.tcl aac62499b76be719fac31e7a3e54a7fd53272e7f @@ -1205,22 +1207,22 @@ F test/malloctraceviewer.tcl b7a54595270c1d201abf1c3f3d461f27eaf24cdef623ad08a0f F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f F test/memdb.test c1f2a343ad14398d5d6debda6ea33e80d0dafcc7 -F test/memdb1.test 58d92c2bf622cc5f0f41461e1b35cf64f3f787199544c2c1dada37d88753f9d4 +F test/memdb1.test 7b76c3262d63c46dd6b408d18f5721071776f2df4ffeb11e668824e427127594 F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2 F test/memsubsys1.test 9e7555a22173b8f1c96c281ce289b338fcba2abe8b157f8798ca195bbf1d347e F test/memsubsys2.test 3e4a8d0c05fd3e5fa92017c64666730a520c7e08 -F test/minmax.test 6751e87b409fe11b02e70a306d846fa544e25a41 -F test/minmax2.test 1edf66901ddfab26ae1e04165e8da834c8d3284e2b20aefb26b80ef217962eab +F test/minmax.test 0015e5cd5e7af48bb3364f26d9f3a9cdbea2a442d4774281c39e2229591b7351 +F test/minmax2.test cf9311babb6f0518d04e42fd6a42c619531c4309a9dd790a2c4e9b3bc595e0de F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354 F test/minmax4.test 272ca395257f05937dc96441c9dde4bc9fbf116a8d4fa02baeb0d13d50e36c87 F test/misc1.test 7ce84b25df9872e7d7878613a96815d2ba5bc974ac4e15a50118dde8f3917599 -F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d +F test/misc2.test 71e746af479119386ac2ed7ab7d81d99970e75b49ffd3e8efffee100b4b5f350 F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d F test/misc4.test 10cd6addb2fa9093df4751a1b92b50440175dd5468a6ec84d0386e78f087db0e F test/misc5.test c4aeaa0fa28faa08f2485309c38db4719e6cd1364215d5687a5b96d340a3fa58 F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91 -F test/misc7.test 7b4c88c1d5ea8c8b9d537d212c08a0343d345fdd5c789598692c1c0e60fbda69 -F test/misc8.test 8782708f4c8a459591c3e8fe1215bd2048bffb4024b3df249e9b9ed407dc61ed +F test/misc7.test d912f3d45c2989191b797504a220ca225d6be80b21acad22ba0d35f4a9ee4579 +F test/misc8.test 4db9f8be59834cea08c87e9658014080efa02678ef54a088f84fa5647e81fee0 F test/misuse.test 9e7f78402005e833af71dcab32d048003869eca5abcaccc985d4f8dc1d86bcc7 F test/mjournal.test 28a08d5cb5fb5b5702a46e19176e45e964e0800d1f894677169e79f34030e152 F test/mmap1.test fb04e0c10492455007624ade884ca0c8852ff3e4e11d95408f9709ca2ef7f626 @@ -1243,18 +1245,18 @@ F test/notify1.test 669b2b743618efdc18ca4b02f45423d5d2304abf F test/notify2.test 2ecabaa1305083856b7c39cf32816b612740c161 F test/notify3.test 10ff25cde502e72a92053a2f215d64bece4ef934 F test/notnull.test a37b663d5bb728d66fc182016613fb8e4a0a4bbf3d75b8876a7527f7d4ed3f18 -F test/notnull2.test 965a893619751255e59c911a8c58504b3174a3788b1458b7c7365b232209711b -F test/notnullfault.test 6126e31300632070ca6021698393c7fcf61ab4791bc2aa1d6d704242c0fcd4f8 +F test/notnull2.test 131365171d973c57fe694fcc46c1e645f6e24ceb43b230ad5011a0ea2182f215 +F test/notnullfault.test fc4bb7845582a2b3db376001ef49118393b1b11abe0d24adb03db057ee2b73d5 F test/null.test b7ff206a1c60fe01aa2abd33ef9ea83c93727d993ca8a613de86e925c9f2bc6f -F test/nulls1.test 82c5bc33148405f21205865abf13c786084438d573a4ac4e87e11b6091cde526 +F test/nulls1.test 7a5e4346ee4285034100b4cd20e6784f16a9d6c927e44ecdf10034086bbee9c9 F test/numcast.test 5d126f7f581432e86a90d1e35cac625164aec4a1 F test/numindex1.test 20a5450d4b056e48cd5db30e659f13347a099823 F test/offset1.test f06b83657bcf26f9ce805e67450e189e282143b2 F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394 F test/optfuzz-db01.c 9f2fa80b8f84ebbf1f2e8b13421a4e0477fe300f6686fbd76cac1d2db66e0fdc F test/optfuzz-db01.txt 21f6bdeadc701cf11528276e2a55c70bfcb846ba42df327f979bd9e7b6ce7041 -F test/optfuzz.c 50e330304eb1992e15ddd11f3daaad9bcc0d9aaad09cb2bcc77f9515df2e88b1 -F test/orderby1.test 6bf0ce45cbfb1cf4779dd418ac5e8cf66abfa04de2c1d2edf1e0e85f1520d8f3 +F test/optfuzz.c 690430a0bf0ad047d5a168bf52b05b2ee97aedaad8c14337e9eb5050faa64994 +F test/orderby1.test a4bba04b9c60a21e53486fbc173a596b29641a3b3a57a0f26a1cbef1360358e9 F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04 F test/orderby3.test 8619d06a3debdcd80a27c0fdea5c40b468854b99 F test/orderby4.test 4d39bfbaaa3ae64d026ca2ff166353d2edca4ba4 @@ -1280,7 +1282,7 @@ F test/pagesize.test 5769fc62d8c890a83a503f67d47508dfdc543305 F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442 F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff -F test/permutations.test 1f08abeae53780436b5a9c6716e1cb48ebf830cd6b0a9df615d952030c05d84b +F test/permutations.test 5dc2b65860e54e2fd15d994065035867368c0e29af17053935ec095ecce4cc85 F test/pg_common.tcl 3b27542224db1e713ae387459b5d117c836a5f6e328846922993b6d2b7640d9f F test/pragma.test 50b91bedea9324d3ab48e793f908ee7d2c7dcf84bfa2281e792838be59641ec8 F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f @@ -1308,22 +1310,22 @@ F test/recover.test ccb8c2623902a92ebb76770edd075cb4f75a4760bb7afde38026572c6e79 F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8 F test/regexp2.test 40e894223b3d6672655481493f1be12012f2b33c F test/reindex.test cd9d6021729910ece82267b4f5e1b5ac2911a7566c43b43c176a6a4732e2118d -F test/releasetest.tcl fb76d8fcc95ac29d6356cd9e52b726ab9e43a24082897618dfbcb7c2b0049153 x -F test/releasetest_data.tcl 3d41ddb3f04f474ac9d925485da24ce6576ff0ebc4c7201c8a340bc09846c261 +F test/releasetest.tcl 6f803ef0b896f8f3f4c26eb072c0399963a5987a509a64d45f5dfbc1ebae2951 x +F test/releasetest_data.tcl f88ed29aa18366ed3956ace36c96ec6868ef5b9ee04cc05d32f4d81031e19e28 F test/resetdb.test 8062cf10a09d8c048f8de7711e94571c38b38168db0e5877ba7561789e5eeb2b F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb -F test/returning1.test 209b910c132cb2015bb1159f852c7124778004963c09095c42c3d2442110c56c +F test/returning1.test 52b4ed60f104a4ce85b38417e5319b2078b2b908c71a768d539cee3c0ce8bdc9 F test/rollback.test 06680159bc6746d0f26276e339e3ae2f951c64812468308838e0a3362d911eaa -F test/rollback2.test bc868d57899dc6972e2b4483faae0e03365a0556941474eec487ae21d8d38bb6 +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/rowvalue.test 6795850abf6243e96f09ef041919d1ea61713332237b60d01371c0fee73f6379 +F test/rowvalue.test 466efbb7bb93ca9f95d89f69c7c140aa52cc57ac6dfa7efba09ea4a9ab3cd9f0 F test/rowvalue2.test 060d238b7e5639a7c5630cb5e63e311b44efef2b F test/rowvalue3.test 3068f508753af69884b12125995f023da0dbb256 -F test/rowvalue4.test 02e35f7762371c2f57ebd856aa056eac56cb27ef7715a0bb31eac1895a745356 +F test/rowvalue4.test 441e7e366ac6d939a3a95a574031c56ec2a854077a91d66eee5ff1d86cb5be58 F test/rowvalue5.test c81c7d8cf36711ab37675ad7376084ae2a359cb6 F test/rowvalue6.test d19b54feb604d5601f8614b15e214e0774c01087 F test/rowvalue7.test c1cbdbf407029db01f87764097c6ac02a1c5a37efd2776eff32a9cdfdf6f2dba @@ -1340,7 +1342,7 @@ F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd F test/savepoint6.test 48a645a7bb3a59a6fcf06a7364cfe5b655c336760de39068f7c241b0fc80d963 F test/savepoint7.test cde525ea3075283eb950cdcdefe23ead4f700daa F test/savepointfault.test f044eac64b59f09746c7020ee261734de82bf9b2 -F test/scanstatus.test 874e35011779b07725a47dbf1dd6282b0ca04af7e028fb0b534ee544b571be42 +F test/scanstatus.test 9a0ed37ab6d57b50567282788fffdf832d9b16739ecc41bff9d77a8d767cf317 F test/schema.test 5dd11c96ba64744de955315d2e4f8992e447533690153b93377dffb2a5ef5431 F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5 F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38 @@ -1353,16 +1355,16 @@ F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5 F test/select1.test 3d23f66bf9ba77570acfe2ca5f1540ece17037cc64ab1a00efec9758ac29c268 F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56 F test/select3.test c49fbb758903f3718e2de5aa4655eda4838131cbea24a86db908f8b6889aa68c -F test/select4.test e8a2502e3623f3058871030599a48abb35789d2244d5b380ecf3696873fdd4a4 -F test/select5.test df9ec0d218cedceb4fe7b63262025b547b50a55e59148c6f40b60ca25f1d4546 +F test/select4.test f0684d3da3bccacbe2a1ebadf6fb49d9df6f53acb4c6ebc228a88d0d6054cc7b +F test/select5.test 8afc5e5dcdebc2be54472e73ebd9cd1adef1225fd15d37a1c62f969159f390ae F test/select6.test 319d45e414cdd321bf17cfacedaf19e3935ad64dac357c53f1492338c6e9b801 F test/select7.test f659f231489349e8c5734e610803d7654207318f F test/select8.test 8c8f5ae43894c891efc5755ed905467d1d67ad5d -F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95 -F test/selectA.test 68de52409e45a3313d00b8461b48bef4fb729faf36ade9067a994eae55cc86f4 +F test/select9.test f7586b207ce2304ab80dc93d3146469a28fd4403621dd3a82d06644563d3c812 +F test/selectA.test 985df11dfc58dedd6f8124dea32754566346b93e294f26291b5c96d10c8cc889 F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25 F test/selectC.test fec14c9015ed4ec941508bbc144f30b42e40ac34a4bb33001450369865dd0b75 -F test/selectD.test fc20452847a01775710090383cfb4423275d2f745fed61f34fbf37573ac0d214 +F test/selectD.test 6d1909b49970bf92f45ce657505befcef5fc7cbc13544e18103a316d32189bfb F test/selectE.test a8730ca330fcf40ace158f134f4fe0eb00c7edbf F test/selectF.test 21c94e6438f76537b72532fa9fd4710cdd455fc3 F test/selectG.test 089f7d3d7e6db91566f00b036cb353107a2cca6220eb1cb264085a836dae8840 @@ -1395,11 +1397,11 @@ F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3 F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5 F test/shrink.test 1b4330b1fd9e818c04726d45cb28db73087535ce F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329 -F test/skipscan1.test ed524bc86f27646b3a297f45d6557b55db338977b6838f8064b196b35848b31b -F test/skipscan2.test 3eb703ce794f139e7b83567911046298bcde29606116727f9b700ce34f559d2d +F test/skipscan1.test 1a9972e1dc15ca3887f306d3cd9a29679afb382eca0f3539f3b746f3c2ccaf68 +F test/skipscan2.test c588cb7ed947db724d300f2a0dc537dd2ad292b0f812641d8481bc0b95dd3f49 F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5 -F test/skipscan5.test 980875ad45d8aacfe7bdec7c288343520cd1d14e84befdcfe50c785f9e6c8709 -F test/skipscan6.test 0b4cd1b4ac9f84d91454df513c99a4932fa07e8f27b8049bea605068b3e34ac7 +F test/skipscan5.test 0672103fd2c8f96bd114133f356192b35ece45c794fe3677e1d9e5e3104a608e +F test/skipscan6.test bddbb35dd335e2d21b7791a61e3b2e1f3255dc307ce80aa6fe19cc298e6feb13 F test/snapshot.test a504f2e7009f512ef66c719f0ea1c55a556bdaf1e1312c80a04d46fc1a3e9632 F test/snapshot2.test 8d6ff5dd9cc503f6e12d408a30409c3f9c653507b24408d9cd7195931c89bc54 F test/snapshot3.test 8744313270c55f6e18574283553d3c5c5fe4c5970585663613a0e75c151e599b @@ -1453,7 +1455,7 @@ F test/sync.test 89539f4973c010eda5638407e71ca7fddbcd8e0594f4c9980229f804d433309 F test/sync2.test 8f9f7d4f6d5be8ca8941a8dadcc4299e558cb6a1ff653a9469146c7a76ef2039 F test/syscall.test a39d9a36f852ae6e4800f861bc2f2e83f68bbc2112d9399931ecfadeabd2d69d F test/sysfault.test c9f2b0d8d677558f74de750c75e12a5454719d04 -F test/tabfunc01.test 5ca6d004157a3e886a55a9387b960cc0db41acd88753eb597ff409ec6cfb1be0 +F test/tabfunc01.test acb5be558868c65d8cf3495539fff23093d77139eb1e4e8c4580568099f98645 F test/table.test eb3463b7add9f16a5bb836badf118cf391b809d09fdccd1f79684600d07ec132 F test/tableapi.test ecbcc29c4ab62c1912c3717c48ea5c5e59f7d64e4a91034e6148bd2b82f177f4 F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930 @@ -1478,6 +1480,7 @@ F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b F test/threadtest2.c a70a8e94bef23339d34226eb9521015ef99f4df8 F test/threadtest3.c cfd72c74a40de3eb7576f1ab2da28183390deadb13f2aa5c8d077aacd41eda60 F test/threadtest4.c c1e67136ceb6c7ec8184e56ac61db28f96bd2925 +F test/threadtest5.c 9b4d782c58d8915d7e955ff8051f3d03628bda0d33b82971ea8c0f2f2808c421 F test/time-wordcount.sh 8e0b0f8109367827ad5d58f5cc849705731e4b90 F test/tkt-02a8e81d44.test 6c80d9c7514e2a42d4918bf87bf6bc54f379110c F test/tkt-18458b1a.test 6a62cb1ee50fa3c620da59e3a6f531eb38fceaf7e2166203816b724524e6f1d6 @@ -1487,7 +1490,7 @@ F test/tkt-2d1a5c67d.test be1326f3061caec85085f4c9ee4490561ca037c0 F test/tkt-2ea2425d34.test 1cf13e6f75d149b3209a0cb32927a82d3d79fb28 F test/tkt-31338dca7e.test 6fb8807851964da0d24e942f2e19c7c705b9fb58 F test/tkt-313723c356.test 4b306ad45c736cedf2f5221f6155b92143244b6d -F test/tkt-385a5b56b9.test 5204a7cba0e28c99df0acbf95af5e1af4d32965a7a14de6eccebf949607618b1 +F test/tkt-385a5b56b9.test 81d7c8ef2d2a378323ba2190c1f02f91022fdff0d8d0b84c04954d02c85ef374 F test/tkt-38cb5df375.test f3cc8671f1eb604d4ae9cf886ed4366bec656678 F test/tkt-3998683a16.test 6d1d04d551ed1704eb3396ca87bb9ccc8c5c1eb7 F test/tkt-3a77c9714e.test 90e3e8455ee945a4076d4c44062b8845708af24a880355328fe7008f2047c9f0 @@ -1502,7 +1505,7 @@ F test/tkt-5e10420e8d.test 904d1687b3c06d43e5b3555bbcf6802e7c0ffd84 F test/tkt-5ee23731f.test 9db6e1d7209dc0794948b260d6f82b2b1de83a9f F test/tkt-6bfb98dfc0.test 24780633627b5cfc0635a5500c2389ebfb563336 F test/tkt-752e1646fc.test ea78d88d14fe9866bdd991c634483334639e13bf -F test/tkt-78e04e52ea.test cb44d0f5e7940223be740a39913a1b9b9b30d7e4a17ed3349141f893bae1b8f2 +F test/tkt-78e04e52ea.test b731f2ab7d1c2482ac5152097da02ef4805a45147ba9498d3cd9da27072f34d1 F test/tkt-7a31705a7e6.test 9e9c057b6a9497c8f7ba7b16871029414ccf6550e7345d9085d6d71c9a56bb6f F test/tkt-7bbfb7d442.test 7b2cd79c7a17ae6750e75ec1a7846712a69c9d18 F test/tkt-80ba201079.test 105a721e6aad0ae3c5946d7615d1e4d03f6145b8 @@ -1521,7 +1524,7 @@ F test/tkt-a8a0d2996a.test 002e1cde8fc30c39611b52cf981c88200b858765748556822da72 F test/tkt-b1d3a2e531.test 8f7576e41ca179289ee1a8fee28386fd8e4b0550 F test/tkt-b351d95f9.test d14a503c414c5c58fdde3e80f9a3cfef986498c0 F test/tkt-b72787b1.test a95e8cdad0b98af1853ac7f0afd4ab27b77bf5f3 -F test/tkt-b75a9ca6b0.test ade89229d853a67a21bbd5e6e1e787a8f9d21f19908d1b7fca6bf3d4d5aa0767 +F test/tkt-b75a9ca6b0.test dc6a853c242f7d0326564ae32e9e5eb462b5e8d2bc5b01ea3b18fd24f8e5894b F test/tkt-ba7cbfaedc.test b4c0deccc12aeb55cfdb57935b16b5d67c5a9877 F test/tkt-bd484a090c.test 60460bf946f79a79712b71f202eda501ca99b898 F test/tkt-bdc6bbbb38.test fc38bb09bdd440e3513a1f5f98fc60a075182d7d @@ -1587,7 +1590,7 @@ F test/tkt3346.test 6f67c3ed7db94dfc5df4f5f0b63809a1f611e01a F test/tkt3357.test 77c37c6482b526fe89941ce951c22d011f5922ed F test/tkt3419.test 1bbf36d7ea03b638c15804251287c2391f5c1f6b F test/tkt3424.test 61f831bd2b071bd128fa5d00fbda57e656ca5812 -F test/tkt3442.test a1fc47c669e651d16494de3ff349bcb53281456f2ca02c8bc14220b6044bbfe8 +F test/tkt3442.test 6287173de5bb2d43693b1f822426018a209f9df49ce2f454808bac1771852330 F test/tkt3457.test 5651e2cbb94645b677ec663160b9e192b87b7d365aecdfb24e19f749575a6fc2 F test/tkt3461.test 228ea328a5a21e8663f80ee3d212a6ad92549a19 F test/tkt3493.test 1686cbde85f8721fc1bdc0ee72f2ef2f63139218 @@ -1623,23 +1626,23 @@ F test/tkt3992.test f3e7d548ac26f763b47bc0f750da3d03c81071da F test/tkt3997.test a335fa41ca3985660a139df7b734a26ef53284bd F test/tkt4018.test 18dbc6617f7a4b90e938d1bd6d26ad18daafaf08 F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7 -F test/tpch01.test 7c4eb8cdd79c568f46d344b3e789c9fdb8a766d112871352704861f3fca32a2a +F test/tpch01.test 4479008f85f6f8f25f7ab2cb305d665752b4727fa28a8df3d8e0ad46520c62ff F test/trace.test a659a9862957f4789e37a92b3bf6d2caf5c86b02cdeefc41e850ae53acf6992a F test/trace2.test f5cb67ad3bc09e0c58e8cca78dfd0b5639259983 F test/trace3.test ae2004df24b585fed9046cc0bae4601762bc6fc4aa321d475f1350bba5047f31 F test/trans.test 45f6f9ab6f66a7b5744f1caac06b558f95da62501916906cf55586a896f9f439 F test/trans2.test 62bd045bfc7a1c14c5ba83ba64d21ade31583f76 F test/trans3.test 91a100e5412b488e22a655fe423a14c26403ab94 -F test/transitive1.test 293300f46916569f08875cdb2fe2134be2c27677 +F test/transitive1.test 06bcfeeb2ed719abf6ae582f9f65a6b07642dd1363fa648ae9a74a35e83a825c F test/trigger1.test d30cd09ae8ac365a088f09daba583cc5c0b8fc7d4e1d70809d0b4be3bf6ae2ab -F test/trigger2.test d15da46f7012832faf3e0c536b47024409d5fb1722d2bb77e29c06d96d704bb1 +F test/trigger2.test 6e35bd7321c49e63d540aee980eb95dec63e1d1caca175224101045bcc80871f F test/trigger3.test aa640bb2bbb03edd5ff69c055117ea088f121945 F test/trigger4.test 74700b76ebf3947b2f7a92405141eb2cf2a5d359 F test/trigger5.test 619391a3e9fc194081d22cefd830d811e7badf83 F test/trigger6.test 0e411654f122552da6590f0b4e6f781048a4a9b9 F test/trigger7.test e7ce54bfda67a88d778aea42544e151c465547a7e617127b6914c2221a6d53c1 F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4 -F test/trigger9.test 2226ec795a33b0460ab5cf8891e9054cc7edef41 +F test/trigger9.test fd49aff8b724ae1a6238989ecf84320d88c0e8f8d9142a891b93f826dfe37b59 F test/triggerA.test 837be862d8721f903dba3f3ceff05b32e0bee5214cf6ea3da5fadf12d3650e9d F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe F test/triggerC.test 29f5a28d0fe39e6e2c01f6e1f53f08c0955170ae10a63ad023e33cb0a1682a51 @@ -1647,7 +1650,7 @@ F test/triggerD.test 8e7f3921a92a5797d472732108109e44575fa650 F test/triggerE.test 612969cb57a4ef792059ad6d01af0117e1ae862c283753ffcc9a6428642b22ee F test/triggerF.test 5d76f0a8c428ff87a4d5ed52da06f6096a2c787a1e21b846111dfac4123de3ad F test/triggerG.test 2b816093c91ba73c733cfa8aedcc210ad819d72a98b1da30768a3c56505233e9 -F test/triggerupfrom.test d25961fa70a99b6736193da7b49a36d8c1d28d56188f0be6406d4366315cd6e4 +F test/triggerupfrom.test d1f9e56090408115c522bee626cc33a2f3370f627a5e341d832589d72e3aa271 F test/trustschema1.test 4e970aef0bfe0cee139703cc7209d0e0f07725d999b180ba50770f49edef1494 F test/tt3_checkpoint.c 9e75cf7c1c364f52e1c47fd0f14c4340a9db0fe1 F test/tt3_core.c 8cd89ead95410f70e7fb02c79f1e040f9c5ad5cf @@ -1659,22 +1662,22 @@ F test/tt3_vacuum.c 1753f45917699c9c1f66b64c717a717c9379f776 F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff F test/types2.test 1aeb81976841a91eef292723649b5c4fe3bc3cac F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a -F test/unionall.test 369dac51f4e7b94442b054d3d7f2e6755cd6994274718228878e3bd47c425f6d -F test/unionall2.test c9a62db63350bcbce3a7bec50dd8c5410f08be33f8af435473756286d4657215 +F test/unionall.test fee6e6adebe5446938475432ae8b042835a286c7e2efdc1b186d2182dfb93ffb +F test/unionall2.test 71e8fa08d5699d50dc9f9dc0c9799c2e7a6bb7931a330d369307a4df7f157fa1 F test/unionallfault.test 652bfbb630e6c43135965dc1e8f0a9a791da83aec885d626a632fe1909c56f73 F test/unionvtab.test e1704ab1b4c1bb3ffc9da4681f8e85a0b909fd80b937984fc94b27415ac8e5a4 F test/unionvtabfault.test e8759f3d14fb938ce9657e2342db34aeac0fb9bc1692b0d1ebb0069630151d06 F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264 F test/unique2.test 3674e9f2a3f1fbbfd4772ac74b7a97090d0f77d2 F test/unixexcl.test d936ba2b06794018e136418addd59a2354eeae97 -F test/unordered.test ffeea7747d5ba962a8009a20b7e53d68cbae05b063604c68702c5998eb50c981 +F test/unordered.test 0edaf3411d300693bca595897c5201421c6c5ec787990a1dfe2f7f60ae93f1e2 F test/update.test e906ca7cb1dc6f52af1ea243e08f727edfa79f924c2691f2f9e72481f847310d F test/update2.test 67455bc61fcbcf96923c45b3bc4f87bc72be7d67575ad35f134906148c7b06d3 F test/upfrom1.tcl 8859d9d437f03b44174c4524a7a734a391fd4526fcff65be08285dafc9dc9041 -F test/upfrom1.test d18f69f7c691bc791e7f31bf0e354eeff04cf2f44edc32d6b1928bad71697073 -F test/upfrom2.test 6ebd3be8c3fac984e89a177d823686f04605b512fc167392bce6d8ba2ba63325 -F test/upfrom3.test 7dab379d128e8dd7beb2055b295fb113c7ba93e8c2038f5ddb7a4a10f0ebb348 -F test/upfromfault.test 70ecf8eb85559727a487283f69374e3ae39879e994d8a2437c49d7c05ecb70c9 +F test/upfrom1.test 8cb06689e99cd707d884faa16da0e8eb26ff658bb01c47ddf72fadade666e6e1 +F test/upfrom2.test f92e47bfc35e9410d3e8716ee626384e89ad026c55fd6148508ca9d707521673 +F test/upfrom3.test 6130f24ebf97f5ea865e5d2a14a2d543fe5428a62e87cc60f62d875e45c1f5f0 +F test/upfromfault.test 3a10075a0043f0c4fad6614b2c371f88a8ba5a4acab68b907438413865d6a8d6 F test/upsert1.test 88f9e258c6a0eeeb85937b08831e8daad440ba41f125af48439e9d33f266fb18 F test/upsert2.test 9c3cdbb1a890227f6504ce4b0e3de68f4cdfa16bb21d8641208a9239896c5a09 F test/upsert3.test 88d7d590a1948a9cb6eac1b54b0642f67a9f35a1fc0f19b200e97d5d39e3179c @@ -1696,7 +1699,8 @@ F test/vacuummem.test 7b42abb3208bd82dd23a7536588396f295a314f2 F test/varint.test bbce22cda8fc4d135bcc2b589574be8410614e62 F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661 F test/view.test ea88361d5e9bc8eabf9f573185a16aea73a885be9b6c6a95ae84908913416a80 -F test/vtab1.test c5d9e90ed02bcacd776dcbb7360199d290f7f53c26b484ddece543060c54319f +F test/view2.test db32c8138b5b556f610b35dfddd38c5a58a292f07fda5281eedb0851b2672679 +F test/vtab1.test 99c0c13b5336ca7f87f137459de144b2f396bb8563fbd602e46bfaa425e3d8cc F test/vtab2.test 14d4ab26cee13ba6cf5c5601b158e4f57552d3b055cdd9406cf7f711e9c84082 F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e F test/vtab4.test 8e73ed268f3d596bc3590f45fc948fb40f28e9c3 @@ -1760,43 +1764,43 @@ F test/walprotocol2.test 7e4bedd5ee83607e2928ac438bf7332a396b980d3e02aa0746509ce F test/walro.test cb438d05ba0d191f10b688e39c4f0cd5b71569a1d1f4440e5bdf3c6880e08c20 F test/walro2.test 0e79dd15cbdb4f482c01ea248373669c732414a726b357d04846a816afafb768 F test/walrofault.test 5a25f91c16a68bae65edec7cdef4495e5c6494c8408743fe9b29045fa6665cd0 -F test/walsetlk.test 11f7fe792fdce54cf09874dab824e0627f2eedecfb9f7983e325606ec5184e0c +F test/walsetlk.test 3185bebc90557e0d611442c8d64f7a0cb7b06f8e156eea37a4a7358f722715be F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417 F test/walslow.test c05c68d4dc2700a982f89133ce103a1a84cc285f F test/walthread.test 14b20fcfa6ae152f5d8e12f5dc8a8a724b7ef189f5d8ef1e2ceab79f2af51747 F test/walvfs.test bccb3e0d235ef85e276f491d34db32c9ada1ea67be8d9f10aabe7b30319ec656 F test/wapp.tcl b440cd8cf57953d3a49e7ee81e6a18f18efdaf113b69f7d8482b0710a64566ec F test/wapptest.tcl 899594e25684861d5b0c0880fb012364def50ef8097041b8ddf74be5ba7fa270 x -F test/where.test e713c0c64e3e6b062235e39a2f7e5508c517df16b63d69fd786e26bc7330b1c6 -F test/where2.test 478d2170637b9211f593120648858593bf2445a1 -F test/where3.test 2341a294e17193a6b1699ea7f192124a5286ca6acfcc3f4b06d16c931fbcda2c +F test/where.test 4f7a3939e5190845ef42142031a1819070f65e065e6a840a09adc54dccfef01f +F test/where2.test 03c21a11e7b90e2845fc3c8b4002fc44cc2797fa74c86ee47d70bd7ea4f29ed6 +F test/where3.test 5b4ffc0ac2ea0fe92f02b1244b7531522fe4d7bccf6fa8741d54e82c10e67753 F test/where4.test 4a371bfcc607f41d233701bdec33ac2972908ba8 F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2 F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b -F test/where7.test 75722434c486ac9e74718caa6cce234f45ba34c0b6c0f9555b29eb8bb5f6ade1 +F test/where7.test ab41d53ce8f2a6919ea3d5b13cd1153c1375a8e3ddaa129b81781f9033981383 F test/where8.test 461ca40265ed996a6305da99bb024b0e41602bb586acf544c08f95922358e49f -F test/where9.test 8e3e0ff42cc17156f52361a1c012281550d0d632912fec92d1d6df74db7a8e6d +F test/where9.test 1ffb75edc50a8faa6e7bd77f8221d783febb00b44b0bdb32fb48cec6e38eca95 F test/whereA.test 9d1077b117f1b68d5f739d94f36956c36cf995eb87bb19b77b2e81af020edd20 F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5 F test/whereC.test cae295158703cb3fc23bf1a108a9ab730efff0f6 F test/whereD.test c1c335e914e28b122e000e9310f02d2be83e1c9dbca2e29f46bd732703944d1b -F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f -F test/whereF.test 3d9412b1199d3e2bed34fcb76b4c48d0bf4df95d27e3f8dd27b6f8b4716d0d89 -F test/whereG.test 77127a4d214bb21da3b5c695cf4106cd9e418c60d9c24471ba55d3772067cd35 +F test/whereE.test 0ac7e61c6225354a980666996539da154991b4325af943a25a9079079c82fb03 +F test/whereF.test 926b65519608e3f2aa28720822b9154fb5c7b13519dd78194f434a511ab3dac5 +F test/whereG.test 8f1a753826d07ed7ae107fbec0d482d348bac6d7edf9db9c5736c06b0b3e9961 F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2 -F test/whereI.test a2874062140ed4aba9ffae76e6190a3df6fc73d1373fdfa8fd632945082a5364 -F test/whereJ.test 88287550f6ee604422403b053455b1ad894eeaa5c35d348532dfa1439286cb9a -F test/whereK.test f8e3cf26a8513ecc7f514f54df9f0572c046c42b -F test/whereL.test 1afe47227f093dc0547236491fb37529b7be9724b8575925a321001b80e6a23a -F test/wherefault.test 1374c3aa198388925246475f84ad4cd5f9528864 +F test/whereI.test c4bb7e2ca56d49bd8ab5c7bd085b8b83e353922b46904d68aefb3c7468643581 +F test/whereJ.test fc05e374cc9f2dc204148d6c06822c380ad388895fe97a6d335b94a26a08aecf +F test/whereK.test 0270ab7f04ba5436fb9156d31d642a1c82727f4c4bfe5ba90d435c78cf44684a +F test/whereL.test 50171e3ec00b4c8ad5ec773119a35d9e9642cec45154b44c366d628326479f4d +F test/wherefault.test 6cf2a9c5712952d463d3f45ebee7f6caf400984df51a195d884cfb7eb0e837a7 F test/wherelfault.test 9012e4ef5259058b771606616bd007af5d154e64cc25fa9fd4170f6411db44e3 -F test/wherelimit.test daa0fd9122c5745cc459ec40b8d3c16ce13ce8382b5b847e7cfff4b871260cbf +F test/wherelimit.test afb46397c6d7e964e6e294ba3569864a0c570fe3807afc634236c2b752372f31 F test/wherelimit2.test 657a3f24aadee62d058c5091ea682dc4af4b95ffe32f137155be49799a58e721 F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2aeee74 F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972 F test/win32longpath.test 4baffc3acb2e5188a5e3a895b2b543ed09e62f7c72d713c1feebf76222fe9976 F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc -F test/window1.test e52b81fff0c3cb122a1240f336688eb81bea2967a99c4ddb78969adec7aadc2a +F test/window1.test 7cb66f49d30d89ca9d28dc20f7f1d85229365651e8e6211f7da1448740866511 F test/window2.tcl 492c125fa550cda1dd3555768a2303b3effbeceee215293adf8871efc25f1476 F test/window2.test e466a88bd626d66edc3d352d7d7e1d5531e0079b549ba44efb029d1fbff9fd3c F test/window3.tcl acea6e86a4324a210fd608d06741010ca83ded9fde438341cb978c49928faf03 @@ -1807,34 +1811,34 @@ F test/window5.test d328dd18221217c49c144181975eea17339eaeaf0e9aa558cee3afb84652 F test/window6.test f8d674254b23289cc17c84d79dec7eda7caa1dfb7836c43122cfdf3640d1df32 F test/window7.tcl 6a1210f05d40ec89c22960213a22cd3f98d4e2f2eb20646c83c8c30d4d76108f F test/window7.test 1d31276961ae7801edc72173edaf7593e3cbc79c06d1f1f09e20d8418af403cd -F test/window8.tcl f2711aa3571e4e6b0dad98db8d95fd6cb8d9db0c92bbdf535f153b07606a1ce2 -F test/window8.test c4331b27a6f66d69fa8f8bab10cc731db1a81d293ae108a68f7c3487fa94e65b -F test/window9.test 4d8c875b73febdbac9b8f2b52ec132b98f48261cdafd6b08db62bc6d8ff913fc +F test/window8.tcl 5e02e41d9d9a80f597063aed1a381eb19d1d0ef677a4f0df352c5365cf23f79c +F test/window8.test 4ab16817414af0c904abe2ebdf88eb6c2b00058b84f9748c6174ff11fc45f1ed +F test/window9.test 349c71eab4288a1ffc19e2f65872ec2c37e6cf8a1dda2ad300364b7450ae4836 F test/windowA.test 6d63dc1260daa17141a55007600581778523a8b420629f1282d2acfc36af23be F test/windowB.test 6e601f8178ba8ba28b2f19e74fe613815084bb4a8d2ad942defc7d42e191e521 F test/windowerr.tcl f5acd6fbc210d7b5546c0e879d157888455cd4a17a1d3f28f07c1c8a387019e0 F test/windowerr.test a8b752402109c15aa1c5efe1b93ccb0ce1ef84fa964ae1cd6684dd0b3cc1819b -F test/windowfault.test d543d46571b32d19f198cb04b6505747fabf3cc369970daae47074ee793612be -F test/windowpushd.test 5b9c114e8173c3addacf58a0fcd941437b14649f2033700184479a13f188ad00 -F test/with1.test 780be387f01e290e768bdfd1827280f9e37ba37223eb4736aba386864fac5a94 +F test/windowfault.test 21919e601f20b976ea2a73aa401220c89ed0e8d203c4f69476ea55bce3726496 +F test/windowpushd.test d8895d08870b7226f7693665bd292eb177e62ca06799184957b3ca7dc03067df +F test/with1.test 7bc5abfe4c80c0cef8a90f5a66d60b9982e8ccd7350c8eb70611323a3b8e07ba F test/with2.test 000fb95f1f29dae868cea0f41505eb5126077d49eb967ff88f9ee46212ad8863 -F test/with3.test 2f1e05aef7aeef9a741cbf36deeb4be73003dc541921c3abc78becbbf5b7852d +F test/with3.test ad32d13ad50661e6fa305f62a0717649c348792e7b658bf2644976227a9e0373 F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f198205 F test/with5.test 6248213c41fab36290b5b73aa3f937309dfba337004d9d8434c3fabc8c7d4be8 -F test/with6.test 3001b59179cbdc26a8c67ff8f46944e3141fdece9ab064c49bbf08459b67b207 +F test/with6.test 661d7e416bef6c0a2556b2c9f0c8178a5b15932bed65246abed99723a8d4e7c0 F test/withM.test 693b61765f2b387b5e3e24a4536e2e82de15ff64 -F test/without_rowid1.test e4034c0849ccc2e8bb749c69f15bd69bb9fcf8fe77e8d17ce02369604242fe83 +F test/without_rowid1.test 6abc5d497f634520944dac0a89a6c240a48d2ee0f8353356a750eb70dc1db41a 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_rowid6.test 8463b20098e9f75a501a9f17dfb42fffc79068eac0b2775fe56ef2281d2df45e +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/zerodamage.test 9c41628db7e8d9e8a0181e59ea5f189df311a9f6ce99cc376dc461f66db6f8dc -F test/zipfile.test 429cb81c518487fa1b644b6b04b6e9af704a4fa767bd1a110204c5f03b2e8616 +F test/zipfile.test 0d8758d8c0d63f16644f959689f78969d223789d998964276554039f067b4548 F test/zipfile2.test 9903388a602a3834189857a985106ff95c3bba6a3969e0134127df991889db5d F test/zipfilefault.test 44d4d7a7f7cca7521d569d7f71026b241d65a6b1757aa409c1a168827edbbc2c F tool/GetFile.cs 47852aa0d806fe47ed1ac5138bdce7f000fe87aaa7f28107d0cb1e26682aeb44 @@ -1858,7 +1862,7 @@ 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 d44ba4f03427c9bd34b601f315fe77c2b6d4bd215801a0259aeedbcc4c94a95c +F tool/lemon.c a5acddd3eec6a388872aae6efc7563336348a9c45e5563642f77e8e3a50e859d F tool/lempar.c 1d3d075da18681c67ecc66c1f171e7094e18cd2cfba6a8a1bd4f3f639d6656e1 F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9 F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862 @@ -1866,11 +1870,11 @@ F tool/logest.c 11346aa019e2e77a00902aa7d0cabd27bd2e8cca F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439 F tool/mkautoconfamal.sh f62353eb6c06ab264da027fd4507d09914433dbdcab9cb011cdc18016f1ab3b8 F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x -F tool/mkctimec.tcl dd183b73ae1c28249669741c250525f0407e579a70482371668fd5f130d9feb3 +F tool/mkctimec.tcl 06b0d503ee0e6c2d4abe83563b43d4925a12e31ec9fb3249ce39661f53fbd1ce F tool/mkkeywordhash.c 08b6e4d7a482a7f37a9a0032e7ba968e26624a027b6b2e9ba589be6f5e3d8c2c F tool/mkmsvcmin.tcl 6ecab9fe22c2c8de4d82d4c46797bda3d2deac8e763885f5a38d0c44a895ab33 F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c -F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21 +F tool/mkopcodeh.tcl acc798757e2c60e4b6e16745505b9595fca76c206815c8ada576a136cf3608ed F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa F tool/mkpragmatab.tcl d189900fe12be39539f7101222968ac7a5774a63638471f0b6bff9c35006743a F tool/mkshellc.tcl 70a9978e363b0f3280ca9ce1c46d72563ff479c1930a12a7375e3881b7325712 @@ -1882,14 +1886,14 @@ F tool/mksqlite3h.tcl 1f5e4a1dbbbc43c83cc6e74fe32c6c620502240b66c7c0f33a51378e78 F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b F tool/mkvsix.tcl b9e0777a213c23156b6542842c238479e496ebf5 F tool/offsets.c 8ed2b344d33f06e71366a9b93ccedaa38c096cc1dbd4c3c26ad08c6115285845 -F tool/omittest.tcl 6616fbf384f0f630113eab27d41d4530435dd94e2883307759988b45f0604a3b +F tool/omittest.tcl 3d222272b1d840b4e3d67bff0cb743ce3f633faddadb3702b2056b726775db8f F tool/opcodesum.tcl 740ed206ba8c5040018988129abbf3089a0ccf4a F tool/pagesig.c ff0ca355fd3c2398e933da5e22439bbff89b803b F tool/replace.tcl 60f91e8dd06ab81f74d213ecbd9c9945f32ac048 F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5 F tool/run-speed-test.sh f95d19fd669b68c4c38b6b475242841d47c66076 -F tool/showdb.c 49e810f5c414c792b5bf38cd5557ca9639713ebfef32aaff32faf7cb7ccce513 +F tool/showdb.c 8c6b1cbb86ee25ca2173497183f8fcd444d4e26923e4cf57ddabe66c633b4dab F tool/showjournal.c 5bad7ae8784a43d2b270d953060423b8bd480818 F tool/showlocks.c 9cc5e66d4ebbf2d194f39db2527ece92077e86ae627ddd233ee48e16e8142564 F tool/showshm.c a0ab6ec32dd1f11218ca2a4018f8fb875b59414801ab8ceed8b2e69b7b45a809 @@ -1941,7 +1945,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 939b9e75307de5067a11351dd4010046a5400e8126c5c2bafea4fbea97e00f86 a1b8d9d2131830510df291832565311803aa3e047fe07ba979fc69bb0ff329b0 -R 7bbf6335d87c431b256bdcc0e37c4449 -U drh -Z bcbd80bc941321d81490b0f3b639d622 +P 4d425e641d3c45692904018aa8fcff678836b45509e640e67fa2d1ade625a746 95cc7783457b39bbe0866295648a86e7ee5e1660048ab133f1ccf300498ef1bf +R 066113fe997854e21efe7108e9d23406 +U dan +Z 8826b40f6989cab227702a244668a78d diff --git a/manifest.uuid b/manifest.uuid index 4725df9725..6fb353864d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4d425e641d3c45692904018aa8fcff678836b45509e640e67fa2d1ade625a746 \ No newline at end of file +4efefb5938c1ec83ee367ae5cc4bba906729b4e8699fa81adc6ca3618c73eb03 \ No newline at end of file diff --git a/src/alter.c b/src/alter.c index c0797db45e..047b407e5b 100644 --- a/src/alter.c +++ b/src/alter.c @@ -29,8 +29,9 @@ ** Or, if zName is not a system table, zero is returned. */ static int isAlterableTable(Parse *pParse, Table *pTab){ - if( 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7) + if( 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7) #ifndef SQLITE_OMIT_VIRTUALTABLE + || (pTab->tabFlags & TF_Eponymous)!=0 || ( (pTab->tabFlags & TF_Shadow)!=0 && sqlite3ReadOnlyShadowTables(pParse->db) ) @@ -54,7 +55,7 @@ static void renameTestSchema( const char *zDb, /* Name of db to verify schema of */ int bTemp, /* True if this is the temp db */ const char *zWhen, /* "when" part of error message */ - const char *zDropColumn /* Name of column being dropped */ + int bNoDQS /* Do not allow DQS in the schema */ ){ pParse->colNamesSet = 1; sqlite3NestedParse(pParse, @@ -62,9 +63,9 @@ static void renameTestSchema( "FROM \"%w\"." DFLT_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, %Q)=NULL ", + " AND sqlite_rename_test(%Q, sql, type, name, %d, %Q, %d)=NULL ", zDb, - zDb, bTemp, zWhen, zDropColumn + zDb, bTemp, zWhen, bNoDQS ); if( bTemp==0 ){ @@ -73,8 +74,32 @@ static void renameTestSchema( "FROM temp." DFLT_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, %Q)=NULL ", - zDb, zWhen, zDropColumn + " AND sqlite_rename_test(%Q, sql, type, name, 1, %Q, %d)=NULL ", + zDb, zWhen, bNoDQS + ); + } +} + +/* +** Generate VM code to replace any double-quoted strings (but not double-quoted +** identifiers) within the "sql" column of the sqlite_schema table in +** database zDb with their single-quoted equivalents. If argument bTemp is +** not true, similarly update all SQL statements in the sqlite_schema table +** of the temp db. +*/ +static void renameFixQuotes(Parse *pParse, const char *zDb, int bTemp){ + sqlite3NestedParse(pParse, + "UPDATE \"%w\"." DFLT_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 + " SET sql = sqlite_rename_quotefix('temp', sql)" + "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" + " AND sql NOT LIKE 'create virtual%%'" ); } } @@ -237,7 +262,7 @@ void sqlite3AlterRenameTable( "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, 1), " "tbl_name = " "CASE WHEN tbl_name=%Q COLLATE nocase AND " - " sqlite_rename_test(%Q, sql, type, name, 1, 'after rename',0) " + " sqlite_rename_test(%Q, sql, type, name, 1, 'after rename', 0) " "THEN %Q ELSE tbl_name END " "WHERE type IN ('view', 'trigger')" , zDb, zTabName, zName, zTabName, zDb, zName); @@ -596,6 +621,10 @@ void sqlite3AlterRenameColumn( goto exit_rename_column; } + /* Ensure the schema contains no double-quoted strings */ + renameTestSchema(pParse, zDb, iSchema==1, "", 0); + renameFixQuotes(pParse, zDb, iSchema==1); + /* Do the rename operation using a recursive UPDATE statement that ** uses the sqlite_rename_column() SQL function to compute the new ** CREATE statement text for the sqlite_schema table. @@ -625,7 +654,7 @@ void sqlite3AlterRenameColumn( /* Drop and reload the database schema. */ renameReloadSchema(pParse, iSchema, INITFLAG_AlterRename); - renameTestSchema(pParse, zDb, iSchema==1, "after rename", 0); + renameTestSchema(pParse, zDb, iSchema==1, "after rename", 1); exit_rename_column: sqlite3SrcListDelete(db, pSrc); @@ -806,7 +835,7 @@ static int renameUnmapSelectCb(Walker *pWalker, Select *p){ Parse *pParse = pWalker->pParse; int i; if( pParse->nErr ) return WRC_Abort; - if( NEVER(p->selFlags & SF_View) ) return WRC_Prune; + if( p->selFlags & SF_View ) return WRC_Prune; if( ALWAYS(p->pEList) ){ ExprList *pList = p->pEList; for(i=0; inExpr; i++){ @@ -890,7 +919,9 @@ static RenameToken *renameTokenFind( void *pPtr ){ RenameToken **pp; - assert( pPtr!=0 ); + if( NEVER(pPtr==0) ){ + return 0; + } for(pp=&pParse->pRename; (*pp); pp=&(*pp)->pNext){ if( (*pp)->p==pPtr ){ RenameToken *pToken = *pp; @@ -1049,17 +1080,12 @@ static int renameParseSql( const char *zDb, /* Name of schema SQL belongs to */ sqlite3 *db, /* Database handle */ const char *zSql, /* SQL to parse */ - int bTemp, /* True if SQL is from temp schema */ - const char *zDropColumn /* Name of column being dropped */ + int bTemp /* True if SQL is from temp schema */ ){ int rc; char *zErr = 0; db->init.iDb = bTemp ? 1 : sqlite3FindDbName(db, zDb); - if( zDropColumn ){ - db->init.bDropColumn = 1; - db->init.azInit = (char**)&zDropColumn; - } /* Parse the SQL statement passed as the first argument. If no error ** occurs and the parse does not result in a new table, index or @@ -1092,7 +1118,6 @@ static int renameParseSql( #endif db->init.iDb = 0; - db->init.bDropColumn = 0; return rc; } @@ -1116,47 +1141,72 @@ static int renameEditSql( int nSql = sqlite3Strlen30(zSql); sqlite3 *db = sqlite3_context_db_handle(pCtx); int rc = SQLITE_OK; - char *zQuot; + char *zQuot = 0; char *zOut; - int nQuot; + int nQuot = 0; + char *zBuf1 = 0; + char *zBuf2 = 0; - /* Set zQuot to point to a buffer containing a quoted copy of the - ** identifier zNew. If the corresponding identifier in the original - ** ALTER TABLE statement was quoted (bQuote==1), then set zNew to - ** point to zQuot so that all substitutions are made using the - ** quoted version of the new column name. */ - zQuot = sqlite3MPrintf(db, "\"%w\"", zNew); - if( zQuot==0 ){ - return SQLITE_NOMEM; + if( zNew ){ + /* Set zQuot to point to a buffer containing a quoted copy of the + ** identifier zNew. If the corresponding identifier in the original + ** ALTER TABLE statement was quoted (bQuote==1), then set zNew to + ** point to zQuot so that all substitutions are made using the + ** quoted version of the new column name. */ + zQuot = sqlite3MPrintf(db, "\"%w\" ", zNew); + if( zQuot==0 ){ + return SQLITE_NOMEM; + }else{ + nQuot = sqlite3Strlen30(zQuot)-1; + } + + assert( nQuot>=nNew ); + zOut = sqlite3DbMallocZero(db, nSql + pRename->nList*nQuot + 1); }else{ - nQuot = sqlite3Strlen30(zQuot); - } - if( bQuote ){ - zNew = zQuot; - nNew = nQuot; + zOut = (char*)sqlite3DbMallocZero(db, (nSql*2+1) * 3); + if( zOut ){ + zBuf1 = &zOut[nSql*2+1]; + zBuf2 = &zOut[nSql*4+2]; + } } /* At this point pRename->pList contains a list of RenameToken objects ** corresponding to all tokens in the input SQL that must be replaced - ** with the new column name. All that remains is to construct and - ** return the edited SQL string. */ - assert( nQuot>=nNew ); - zOut = sqlite3DbMallocZero(db, nSql + pRename->nList*nQuot + 1); + ** with the new column name, or with single-quoted versions of themselves. + ** All that remains is to construct and return the edited SQL string. */ if( zOut ){ int nOut = nSql; memcpy(zOut, zSql, nSql); while( pRename->pList ){ int iOff; /* Offset of token to replace in zOut */ - RenameToken *pBest = renameColumnTokenNext(pRename); - u32 nReplace; const char *zReplace; - if( sqlite3IsIdChar(*pBest->t.z) ){ - nReplace = nNew; - zReplace = zNew; + RenameToken *pBest = renameColumnTokenNext(pRename); + + if( zNew ){ + if( bQuote==0 && sqlite3IsIdChar(*pBest->t.z) ){ + nReplace = nNew; + zReplace = zNew; + }else{ + nReplace = nQuot; + zReplace = zQuot; + if( pBest->t.z[pBest->t.n]=='"' ) nReplace++; + } }else{ - nReplace = nQuot; - zReplace = zQuot; + /* Dequote the double-quoted token. Then requote it again, this time + ** using single quotes. If the character immediately following the + ** original token within the input SQL was a single quote ('), then + ** add another space after the new, single-quoted version of the + ** token. This is so that (SELECT "string"'alias') maps to + ** (SELECT 'string' 'alias'), and not (SELECT 'string''alias'). */ + memcpy(zBuf1, pBest->t.z, pBest->t.n); + zBuf1[pBest->t.n] = 0; + sqlite3Dequote(zBuf1); + sqlite3_snprintf(nSql*2, zBuf2, "%Q%s", zBuf1, + pBest->t.z[pBest->t.n]=='\'' ? " " : "" + ); + zReplace = zBuf2; + nReplace = sqlite3Strlen30(zReplace); } iOff = pBest->t.z - zSql; @@ -1394,7 +1444,7 @@ static void renameColumnFunc( #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = 0; #endif - rc = renameParseSql(&sParse, zDb, db, zSql, bTemp, 0); + rc = renameParseSql(&sParse, zDb, db, zSql, bTemp); /* Find tokens that need to be replaced. */ memset(&sWalker, 0, sizeof(Walker)); @@ -1528,7 +1578,7 @@ static int renameTableSelectCb(Walker *pWalker, Select *pSelect){ RenameCtx *p = pWalker->u.pRename; SrcList *pSrc = pSelect->pSrc; if( pSelect->selFlags & SF_View ) return WRC_Prune; - if( pSrc==0 ){ + if( NEVER(pSrc==0) ){ assert( pWalker->pParse->db->mallocFailed ); return WRC_Abort; } @@ -1598,7 +1648,7 @@ static void renameTableFunc( sWalker.xSelectCallback = renameTableSelectCb; sWalker.u.pRename = &sCtx; - rc = renameParseSql(&sParse, zDb, db, zInput, bTemp, 0); + rc = renameParseSql(&sParse, zDb, db, zInput, bTemp); if( rc==SQLITE_OK ){ int isLegacy = (db->flags & SQLITE_LegacyAlter); @@ -1701,6 +1751,119 @@ static void renameTableFunc( return; } +static int renameQuotefixExprCb(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_STRING && (pExpr->flags & EP_DblQuoted) ){ + renameTokenFind(pWalker->pParse, pWalker->u.pRename, (void*)pExpr); + } + return WRC_Continue; +} + +/* +** The implementation of an SQL scalar function that rewrites DDL statements +** so that any string literals that use double-quotes are modified so that +** they use single quotes. +** +** Two arguments must be passed: +** +** 0: Database name ("main", "temp" etc.). +** 1: SQL statement to edit. +** +** The returned value is the modified SQL statement. For example, given +** the database schema: +** +** CREATE TABLE t1(a, b, c); +** +** SELECT sqlite_rename_quotefix('main', +** 'CREATE VIEW v1 AS SELECT "a", "string" FROM t1' +** ); +** +** returns the string: +** +** CREATE VIEW v1 AS SELECT "a", 'string' FROM t1 +*/ +static void renameQuotefixFunc( + sqlite3_context *context, + int NotUsed, + sqlite3_value **argv +){ + sqlite3 *db = sqlite3_context_db_handle(context); + char const *zDb = (const char*)sqlite3_value_text(argv[0]); + char const *zInput = (const char*)sqlite3_value_text(argv[1]); + +#ifndef SQLITE_OMIT_AUTHORIZATION + sqlite3_xauth xAuth = db->xAuth; + db->xAuth = 0; +#endif + + sqlite3BtreeEnterAll(db); + + UNUSED_PARAMETER(NotUsed); + if( zDb && zInput ){ + int rc; + Parse sParse; + rc = renameParseSql(&sParse, zDb, db, zInput, 0); + + if( rc==SQLITE_OK ){ + RenameCtx sCtx; + Walker sWalker; + + /* Walker to find tokens that need to be replaced. */ + memset(&sCtx, 0, sizeof(RenameCtx)); + memset(&sWalker, 0, sizeof(Walker)); + sWalker.pParse = &sParse; + sWalker.xExprCallback = renameQuotefixExprCb; + sWalker.xSelectCallback = renameColumnSelectCb; + sWalker.u.pRename = &sCtx; + + if( sParse.pNewTable ){ + Select *pSelect = sParse.pNewTable->pSelect; + if( pSelect ){ + pSelect->selFlags &= ~SF_View; + sParse.rc = SQLITE_OK; + sqlite3SelectPrep(&sParse, pSelect, 0); + rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc); + if( rc==SQLITE_OK ){ + sqlite3WalkSelect(&sWalker, pSelect); + } + }else{ + int i; + sqlite3WalkExprList(&sWalker, sParse.pNewTable->pCheck); +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + for(i=0; inCol; i++){ + sqlite3WalkExpr(&sWalker, sParse.pNewTable->aCol[i].pDflt); + } +#endif /* SQLITE_OMIT_GENERATED_COLUMNS */ + } + }else if( sParse.pNewIndex ){ + sqlite3WalkExprList(&sWalker, sParse.pNewIndex->aColExpr); + sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere); + }else{ +#ifndef SQLITE_OMIT_TRIGGER + rc = renameResolveTrigger(&sParse); + if( rc==SQLITE_OK ){ + renameWalkTrigger(&sWalker, sParse.pNewTrigger); + } +#endif /* SQLITE_OMIT_TRIGGER */ + } + + if( rc==SQLITE_OK ){ + rc = renameEditSql(context, &sCtx, zInput, 0, 0); + } + renameTokenFree(db, sCtx.pList); + } + if( rc!=SQLITE_OK ){ + sqlite3_result_error_code(context, rc); + } + renameParseCleanup(&sParse); + } + +#ifndef SQLITE_OMIT_AUTHORIZATION + db->xAuth = xAuth; +#endif + + sqlite3BtreeLeaveAll(db); +} + /* ** An SQL user function that checks that there are no parse or symbol ** resolution problems in a CREATE TRIGGER|TABLE|VIEW|INDEX statement. @@ -1714,7 +1877,7 @@ static void renameTableFunc( ** 3: Object name. ** 4: True if object is from temp schema. ** 5: "when" part of error message. -** 6: Name of column being dropped, or NULL. +** 6: True to disable the DQS quirk when parsing SQL. ** ** Unless it finds an error, this function normally returns NULL. However, it ** returns integer value 1 if: @@ -1733,7 +1896,7 @@ static void renameTableTest( int bTemp = sqlite3_value_int(argv[4]); int isLegacy = (db->flags & SQLITE_LegacyAlter); char const *zWhen = (const char*)sqlite3_value_text(argv[5]); - char const *zDropColumn = (const char*)sqlite3_value_text(argv[6]); + int bNoDQS = sqlite3_value_int(argv[6]); #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth = db->xAuth; @@ -1741,10 +1904,14 @@ static void renameTableTest( #endif UNUSED_PARAMETER(NotUsed); + if( zDb && zInput ){ int rc; Parse sParse; - rc = renameParseSql(&sParse, zDb, db, zInput, bTemp, zDropColumn); + int flags = db->flags; + if( bNoDQS ) db->flags &= ~(SQLITE_DqsDML|SQLITE_DqsDDL); + 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 ){ NameContext sNC; @@ -1812,7 +1979,7 @@ static void dropColumnFunc( #endif UNUSED_PARAMETER(NotUsed); - rc = renameParseSql(&sParse, zDb, db, zSql, iSchema==1, 0); + rc = renameParseSql(&sParse, zDb, db, zSql, iSchema==1); if( rc!=SQLITE_OK ) goto drop_column_done; pTab = sParse.pNewTable; if( pTab==0 || pTab->nCol==1 || iCol>=pTab->nCol ){ @@ -1906,6 +2073,7 @@ void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, Token *pName){ assert( iDb>=0 ); zDb = db->aDb[iDb].zDbSName; renameTestSchema(pParse, zDb, iDb==1, "", 0); + renameFixQuotes(pParse, zDb, iDb==1); sqlite3NestedParse(pParse, "UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET " "sql = sqlite_drop_column(%d, sql, %d) " @@ -1915,7 +2083,7 @@ void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, Token *pName){ /* Drop and reload the database schema. */ renameReloadSchema(pParse, iDb, INITFLAG_AlterDrop); - renameTestSchema(pParse, zDb, iDb==1, "after drop column", zCol); + renameTestSchema(pParse, zDb, iDb==1, "after drop column", 1); /* Edit rows of table on disk */ if( pParse->nErr==0 && (pTab->aCol[iCol].colFlags & COLFLAG_VIRTUAL)==0 ){ @@ -1931,33 +2099,44 @@ void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, Token *pName){ sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite); addr = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v); reg = ++pParse->nMem; - pParse->nMem += pTab->nCol; if( HasRowid(pTab) ){ sqlite3VdbeAddOp2(v, OP_Rowid, iCur, reg); + pParse->nMem += pTab->nCol; }else{ pPk = sqlite3PrimaryKeyIndex(pTab); + pParse->nMem += pPk->nColumn; + for(i=0; inKeyCol; i++){ + sqlite3VdbeAddOp3(v, OP_Column, iCur, i, reg+i+1); + } + nField = pPk->nKeyCol; } + regRec = ++pParse->nMem; for(i=0; inCol; i++){ if( i!=iCol && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){ int regOut; if( pPk ){ int iPos = sqlite3TableColumnToIndex(pPk, i); int iColPos = sqlite3TableColumnToIndex(pPk, iCol); + if( iPosnKeyCol ) continue; regOut = reg+1+iPos-(iPos>iColPos); }else{ regOut = reg+1+nField; } - sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut); + if( i==pTab->iPKey ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, regOut); + }else{ + sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut); + } nField++; } } - regRec = reg + pTab->nCol; sqlite3VdbeAddOp3(v, OP_MakeRecord, reg+1, nField, regRec); if( pPk ){ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iCur, regRec, reg+1, pPk->nKeyCol); }else{ sqlite3VdbeAddOp3(v, OP_Insert, iCur, regRec, reg); } + sqlite3VdbeChangeP5(v, OPFLAG_SAVEPOSITION); sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr); @@ -1977,6 +2156,7 @@ void sqlite3AlterFunctions(void){ INTERNAL_FUNCTION(sqlite_rename_table, 7, renameTableFunc), INTERNAL_FUNCTION(sqlite_rename_test, 7, renameTableTest), INTERNAL_FUNCTION(sqlite_drop_column, 3, dropColumnFunc), + INTERNAL_FUNCTION(sqlite_rename_quotefix,2, renameQuotefixFunc), }; sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs)); } diff --git a/src/attach.c b/src/attach.c index 8eb4486e58..2fc84e5b84 100644 --- a/src/attach.c +++ b/src/attach.c @@ -95,7 +95,7 @@ static void attachFunc( if( zFile==0 ) zFile = ""; if( zName==0 ) zName = ""; -#ifdef SQLITE_ENABLE_DESERIALIZE +#ifndef SQLITE_OMIT_DESERIALIZE # define REOPEN_AS_MEMDB(db) (db->init.reopenMemdb) #else # define REOPEN_AS_MEMDB(db) (0) @@ -464,14 +464,17 @@ static int fixSelectCb(Walker *p, Select *pSelect){ if( NEVER(pList==0) ) return WRC_Continue; for(i=0, pItem=pList->a; inSrc; i++, pItem++){ if( pFix->bTemp==0 ){ - if( pItem->zDatabase && iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){ - sqlite3ErrorMsg(pFix->pParse, - "%s %T cannot reference objects in database %s", - pFix->zType, pFix->pName, pItem->zDatabase); - return WRC_Abort; + if( pItem->zDatabase ){ + if( iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){ + sqlite3ErrorMsg(pFix->pParse, + "%s %T cannot reference objects in database %s", + pFix->zType, pFix->pName, pItem->zDatabase); + return WRC_Abort; + } + sqlite3DbFree(db, pItem->zDatabase); + pItem->zDatabase = 0; + pItem->fg.notCte = 1; } - sqlite3DbFree(db, pItem->zDatabase); - pItem->zDatabase = 0; pItem->pSchema = pFix->pSchema; pItem->fg.fromDDL = 1; } @@ -511,7 +514,7 @@ void sqlite3FixInit( pFix->w.pParse = pParse; pFix->w.xExprCallback = fixExprCb; pFix->w.xSelectCallback = fixSelectCb; - pFix->w.xSelectCallback2 = 0; + pFix->w.xSelectCallback2 = sqlite3WalkWinDefnDummyCallback; pFix->w.walkerDepth = 0; pFix->w.eCode = 0; pFix->w.u.pFix = pFix; @@ -573,14 +576,16 @@ int sqlite3FixTriggerStep( return 1; } #ifndef SQLITE_OMIT_UPSERT - if( pStep->pUpsert ){ - Upsert *pUp = pStep->pUpsert; - if( sqlite3WalkExprList(&pFix->w, pUp->pUpsertTarget) - || sqlite3WalkExpr(&pFix->w, pUp->pUpsertTargetWhere) - || sqlite3WalkExprList(&pFix->w, pUp->pUpsertSet) - || sqlite3WalkExpr(&pFix->w, pUp->pUpsertWhere) - ){ - return 1; + { + Upsert *pUp; + for(pUp=pStep->pUpsert; pUp; pUp=pUp->pNextUpsert){ + if( sqlite3WalkExprList(&pFix->w, pUp->pUpsertTarget) + || sqlite3WalkExpr(&pFix->w, pUp->pUpsertTargetWhere) + || sqlite3WalkExprList(&pFix->w, pUp->pUpsertSet) + || sqlite3WalkExpr(&pFix->w, pUp->pUpsertWhere) + ){ + return 1; + } } } #endif diff --git a/src/btree.c b/src/btree.c index c6f205bba3..8c8268835a 100644 --- a/src/btree.c +++ b/src/btree.c @@ -780,7 +780,7 @@ static void invalidateIncrblobCursors( int isClearTable /* True if all rows are being deleted */ ){ BtCursor *p; - if( pBtree->hasIncrblobCur==0 ) return; + assert( pBtree->hasIncrblobCur ); assert( sqlite3BtreeHoldsMutex(pBtree) ); pBtree->hasIncrblobCur = 0; for(p=pBtree->pBt->pCursor; p; p=p->pNext){ @@ -1688,6 +1688,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ unsigned char *src; /* Source of content */ int iCellFirst; /* First allowable cell index */ int iCellLast; /* Last possible cell index */ + int iCellStart; /* First cell offset in input */ assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( pPage->pBt!=0 ); @@ -1729,7 +1730,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( NEVER(iFree+sz>usableSize) ){ + }else if( iFree+sz>usableSize ){ return SQLITE_CORRUPT_PAGE(pPage); } @@ -1748,6 +1749,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ cbrk = usableSize; iCellLast = usableSize - 4; + iCellStart = get2byte(&data[hdr+5]); for(i=0; iiCellLast ){ + if( pciCellLast ){ return SQLITE_CORRUPT_PAGE(pPage); } - assert( pc>=iCellFirst && pc<=iCellLast ); + assert( pc>=iCellStart && pc<=iCellLast ); size = pPage->xCellSize(pPage, &src[pc]); cbrk -= size; - if( cbrkusableSize ){ + if( cbrkusableSize ){ return SQLITE_CORRUPT_PAGE(pPage); } - assert( cbrk+size<=usableSize && cbrk>=iCellFirst ); + assert( cbrk+size<=usableSize && cbrk>=iCellStart ); testcase( cbrk+size==usableSize ); testcase( pc+size==usableSize ); put2byte(pAddr, cbrk); if( temp==0 ){ - int x; if( cbrk==pc ) continue; temp = sqlite3PagerTempSpace(pPage->pBt->pPager); - x = get2byte(&data[hdr+5]); - memcpy(&temp[x], &data[x], (cbrk+size) - x); + memcpy(&temp[iCellStart], &data[iCellStart], (cbrk+size) - iCellStart); src = temp; } memcpy(&data[cbrk], &src[pc], size); @@ -5852,7 +5852,9 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ for(ii=0; iiiPage; ii++){ assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell ); } - assert( pCur->ix==pCur->pPage->nCell-1 ); + assert( pCur->ix==pCur->pPage->nCell-1 || CORRUPT_DB ); + testcase( pCur->ix!=pCur->pPage->nCell-1 ); + /* ^-- dbsqlfuzz b92b72e4de80b5140c30ab71372ca719b8feb618 */ assert( pCur->pPage->leaf ); #endif *pRes = 0; @@ -6629,7 +6631,7 @@ static int allocateBtreePage( iPage = get4byte(&aData[8+closest*4]); testcase( iPage==mxPage ); - if( iPage>mxPage ){ + if( iPage>mxPage || iPage<2 ){ rc = SQLITE_CORRUPT_PGNO(iTrunk); goto end_allocate_page; } @@ -6885,10 +6887,9 @@ static void freePage(MemPage *pPage, int *pRC){ } /* -** Free any overflow pages associated with the given Cell. Store -** size information about the cell in pInfo. +** Free the overflow pages associated with the given Cell. */ -static int clearCell( +static SQLITE_NOINLINE int clearCellOverflow( MemPage *pPage, /* The page that contains the Cell */ unsigned char *pCell, /* First byte of the Cell */ CellInfo *pInfo /* Size information about the cell */ @@ -6900,10 +6901,7 @@ static int clearCell( u32 ovflPageSize; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); - pPage->xParseCell(pPage, pCell, pInfo); - if( pInfo->nLocal==pInfo->nPayload ){ - return SQLITE_OK; /* No overflow pages. Return without doing anything */ - } + assert( pInfo->nLocal!=pInfo->nPayload ); testcase( pCell + pInfo->nSize == pPage->aDataEnd ); testcase( pCell + (pInfo->nSize-1) == pPage->aDataEnd ); if( pCell + pInfo->nSize > pPage->aDataEnd ){ @@ -6959,6 +6957,21 @@ static int clearCell( return SQLITE_OK; } +/* Call xParseCell to compute the size of a cell. If the cell contains +** overflow, then invoke cellClearOverflow to clear out that overflow. +** STore the result code (SQLITE_OK or some error code) in rc. +** +** Implemented as macro to force inlining for performance. +*/ +#define BTREE_CLEAR_CELL(rc, pPage, pCell, sInfo) \ + pPage->xParseCell(pPage, pCell, &sInfo); \ + if( sInfo.nLocal!=sInfo.nPayload ){ \ + rc = clearCellOverflow(pPage, pCell, &sInfo); \ + }else{ \ + rc = SQLITE_OK; \ + } + + /* ** Create the byte sequence used to represent a cell on page pPage ** and write that byte sequence into pCell[]. Overflow pages are @@ -7479,7 +7492,7 @@ static int rebuildPage( u8 *pCell = pCArray->apCell[i]; u16 sz = pCArray->szCell[i]; assert( sz>0 ); - if( SQLITE_WITHIN(pCell,aData,pEnd) ){ + if( SQLITE_WITHIN(pCell,aData+j,pEnd) ){ if( ((uptr)(pCell+sz))>(uptr)pEnd ) return SQLITE_CORRUPT_BKPT; pCell = &pTmp[pCell - aData]; }else if( (uptr)(pCell+sz)>(uptr)pSrcEnd @@ -7492,9 +7505,8 @@ static int rebuildPage( put2byte(pCellptr, (pData - aData)); pCellptr += 2; if( pData < pCellptr ) return SQLITE_CORRUPT_BKPT; - memcpy(pData, pCell, sz); + memmove(pData, pCell, sz); assert( sz==pPg->xCellSize(pPg, pCell) || CORRUPT_DB ); - testcase( sz!=pPg->xCellSize(pPg,pCell) ) i++; if( i>=iEnd ) break; if( pCArray->ixNx[k]<=i ){ @@ -7633,7 +7645,9 @@ static int pageFreeArray( } pFree = pCell; szFree = sz; - if( pFree+sz>pEnd ) return 0; + if( pFree+sz>pEnd ){ + return 0; + } }else{ pFree = pCell; szFree += sz; @@ -8288,7 +8302,7 @@ static int balance_nonroot( b.szCell[b.nCell] = b.szCell[b.nCell] - leafCorrection; if( !pOld->leaf ){ assert( leafCorrection==0 ); - assert( pOld->hdrOffset==0 ); + assert( pOld->hdrOffset==0 || CORRUPT_DB ); /* The right pointer of the child page pOld becomes the left ** pointer of the divider cell */ memcpy(b.apCell[b.nCell], &pOld->aData[8], 4); @@ -8611,6 +8625,7 @@ static int balance_nonroot( u8 *pCell; u8 *pTemp; int sz; + u8 *pSrcEnd; MemPage *pNew = apNew[i]; j = cntNew[i]; @@ -8654,6 +8669,12 @@ static int balance_nonroot( iOvflSpace += sz; assert( sz<=pBt->maxLocal+23 ); assert( iOvflSpace <= (int)pBt->pageSize ); + for(k=0; b.ixNx[k]<=i && ALWAYS(kpgno, &rc); if( rc!=SQLITE_OK ) goto balance_cleanup; assert( sqlite3PagerIswriteable(pParent->pDbPage) ); @@ -9196,13 +9217,23 @@ int sqlite3BtreeInsert( if( pCur->curFlags & BTCF_Multiple ){ rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur); if( rc ) return rc; + if( loc && pCur->iPage<0 ){ + /* This can only happen if the schema is corrupt such that there is more + ** than one table or index with the same root page as used by the cursor. + ** Which can only happen if the SQLITE_NoSchemaError flag was set when + ** the schema was loaded. This cannot be asserted though, as a user might + ** set the flag, load the schema, and then unset the flag. */ + return SQLITE_CORRUPT_BKPT; + } } if( pCur->pKeyInfo==0 ){ assert( pX->pKey==0 ); /* If this is an insert into a table b-tree, invalidate any incrblob ** cursors open on the row being replaced */ - invalidateIncrblobCursors(p, pCur->pgnoRoot, pX->nKey, 0); + if( p->hasIncrblobCur ){ + invalidateIncrblobCursors(p, pCur->pgnoRoot, pX->nKey, 0); + } /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing ** to a row with the same key as the new entry being inserted. @@ -9283,7 +9314,6 @@ int sqlite3BtreeInsert( return btreeOverwriteCell(pCur, &x2); } } - } assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) @@ -9293,7 +9323,7 @@ int sqlite3BtreeInsert( assert( pPage->intKey || pX->nKey>=0 || (flags & BTREE_PREFORMAT) ); assert( pPage->leaf || !pPage->intKey ); if( pPage->nFree<0 ){ - if( pCur->eState>CURSOR_INVALID ){ + if( NEVER(pCur->eState>CURSOR_INVALID) ){ rc = SQLITE_CORRUPT_BKPT; }else{ rc = btreeComputeFreeSpace(pPage); @@ -9337,7 +9367,7 @@ int sqlite3BtreeInsert( if( !pPage->leaf ){ memcpy(newCell, oldCell, 4); } - rc = clearCell(pPage, oldCell, &info); + BTREE_CLEAR_CELL(rc, pPage, oldCell, info); testcase( pCur->curFlags & BTCF_ValidOvfl ); invalidateOverflowCache(pCur); if( info.nSize==szNew && info.nLocal==info.nPayload @@ -9574,9 +9604,10 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 ); if( pCur->eState==CURSOR_REQUIRESEEK ){ rc = btreeRestoreCursorPosition(pCur); - if( rc ) return rc; + assert( rc!=SQLITE_OK || CORRUPT_DB || pCur->eState==CURSOR_VALID ); + if( rc || pCur->eState!=CURSOR_VALID ) return rc; } - assert( pCur->eState==CURSOR_VALID ); + assert( CORRUPT_DB || pCur->eState==CURSOR_VALID ); iCellDepth = pCur->iPage; iCellIdx = pCur->ix; @@ -9629,7 +9660,7 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ /* If this is a delete operation to remove a row from a table b-tree, ** invalidate any incrblob cursors open on the row being deleted. */ - if( pCur->pKeyInfo==0 ){ + if( pCur->pKeyInfo==0 && p->hasIncrblobCur ){ invalidateIncrblobCursors(p, pCur->pgnoRoot, pCur->info.nKey, 0); } @@ -9638,7 +9669,7 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ ** itself from within the page. */ rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ) return rc; - rc = clearCell(pPage, pCell, &info); + BTREE_CLEAR_CELL(rc, pPage, pCell, info); dropCell(pPage, iCellIdx, info.nSize, &rc); if( rc ) return rc; @@ -9927,7 +9958,7 @@ static int clearDatabasePage( rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange, pgnoRoot); if( rc ) goto cleardatabasepage_out; } - rc = clearCell(pPage, pCell, &info); + BTREE_CLEAR_CELL(rc, pPage, pCell, info); if( rc ) goto cleardatabasepage_out; } if( !pPage->leaf ){ @@ -9977,7 +10008,9 @@ int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){ /* Invalidate all incrblob cursors open on table iTable (assuming iTable ** is the root of a table b-tree - if it is not, the following call is ** a no-op). */ - invalidateIncrblobCursors(p, (Pgno)iTable, 0, 1); + if( p->hasIncrblobCur ){ + invalidateIncrblobCursors(p, (Pgno)iTable, 0, 1); + } rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange, (Pgno)iTable); } sqlite3BtreeLeave(p); diff --git a/src/build.c b/src/build.c index f201e00cdc..56ce41bc92 100644 --- a/src/build.c +++ b/src/build.c @@ -46,7 +46,7 @@ struct TableLock { ** code to make the lock occur is generated by a later call to ** codeTableLocks() which occurs during sqlite3FinishCoding(). */ -void sqlite3TableLock( +static SQLITE_NOINLINE void lockTable( Parse *pParse, /* Parsing context */ int iDb, /* Index of the database containing the table to lock */ Pgno iTab, /* Root page number of the table to be locked */ @@ -59,10 +59,6 @@ void sqlite3TableLock( TableLock *p; assert( iDb>=0 ); -#ifdef SQLITE_OMIT_CONCURRENT - if( iDb==1 ) return; - if( !sqlite3BtreeSharable(pParse->db->aDb[iDb].pBt) ) return; -#endif pToplevel = sqlite3ParseToplevel(pParse); for(i=0; inTableLock; i++){ p = &pToplevel->aTableLock[i]; @@ -86,6 +82,17 @@ void sqlite3TableLock( sqlite3OomFault(pToplevel->db); } } +void sqlite3TableLock( + Parse *pParse, /* Parsing context */ + int iDb, /* Index of the database containing the table to lock */ + Pgno iTab, /* Root page number of the table to be locked */ + u8 isWriteLock, /* True for a write lock */ + const char *zName /* Name of the table to be locked */ +){ + if( iDb==1 ) return; + if( !sqlite3BtreeSharable(pParse->db->aDb[iDb].pBt) ) return; + lockTable(pParse, iDb, iTab, isWriteLock, zName); +} /* ** Code an OP_TableLock instruction for each table locked by the @@ -440,7 +447,7 @@ Table *sqlite3LocateTable( /* If zName is the not the name of a table in the schema created using ** CREATE, then check to see if it is the name of an virtual table that ** can be an eponymous virtual table. */ - if( pParse->disableVtab==0 ){ + if( pParse->disableVtab==0 && db->init.busy==0 ){ Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName); if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){ pMod = sqlite3PragmaVtabRegister(db, zName); @@ -463,6 +470,8 @@ Table *sqlite3LocateTable( }else{ sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName); } + }else{ + assert( HasRowid(p) || p->iPKey<0 ); } return p; @@ -1048,6 +1057,23 @@ i16 sqlite3TableColumnToStorage(Table *pTab, i16 iCol){ } #endif +/* +** Insert a single OP_JournalMode query opcode in order to force the +** prepared statement to return false for sqlite3_stmt_readonly(). This +** is used by CREATE TABLE IF NOT EXISTS and similar if the table already +** exists, so that the prepared statement for CREATE TABLE IF NOT EXISTS +** will return false for sqlite3_stmt_readonly() even if that statement +** is a read-only no-op. +*/ +static void sqlite3ForceNotReadOnly(Parse *pParse){ + int iReg = ++pParse->nMem; + Vdbe *v = sqlite3GetVdbe(pParse); + if( v ){ + sqlite3VdbeAddOp3(v, OP_JournalMode, 0, iReg, PAGER_JOURNALMODE_QUERY); + sqlite3VdbeUsesBtree(v, 0); + } +} + /* ** Begin constructing a new table representation in memory. This is ** the first of several action routines that get called in response @@ -1147,6 +1173,7 @@ void sqlite3StartTable( }else{ assert( !db->init.busy || CORRUPT_DB ); sqlite3CodeVerifySchema(pParse, iDb); + sqlite3ForceNotReadOnly(pParse); } goto begin_table_error; } @@ -1175,17 +1202,6 @@ void sqlite3StartTable( assert( pParse->pNewTable==0 ); pParse->pNewTable = pTable; - /* If this is the magic sqlite_sequence table used by autoincrement, - ** then record a pointer to this table in the main database structure - ** so that INSERT can find the table easily. - */ -#ifndef SQLITE_OMIT_AUTOINCREMENT - if( !pParse->nested && strcmp(zName, "sqlite_sequence")==0 ){ - assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - pTable->pSchema->pSeqTab = pTable; - } -#endif - /* Begin generating the code that will insert the table record into ** the schema table. Note in particular that we must go ahead ** and allocate the record number for the table entry now. Before any @@ -1334,6 +1350,7 @@ void sqlite3AddReturning(Parse *pParse, ExprList *pList){ pRet->retTrig.tr_tm = TRIGGER_AFTER; pRet->retTrig.bReturning = 1; pRet->retTrig.pSchema = db->aDb[1].pSchema; + pRet->retTrig.pTabSchema = db->aDb[1].pSchema; pRet->retTrig.step_list = &pRet->retTStep; pRet->retTStep.op = TK_RETURNING; pRet->retTStep.pTrig = &pRet->retTrig; @@ -2192,7 +2209,10 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ sqlite3TokenInit(&ipkToken, pTab->aCol[pTab->iPKey].zName); pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0)); - if( pList==0 ) return; + if( pList==0 ){ + pTab->tabFlags &= ~TF_WithoutRowid; + return; + } if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, pList->a[0].pExpr, &pTab->iPKey); } @@ -2201,7 +2221,10 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ pTab->iPKey = -1; sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0, SQLITE_IDXTYPE_PRIMARYKEY); - if( db->mallocFailed || pParse->nErr ) return; + if( db->mallocFailed || pParse->nErr ){ + pTab->tabFlags &= ~TF_WithoutRowid; + return; + } pPk = sqlite3PrimaryKeyIndex(pTab); assert( pPk->nKeyCol==1 ); }else{ @@ -2405,7 +2428,6 @@ void sqlite3EndTable( if( pEnd==0 && pSelect==0 ){ return; } - assert( !db->mallocFailed ); p = pParse->pNewTable; if( p==0 ) return; @@ -2630,7 +2652,7 @@ void sqlite3EndTable( /* Check to see if we need to create an sqlite_sequence table for ** keeping track of autoincrement keys. */ - if( (p->tabFlags & TF_Autoincrement)!=0 ){ + if( (p->tabFlags & TF_Autoincrement)!=0 && !IN_SPECIAL_PARSE ){ Db *pDb = &db->aDb[iDb]; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( pDb->pSchema->pSeqTab==0 ){ @@ -2653,6 +2675,7 @@ void sqlite3EndTable( Table *pOld; Schema *pSchema = p->pSchema; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + assert( HasRowid(p) || p->iPKey<0 ); pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, p); if( pOld ){ assert( p==pOld ); /* Malloc must have failed inside HashInsert() */ @@ -2661,6 +2684,17 @@ void sqlite3EndTable( } pParse->pNewTable = 0; db->mDbFlags |= DBFLAG_SchemaChange; + + /* If this is the magic sqlite_sequence table used by autoincrement, + ** then record a pointer to this table in the main database structure + ** so that INSERT can find the table easily. */ + assert( !pParse->nested ); +#ifndef SQLITE_OMIT_AUTOINCREMENT + if( strcmp(p->zName, "sqlite_sequence")==0 ){ + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + p->pSchema->pSeqTab = p; + } +#endif } #ifndef SQLITE_OMIT_ALTERTABLE @@ -2704,6 +2738,16 @@ void sqlite3CreateView( sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr); p = pParse->pNewTable; if( p==0 || pParse->nErr ) goto create_view_fail; + + /* Legacy versions of SQLite allowed the use of the magic "rowid" column + ** on a view, even though views do not have rowids. The following flag + ** setting fixes this problem. But the fix can be disabled by compiling + ** with -DSQLITE_ALLOW_ROWID_IN_VIEW in case there are legacy apps that + ** depend upon the old buggy behavior. */ +#ifndef SQLITE_ALLOW_ROWID_IN_VIEW + p->tabFlags |= TF_NoVisibleRowid; +#endif + sqlite3TwoPartName(pParse, pName1, pName2, &pName); iDb = sqlite3SchemaToIndex(db, p->pSchema); sqlite3FixInit(&sFix, pParse, iDb, "view", pName); @@ -3180,7 +3224,10 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ if( noErr ) db->suppressErr--; if( pTab==0 ){ - if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); + if( noErr ){ + sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); + sqlite3ForceNotReadOnly(pParse); + } goto exit_drop_table; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); @@ -3750,6 +3797,7 @@ void sqlite3CreateIndex( }else{ assert( !db->init.busy ); sqlite3CodeVerifySchema(pParse, iDb); + sqlite3ForceNotReadOnly(pParse); } goto exit_create_index; } @@ -4230,7 +4278,7 @@ void sqlite3DefaultRowEst(Index *pIdx){ if( x<99 ){ pIdx->pTable->nRowLogEst = x = 99; } - if( pIdx->pPartIdxWhere!=0 ) x -= 10; assert( 10==sqlite3LogEst(2) ); + if( pIdx->pPartIdxWhere!=0 ){ x -= 10; assert( 10==sqlite3LogEst(2) ); } a[0] = x; /* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is @@ -4265,9 +4313,10 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){ pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase); if( pIndex==0 ){ if( !ifExists ){ - sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0); + sqlite3ErrorMsg(pParse, "no such index: %S", pName->a); }else{ sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); + sqlite3ForceNotReadOnly(pParse); } pParse->checkSchema = 1; goto exit_drop_index; @@ -4579,8 +4628,8 @@ SrcList *sqlite3SrcListAppend( void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){ int i; SrcItem *pItem; - assert(pList || pParse->db->mallocFailed ); - if( pList ){ + assert( pList || pParse->db->mallocFailed ); + if( ALWAYS(pList) ){ for(i=0, pItem=pList->a; inSrc; i++, pItem++){ if( pItem->iCursor>=0 ) continue; pItem->iCursor = pParse->nTab++; diff --git a/src/ctime.c b/src/ctime.c index 7982f23aeb..fa69216c6d 100644 --- a/src/ctime.c +++ b/src/ctime.c @@ -58,8 +58,10 @@ static const char * const sqlite3azCompileOpt[] = { #if SQLITE_64BIT_STATS "64BIT_STATS", #endif -#if SQLITE_ALLOW_COVERING_INDEX_SCAN - "ALLOW_COVERING_INDEX_SCAN", +#ifdef SQLITE_ALLOW_COVERING_INDEX_SCAN +# if SQLITE_ALLOW_COVERING_INDEX_SCAN != 1 + "ALLOW_COVERING_INDEX_SCAN=" CTIMEOPT_VAL(SQLITE_ALLOW_COVERING_INDEX_SCAN), +# endif #endif #if SQLITE_ALLOW_URI_AUTHORITY "ALLOW_URI_AUTHORITY", @@ -121,8 +123,10 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_DEFAULT_LOOKASIDE "DEFAULT_LOOKASIDE=" CTIMEOPT_VAL2(SQLITE_DEFAULT_LOOKASIDE), #endif -#if SQLITE_DEFAULT_MEMSTATUS - "DEFAULT_MEMSTATUS", +#ifdef SQLITE_DEFAULT_MEMSTATUS +# if SQLITE_DEFAULT_MEMSTATUS != 1 + "DEFAULT_MEMSTATUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_MEMSTATUS), +# endif #endif #ifdef SQLITE_DEFAULT_MMAP_SIZE "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE), @@ -196,7 +200,7 @@ static const char * const sqlite3azCompileOpt[] = { #if SQLITE_ENABLE_BYTECODE_VTAB "ENABLE_BYTECODE_VTAB", #endif -#if SQLITE_ENABLE_CEROD +#ifdef SQLITE_ENABLE_CEROD "ENABLE_CEROD=" CTIMEOPT_VAL(SQLITE_ENABLE_CEROD), #endif #if SQLITE_ENABLE_COLUMN_METADATA @@ -211,17 +215,17 @@ static const char * const sqlite3azCompileOpt[] = { #if SQLITE_ENABLE_CURSOR_HINTS "ENABLE_CURSOR_HINTS", #endif +#if SQLITE_ENABLE_DBPAGE_VTAB + "ENABLE_DBPAGE_VTAB", +#endif #if SQLITE_ENABLE_DBSTAT_VTAB "ENABLE_DBSTAT_VTAB", #endif #if SQLITE_ENABLE_EXPENSIVE_ASSERT "ENABLE_EXPENSIVE_ASSERT", #endif -#if SQLITE_ENABLE_FTS1 - "ENABLE_FTS1", -#endif -#if SQLITE_ENABLE_FTS2 - "ENABLE_FTS2", +#if SQLITE_ENABLE_EXPLAIN_COMMENTS + "ENABLE_EXPLAIN_COMMENTS", #endif #if SQLITE_ENABLE_FTS3 "ENABLE_FTS3", @@ -280,6 +284,9 @@ static const char * const sqlite3azCompileOpt[] = { #if SQLITE_ENABLE_NULL_TRIM "ENABLE_NULL_TRIM", #endif +#if SQLITE_ENABLE_OFFSET_SQL_FUNC + "ENABLE_OFFSET_SQL_FUNC", +#endif #if SQLITE_ENABLE_OVERSIZE_CELL_CHECK "ENABLE_OVERSIZE_CELL_CHECK", #endif @@ -310,7 +317,7 @@ static const char * const sqlite3azCompileOpt[] = { #if SQLITE_ENABLE_SQLLOG "ENABLE_SQLLOG", #endif -#if defined(SQLITE_ENABLE_STAT4) +#if SQLITE_ENABLE_STAT4 "ENABLE_STAT4", #endif #if SQLITE_ENABLE_STMTVTAB @@ -364,8 +371,10 @@ static const char * const sqlite3azCompileOpt[] = { #if HAVE_ISNAN || SQLITE_HAVE_ISNAN "HAVE_ISNAN", #endif -#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX - "HOMEGROWN_RECURSIVE_MUTEX", +#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX +# if SQLITE_HOMEGROWN_RECURSIVE_MUTEX != 1 + "HOMEGROWN_RECURSIVE_MUTEX=" CTIMEOPT_VAL(SQLITE_HOMEGROWN_RECURSIVE_MUTEX), +# endif #endif #if SQLITE_IGNORE_AFP_LOCK_ERRORS "IGNORE_AFP_LOCK_ERRORS", @@ -463,9 +472,6 @@ static const char * const sqlite3azCompileOpt[] = { #if SQLITE_MUTEX_NOOP "MUTEX_NOOP", #endif -#if SQLITE_MUTEX_NREF - "MUTEX_NREF", -#endif #if SQLITE_MUTEX_OMIT "MUTEX_OMIT", #endif @@ -535,7 +541,7 @@ static const char * const sqlite3azCompileOpt[] = { #if SQLITE_OMIT_CTE "OMIT_CTE", #endif -#if SQLITE_OMIT_DATETIME_FUNCS +#if defined(SQLITE_OMIT_DATETIME_FUNCS) || defined(SQLITE_OMIT_FLOATING_POINT) "OMIT_DATETIME_FUNCS", #endif #if SQLITE_OMIT_DECLTYPE @@ -544,6 +550,9 @@ static const char * const sqlite3azCompileOpt[] = { #if SQLITE_OMIT_DEPRECATED "OMIT_DEPRECATED", #endif +#if SQLITE_OMIT_DESERIALIZE + "OMIT_DESERIALIZE", +#endif #if SQLITE_OMIT_DISKIO "OMIT_DISKIO", #endif @@ -571,6 +580,9 @@ static const char * const sqlite3azCompileOpt[] = { #if SQLITE_OMIT_INTEGRITY_CHECK "OMIT_INTEGRITY_CHECK", #endif +#if SQLITE_OMIT_INTROSPECTION_PRAGMAS + "OMIT_INTROSPECTION_PRAGMAS", +#endif #if SQLITE_OMIT_LIKE_OPTIMIZATION "OMIT_LIKE_OPTIMIZATION", #endif @@ -634,8 +646,10 @@ static const char * const sqlite3azCompileOpt[] = { #if SQLITE_OMIT_TEST_CONTROL "OMIT_TEST_CONTROL", #endif -#if SQLITE_OMIT_TRACE - "OMIT_TRACE", +#ifdef SQLITE_OMIT_TRACE +# if SQLITE_OMIT_TRACE != 1 + "OMIT_TRACE=" CTIMEOPT_VAL(SQLITE_OMIT_TRACE), +# endif #endif #if SQLITE_OMIT_TRIGGER "OMIT_TRIGGER", @@ -670,8 +684,10 @@ static const char * const sqlite3azCompileOpt[] = { #if SQLITE_PERFORMANCE_TRACE "PERFORMANCE_TRACE", #endif -#if SQLITE_POWERSAFE_OVERWRITE - "POWERSAFE_OVERWRITE", +#ifdef SQLITE_POWERSAFE_OVERWRITE +# if SQLITE_POWERSAFE_OVERWRITE != 1 + "POWERSAFE_OVERWRITE=" CTIMEOPT_VAL(SQLITE_POWERSAFE_OVERWRITE), +# endif #endif #if SQLITE_PREFER_PROXY_LOCKING "PREFER_PROXY_LOCKING", @@ -706,7 +722,10 @@ static const char * const sqlite3azCompileOpt[] = { #if SQLITE_SUBSTR_COMPATIBILITY "SUBSTR_COMPATIBILITY", #endif -#if SQLITE_SYSTEM_MALLOC +#if (!defined(SQLITE_WIN32_MALLOC) \ + && !defined(SQLITE_ZERO_MALLOC) \ + && !defined(SQLITE_MEMDEBUG) \ + ) || defined(SQLITE_SYSTEM_MALLOC) "SYSTEM_MALLOC", #endif #if SQLITE_TCL diff --git a/src/expr.c b/src/expr.c index bd12ad9f0c..6af6493c70 100644 --- a/src/expr.c +++ b/src/expr.c @@ -52,6 +52,10 @@ char sqlite3ExprAffinity(const Expr *pExpr){ assert( pExpr!=0 ); } 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_SELECT ){ assert( pExpr->flags&EP_xIsSelect ); assert( pExpr->x.pSelect!=0 ); @@ -59,16 +63,12 @@ char sqlite3ExprAffinity(const Expr *pExpr){ assert( pExpr->x.pSelect->pEList->a[0].pExpr!=0 ); return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr); } - if( op==TK_REGISTER ) op = pExpr->op2; #ifndef SQLITE_OMIT_CAST if( op==TK_CAST ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); return sqlite3AffinityType(pExpr->u.zToken, 0); } #endif - if( (op==TK_AGG_COLUMN || op==TK_COLUMN) && pExpr->y.pTab ){ - return sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); - } if( op==TK_SELECT_COLUMN ){ assert( pExpr->pLeft->flags&EP_xIsSelect ); return sqlite3ExprAffinity( @@ -95,18 +95,7 @@ Expr *sqlite3ExprAddCollateToken( const Token *pCollName, /* Name of collating sequence */ int dequote /* True to dequote pCollName */ ){ - assert( pExpr!=0 || pParse->db->mallocFailed ); - if( pExpr==0 ) return 0; - if( pExpr->op==TK_VECTOR ){ - ExprList *pList = pExpr->x.pList; - if( ALWAYS(pList!=0) ){ - int i; - for(i=0; inExpr; i++){ - pList->a[i].pExpr = sqlite3ExprAddCollateToken(pParse,pList->a[i].pExpr, - pCollName, dequote); - } - } - }else if( pCollName->n>0 ){ + if( pCollName->n>0 ){ Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, dequote); if( pNew ){ pNew->pLeft = pExpr; @@ -611,6 +600,7 @@ static void codeVectorCompare( int regLeft = 0; int regRight = 0; u8 opx = op; + int addrCmp = 0; int addrDone = sqlite3VdbeMakeLabel(pParse); int isCommuted = ExprHasProperty(pExpr,EP_Commuted); @@ -630,21 +620,24 @@ static void codeVectorCompare( assert( p5==0 || pExpr->op!=op ); assert( p5==SQLITE_NULLEQ || pExpr->op==op ); - p5 |= SQLITE_STOREP2; - if( opx==TK_LE ) opx = TK_LT; - if( opx==TK_GE ) opx = TK_GT; + if( op==TK_LE ) opx = TK_LT; + if( op==TK_GE ) opx = TK_GT; + if( op==TK_NE ) opx = TK_EQ; regLeft = exprCodeSubselect(pParse, pLeft); regRight = exprCodeSubselect(pParse, pRight); + sqlite3VdbeAddOp2(v, OP_Integer, 1, dest); for(i=0; 1 /*Loop exits by "break"*/; i++){ int regFree1 = 0, regFree2 = 0; Expr *pL, *pR; int r1, r2; assert( i>=0 && i0 @@ -958,8 +957,8 @@ Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){ }else if( (ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight)) && !IN_RENAME_OBJECT ){ - sqlite3ExprDelete(db, pLeft); - sqlite3ExprDelete(db, pRight); + sqlite3ExprDeferredDelete(pParse, pLeft); + sqlite3ExprDeferredDelete(pParse, pRight); return sqlite3Expr(db, TK_INTEGER, "0"); }else{ return sqlite3PExpr(pParse, TK_AND, pLeft, pRight); @@ -1156,6 +1155,22 @@ void sqlite3ExprDelete(sqlite3 *db, Expr *p){ if( p ) sqlite3ExprDeleteNN(db, p); } + +/* +** Arrange to cause pExpr to be deleted when the pParse is deleted. +** This is similar to sqlite3ExprDelete() except that the delete is +** deferred untilthe pParse is deleted. +** +** The pExpr might be deleted immediately on an OOM error. +** +** The deferred delete is (currently) implemented by adding the +** pExpr to the pParse->pConstExpr list with a register number of 0. +*/ +void sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){ + pParse->pConstExpr = + sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr); +} + /* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the ** expression. */ @@ -1298,6 +1313,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ if( pzBuffer ){ zAlloc = *pzBuffer; staticFlag = EP_Static; + assert( zAlloc!=0 ); }else{ zAlloc = sqlite3DbMallocRawNN(db, dupedExprSize(p, dupFlags)); staticFlag = 0; @@ -1376,7 +1392,8 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ 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 ); + assert( p->pRight==0 || p->pRight==p->pLeft + || ExprHasProperty(p->pLeft, EP_Subquery) ); }else{ pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0); } @@ -1478,6 +1495,7 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){ pNew = sqlite3DbMallocRawNN(db, sqlite3DbMallocSize(db, p)); if( pNew==0 ) return 0; pNew->nExpr = p->nExpr; + pNew->nAlloc = p->nAlloc; pItem = pNew->a; pOldItem = p->a; for(i=0; inExpr; i++, pItem++, pOldItem++){ @@ -1490,7 +1508,8 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){ ){ assert( pNewExpr->iColumn==0 || i>0 ); if( pNewExpr->iColumn==0 ){ - assert( pOldExpr->pLeft==pOldExpr->pRight ); + assert( pOldExpr->pLeft==pOldExpr->pRight + || ExprHasProperty(pOldExpr->pLeft, EP_Subquery) ); pPriorSelectCol = pNewExpr->pLeft = pNewExpr->pRight; }else{ assert( i>0 ); @@ -1620,6 +1639,14 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){ if( p->pWin && db->mallocFailed==0 ) gatherSelectWindows(pNew); #endif pNew->selId = p->selId; + if( db->mallocFailed ){ + /* Any prior OOM might have left the Select object incomplete. + ** Delete the whole thing rather than allow an incomplete Select + ** to be used by the code generator. */ + pNew->pNext = 0; + sqlite3SelectDelete(db, pNew); + break; + } *pp = pNew; pp = &pNew->pPrior; pNext = pNew; @@ -1650,41 +1677,64 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){ ** NULL is returned. If non-NULL is returned, then it is guaranteed ** that the new entry was successfully appended. */ +static const struct ExprList_item zeroItem = {0}; +SQLITE_NOINLINE ExprList *sqlite3ExprListAppendNew( + sqlite3 *db, /* Database handle. Used for memory allocation */ + Expr *pExpr /* Expression to be appended. Might be NULL */ +){ + struct ExprList_item *pItem; + ExprList *pList; + + pList = sqlite3DbMallocRawNN(db, sizeof(ExprList)+sizeof(pList->a[0])*4 ); + if( pList==0 ){ + sqlite3ExprDelete(db, pExpr); + return 0; + } + pList->nAlloc = 4; + pList->nExpr = 1; + pItem = &pList->a[0]; + *pItem = zeroItem; + pItem->pExpr = pExpr; + return pList; +} +SQLITE_NOINLINE ExprList *sqlite3ExprListAppendGrow( + sqlite3 *db, /* Database handle. Used for memory allocation */ + ExprList *pList, /* List to which to append. Might be NULL */ + Expr *pExpr /* Expression to be appended. Might be NULL */ +){ + struct ExprList_item *pItem; + ExprList *pNew; + pList->nAlloc *= 2; + pNew = sqlite3DbRealloc(db, pList, + sizeof(*pList)+(pList->nAlloc-1)*sizeof(pList->a[0])); + if( pNew==0 ){ + sqlite3ExprListDelete(db, pList); + sqlite3ExprDelete(db, pExpr); + return 0; + }else{ + pList = pNew; + } + pItem = &pList->a[pList->nExpr++]; + *pItem = zeroItem; + pItem->pExpr = pExpr; + return pList; +} ExprList *sqlite3ExprListAppend( Parse *pParse, /* Parsing context */ ExprList *pList, /* List to which to append. Might be NULL */ Expr *pExpr /* Expression to be appended. Might be NULL */ ){ struct ExprList_item *pItem; - sqlite3 *db = pParse->db; - assert( db!=0 ); if( pList==0 ){ - pList = sqlite3DbMallocRawNN(db, sizeof(ExprList) ); - if( pList==0 ){ - goto no_mem; - } - pList->nExpr = 0; - }else if( (pList->nExpr & (pList->nExpr-1))==0 ){ - ExprList *pNew; - pNew = sqlite3DbRealloc(db, pList, - sizeof(*pList)+(2*(sqlite3_int64)pList->nExpr-1)*sizeof(pList->a[0])); - if( pNew==0 ){ - goto no_mem; - } - pList = pNew; + return sqlite3ExprListAppendNew(pParse->db,pExpr); + } + if( pList->nAllocnExpr+1 ){ + return sqlite3ExprListAppendGrow(pParse->db,pList,pExpr); } pItem = &pList->a[pList->nExpr++]; - assert( offsetof(struct ExprList_item,zEName)==sizeof(pItem->pExpr) ); - assert( offsetof(struct ExprList_item,pExpr)==0 ); - memset(&pItem->zEName,0,sizeof(*pItem)-offsetof(struct ExprList_item,zEName)); + *pItem = zeroItem; pItem->pExpr = pExpr; return pList; - -no_mem: - /* Avoid leaking memory if malloc has failed. */ - sqlite3ExprDelete(db, pExpr); - sqlite3ExprListDelete(db, pList); - return 0; } /* @@ -2297,8 +2347,10 @@ int sqlite3ExprIsInteger(Expr *p, int *pValue){ */ int sqlite3ExprCanBeNull(const Expr *p){ u8 op; + assert( p!=0 ); while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ p = p->pLeft; + assert( p!=0 ); } op = p->op; if( op==TK_REGISTER ) op = p->op2; @@ -3148,7 +3200,7 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ */ int sqlite3ExprCheckIN(Parse *pParse, Expr *pIn){ int nVector = sqlite3ExprVectorSize(pIn->pLeft); - if( (pIn->flags & EP_xIsSelect) ){ + if( (pIn->flags & EP_xIsSelect)!=0 && !pParse->db->mallocFailed ){ if( nVector!=pIn->x.pSelect->pEList->nExpr ){ sqlite3SubselectError(pParse, pIn->x.pSelect->pEList->nExpr, nVector); return 1; @@ -3339,6 +3391,7 @@ static void sqlite3ExprCodeIN( if( pParse->nErr ) goto sqlite3ExprCodeIN_finished; for(i=0; ipLeft, i); + if( pParse->db->mallocFailed ) goto sqlite3ExprCodeIN_oom_error; if( sqlite3ExprCanBeNull(p) ){ sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+i, destStep2); VdbeCoverage(v); @@ -3964,7 +4017,7 @@ expr_code_doover: ** Expr node to be passed into this function, it will be handled ** sanely and not crash. But keep the assert() to bring the problem ** to the attention of the developers. */ - assert( op==TK_NULL ); + assert( op==TK_NULL || pParse->db->mallocFailed ); sqlite3VdbeAddOp2(v, OP_Null, 0, target); return target; } @@ -4030,8 +4083,9 @@ expr_code_doover: }else{ r1 = sqlite3ExprCodeTemp(pParse, pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); - codeCompare(pParse, pLeft, pExpr->pRight, op, - r1, r2, inReg, SQLITE_STOREP2 | p5, + sqlite3VdbeAddOp2(v, OP_Integer, 1, inReg); + codeCompare(pParse, pLeft, pExpr->pRight, op, r1, r2, + sqlite3VdbeCurrentAddr(v)+2, p5, ExprHasProperty(pExpr,EP_Commuted)); assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); @@ -4039,6 +4093,11 @@ expr_code_doover: assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq); assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne); + if( p5==SQLITE_NULLEQ ){ + sqlite3VdbeAddOp2(v, OP_Integer, 0, inReg); + }else{ + sqlite3VdbeAddOp3(v, OP_ZeroOrNull, r1, inReg, r2); + } testcase( regFree1==0 ); testcase( regFree2==0 ); } @@ -5781,8 +5840,7 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){ pExpr = sqlite3ExprDup(db, pExpr, 0); if( pExpr ){ pAggInfo->aCol[iAgg].pCExpr = pExpr; - pParse->pConstExpr = - sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr); + sqlite3ExprDeferredDelete(pParse, pExpr); } } }else{ @@ -5791,8 +5849,7 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){ pExpr = sqlite3ExprDup(db, pExpr, 0); if( pExpr ){ pAggInfo->aFunc[iAgg].pFExpr = pExpr; - pParse->pConstExpr = - sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr); + sqlite3ExprDeferredDelete(pParse, pExpr); } } } diff --git a/src/func.c b/src/func.c index 5e7eae873c..83312c0cce 100644 --- a/src/func.c +++ b/src/func.c @@ -2073,9 +2073,7 @@ static void math2Func( } /* -** Implementation of 2-argument SQL math functions: -** -** power(X,Y) - Compute X to the Y-th power +** Implementation of 0-argument pi() function. */ static void piFunc( sqlite3_context *context, diff --git a/src/global.c b/src/global.c index b5239ad81a..4648c26d95 100644 --- a/src/global.c +++ b/src/global.c @@ -37,7 +37,7 @@ const unsigned char sqlite3UpperToLower[] = { 198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215, 216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233, 234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251, - 252,253,254,255 + 252,253,254,255, #endif #ifdef SQLITE_EBCDIC 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 0x */ @@ -57,7 +57,35 @@ const unsigned char sqlite3UpperToLower[] = { 224,225,162,163,164,165,166,167,168,169,234,235,236,237,238,239, /* Ex */ 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, /* Fx */ #endif +/* All of the upper-to-lower conversion data is above. The following +** 18 integers are completely unrelated. They are appended to the +** sqlite3UpperToLower[] array to avoid UBSAN warnings. Here's what is +** going on: +** +** The SQL comparison operators (<>, =, >, <=, <, and >=) are implemented +** by invoking sqlite3MemCompare(A,B) which compares values A and B and +** returns negative, zero, or positive if A is less then, equal to, or +** greater than B, respectively. Then the true false results is found by +** consulting sqlite3aLTb[opcode], sqlite3aEQb[opcode], or +** sqlite3aGTb[opcode] depending on whether the result of compare(A,B) +** is negative, zero, or positive, where opcode is the specific opcode. +** The only works because the comparison opcodes are consecutive and in +** this order: NE EQ GT LE LT GE. Various assert()s throughout the code +** ensure that is the case. +** +** These elements must be appended to another array. Otherwise the +** index (here shown as [256-OP_Ne]) would be out-of-bounds and thus +** be undefined behavior. That's goofy, but the C-standards people thought +** it was a good idea, so here we are. +*/ +/* NE EQ GT LE LT GE */ + 1, 0, 0, 1, 1, 0, /* aLTb[]: Use when compare(A,B) less than zero */ + 0, 1, 0, 1, 0, 1, /* aEQb[]: Use when compare(A,B) equals zero */ + 1, 0, 1, 0, 0, 1 /* aGTb[]: Use when compare(A,B) greater than zero*/ }; +const unsigned char *sqlite3aLTb = &sqlite3UpperToLower[256-OP_Ne]; +const unsigned char *sqlite3aEQb = &sqlite3UpperToLower[256+6-OP_Ne]; +const unsigned char *sqlite3aGTb = &sqlite3UpperToLower[256+12-OP_Ne]; /* ** The following 256 byte lookup table is used to support SQLites built-in @@ -251,7 +279,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = { 0, /* xVdbeBranch */ 0, /* pVbeBranchArg */ #endif -#ifdef SQLITE_ENABLE_DESERIALIZE +#ifndef SQLITE_OMIT_DESERIALIZE SQLITE_MEMDB_DEFAULT_MAXSIZE, /* mxMemdbSize */ #endif #ifndef SQLITE_UNTESTABLE diff --git a/src/insert.c b/src/insert.c index 89b66baf07..1ed0b43156 100644 --- a/src/insert.c +++ b/src/insert.c @@ -358,7 +358,7 @@ static int autoIncBegin( ** Ticket d8dc2b3a58cd5dc2918a1d4acb 2018-05-23 */ if( pSeqTab==0 || !HasRowid(pSeqTab) - || IsVirtual(pSeqTab) + || NEVER(IsVirtual(pSeqTab)) || pSeqTab->nCol!=2 ){ pParse->nErr++; @@ -817,7 +817,7 @@ void sqlite3Insert( bIdListInOrder = 0; }else{ sqlite3ErrorMsg(pParse, "table %S has no column named %s", - pTabList, 0, pColumn->a[i].zName); + pTabList->a, pColumn->a[i].zName); pParse->checkSchema = 1; goto insert_cleanup; } @@ -945,7 +945,7 @@ void sqlite3Insert( if( nColumn!=(pTab->nCol-nHidden) ){ sqlite3ErrorMsg(pParse, "table %S has %d columns but %d values were supplied", - pTabList, 0, pTab->nCol-nHidden, nColumn); + pTabList->a, pTab->nCol-nHidden, nColumn); goto insert_cleanup; } } @@ -1248,7 +1248,7 @@ void sqlite3Insert( }else #endif { - int isReplace; /* Set to true if constraints may cause a replace */ + int isReplace = 0;/* Set to true if constraints may cause a replace */ int bUseSeek; /* True to use OPFLAG_SEEKRESULT */ sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur, regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0, pUpsert @@ -1268,6 +1268,13 @@ void sqlite3Insert( regIns, aRegIdx, 0, appendFlag, bUseSeek ); } +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + }else if( pParse->bReturning ){ + /* If there is a RETURNING clause, populate the rowid register with + ** constant value -1, in case one or more of the returned expressions + ** refer to the "rowid" of the view. */ + sqlite3VdbeAddOp2(v, OP_Integer, -1, regRowid); +#endif } /* Update the count of rows that are inserted diff --git a/src/main.c b/src/main.c index 02a61772ab..7ea1383d1c 100644 --- a/src/main.c +++ b/src/main.c @@ -305,7 +305,7 @@ int sqlite3_initialize(void){ sqlite3GlobalConfig.isPCacheInit = 1; rc = sqlite3OsInit(); } -#ifdef SQLITE_ENABLE_DESERIALIZE +#ifndef SQLITE_OMIT_DESERIALIZE if( rc==SQLITE_OK ){ rc = sqlite3MemdbInit(); } @@ -720,12 +720,12 @@ int sqlite3_config(int op, ...){ } #endif /* SQLITE_ENABLE_SORTER_REFERENCES */ -#ifdef SQLITE_ENABLE_DESERIALIZE +#ifndef SQLITE_OMIT_DESERIALIZE case SQLITE_CONFIG_MEMDB_MAXSIZE: { sqlite3GlobalConfig.mxMemdbSize = va_arg(ap, sqlite3_int64); break; } -#endif /* SQLITE_ENABLE_DESERIALIZE */ +#endif /* SQLITE_OMIT_DESERIALIZE */ default: { rc = SQLITE_ERROR; @@ -1274,7 +1274,7 @@ int sqlite3_txn_state(sqlite3 *db, const char *zSchema){ /* ** Two variations on the public interface for closing a database ** connection. The sqlite3_close() version returns SQLITE_BUSY and -** leaves the connection option if there are unfinalized prepared +** leaves the connection open if there are unfinalized prepared ** statements or unfinished sqlite3_backups. The sqlite3_close_v2() ** version forces the connection to become a zombie if there are ** unclosed resources, and arranges for deallocation when the last @@ -1884,6 +1884,10 @@ int sqlite3CreateFunc( }else{ sqlite3ExpirePreparedStatements(db, 0); } + }else if( xSFunc==0 && xFinal==0 ){ + /* Trying to delete a function that does not exist. This is a no-op. + ** https://sqlite.org/forum/forumpost/726219164b */ + return SQLITE_OK; } p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 1); diff --git a/src/memdb.c b/src/memdb.c index a48980aa34..965ec36d41 100644 --- a/src/memdb.c +++ b/src/memdb.c @@ -17,31 +17,88 @@ ** sqlite3_deserialize(). */ #include "sqliteInt.h" -#ifdef SQLITE_ENABLE_DESERIALIZE +#ifndef SQLITE_OMIT_DESERIALIZE /* ** Forward declaration of objects used by this utility */ typedef struct sqlite3_vfs MemVfs; typedef struct MemFile MemFile; +typedef struct MemStore MemStore; /* Access to a lower-level VFS that (might) implement dynamic loading, ** access to randomness, etc. */ #define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData)) -/* An open file */ -struct MemFile { - sqlite3_file base; /* IO methods */ +/* Storage for a memdb file. +** +** An memdb object can be shared or separate. Shared memdb objects can be +** used by more than one database connection. Mutexes are used by shared +** memdb objects to coordinate access. Separate memdb objects are only +** connected to a single database connection and do not require additional +** mutexes. +** +** Shared memdb objects have .zFName!=0 and .pMutex!=0. They are created +** using "file:/name?vfs=memdb". The first character of the name must be +** "/" or else the object will be a separate memdb object. All shared +** memdb objects are stored in memdb_g.apMemStore[] in an arbitrary order. +** +** Separate memdb objects are created using a name that does not begin +** with "/" or using sqlite3_deserialize(). +** +** Access rules for shared MemStore objects: +** +** * .zFName is initialized when the object is created and afterwards +** is unchanged until the object is destroyed. So it can be accessed +** at any time as long as we know the object is not being destroyed, +** which means while either the SQLITE_MUTEX_STATIC_VFS1 or +** .pMutex is held or the object is not part of memdb_g.apMemStore[]. +** +** * Can .pMutex can only be changed while holding the +** SQLITE_MUTEX_STATIC_VFS1 mutex or while the object is not part +** of memdb_g.apMemStore[]. +** +** * Other fields can only be changed while holding the .pMutex mutex +** or when the .nRef is less than zero and the object is not part of +** memdb_g.apMemStore[]. +** +** * The .aData pointer has the added requirement that it can can only +** be changed (for resizing) when nMmap is zero. +** +*/ +struct MemStore { sqlite3_int64 sz; /* Size of the file */ sqlite3_int64 szAlloc; /* Space allocated to aData */ sqlite3_int64 szMax; /* Maximum allowed size of the file */ unsigned char *aData; /* content of the file */ + sqlite3_mutex *pMutex; /* Used by shared stores only */ int nMmap; /* Number of memory mapped pages */ unsigned mFlags; /* Flags */ + int nRdLock; /* Number of readers */ + int nWrLock; /* Number of writers. (Always 0 or 1) */ + int nRef; /* Number of users of this MemStore */ + char *zFName; /* The filename for shared stores */ +}; + +/* An open file */ +struct MemFile { + sqlite3_file base; /* IO methods */ + MemStore *pStore; /* The storage */ int eLock; /* Most recent lock against this file */ }; +/* +** File-scope variables for holding the memdb files that are accessible +** to multiple database connections in separate threads. +** +** Must hold SQLITE_MUTEX_STATIC_VFS1 to access any part of this object. +*/ +static struct MemFS { + int nMemStore; /* Number of shared MemStore objects */ + MemStore **apMemStore; /* Array of all shared MemStore objects */ +} memdb_g; + /* ** Methods for MemFile */ @@ -95,7 +152,10 @@ static sqlite3_vfs memdb_vfs = { memdbSleep, /* xSleep */ 0, /* memdbCurrentTime, */ /* xCurrentTime */ memdbGetLastError, /* xGetLastError */ - memdbCurrentTimeInt64 /* xCurrentTimeInt64 */ + memdbCurrentTimeInt64, /* xCurrentTimeInt64 */ + 0, /* xSetSystemCall */ + 0, /* xGetSystemCall */ + 0, /* xNextSystemCall */ }; static const sqlite3_io_methods memdb_io_methods = { @@ -120,19 +180,67 @@ static const sqlite3_io_methods memdb_io_methods = { memdbUnfetch /* xUnfetch */ }; +/* +** Enter/leave the mutex on a MemStore +*/ +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE==0 +static void memdbEnter(MemStore *p){ + UNUSED_PARAMETER(p); +} +static void memdbLeave(MemStore *p){ + UNUSED_PARAMETER(p); +} +#else +static void memdbEnter(MemStore *p){ + sqlite3_mutex_enter(p->pMutex); +} +static void memdbLeave(MemStore *p){ + sqlite3_mutex_leave(p->pMutex); +} +#endif + /* ** Close an memdb-file. -** -** The pData pointer is owned by the application, so there is nothing -** to free. Unless the SQLITE_DESERIALIZE_FREEONCLOSE flag is set, -** in which case we own the pData pointer and need to free it. +** Free the underlying MemStore object when its refcount drops to zero +** or less. */ static int memdbClose(sqlite3_file *pFile){ - MemFile *p = (MemFile *)pFile; - if( p->mFlags & SQLITE_DESERIALIZE_FREEONCLOSE ){ - sqlite3_free(p->aData); + MemStore *p = ((MemFile*)pFile)->pStore; + if( p->zFName ){ + int i; +#ifndef SQLITE_MUTEX_OMIT + sqlite3_mutex *pVfsMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); +#endif + sqlite3_mutex_enter(pVfsMutex); + for(i=0; ALWAYS(inRef==1 ){ + memdb_g.apMemStore[i] = memdb_g.apMemStore[--memdb_g.nMemStore]; + if( memdb_g.nMemStore==0 ){ + sqlite3_free(memdb_g.apMemStore); + memdb_g.apMemStore = 0; + } + } + break; + } + } + sqlite3_mutex_leave(pVfsMutex); + }else{ + memdbEnter(p); + } + p->nRef--; + if( p->nRef<=0 ){ + if( p->mFlags & SQLITE_DESERIALIZE_FREEONCLOSE ){ + sqlite3_free(p->aData); + } + memdbLeave(p); + sqlite3_mutex_free(p->pMutex); + sqlite3_free(p); + }else{ + memdbLeave(p); } return SQLITE_OK; } @@ -146,20 +254,23 @@ static int memdbRead( int iAmt, sqlite_int64 iOfst ){ - MemFile *p = (MemFile *)pFile; + MemStore *p = ((MemFile*)pFile)->pStore; + memdbEnter(p); if( iOfst+iAmt>p->sz ){ memset(zBuf, 0, iAmt); if( iOfstsz ) memcpy(zBuf, p->aData+iOfst, p->sz - iOfst); + memdbLeave(p); return SQLITE_IOERR_SHORT_READ; } memcpy(zBuf, p->aData+iOfst, iAmt); + memdbLeave(p); return SQLITE_OK; } /* ** Try to enlarge the memory allocation to hold at least sz bytes */ -static int memdbEnlarge(MemFile *p, sqlite3_int64 newSz){ +static int memdbEnlarge(MemStore *p, sqlite3_int64 newSz){ unsigned char *pNew; if( (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)==0 || p->nMmap>0 ){ return SQLITE_FULL; @@ -170,7 +281,7 @@ static int memdbEnlarge(MemFile *p, sqlite3_int64 newSz){ newSz *= 2; if( newSz>p->szMax ) newSz = p->szMax; pNew = sqlite3Realloc(p->aData, newSz); - if( pNew==0 ) return SQLITE_NOMEM; + if( pNew==0 ) return SQLITE_IOERR_NOMEM; p->aData = pNew; p->szAlloc = newSz; return SQLITE_OK; @@ -185,19 +296,27 @@ static int memdbWrite( int iAmt, sqlite_int64 iOfst ){ - MemFile *p = (MemFile *)pFile; - if( NEVER(p->mFlags & SQLITE_DESERIALIZE_READONLY) ) return SQLITE_READONLY; + MemStore *p = ((MemFile*)pFile)->pStore; + memdbEnter(p); + if( NEVER(p->mFlags & SQLITE_DESERIALIZE_READONLY) ){ + /* Can't happen: memdbLock() will return SQLITE_READONLY before + ** reaching this point */ + memdbLeave(p); + return SQLITE_IOERR_WRITE; + } if( iOfst+iAmt>p->sz ){ int rc; if( iOfst+iAmt>p->szAlloc && (rc = memdbEnlarge(p, iOfst+iAmt))!=SQLITE_OK ){ + memdbLeave(p); return rc; } if( iOfst>p->sz ) memset(p->aData+p->sz, 0, iOfst-p->sz); p->sz = iOfst+iAmt; } memcpy(p->aData+iOfst, z, iAmt); + memdbLeave(p); return SQLITE_OK; } @@ -209,16 +328,24 @@ static int memdbWrite( ** the size of a file, never to increase the size. */ static int memdbTruncate(sqlite3_file *pFile, sqlite_int64 size){ - MemFile *p = (MemFile *)pFile; - if( NEVER(size>p->sz) ) return SQLITE_FULL; - p->sz = size; - return SQLITE_OK; + MemStore *p = ((MemFile*)pFile)->pStore; + int rc = SQLITE_OK; + memdbEnter(p); + if( NEVER(size>p->sz) ){ + rc = SQLITE_FULL; + }else{ + p->sz = size; + } + memdbLeave(p); + return rc; } /* ** Sync an memdb-file. */ static int memdbSync(sqlite3_file *pFile, int flags){ + UNUSED_PARAMETER(pFile); + UNUSED_PARAMETER(flags); return SQLITE_OK; } @@ -226,8 +353,10 @@ static int memdbSync(sqlite3_file *pFile, int flags){ ** Return the current file-size of an memdb-file. */ static int memdbFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ - MemFile *p = (MemFile *)pFile; + MemStore *p = ((MemFile*)pFile)->pStore; + memdbEnter(p); *pSize = p->sz; + memdbLeave(p); return SQLITE_OK; } @@ -235,19 +364,48 @@ static int memdbFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ ** Lock an memdb-file. */ static int memdbLock(sqlite3_file *pFile, int eLock){ - MemFile *p = (MemFile *)pFile; - if( eLock>SQLITE_LOCK_SHARED - && (p->mFlags & SQLITE_DESERIALIZE_READONLY)!=0 - ){ - return SQLITE_READONLY; + MemFile *pThis = (MemFile*)pFile; + MemStore *p = pThis->pStore; + int rc = SQLITE_OK; + if( eLock==pThis->eLock ) return SQLITE_OK; + memdbEnter(p); + if( eLock>SQLITE_LOCK_SHARED ){ + if( p->mFlags & SQLITE_DESERIALIZE_READONLY ){ + rc = SQLITE_READONLY; + }else if( pThis->eLock<=SQLITE_LOCK_SHARED ){ + if( p->nWrLock ){ + rc = SQLITE_BUSY; + }else{ + p->nWrLock = 1; + } + } + }else if( eLock==SQLITE_LOCK_SHARED ){ + if( pThis->eLock > SQLITE_LOCK_SHARED ){ + assert( p->nWrLock==1 ); + p->nWrLock = 0; + }else if( p->nWrLock ){ + rc = SQLITE_BUSY; + }else{ + p->nRdLock++; + } + }else{ + assert( eLock==SQLITE_LOCK_NONE ); + if( pThis->eLock>SQLITE_LOCK_SHARED ){ + assert( p->nWrLock==1 ); + p->nWrLock = 0; + } + assert( p->nRdLock>0 ); + p->nRdLock--; } - p->eLock = eLock; - return SQLITE_OK; + if( rc==SQLITE_OK ) pThis->eLock = eLock; + memdbLeave(p); + return rc; } -#if 0 /* Never used because memdbAccess() always returns false */ +#if 0 /* -** Check if another file-handle holds a RESERVED lock on an memdb-file. +** This interface is only used for crash recovery, which does not +** occur on an in-memory database. */ static int memdbCheckReservedLock(sqlite3_file *pFile, int *pResOut){ *pResOut = 0; @@ -255,12 +413,14 @@ static int memdbCheckReservedLock(sqlite3_file *pFile, int *pResOut){ } #endif + /* ** File control method. For custom operations on an memdb-file. */ static int memdbFileControl(sqlite3_file *pFile, int op, void *pArg){ - MemFile *p = (MemFile *)pFile; + MemStore *p = ((MemFile*)pFile)->pStore; int rc = SQLITE_NOTFOUND; + memdbEnter(p); if( op==SQLITE_FCNTL_VFSNAME ){ *(char**)pArg = sqlite3_mprintf("memdb(%p,%lld)", p->aData, p->sz); rc = SQLITE_OK; @@ -278,6 +438,7 @@ static int memdbFileControl(sqlite3_file *pFile, int op, void *pArg){ *(sqlite3_int64*)pArg = iLimit; rc = SQLITE_OK; } + memdbLeave(p); return rc; } @@ -294,6 +455,7 @@ static int memdbSectorSize(sqlite3_file *pFile){ ** Return the device characteristic flags supported by an memdb-file. */ static int memdbDeviceCharacteristics(sqlite3_file *pFile){ + UNUSED_PARAMETER(pFile); return SQLITE_IOCAP_ATOMIC | SQLITE_IOCAP_POWERSAFE_OVERWRITE | SQLITE_IOCAP_SAFE_APPEND | @@ -307,20 +469,26 @@ static int memdbFetch( int iAmt, void **pp ){ - MemFile *p = (MemFile *)pFile; + MemStore *p = ((MemFile*)pFile)->pStore; + memdbEnter(p); if( iOfst+iAmt>p->sz ){ *pp = 0; }else{ p->nMmap++; *pp = (void*)(p->aData + iOfst); } + memdbLeave(p); return SQLITE_OK; } /* Release a memory-mapped page */ static int memdbUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ - MemFile *p = (MemFile *)pFile; + MemStore *p = ((MemFile*)pFile)->pStore; + UNUSED_PARAMETER(iOfst); + UNUSED_PARAMETER(pPage); + memdbEnter(p); p->nMmap--; + memdbLeave(p); return SQLITE_OK; } @@ -330,20 +498,79 @@ static int memdbUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ static int memdbOpen( sqlite3_vfs *pVfs, const char *zName, - sqlite3_file *pFile, + sqlite3_file *pFd, int flags, int *pOutFlags ){ - MemFile *p = (MemFile*)pFile; + MemFile *pFile = (MemFile*)pFd; + MemStore *p = 0; + int szName; if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){ - return ORIGVFS(pVfs)->xOpen(ORIGVFS(pVfs), zName, pFile, flags, pOutFlags); + return ORIGVFS(pVfs)->xOpen(ORIGVFS(pVfs), zName, pFd, flags, pOutFlags); } - memset(p, 0, sizeof(*p)); - p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE; + memset(pFile, 0, sizeof(*p)); + szName = sqlite3Strlen30(zName); + if( szName>1 && zName[0]=='/' ){ + int i; +#ifndef SQLITE_MUTEX_OMIT + sqlite3_mutex *pVfsMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); +#endif + sqlite3_mutex_enter(pVfsMutex); + for(i=0; izFName,zName)==0 ){ + p = memdb_g.apMemStore[i]; + break; + } + } + if( p==0 ){ + MemStore **apNew; + p = sqlite3Malloc( sizeof(*p) + szName + 3 ); + if( p==0 ){ + sqlite3_mutex_leave(pVfsMutex); + return SQLITE_NOMEM; + } + apNew = sqlite3Realloc(memdb_g.apMemStore, + sizeof(apNew[0])*(memdb_g.nMemStore+1) ); + if( apNew==0 ){ + sqlite3_free(p); + sqlite3_mutex_leave(pVfsMutex); + return SQLITE_NOMEM; + } + apNew[memdb_g.nMemStore++] = p; + memdb_g.apMemStore = apNew; + memset(p, 0, sizeof(*p)); + p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE|SQLITE_DESERIALIZE_FREEONCLOSE; + p->szMax = sqlite3GlobalConfig.mxMemdbSize; + p->zFName = (char*)&p[1]; + memcpy(p->zFName, zName, szName+1); + p->pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + if( p->pMutex==0 ){ + memdb_g.nMemStore--; + sqlite3_free(p); + sqlite3_mutex_leave(pVfsMutex); + return SQLITE_NOMEM; + } + p->nRef = 1; + memdbEnter(p); + }else{ + memdbEnter(p); + p->nRef++; + } + sqlite3_mutex_leave(pVfsMutex); + }else{ + p = sqlite3Malloc( sizeof(*p) ); + if( p==0 ){ + return SQLITE_NOMEM; + } + memset(p, 0, sizeof(*p)); + p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE; + p->szMax = sqlite3GlobalConfig.mxMemdbSize; + } + pFile->pStore = p; assert( pOutFlags!=0 ); /* True because flags==SQLITE_OPEN_MAIN_DB */ *pOutFlags = flags | SQLITE_OPEN_MEMORY; - pFile->pMethods = &memdb_io_methods; - p->szMax = sqlite3GlobalConfig.mxMemdbSize; + pFd->pMethods = &memdb_io_methods; + memdbLeave(p); return SQLITE_OK; } @@ -371,6 +598,9 @@ static int memdbAccess( int flags, int *pResOut ){ + UNUSED_PARAMETER(pVfs); + UNUSED_PARAMETER(zPath); + UNUSED_PARAMETER(flags); *pResOut = 0; return SQLITE_OK; } @@ -386,6 +616,7 @@ static int memdbFullPathname( int nOut, char *zOut ){ + UNUSED_PARAMETER(pVfs); sqlite3_snprintf(nOut, zOut, "%s", zPath); return SQLITE_OK; } @@ -458,9 +689,14 @@ static int memdbCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){ */ static MemFile *memdbFromDbSchema(sqlite3 *db, const char *zSchema){ MemFile *p = 0; + MemStore *pStore; int rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_FILE_POINTER, &p); if( rc ) return 0; if( p->base.pMethods!=&memdb_io_methods ) return 0; + pStore = p->pStore; + memdbEnter(pStore); + if( pStore->zFName!=0 ) p = 0; + memdbLeave(pStore); return p; } @@ -496,12 +732,14 @@ unsigned char *sqlite3_serialize( if( piSize ) *piSize = -1; if( iDb<0 ) return 0; if( p ){ - if( piSize ) *piSize = p->sz; + MemStore *pStore = p->pStore; + assert( pStore->pMutex==0 ); + if( piSize ) *piSize = pStore->sz; if( mFlags & SQLITE_SERIALIZE_NOCOPY ){ - pOut = p->aData; + pOut = pStore->aData; }else{ - pOut = sqlite3_malloc64( p->sz ); - if( pOut ) memcpy(pOut, p->aData, p->sz); + pOut = sqlite3_malloc64( pStore->sz ); + if( pOut ) memcpy(pOut, pStore->aData, pStore->sz); } return pOut; } @@ -595,15 +833,16 @@ int sqlite3_deserialize( if( p==0 ){ rc = SQLITE_ERROR; }else{ - p->aData = pData; + MemStore *pStore = p->pStore; + pStore->aData = pData; pData = 0; - p->sz = szDb; - p->szAlloc = szBuf; - p->szMax = szBuf; - if( p->szMaxszMax = sqlite3GlobalConfig.mxMemdbSize; + pStore->sz = szDb; + pStore->szAlloc = szBuf; + pStore->szMax = szBuf; + if( pStore->szMaxszMax = sqlite3GlobalConfig.mxMemdbSize; } - p->mFlags = mFlags; + pStore->mFlags = mFlags; rc = SQLITE_OK; } @@ -622,7 +861,7 @@ end_deserialize: */ int sqlite3MemdbInit(void){ sqlite3_vfs *pLower = sqlite3_vfs_find(0); - int sz = pLower->szOsFile; + unsigned int sz = pLower->szOsFile; memdb_vfs.pAppData = pLower; /* The following conditional can only be true when compiled for ** Windows x86 and SQLITE_MAX_MMAP_SIZE=0. We always leave @@ -632,4 +871,4 @@ int sqlite3MemdbInit(void){ memdb_vfs.szOsFile = sz; return sqlite3_vfs_register(&memdb_vfs, 0); } -#endif /* SQLITE_ENABLE_DESERIALIZE */ +#endif /* SQLITE_OMIT_DESERIALIZE */ diff --git a/src/os.c b/src/os.c index 693d78dc91..b11c49c1d5 100644 --- a/src/os.c +++ b/src/os.c @@ -229,7 +229,7 @@ int sqlite3OsOpen( int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ DO_OS_MALLOC_TEST(0); assert( dirSync==0 || dirSync==1 ); - return pVfs->xDelete(pVfs, zPath, dirSync); + return pVfs->xDelete!=0 ? pVfs->xDelete(pVfs, zPath, dirSync) : SQLITE_OK; } int sqlite3OsAccess( sqlite3_vfs *pVfs, diff --git a/src/os_unix.c b/src/os_unix.c index c212aaf17a..2053fbac00 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -3980,6 +3980,7 @@ static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){ /* Forward declaration */ static int unixGetTempname(int nBuf, char *zBuf); +static int unixFcntlExternalReader(unixFile*, int*); /* ** Information and control of an open file handle. @@ -4099,6 +4100,10 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ return proxyFileControl(id,op,pArg); } #endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */ + + case SQLITE_FCNTL_EXTERNAL_READER: { + return unixFcntlExternalReader((unixFile*)id, (int*)pArg); + } } return SQLITE_NOTFOUND; } @@ -4380,6 +4385,40 @@ struct unixShm { #define UNIX_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ #define UNIX_SHM_DMS (UNIX_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ +/* +** Use F_GETLK to check whether or not there are any readers with open +** wal-mode transactions in other processes on database file pFile. If +** no error occurs, return SQLITE_OK and set (*piOut) to 1 if there are +** such transactions, or 0 otherwise. If an error occurs, return an +** SQLite error code. The final value of *piOut is undefined in this +** case. +*/ +static int unixFcntlExternalReader(unixFile *pFile, int *piOut){ + int rc = SQLITE_OK; + *piOut = 0; + if( pFile->pShm){ + unixShmNode *pShmNode = pFile->pShm->pShmNode; + struct flock f; + + memset(&f, 0, sizeof(f)); + f.l_type = F_WRLCK; + f.l_whence = SEEK_SET; + f.l_start = UNIX_SHM_BASE + 3; + f.l_len = SQLITE_SHM_NLOCK - 3; + + sqlite3_mutex_enter(pShmNode->pShmMutex); + if( osFcntl(pShmNode->hShm, F_GETLK, &f)<0 ){ + rc = SQLITE_IOERR_LOCK; + }else{ + *piOut = (f.l_type!=F_UNLCK); + } + sqlite3_mutex_leave(pShmNode->pShmMutex); + } + + return rc; +} + + /* ** Apply posix advisory locks for all bytes from ofst through ofst+n-1. ** @@ -8214,6 +8253,22 @@ int sqlite3_os_init(void){ sqlite3_vfs_register(&aVfs[i], i==0); } unixBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); + + /* Validate lock assumptions */ + assert( SQLITE_SHM_NLOCK==8 ); /* Number of available locks */ + assert( UNIX_SHM_BASE==120 ); /* Start of locking area */ + /* Locks: + ** WRITE UNIX_SHM_BASE 120 + ** CKPT UNIX_SHM_BASE+1 121 + ** RECOVER UNIX_SHM_BASE+2 122 + ** READ-0 UNIX_SHM_BASE+3 123 + ** READ-1 UNIX_SHM_BASE+4 124 + ** READ-2 UNIX_SHM_BASE+5 125 + ** READ-3 UNIX_SHM_BASE+6 126 + ** READ-4 UNIX_SHM_BASE+7 127 + ** DMS UNIX_SHM_BASE+8 128 + */ + assert( UNIX_SHM_DMS==128 ); /* Byte offset of the deadman-switch */ return SQLITE_OK; } diff --git a/src/pager.c b/src/pager.c index 698ff695f6..cd19eb5e1c 100644 --- a/src/pager.c +++ b/src/pager.c @@ -3998,7 +3998,8 @@ static void assertTruncateConstraint(Pager *pPager){ ** then continue writing to the database. */ void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){ - assert( pPager->dbSize>=nPage ); + assert( pPager->dbSize>=nPage || CORRUPT_DB ); + testcase( pPager->dbSizeeState>=PAGER_WRITER_CACHEMOD ); pPager->dbSize = nPage; @@ -4732,7 +4733,7 @@ int sqlite3PagerOpen( int rc = SQLITE_OK; /* Return code */ int tempFile = 0; /* True for temp files (incl. in-memory files) */ int memDb = 0; /* True if this is an in-memory file */ -#ifdef SQLITE_ENABLE_DESERIALIZE +#ifndef SQLITE_OMIT_DESERIALIZE int memJM = 0; /* Memory journal mode */ #else # define memJM 0 @@ -4939,7 +4940,7 @@ int sqlite3PagerOpen( int fout = 0; /* VFS flags returned by xOpen() */ rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout); assert( !memDb ); -#ifdef SQLITE_ENABLE_DESERIALIZE +#ifndef SQLITE_OMIT_DESERIALIZE memJM = (fout&SQLITE_OPEN_MEMORY)!=0; #endif readOnly = (fout&SQLITE_OPEN_READONLY)!=0; @@ -5922,7 +5923,7 @@ int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){ assert( pPager->eState>=PAGER_READER && pPager->eStatesubjInMemory = (u8)subjInMemory; - if( ALWAYS(pPager->eState==PAGER_READER) ){ + if( pPager->eState==PAGER_READER ){ assert( pPager->pInJournal==0 ); if( pagerUseWal(pPager) ){ /* If the pager is configured to use locking_mode=exclusive, and an diff --git a/src/parse.y b/src/parse.y index bd3eb13ac2..0da6e47ff5 100644 --- a/src/parse.y +++ b/src/parse.y @@ -209,7 +209,7 @@ ifnotexists(A) ::= . {A = 0;} ifnotexists(A) ::= IF NOT EXISTS. {A = 1;} %type temp {int} %ifndef SQLITE_OMIT_TEMPDB -temp(A) ::= TEMP. {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). { @@ -1816,7 +1816,11 @@ frame_exclude(A) ::= GROUP|TIES(X). {A = @X; /*A-overwrites-X*/} window_clause(A) ::= WINDOW windowdefn_list(B). { A = B; } filter_over(A) ::= filter_clause(F) over_clause(O). { - O->pFilter = F; + if( O ){ + O->pFilter = F; + }else{ + sqlite3ExprDelete(pParse->db, F); + } A = O; } filter_over(A) ::= over_clause(O). { diff --git a/src/prepare.c b/src/prepare.c index eb4627f0d2..b18716c9e3 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -96,6 +96,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){ UNUSED_PARAMETER2(NotUsed, argc); assert( sqlite3_mutex_held(db->mutex) ); db->mDbFlags |= DBFLAG_EncodingFixed; + if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ pData->nInitRow++; if( db->mallocFailed ){ corruptSchema(pData, argv, 0); @@ -103,7 +104,6 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){ } assert( iDb>=0 && iDbnDb ); - if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ if( argv[3]==0 ){ corruptSchema(pData, argv, 0); }else if( argv[4] @@ -380,15 +380,17 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){ if( db->mallocFailed ){ rc = SQLITE_NOMEM_BKPT; sqlite3ResetAllSchemasOfConnection(db); - } + }else if( rc==SQLITE_OK || (db->flags&SQLITE_NoSchemaError)){ - /* Black magic: If the SQLITE_NoSchemaError flag is set, then consider - ** the schema loaded, even if errors occurred. In this situation the - ** current sqlite3_prepare() operation will fail, but the following one - ** will attempt to compile the supplied statement against whatever subset - ** of the schema was loaded before the error occurred. The primary - ** purpose of this is to allow access to the sqlite_schema table - ** even when its contents have been corrupted. + /* Hack: If the SQLITE_NoSchemaError flag is set, then consider + ** the schema loaded, even if errors (other than OOM) occurred. In + ** this situation the current sqlite3_prepare() operation will fail, + ** but the following one will attempt to compile the supplied statement + ** against whatever subset of the schema was loaded before the error + ** occurred. + ** + ** The primary purpose of this is to allow access to the sqlite_schema + ** table even when its contents have been corrupted. */ DbSetProperty(db, iDb, DB_SchemaLoaded); rc = SQLITE_OK; @@ -498,6 +500,7 @@ static void schemaIsValid(Parse *pParse){ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ sqlite3OomFault(db); + pParse->rc = SQLITE_NOMEM; } if( rc!=SQLITE_OK ) return; openedTransaction = 1; @@ -733,6 +736,7 @@ static int sqlite3Prepare( } if( db->mallocFailed ){ sParse.rc = SQLITE_NOMEM_BKPT; + sParse.checkSchema = 0; } if( sParse.rc!=SQLITE_OK && sParse.rc!=SQLITE_DONE ){ if( sParse.checkSchema ){ diff --git a/src/printf.c b/src/printf.c index 9aab863ed2..f663e1b1ed 100644 --- a/src/printf.c +++ b/src/printf.c @@ -29,7 +29,7 @@ #define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '', NULL pointers replaced by SQL NULL. %Q */ #define etTOKEN 11 /* a pointer to a Token structure */ -#define etSRCLIST 12 /* a pointer to a SrcList */ +#define etSRCITEM 12 /* a pointer to a SrcItem */ #define etPOINTER 13 /* The %p conversion */ #define etSQLESCAPE3 14 /* %w -> Strings with '\"' doubled */ #define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */ @@ -95,10 +95,16 @@ static const et_info fmtinfo[] = { /* All the rest are undocumented and are for internal use only */ { 'T', 0, 0, etTOKEN, 0, 0 }, - { 'S', 0, 0, etSRCLIST, 0, 0 }, + { 'S', 0, 0, etSRCITEM, 0, 0 }, { 'r', 10, 1, etORDINAL, 0, 0 }, }; +/* Notes: +** +** %S Takes a pointer to SrcItem. Shows name or database.name +** %!S Like %S but prefer the zName over the zAlias +*/ + /* Floating point constants used for rounding */ static const double arRound[] = { 5.0e-01, 5.0e-02, 5.0e-03, 5.0e-04, 5.0e-05, @@ -853,21 +859,24 @@ void sqlite3_str_vappendf( length = width = 0; break; } - case etSRCLIST: { - SrcList *pSrc; - int k; + case etSRCITEM: { SrcItem *pItem; if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return; - pSrc = va_arg(ap, SrcList*); - k = va_arg(ap, int); - pItem = &pSrc->a[k]; + pItem = va_arg(ap, SrcItem*); assert( bArgList==0 ); - assert( k>=0 && knSrc ); - if( pItem->zDatabase ){ - sqlite3_str_appendall(pAccum, pItem->zDatabase); - sqlite3_str_append(pAccum, ".", 1); + if( pItem->zAlias && !flag_altform2 ){ + sqlite3_str_appendall(pAccum, pItem->zAlias); + }else if( pItem->zName ){ + if( pItem->zDatabase ){ + sqlite3_str_appendall(pAccum, pItem->zDatabase); + sqlite3_str_append(pAccum, ".", 1); + } + sqlite3_str_appendall(pAccum, pItem->zName); + }else if( pItem->zAlias ){ + sqlite3_str_appendall(pAccum, pItem->zAlias); + }else if( ALWAYS(pItem->pSelect) ){ + sqlite3_str_appendf(pAccum, "SUBQUERY %u", pItem->pSelect->selId); } - sqlite3_str_appendall(pAccum, pItem->zName); length = width = 0; break; } diff --git a/src/resolve.c b/src/resolve.c index ee75d2acb8..d5cec3550a 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -81,7 +81,10 @@ static void resolveAlias( assert( pOrig!=0 ); db = pParse->db; pDup = sqlite3ExprDup(db, pOrig, 0); - if( pDup!=0 ){ + if( db->mallocFailed ){ + sqlite3ExprDelete(db, pDup); + pDup = 0; + }else{ incrAggFunctionDepth(pDup, nSubquery); if( pExpr->op==TK_COLLATE ){ pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken); @@ -103,10 +106,8 @@ static void resolveAlias( pExpr->flags |= EP_MemToken; } if( ExprHasProperty(pExpr, EP_WinFunc) ){ - if( pExpr->y.pWin!=0 ){ + if( ALWAYS(pExpr->y.pWin!=0) ){ pExpr->y.pWin->pOwner = pExpr; - }else{ - assert( db->mallocFailed ); } } sqlite3DbFree(db, pDup); @@ -376,15 +377,19 @@ static int lookupName( if( pParse->pTriggerTab!=0 ){ int op = pParse->eTriggerOp; assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT ); - if( op!=TK_DELETE && zTab && sqlite3StrICmp("new",zTab) == 0 ){ + if( pParse->bReturning ){ + if( (pNC->ncFlags & NC_UBaseReg)!=0 + && (zTab==0 || sqlite3StrICmp(zTab,pParse->pTriggerTab->zName)==0) + ){ + pExpr->iTable = op!=TK_DELETE; + pTab = pParse->pTriggerTab; + } + }else if( op!=TK_DELETE && zTab && sqlite3StrICmp("new",zTab) == 0 ){ pExpr->iTable = 1; pTab = pParse->pTriggerTab; }else if( op!=TK_INSERT && zTab && sqlite3StrICmp("old",zTab)==0 ){ pExpr->iTable = 0; pTab = pParse->pTriggerTab; - }else if( pParse->bReturning && (pNC->ncFlags & NC_UBaseReg)!=0 ){ - pExpr->iTable = op!=TK_DELETE; - pTab = pParse->pTriggerTab; } } #endif /* SQLITE_OMIT_TRIGGER */ @@ -494,8 +499,8 @@ static int lookupName( ** is supported for backwards compatibility only. Hence, we issue a warning ** on sqlite3_log() whenever the capability is used. */ - if( (pNC->ncFlags & NC_UEList)!=0 - && cnt==0 + if( cnt==0 + && (pNC->ncFlags & NC_UEList)!=0 && zTab==0 ){ pEList = pNC->uNC.pEList; @@ -559,7 +564,6 @@ static int lookupName( assert( pExpr->op==TK_ID ); if( ExprHasProperty(pExpr,EP_DblQuoted) && areDoubleQuotedStringsEnabled(db, pTopNC) - && (db->init.bDropColumn==0 || sqlite3StrICmp(zCol, db->init.azInit[0])!=0) ){ /* If a double-quoted identifier does not match any known column name, ** then treat it as a string. @@ -574,11 +578,6 @@ static int lookupName( ** Someday, I hope to get rid of this hack. Unfortunately there is ** a huge amount of legacy SQL that uses it. So for now, we just ** issue a warning. - ** - ** 2021-03-15: ticket 1c24a659e6d7f3a1 - ** Do not do the ID-to-STRING conversion when doing the schema - ** sanity check following a DROP COLUMN if the identifer name matches - ** the name of the column being dropped. */ sqlite3_log(SQLITE_WARNING, "double-quoted string literal: \"%w\"", zCol); @@ -609,7 +608,7 @@ static int lookupName( sqlite3ErrorMsg(pParse, "%s: %s", zErr, zCol); } pParse->checkSchema = 1; - pTopNC->nErr++; + pTopNC->nNcErr++; } /* If a column from a table in pSrcList is referenced, then record @@ -916,7 +915,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ sqlite3ErrorMsg(pParse, "second argument to likelihood() must be a " "constant between 0.0 and 1.0"); - pNC->nErr++; + pNC->nNcErr++; } }else{ /* EVIDENCE-OF: R-61304-29449 The unlikely(X) function is @@ -938,7 +937,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ if( auth==SQLITE_DENY ){ sqlite3ErrorMsg(pParse, "not authorized to use function: %s", pDef->zName); - pNC->nErr++; + pNC->nNcErr++; } pExpr->op = TK_NULL; return WRC_Prune; @@ -994,7 +993,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ sqlite3ErrorMsg(pParse, "%.*s() may not be used as a window function", nId, zId ); - pNC->nErr++; + pNC->nNcErr++; }else if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) || (is_agg && (pDef->funcFlags&SQLITE_FUNC_WINDOW) && !pWin) @@ -1007,13 +1006,13 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ zType = "aggregate"; } sqlite3ErrorMsg(pParse, "misuse of %s function %.*s()",zType,nId,zId); - pNC->nErr++; + pNC->nNcErr++; is_agg = 0; } #else if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) ){ sqlite3ErrorMsg(pParse,"misuse of aggregate function %.*s()",nId,zId); - pNC->nErr++; + pNC->nNcErr++; is_agg = 0; } #endif @@ -1023,11 +1022,11 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ #endif ){ sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId); - pNC->nErr++; + pNC->nNcErr++; }else if( wrong_num_args ){ sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()", nId, zId); - pNC->nErr++; + pNC->nNcErr++; } #ifndef SQLITE_OMIT_WINDOWFUNC else if( is_agg==0 && ExprHasProperty(pExpr, EP_WinFunc) ){ @@ -1035,7 +1034,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ "FILTER may not be used with non-aggregate %.*s()", nId, zId ); - pNC->nErr++; + pNC->nNcErr++; } #endif if( is_agg ){ @@ -1259,8 +1258,8 @@ static int resolveOrderByTermToExprList( nc.pParse = pParse; nc.pSrcList = pSelect->pSrc; nc.uNC.pEList = pEList; - nc.ncFlags = NC_AllowAgg|NC_UEList; - nc.nErr = 0; + nc.ncFlags = NC_AllowAgg|NC_UEList|NC_NoSelect; + nc.nNcErr = 0; db = pParse->db; savedSuppErr = db->suppressErr; if( IN_RENAME_OBJECT==0 ) db->suppressErr = 1; @@ -1519,7 +1518,7 @@ static int resolveOrderGroupBy( Parse *pParse; /* Parsing context */ int nResult; /* Number of terms in the result set */ - if( pOrderBy==0 ) return 0; + assert( pOrderBy!=0 ); nResult = pSelect->pEList->nExpr; pParse = pNC->pParse; for(i=0, pItem=pOrderBy->a; inExpr; i++, pItem++){ @@ -1609,8 +1608,10 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ while( p ){ assert( (p->selFlags & SF_Expanded)!=0 ); assert( (p->selFlags & SF_Resolved)==0 ); + assert( db->suppressErr==0 ); /* SF_Resolved not set if errors suppressed */ p->selFlags |= SF_Resolved; + /* Resolve the expressions in the LIMIT and OFFSET clauses. These ** are not allowed to refer to any names, so pass an empty NameContext. */ @@ -1684,13 +1685,6 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ sNC.ncFlags &= ~NC_AllowAgg; } - /* If a HAVING clause is present, then there must be a GROUP BY clause. - */ - if( p->pHaving && !pGroupBy ){ - sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING"); - return WRC_Abort; - } - /* Add the output column list to the name-context before parsing the ** other expressions in the SELECT statement. This is so that ** expressions in the WHERE clause (etc.) can refer to expressions by @@ -1702,7 +1696,13 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ assert( (sNC.ncFlags & (NC_UAggInfo|NC_UUpsert|NC_UBaseReg))==0 ); sNC.uNC.pEList = p->pEList; sNC.ncFlags |= NC_UEList; - if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort; + if( p->pHaving ){ + if( !pGroupBy ){ + sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING"); + return WRC_Abort; + } + if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort; + } if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort; /* Resolve names in table-valued-function arguments */ @@ -1715,6 +1715,19 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ } } +#ifndef SQLITE_OMIT_WINDOWFUNC + if( IN_RENAME_OBJECT ){ + Window *pWin; + for(pWin=p->pWinDefn; pWin; pWin=pWin->pNextWin){ + if( sqlite3ResolveExprListNames(&sNC, pWin->pOrderBy) + || sqlite3ResolveExprListNames(&sNC, pWin->pPartition) + ){ + return WRC_Abort; + } + } + } +#endif + /* The ORDER BY and GROUP BY clauses may not refer to terms in ** outer queries */ @@ -1742,7 +1755,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ ** is not detected until much later, and so we need to go ahead and ** resolve those symbols on the incorrect ORDER BY for consistency. */ - if( isCompound<=nCompound /* Defer right-most ORDER BY of a compound */ + if( p->pOrderBy!=0 + && isCompound<=nCompound /* Defer right-most ORDER BY of a compound */ && resolveOrderGroupBy(&sNC, p, p->pOrderBy, "ORDER") ){ return WRC_Abort; @@ -1770,19 +1784,6 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ } } -#ifndef SQLITE_OMIT_WINDOWFUNC - if( IN_RENAME_OBJECT ){ - Window *pWin; - for(pWin=p->pWinDefn; pWin; pWin=pWin->pNextWin){ - if( sqlite3ResolveExprListNames(&sNC, pWin->pOrderBy) - || sqlite3ResolveExprListNames(&sNC, pWin->pPartition) - ){ - return WRC_Abort; - } - } - } -#endif - /* If this is part of a compound SELECT, check that it has the right ** number of expressions in the select list. */ if( p->pNext && p->pEList->nExpr!=p->pNext->pEList->nExpr ){ @@ -1866,7 +1867,7 @@ int sqlite3ResolveExprNames( pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin); w.pParse = pNC->pParse; w.xExprCallback = resolveExprStep; - w.xSelectCallback = resolveSelectStep; + w.xSelectCallback = (pNC->ncFlags & NC_NoSelect) ? 0 : resolveSelectStep; w.xSelectCallback2 = 0; w.u.pNC = pNC; #if SQLITE_MAX_EXPR_DEPTH>0 @@ -1885,7 +1886,7 @@ int sqlite3ResolveExprNames( testcase( pNC->ncFlags & NC_HasWin ); ExprSetProperty(pExpr, pNC->ncFlags & (NC_HasAgg|NC_HasWin) ); pNC->ncFlags |= savedHasAgg; - return pNC->nErr>0 || w.pParse->nErr>0; + return pNC->nNcErr>0 || w.pParse->nErr>0; } /* @@ -1930,7 +1931,7 @@ int sqlite3ResolveExprListNames( savedHasAgg |= pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin); pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin); } - if( pNC->nErr>0 || w.pParse->nErr>0 ) return WRC_Abort; + if( w.pParse->nErr>0 ) return WRC_Abort; } pNC->ncFlags |= savedHasAgg; return WRC_Continue; diff --git a/src/select.c b/src/select.c index 1c001aa761..58f23caba9 100644 --- a/src/select.c +++ b/src/select.c @@ -741,31 +741,155 @@ static void codeOffset( } /* -** Add code that will check to make sure the N registers starting at iMem -** form a distinct entry. iTab is a sorting index that holds previously -** seen combinations of the N values. A new entry is made in iTab -** if the current N values are new. +** Add code that will check to make sure the array of registers starting at +** iMem form a distinct entry. This is used by both "SELECT DISTINCT ..." and +** distinct aggregates ("SELECT count(DISTINCT ) ..."). Three strategies +** are available. Which is used depends on the value of parameter eTnctType, +** as follows: ** -** A jump to addrRepeat is made and the N+1 values are popped from the -** stack if the top N elements are not distinct. +** WHERE_DISTINCT_UNORDERED/WHERE_DISTINCT_NOOP: +** Build an ephemeral table that contains all entries seen before and +** skip entries which have been seen before. +** +** Parameter iTab is the cursor number of an ephemeral table that must +** be opened before the VM code generated by this routine is executed. +** The ephemeral cursor table is queried for a record identical to the +** record formed by the current array of registers. If one is found, +** jump to VM address addrRepeat. Otherwise, insert a new record into +** the ephemeral cursor and proceed. +** +** The returned value in this case is a copy of parameter iTab. +** +** WHERE_DISTINCT_ORDERED: +** In this case rows are being delivered sorted order. The ephermal +** table is not required. Instead, the current set of values +** is compared against previous row. If they match, the new row +** is not distinct and control jumps to VM address addrRepeat. Otherwise, +** the VM program proceeds with processing the new row. +** +** The returned value in this case is the register number of the first +** in an array of registers used to store the previous result row so that +** it can be compared to the next. The caller must ensure that this +** register is initialized to NULL. (The fixDistinctOpenEph() routine +** will take care of this initialization.) +** +** WHERE_DISTINCT_UNIQUE: +** In this case it has already been determined that the rows are distinct. +** No special action is required. The return value is zero. +** +** Parameter pEList is the list of expressions used to generated the +** contents of each row. It is used by this routine to determine (a) +** how many elements there are in the array of registers and (b) the +** collation sequences that should be used for the comparisons if +** eTnctType is WHERE_DISTINCT_ORDERED. */ -static void codeDistinct( +static int codeDistinct( Parse *pParse, /* Parsing and code generating context */ + int eTnctType, /* WHERE_DISTINCT_* value */ int iTab, /* A sorting index used to test for distinctness */ int addrRepeat, /* Jump to here if not distinct */ - int N, /* Number of elements */ - int iMem /* First element */ + ExprList *pEList, /* Expression for each element */ + int regElem /* First element */ ){ - Vdbe *v; - int r1; + int iRet = 0; + int nResultCol = pEList->nExpr; + Vdbe *v = pParse->pVdbe; - v = pParse->pVdbe; - r1 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, iMem, N); VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1); - sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r1, iMem, N); - sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); - sqlite3ReleaseTempReg(pParse, r1); + switch( eTnctType ){ + case WHERE_DISTINCT_ORDERED: { + int i; + int iJump; /* Jump destination */ + int regPrev; /* Previous row content */ + + /* Allocate space for the previous row */ + iRet = regPrev = pParse->nMem+1; + pParse->nMem += nResultCol; + + iJump = sqlite3VdbeCurrentAddr(v) + nResultCol; + for(i=0; ia[i].pExpr); + if( idb->mallocFailed ); + sqlite3VdbeAddOp3(v, OP_Copy, regElem, regPrev, nResultCol-1); + break; + } + + case WHERE_DISTINCT_UNIQUE: { + /* nothing to do */ + break; + } + + default: { + int r1 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, regElem, nResultCol); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regElem, nResultCol, r1); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r1, regElem, nResultCol); + sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); + sqlite3ReleaseTempReg(pParse, r1); + iRet = iTab; + break; + } + } + + return iRet; +} + +/* +** This routine runs after codeDistinct(). It makes necessary +** adjustments to the OP_OpenEphemeral opcode that the codeDistinct() +** routine made use of. This processing must be done separately since +** sometimes codeDistinct is called before the OP_OpenEphemeral is actually +** laid down. +** +** WHERE_DISTINCT_NOOP: +** WHERE_DISTINCT_UNORDERED: +** +** No adjustments necessary. This function is a no-op. +** +** WHERE_DISTINCT_UNIQUE: +** +** The ephemeral table is not needed. So change the +** OP_OpenEphemeral opcode into an OP_Noop. +** +** WHERE_DISTINCT_ORDERED: +** +** The ephemeral table is not needed. But we do need register +** iVal to be initialized to NULL. So change the OP_OpenEphemeral +** into an OP_Null on the iVal register. +*/ +static void fixDistinctOpenEph( + Parse *pParse, /* Parsing and code generating context */ + int eTnctType, /* WHERE_DISTINCT_* value */ + int iVal, /* Value returned by codeDistinct() */ + int iOpenEphAddr /* Address of OP_OpenEphemeral instruction for iTab */ +){ + if( eTnctType==WHERE_DISTINCT_UNIQUE || eTnctType==WHERE_DISTINCT_ORDERED ){ + Vdbe *v = pParse->pVdbe; + sqlite3VdbeChangeToNoop(v, iOpenEphAddr); + if( sqlite3VdbeGetOp(v, iOpenEphAddr+1)->opcode==OP_Explain ){ + sqlite3VdbeChangeToNoop(v, iOpenEphAddr+1); + } + if( eTnctType==WHERE_DISTINCT_ORDERED ){ + /* Change the OP_OpenEphemeral to an OP_Null that sets the MEM_Cleared + ** bit on the first register of the previous value. This will cause the + ** OP_Ne added in codeDistinct() to always fail on the first iteration of + ** the loop even if the first row is all NULLs. */ + VdbeOp *pOp = sqlite3VdbeGetOp(v, iOpenEphAddr); + pOp->opcode = OP_Null; + pOp->p1 = 1; + pOp->p2 = iVal; + } + } } #ifdef SQLITE_ENABLE_SORTER_REFERENCES @@ -1013,59 +1137,11 @@ static void selectInnerLoop( ** part of the result. */ if( hasDistinct ){ - switch( pDistinct->eTnctType ){ - case WHERE_DISTINCT_ORDERED: { - VdbeOp *pOp; /* No longer required OpenEphemeral instr. */ - int iJump; /* Jump destination */ - int regPrev; /* Previous row content */ - - /* Allocate space for the previous row */ - regPrev = pParse->nMem+1; - pParse->nMem += nResultCol; - - /* Change the OP_OpenEphemeral coded earlier to an OP_Null - ** sets the MEM_Cleared bit on the first register of the - ** previous value. This will cause the OP_Ne below to always - ** fail on the first iteration of the loop even if the first - ** row is all NULLs. - */ - sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct); - pOp = sqlite3VdbeGetOp(v, pDistinct->addrTnct); - pOp->opcode = OP_Null; - pOp->p1 = 1; - pOp->p2 = regPrev; - pOp = 0; /* Ensure pOp is not used after sqlite3VdbeAddOp() */ - - iJump = sqlite3VdbeCurrentAddr(v) + nResultCol; - for(i=0; ipEList->a[i].pExpr); - if( idb->mallocFailed ); - sqlite3VdbeAddOp3(v, OP_Copy, regResult, regPrev, nResultCol-1); - break; - } - - case WHERE_DISTINCT_UNIQUE: { - sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct); - break; - } - - default: { - assert( pDistinct->eTnctType==WHERE_DISTINCT_UNORDERED ); - codeDistinct(pParse, pDistinct->tabTnct, iContinue, nResultCol, - regResult); - break; - } - } + int eType = pDistinct->eTnctType; + int iTab = pDistinct->tabTnct; + assert( nResultCol==p->pEList->nExpr ); + iTab = codeDistinct(pParse, eType, iTab, iContinue, p->pEList, regResult); + fixDistinctOpenEph(pParse, eType, iTab, pDistinct->addrTnct); if( pSort==0 ){ codeOffset(v, p->iOffset, iContinue); } @@ -1731,7 +1807,13 @@ static const char *columnTypeImpl( ** of the SELECT statement. Return the declaration type and origin ** data for the result-set column of the sub-select. */ - if( iCol>=0 && iColpEList->nExpr ){ + if( iColpEList->nExpr +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + && iCol>=0 +#else + && ALWAYS(iCol>=0) +#endif + ){ /* If iCol is less than zero, then the expression requests the ** rowid of the sub-select or view. This expression is legal (see ** test case misc2.2.2) - it always evaluates to NULL. @@ -1873,7 +1955,7 @@ static void generateColumnTypes( ** then the result column name with the table name ** prefix, ex: TABLE.COLUMN. Otherwise use zSpan. */ -static void generateColumnNames( +void sqlite3GenerateColumnNames( Parse *pParse, /* Parser context */ Select *pSelect /* Generate column names for this SELECT statement */ ){ @@ -1963,7 +2045,7 @@ static void generateColumnNames( ** and will break if those assumptions changes. Hence, use extreme caution ** when modifying this routine to avoid breaking legacy. ** -** See Also: generateColumnNames() +** See Also: sqlite3GenerateColumnNames() */ int sqlite3ColumnsFromExprList( Parse *pParse, /* Parsing context */ @@ -2661,11 +2743,12 @@ static int multiSelect( switch( p->op ){ case TK_ALL: { int addr = 0; - int nLimit; + int nLimit = 0; /* Initialize to suppress harmless compiler warning */ assert( !pPrior->pLimit ); pPrior->iLimit = p->iLimit; pPrior->iOffset = p->iOffset; pPrior->pLimit = p->pLimit; + SELECTTRACE(1, pParse, p, ("multiSelect UNION ALL left...\n")); rc = sqlite3Select(pParse, pPrior, &dest); pPrior->pLimit = 0; if( rc ){ @@ -2683,6 +2766,7 @@ static int multiSelect( } } ExplainQueryPlan((pParse, 1, "UNION ALL")); + SELECTTRACE(1, pParse, p, ("multiSelect UNION ALL right...\n")); rc = sqlite3Select(pParse, p, &dest); testcase( rc!=SQLITE_OK ); pDelete = p->pPrior; @@ -2735,6 +2819,7 @@ static int multiSelect( */ assert( !pPrior->pOrderBy ); sqlite3SelectDestInit(&uniondest, priorOp, unionTab); + SELECTTRACE(1, pParse, p, ("multiSelect EXCEPT/UNION left...\n")); rc = sqlite3Select(pParse, pPrior, &uniondest); if( rc ){ goto multi_select_end; @@ -2754,6 +2839,7 @@ static int multiSelect( uniondest.eDest = op; ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE", sqlite3SelectOpName(p->op))); + SELECTTRACE(1, pParse, p, ("multiSelect EXCEPT/UNION right...\n")); rc = sqlite3Select(pParse, p, &uniondest); testcase( rc!=SQLITE_OK ); assert( p->pOrderBy==0 ); @@ -2814,6 +2900,7 @@ static int multiSelect( /* Code the SELECTs to our left into temporary table "tab1". */ sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1); + SELECTTRACE(1, pParse, p, ("multiSelect INTERSECT left...\n")); rc = sqlite3Select(pParse, pPrior, &intersectdest); if( rc ){ goto multi_select_end; @@ -2830,6 +2917,7 @@ static int multiSelect( intersectdest.iSDParm = tab2; ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE", sqlite3SelectOpName(p->op))); + SELECTTRACE(1, pParse, p, ("multiSelect INTERSECT right...\n")); rc = sqlite3Select(pParse, p, &intersectdest); testcase( rc!=SQLITE_OK ); pDelete = p->pPrior; @@ -3463,6 +3551,9 @@ static int multiSelectOrderBy( p->pPrior = pPrior; pPrior->pNext = p; + sqlite3ExprListDelete(db, pPrior->pOrderBy); + pPrior->pOrderBy = 0; + /*** TBD: Insert subroutine calls to close cursors on incomplete **** subqueries ****/ ExplainQueryPlanPop(pParse); @@ -3517,9 +3608,12 @@ static Expr *substExpr( && pExpr->iTable==pSubst->iTable && !ExprHasProperty(pExpr, EP_FixedCol) ){ +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW if( pExpr->iColumn<0 ){ pExpr->op = TK_NULL; - }else{ + }else +#endif + { Expr *pNew; Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr; Expr ifNullRow; @@ -3539,10 +3633,14 @@ static Expr *substExpr( } testcase( ExprHasProperty(pCopy, EP_Subquery) ); pNew = sqlite3ExprDup(db, pCopy, 0); - if( pNew && pSubst->isLeftJoin ){ + if( db->mallocFailed ){ + sqlite3ExprDelete(db, pNew); + return pExpr; + } + if( pSubst->isLeftJoin ){ ExprSetProperty(pNew, EP_CanBeNull); } - if( pNew && ExprHasProperty(pExpr,EP_FromJoin) ){ + if( ExprHasProperty(pExpr,EP_FromJoin) ){ sqlite3SetJoinExpr(pNew, pExpr->iRightJoinTable); } sqlite3ExprDelete(db, pExpr); @@ -3550,15 +3648,13 @@ static Expr *substExpr( /* Ensure that the expression now has an implicit collation sequence, ** just as it did when it was a column of a view or sub-query. */ - if( pExpr ){ - if( pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE ){ - CollSeq *pColl = sqlite3ExprCollSeq(pSubst->pParse, pExpr); - pExpr = sqlite3ExprAddCollateString(pSubst->pParse, pExpr, - (pColl ? pColl->zName : "BINARY") - ); - } - ExprClearProperty(pExpr, EP_Collate); + if( pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE ){ + CollSeq *pColl = sqlite3ExprCollSeq(pSubst->pParse, pExpr); + pExpr = sqlite3ExprAddCollateString(pSubst->pParse, pExpr, + (pColl ? pColl->zName : "BINARY") + ); } + ExprClearProperty(pExpr, EP_Collate); } } }else{ @@ -3677,7 +3773,10 @@ static void srclistRenumberCursors( for(i=0, pItem=pSrc->a; inSrc; i++, pItem++){ if( i!=iExcept ){ Select *p; - pItem->iCursor = aCsrMap[pItem->iCursor] = pParse->nTab++; + if( !pItem->fg.isRecursive || aCsrMap[pItem->iCursor]==0 ){ + aCsrMap[pItem->iCursor] = pParse->nTab++; + } + pItem->iCursor = aCsrMap[pItem->iCursor]; for(p=pItem->pSelect; p; p=p->pPrior){ srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1); } @@ -4117,7 +4216,7 @@ static int flattenSubquery( p->pPrior = pPrior; }else{ pNew->selId = ++pParse->nSelect; - if( aCsrMap && db->mallocFailed==0 ){ + if( aCsrMap && ALWAYS(db->mallocFailed==0) ){ renumberCursors(pParse, pNew, iFrom, aCsrMap); } pNew->pPrior = pPrior; @@ -4376,7 +4475,7 @@ static void constInsert( */ static void findConstInWhere(WhereConst *pConst, Expr *pExpr){ Expr *pRight, *pLeft; - if( pExpr==0 ) return; + if( NEVER(pExpr==0) ) return; if( ExprHasProperty(pExpr, EP_FromJoin) ) return; if( pExpr->op==TK_AND ){ findConstInWhere(pConst, pExpr->pRight); @@ -4912,6 +5011,7 @@ static struct Cte *searchWith( return &p->a[i]; } } + if( p->bView ) break; } return 0; } @@ -4972,6 +5072,14 @@ static int resolveFromTermToCte( ** it cannot possibly be a CTE reference. */ return 0; } + if( pFrom->fg.notCte ){ + /* The FROM term is specifically excluded from matching a CTE. + ** (1) It is part of a trigger that used to have zDatabase but had + ** zDatabase removed by sqlite3FixTriggerStep(). + ** (2) This is the first term in the FROM clause of an UPDATE. + */ + return 0; + } pCte = searchWith(pParse->pWith, pFrom, &pWith); if( pCte ){ sqlite3 *db = pParse->db; @@ -5120,7 +5228,7 @@ static int resolveFromTermToCte( ** sqlite3SelectExpand() when walking a SELECT tree to resolve table ** names and other FROM clause elements. */ -static void selectPopWith(Walker *pWalker, Select *p){ +void sqlite3SelectPopWith(Walker *pWalker, Select *p){ Parse *pParse = pWalker->pParse; if( OK_IF_ALWAYS_TRUE(pParse->pWith) && p->pPrior==0 ){ With *pWith = findRightmost(p)->pWith; @@ -5130,8 +5238,6 @@ static void selectPopWith(Walker *pWalker, Select *p){ } } } -#else -#define selectPopWith 0 #endif /* @@ -5158,7 +5264,13 @@ int sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){ sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol); pTab->iPKey = -1; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); - pTab->tabFlags |= TF_Ephemeral; +#ifndef SQLITE_ALLOW_ROWID_IN_VIEW + /* The usual case - do not allow ROWID on a subquery */ + pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid; +#else + pTab->tabFlags |= TF_Ephemeral; /* Legacy compatibility mode */ +#endif + return pParse->nErr ? SQLITE_ERROR : SQLITE_OK; } @@ -5212,6 +5324,15 @@ static int selectExpander(Walker *pWalker, Select *p){ } pTabList = p->pSrc; pEList = p->pEList; + if( pParse->pWith && (p->selFlags & SF_View) ){ + if( p->pWith==0 ){ + p->pWith = (With*)sqlite3DbMallocZero(db, sizeof(With)); + if( p->pWith==0 ){ + return WRC_Abort; + } + } + p->pWith->bView = 1; + } sqlite3WithPush(pParse, p->pWith, 0); /* Make sure cursor numbers have been assigned to all entries in @@ -5512,7 +5633,7 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){ sqlite3WalkSelect(&w, pSelect); } w.xSelectCallback = selectExpander; - w.xSelectCallback2 = selectPopWith; + w.xSelectCallback2 = sqlite3SelectPopWith; w.eCode = 0; sqlite3WalkSelect(&w, pSelect); } @@ -5645,8 +5766,10 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){ pFunc->iDistinct = -1; }else{ KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pE->x.pList,0,0); - sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0, - (char*)pKeyInfo, P4_KEYINFO); + pFunc->iDistAddr = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, + pFunc->iDistinct, 0, 0, (char*)pKeyInfo, P4_KEYINFO); + ExplainQueryPlan((pParse, 0, "USE TEMP B-TREE FOR %s(DISTINCT)", + pFunc->pFunc->zName)); } } } @@ -5678,7 +5801,12 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){ ** registers if register regAcc contains 0. The caller will take care ** of setting and clearing regAcc. */ -static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){ +static void updateAccumulator( + Parse *pParse, + int regAcc, + AggInfo *pAggInfo, + int eDistinctType +){ Vdbe *v = pParse->pVdbe; int i; int regHit = 0; @@ -5724,13 +5852,12 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){ nArg = 0; regAgg = 0; } - if( pF->iDistinct>=0 ){ + if( pF->iDistinct>=0 && pList ){ if( addrNext==0 ){ addrNext = sqlite3VdbeMakeLabel(pParse); } - testcase( nArg==0 ); /* Error condition */ - testcase( nArg>1 ); /* Also an error */ - codeDistinct(pParse, pF->iDistinct, addrNext, 1, regAgg); + pF->iDistinct = codeDistinct(pParse, eDistinctType, + pF->iDistinct, addrNext, pList, regAgg); } if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ CollSeq *pColl = 0; @@ -5782,7 +5909,7 @@ static void explainSimpleCount( ){ if( pParse->explain==2 ){ int bCover = (pIdx!=0 && (HasRowid(pTab) || !IsPrimaryKeyIndex(pIdx))); - sqlite3VdbeExplain(pParse, 0, "SCAN TABLE %s%s%s", + sqlite3VdbeExplain(pParse, 0, "SCAN %s%s%s", pTab->zName, bCover ? " USING COVERING INDEX " : "", bCover ? pIdx->zName : "" @@ -6093,12 +6220,11 @@ int sqlite3Select( } if( pDest->eDest==SRT_Output ){ - generateColumnNames(pParse, p); + sqlite3GenerateColumnNames(pParse, p); } #ifndef SQLITE_OMIT_WINDOWFUNC - rc = sqlite3WindowRewrite(pParse, p); - if( rc ){ + if( sqlite3WindowRewrite(pParse, p) ){ assert( db->mallocFailed || pParse->nErr>0 ); goto select_end; } @@ -6224,7 +6350,8 @@ int sqlite3Select( ** as the equivalent optimization will be handled by query planner in ** sqlite3WhereBegin(). */ - if( pTabList->nSrc>1 + if( p->pWhere!=0 + && p->pWhere->op==TK_AND && OptimizationEnabled(db, SQLITE_PropagateConst) && propagateConstants(pParse, p) ){ @@ -6355,10 +6482,10 @@ int sqlite3Select( pItem->regReturn = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); - VdbeComment((v, "%s", pItem->pTab->zName)); + VdbeComment((v, "%!S", pItem)); pItem->addrFillSub = addrTop; sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); - ExplainQueryPlan((pParse, 1, "CO-ROUTINE %u", pSub->selId)); + ExplainQueryPlan((pParse, 1, "CO-ROUTINE %!S", pItem)); sqlite3Select(pParse, pSub, &dest); pItem->pTab->nRowLogEst = pSub->nSelectRow; pItem->fg.viaCoroutine = 1; @@ -6402,17 +6529,17 @@ int sqlite3Select( ** a trigger, then we only need to compute the value of the subquery ** once. */ onceAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); - VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName)); + VdbeComment((v, "materialize %!S", pItem)); }else{ - VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName)); + VdbeNoopComment((v, "materialize %!S", pItem)); } sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); - ExplainQueryPlan((pParse, 1, "MATERIALIZE %u", pSub->selId)); + ExplainQueryPlan((pParse, 1, "MATERIALIZE %!S", pItem)); sqlite3Select(pParse, pSub, &dest); pItem->pTab->nRowLogEst = pSub->nSelectRow; if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr); retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn); - VdbeComment((v, "end %s", pItem->pTab->zName)); + VdbeComment((v, "end %!S", pItem)); sqlite3VdbeChangeP1(v, topAddr, retAddr); sqlite3ClearTempRegCache(pParse); if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){ @@ -6762,6 +6889,20 @@ int sqlite3Select( int addrSortingIdx; /* The OP_OpenEphemeral for the sorting index */ int addrReset; /* Subroutine for resetting the accumulator */ int regReset; /* Return address register for reset subroutine */ + ExprList *pDistinct = 0; + u16 distFlag = 0; + int eDist = WHERE_DISTINCT_NOOP; + + if( pAggInfo->nFunc==1 + && pAggInfo->aFunc[0].iDistinct>=0 + && pAggInfo->aFunc[0].pFExpr->x.pList + ){ + Expr *pExpr = pAggInfo->aFunc[0].pFExpr->x.pList->a[0].pExpr; + pExpr = sqlite3ExprDup(db, pExpr, 0); + pDistinct = sqlite3ExprListDup(db, pGroupBy, 0); + pDistinct = sqlite3ExprListAppend(pParse, pDistinct, pExpr); + distFlag = pDistinct ? (WHERE_WANT_DISTINCT|WHERE_AGG_DISTINCT) : 0; + } /* If there is a GROUP BY clause we might need a sorting index to ** implement it. Allocate that sorting index now. If it turns out @@ -6798,10 +6939,14 @@ int sqlite3Select( */ sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); SELECTTRACE(1,pParse,p,("WhereBegin\n")); - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0, - WHERE_GROUPBY | (orderByGrp ? WHERE_SORTBYGROUP : 0), 0 + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, pDistinct, + WHERE_GROUPBY | (orderByGrp ? WHERE_SORTBYGROUP : 0) | distFlag, 0 ); - if( pWInfo==0 ) goto select_end; + if( pWInfo==0 ){ + sqlite3ExprListDelete(db, pDistinct); + goto select_end; + } + eDist = sqlite3WhereIsDistinct(pWInfo); SELECTTRACE(1,pParse,p,("WhereBegin returns\n")); if( sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){ /* The optimizer is able to deliver rows in group by order so @@ -6919,7 +7064,7 @@ int sqlite3Select( ** the current row */ sqlite3VdbeJumpHere(v, addr1); - updateAccumulator(pParse, iUseFlag, pAggInfo); + updateAccumulator(pParse, iUseFlag, pAggInfo, eDist); sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag); VdbeComment((v, "indicate data in accumulator")); @@ -6933,6 +7078,7 @@ int sqlite3Select( sqlite3WhereEnd(pWInfo); sqlite3VdbeChangeToNoop(v, addrSortingIdx); } + sqlite3ExprListDelete(db, pDistinct); /* Output the final row of result */ @@ -6975,7 +7121,11 @@ int sqlite3Select( sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag); VdbeComment((v, "indicate accumulator empty")); sqlite3VdbeAddOp1(v, OP_Return, regReset); - + + if( eDist!=WHERE_DISTINCT_NOOP ){ + struct AggInfo_func *pF = &pAggInfo->aFunc[0]; + fixDistinctOpenEph(pParse, eDist, pF->iDistinct, pF->iDistAddr); + } } /* endif pGroupBy. Begin aggregate queries without GROUP BY: */ else { Table *pTab; @@ -7039,6 +7189,9 @@ int sqlite3Select( explainSimpleCount(pParse, pTab, pBest); }else{ int regAcc = 0; /* "populate accumulators" flag */ + ExprList *pDistinct = 0; + u16 distFlag = 0; + int eDist; /* If there are accumulator registers but no min() or max() functions ** without FILTER clauses, allocate register regAcc. Register regAcc @@ -7062,6 +7215,9 @@ int sqlite3Select( regAcc = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, regAcc); } + }else if( pAggInfo->nFunc==1 && pAggInfo->aFunc[0].iDistinct>=0 ){ + pDistinct = pAggInfo->aFunc[0].pFExpr->x.pList; + distFlag = pDistinct ? (WHERE_WANT_DISTINCT|WHERE_AGG_DISTINCT) : 0; } /* This case runs if the aggregate has no GROUP BY clause. The @@ -7081,12 +7237,18 @@ int sqlite3Select( SELECTTRACE(1,pParse,p,("WhereBegin\n")); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMaxOrderBy, - 0, minMaxFlag, 0); + pDistinct, minMaxFlag|distFlag, 0); if( pWInfo==0 ){ goto select_end; } SELECTTRACE(1,pParse,p,("WhereBegin returns\n")); - updateAccumulator(pParse, regAcc, pAggInfo); + eDist = sqlite3WhereIsDistinct(pWInfo); + updateAccumulator(pParse, regAcc, pAggInfo, eDist); + if( eDist!=WHERE_DISTINCT_NOOP ){ + struct AggInfo_func *pF = &pAggInfo->aFunc[0]; + fixDistinctOpenEph(pParse, eDist, pF->iDistinct, pF->iDistAddr); + } + if( regAcc ) sqlite3VdbeAddOp2(v, OP_Integer, 1, regAcc); if( minMaxFlag ){ sqlite3WhereMinMaxOptEarlyOut(v, pWInfo); @@ -7131,6 +7293,8 @@ int sqlite3Select( ** successful coding of the SELECT. */ select_end: + assert( db->mallocFailed==0 || db->mallocFailed==1 ); + pParse->nErr += db->mallocFailed; sqlite3ExprListDelete(db, pMinMaxOrderBy); #ifdef SQLITE_DEBUG if( pAggInfo && !db->mallocFailed ){ diff --git a/src/shell.c.in b/src/shell.c.in index 2ec454ffbf..462cd717ba 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -2915,7 +2915,7 @@ static void bind_table_init(ShellState *p){ sqlite3_exec(p->db, "CREATE TABLE IF NOT EXISTS temp.sqlite_parameters(\n" " key TEXT PRIMARY KEY,\n" - " value ANY\n" + " value\n" ") WITHOUT ROWID;", 0, 0, 0); sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, wrSchema, 0); @@ -3978,8 +3978,8 @@ static const char *(azHelp[]) = { ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE", " Options:", " --append Use appendvfs to append database to the end of FILE", -#ifdef SQLITE_ENABLE_DESERIALIZE - " --deserialize Load into memory useing sqlite3_deserialize()", +#ifndef SQLITE_OMIT_DESERIALIZE + " --deserialize Load into memory using sqlite3_deserialize()", " --hexdb Load the output of \"dbtotxt\" as an in-memory db", " --maxsize N Maximum size for --hexdb or --deserialized database", #endif @@ -4300,7 +4300,7 @@ int deduceDatabaseType(const char *zName, int dfltZip){ return rc; } -#ifdef SQLITE_ENABLE_DESERIALIZE +#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 @@ -4389,7 +4389,7 @@ readHexDb_error: utf8_printf(stderr,"Error on line %d of --hexdb input\n", nLine); return 0; } -#endif /* SQLITE_ENABLE_DESERIALIZE */ +#endif /* SQLITE_OMIT_DESERIALIZE */ /* ** Scalar function "shell_int32". The first argument to this function @@ -4650,7 +4650,7 @@ static void open_db(ShellState *p, int openFlags){ sqlite3_exec(p->db, zSql, 0, 0, 0); sqlite3_free(zSql); } -#ifdef SQLITE_ENABLE_DESERIALIZE +#ifndef SQLITE_OMIT_DESERIALIZE else if( p->openMode==SHELL_OPEN_DESERIALIZE || p->openMode==SHELL_OPEN_HEXDB ){ int rc; @@ -5779,7 +5779,7 @@ static int lintFkeyIndexes( " || fkey_collate_clause(" " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]),' AND ')" ", " - " 'SEARCH TABLE ' || s.name || ' USING COVERING INDEX*('" + " 'SEARCH ' || s.name || ' USING COVERING INDEX*('" " || group_concat('*=?', ' AND ') || ')'" ", " " s.name || '(' || group_concat(f.[from], ', ') || ')'" @@ -5799,7 +5799,7 @@ static int lintFkeyIndexes( "GROUP BY s.name, f.id " "ORDER BY (CASE WHEN ? THEN f.[table] ELSE s.name END)" ; - const char *zGlobIPK = "SEARCH TABLE * USING INTEGER PRIMARY KEY (rowid=?)"; + const char *zGlobIPK = "SEARCH * USING INTEGER PRIMARY KEY (rowid=?)"; for(i=2; iout, "ANALYZE sqlite_schema;\n"); sqlite3_exec(p->db, "SELECT 'ANALYZE sqlite_schema'", - callback, &data, &zErrMsg); + callback, &data, 0); data.cMode = data.mode = MODE_Insert; data.zDestTable = "sqlite_stat1"; - shell_exec(&data, "SELECT * FROM sqlite_stat1", &zErrMsg); + shell_exec(&data, "SELECT * FROM sqlite_stat1", 0); data.zDestTable = "sqlite_stat4"; - shell_exec(&data, "SELECT * FROM sqlite_stat4", &zErrMsg); + shell_exec(&data, "SELECT * FROM sqlite_stat4", 0); raw_printf(p->out, "ANALYZE sqlite_schema;\n"); } }else @@ -8712,14 +8712,14 @@ static int do_meta_command(char *zLine, ShellState *p){ p->openMode = SHELL_OPEN_READONLY; }else if( optionMatch(z, "nofollow") ){ p->openFlags |= SQLITE_OPEN_NOFOLLOW; -#ifdef SQLITE_ENABLE_DESERIALIZE +#ifndef SQLITE_OMIT_DESERIALIZE }else if( optionMatch(z, "deserialize") ){ p->openMode = SHELL_OPEN_DESERIALIZE; }else if( optionMatch(z, "hexdb") ){ p->openMode = SHELL_OPEN_HEXDB; }else if( optionMatch(z, "maxsize") && iName+1szMax = integerValue(azArg[++iName]); -#endif /* SQLITE_ENABLE_DESERIALIZE */ +#endif /* SQLITE_OMIT_DESERIALIZE */ }else if( z[0]=='-' ){ utf8_printf(stderr, "unknown option: %s\n", z); rc = 1; @@ -10703,7 +10703,7 @@ static const char zOptions[] = " -column set output mode to 'column'\n" " -cmd COMMAND run \"COMMAND\" before reading stdin\n" " -csv set output mode to 'csv'\n" -#if defined(SQLITE_ENABLE_DESERIALIZE) +#if !defined(SQLITE_OMIT_DESERIALIZE) " -deserialize open the database using sqlite3_deserialize()\n" #endif " -echo print commands before execution\n" @@ -10720,7 +10720,7 @@ static const char zOptions[] = " -list set output mode to 'list'\n" " -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n" " -markdown set output mode to 'markdown'\n" -#if defined(SQLITE_ENABLE_DESERIALIZE) +#if !defined(SQLITE_OMIT_DESERIALIZE) " -maxsize N maximum size for a --deserialize database\n" #endif " -memtrace trace all memory allocations and deallocations\n" @@ -11050,7 +11050,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ #endif }else if( strcmp(z,"-append")==0 ){ data.openMode = SHELL_OPEN_APPENDVFS; -#ifdef SQLITE_ENABLE_DESERIALIZE +#ifndef SQLITE_OMIT_DESERIALIZE }else if( strcmp(z,"-deserialize")==0 ){ data.openMode = SHELL_OPEN_DESERIALIZE; }else if( strcmp(z,"-maxsize")==0 && i+1 +** +**
  • [[SQLITE_FCNTL_EXTERNAL_READER]] +** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect +** whether or not there is a database client in another process with a wal-mode +** transaction open on the database or not. It is only available on unix.The +** (void*) argument passed with this file-control should be a pointer to a +** value of type (int). The integer value is set to 1 if the database is a wal +** mode database and there exists at least one client in another process that +** currently has an SQL transaction open on the database. It is set to 0 if +** the database is not a wal-mode db, or if there is no such connection in any +** other process. This opcode cannot be used to detect transactions opened +** by clients within the current process, only within other processes. +** +** +**
  • [[SQLITE_FCNTL_CKSM_FILE]] +** Used by the cksmvfs VFS module only. +** */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_FCNTL_GET_LOCKPROXYFILE 2 @@ -1167,6 +1184,8 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_CKPT_DONE 37 #define SQLITE_FCNTL_RESERVE_BYTES 38 #define SQLITE_FCNTL_CKPT_START 39 +#define SQLITE_FCNTL_EXTERNAL_READER 40 +#define SQLITE_FCNTL_CKSM_FILE 41 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE @@ -4179,6 +4198,15 @@ const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt); ** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and ** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so ** sqlite3_stmt_readonly() returns false for those commands. +** +** ^This routine returns false if there is any possibility that the +** statement might change the database file. ^A false return does +** not guarantee that the statement will change the database file. +** ^For example, an UPDATE statement might have a WHERE clause that +** makes it a no-op, but the sqlite3_stmt_readonly() result would still +** be false. ^Similarly, a CREATE TABLE IF NOT EXISTS statement is a +** read-only no-op if the table already exists, but +** sqlite3_stmt_readonly() still returns false for such a statement. */ int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); @@ -4348,18 +4376,22 @@ typedef struct sqlite3_context sqlite3_context; ** contain embedded NULs. The result of expressions involving strings ** with embedded NULs is undefined. ** -** ^The fifth argument to the BLOB and string binding interfaces -** is a destructor used to dispose of the BLOB or -** string after SQLite has finished with it. ^The destructor is called -** to dispose of the BLOB or string even if the call to the bind API fails, -** except the destructor is not called if the third parameter is a NULL -** pointer or the fourth parameter is negative. -** ^If the fifth argument is -** the special value [SQLITE_STATIC], then SQLite assumes that the -** information is in static, unmanaged space and does not need to be freed. -** ^If the fifth argument has the value [SQLITE_TRANSIENT], then -** SQLite makes its own private copy of the data immediately, before -** the sqlite3_bind_*() routine returns. +** ^The fifth argument to the BLOB and string binding interfaces controls +** or indicates the lifetime of the object referenced by the third parameter. +** ^These three options exist: +** ^(1) A destructor to dispose of the BLOB or string after SQLite has finished +** with it may be passed. ^It is called to dispose of the BLOB or string even +** if the call to the bind API fails, except the destructor is not called if +** the third parameter is a NULL pointer or the fourth parameter is negative. +** ^(2) The special constant, [SQLITE_STATIC], may be passsed to indicate that +** the application remains responsible for disposing of the object. ^In this +** case, the object and the provided pointer to it must remain valid until +** either the prepared statement is finalized or the same SQL parameter is +** bound to something else, whichever occurs sooner. +** ^(3) The constant, [SQLITE_TRANSIENT], may be passed to indicate that the +** object is to be copied prior to the return from sqlite3_bind_*(). ^The +** object and pointer to it must remain valid until then. ^SQLite will then +** manage the lifetime of its private copy. ** ** ^The sixth argument to sqlite3_bind_text64() must be one of ** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE] @@ -9531,6 +9563,15 @@ int sqlite3_db_cacheflush(sqlite3*); ** triggers; or 2 for changes resulting from triggers called by top-level ** triggers; and so forth. ** +** When the [sqlite3_blob_write()] API is used to update a blob column, +** the pre-update hook is invoked with SQLITE_DELETE. This is because the +** in this case the new values are not available. In this case, when a +** callback made with op==SQLITE_DELETE is actuall a write using the +** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns +** the index of the column being written. In other cases, where the +** pre-update hook is being invoked for some other reason, including a +** regular DELETE, sqlite3_preupdate_blobwrite() returns -1. +** ** See also: [sqlite3_update_hook()] */ #if defined(SQLITE_ENABLE_PREUPDATE_HOOK) @@ -9551,6 +9592,7 @@ int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **); int sqlite3_preupdate_count(sqlite3 *); int sqlite3_preupdate_depth(sqlite3 *); int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **); +int sqlite3_preupdate_blobwrite(sqlite3 *); #endif /* @@ -9814,8 +9856,8 @@ SQLITE_EXPERIMENTAL int sqlite3_wal_info( ** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory ** allocation error occurs. ** -** This interface is only available if SQLite is compiled with the -** [SQLITE_ENABLE_DESERIALIZE] option. +** This interface is omitted if SQLite is compiled with the +** [SQLITE_OMIT_DESERIALIZE] option. */ unsigned char *sqlite3_serialize( sqlite3 *db, /* The database connection */ @@ -9866,8 +9908,8 @@ unsigned char *sqlite3_serialize( ** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then ** [sqlite3_free()] is invoked on argument P prior to returning. ** -** This interface is only available if SQLite is compiled with the -** [SQLITE_ENABLE_DESERIALIZE] option. +** This interface is omitted if SQLite is compiled with the +** [SQLITE_OMIT_DESERIALIZE] option. */ int sqlite3_deserialize( sqlite3 *db, /* The database connection */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 3f662fe683..7bc9a7f6c3 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1544,10 +1544,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 */ - unsigned bDropColumn : 1; /* Doing schema check after DROP COLUMN */ char **azInit; /* "type", "name", and "tbl_name" columns */ - /* or if bDropColumn, then azInit[0] is the */ - /* name of the column being dropped */ } init; int nVdbeActive; /* Number of VDBEs currently running */ int nVdbeRead; /* Number of active VDBEs that read or write */ @@ -1753,7 +1750,6 @@ struct sqlite3 { #define SQLITE_SkipScan 0x00004000 /* Skip-scans */ #define SQLITE_PropagateConst 0x00008000 /* The constant propagation opt */ #define SQLITE_MinMaxOpt 0x00010000 /* The min/max optimization */ -#define SQLITE_ExistsToIN 0x00020000 /* The EXISTS-to-IN optimization */ #define SQLITE_AllOpts 0xffffffff /* All optimizations */ /* @@ -2126,9 +2122,7 @@ struct CollSeq { ** operator is NULL. It is added to certain comparison operators to ** prove that the operands are always NOT NULL. */ -#define SQLITE_KEEPNULL 0x08 /* Used by vector == or <> */ #define SQLITE_JUMPIFNULL 0x10 /* jumps if either operand is NULL */ -#define SQLITE_STOREP2 0x20 /* Store result in reg[P2] rather than jump */ #define SQLITE_NULLEQ 0x80 /* NULL=NULL */ #define SQLITE_NOTNULL 0x90 /* Assert that operands are never NULL */ @@ -2260,6 +2254,7 @@ struct Table { #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 */ /* ** Test to see whether or not a table is a virtual table. This is @@ -2625,6 +2620,7 @@ struct AggInfo { FuncDef *pFunc; /* The aggregate function implementation */ int iMem; /* Memory location that acts as accumulator */ int iDistinct; /* Ephemeral table used to enforce DISTINCT */ + int iDistAddr; /* Address of OP_OpenEphemeral */ } *aFunc; int nFunc; /* Number of entries in aFunc[] */ u32 selId; /* Select to which this AggInfo belongs */ @@ -2897,6 +2893,7 @@ struct Expr { */ struct ExprList { int nExpr; /* Number of expressions on the list */ + int nAlloc; /* Number of a[] slots allocated */ struct ExprList_item { /* For each expression in the list */ Expr *pExpr; /* The parse tree for this expression */ char *zEName; /* Token associated with this expression */ @@ -2970,6 +2967,7 @@ struct SrcItem { unsigned isRecursive :1; /* True for recursive reference in WITH */ unsigned fromDDL :1; /* Comes from sqlite_schema */ unsigned isCte :1; /* This is a CTE */ + unsigned notCte :1; /* This item may not match a CTE */ } fg; int iCursor; /* The VDBE cursor number used to access this table */ Expr *pOn; /* The ON clause of a join */ @@ -3041,7 +3039,7 @@ struct SrcList { #define WHERE_DISTINCTBY 0x0080 /* pOrderby is really a DISTINCT clause */ #define WHERE_WANT_DISTINCT 0x0100 /* All output needs to be distinct */ #define WHERE_SORTBYGROUP 0x0200 /* Support sqlite3WhereIsSorted() */ - /* 0x0400 not currently used */ +#define WHERE_AGG_DISTINCT 0x0400 /* Query is "SELECT agg(DISTINCT ...)" */ #define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */ /* 0x1000 not currently used */ /* 0x2000 not currently used */ @@ -3087,7 +3085,7 @@ struct NameContext { } uNC; NameContext *pNext; /* Next outer name context. NULL for outermost */ int nRef; /* Number of names resolved by this context */ - int nErr; /* Number of errors encountered while resolving names */ + int nNcErr; /* Number of errors encountered while resolving names */ int ncFlags; /* Zero or more NC_* flags defined below */ Select *pWinSelect; /* SELECT statement for any window functions */ }; @@ -3120,6 +3118,7 @@ struct NameContext { #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 */ /* ** An instance of the following object describes a single ON CONFLICT @@ -3814,7 +3813,7 @@ struct Sqlite3Config { void (*xVdbeBranch)(void*,unsigned iSrcLine,u8 eThis,u8 eMx); /* Callback */ void *pVdbeBranchArg; /* 1st argument */ #endif -#ifdef SQLITE_ENABLE_DESERIALIZE +#ifndef SQLITE_OMIT_DESERIALIZE sqlite3_int64 mxMemdbSize; /* Default max memdb size */ #endif #ifndef SQLITE_UNTESTABLE @@ -3901,11 +3900,18 @@ int sqlite3SelectWalkNoop(Walker*, Select*); int sqlite3SelectWalkFail(Walker*, Select*); int sqlite3WalkerDepthIncrease(Walker*,Select*); void sqlite3WalkerDepthDecrease(Walker*,Select*); +void sqlite3WalkWinDefnDummyCallback(Walker*,Select*); #ifdef SQLITE_DEBUG void sqlite3SelectWalkAssert2(Walker*, Select*); #endif +#ifndef SQLITE_OMIT_CTE +void sqlite3SelectPopWith(Walker*, Select*); +#else +# define sqlite3SelectPopWith 0 +#endif + /* ** Return code from the parse-tree walking primitives and their ** callbacks. @@ -3939,6 +3945,7 @@ struct Cte { */ struct With { int nCte; /* Number of CTEs in the WITH clause */ + int bView; /* Belongs to the outermost Select of a view */ With *pOuter; /* Containing WITH clause, or NULL */ Cte a[1]; /* For each CTE in the WITH clause.... */ }; @@ -4309,6 +4316,7 @@ Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*, int); void sqlite3ExprFunctionUsable(Parse*,Expr*,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*); @@ -4330,6 +4338,7 @@ void sqlite3ResetOneSchema(sqlite3*,int); void sqlite3CollapseDatabaseArray(sqlite3*); void sqlite3CommitInternalChanges(sqlite3*); void sqlite3DeleteColumnNames(sqlite3*,Table*); +void sqlite3GenerateColumnNames(Parse *pParse, Select *pSelect); int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**); void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*,char); Table *sqlite3ResultSetOfSelect(Parse*,Select*,char); @@ -4710,7 +4719,7 @@ int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); const char *sqlite3ErrName(int); #endif -#ifdef SQLITE_ENABLE_DESERIALIZE +#ifndef SQLITE_OMIT_DESERIALIZE int sqlite3MemdbInit(void); #endif @@ -4761,6 +4770,9 @@ void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8); extern const unsigned char sqlite3OpcodeProperty[]; extern const char sqlite3StrBINARY[]; extern const unsigned char sqlite3UpperToLower[]; +extern const unsigned char *sqlite3aLTb; +extern const unsigned char *sqlite3aEQb; +extern const unsigned char *sqlite3aGTb; extern const unsigned char sqlite3CtypeMap[]; extern SQLITE_WSD struct Sqlite3Config sqlite3Config; extern FuncDefHash sqlite3BuiltinFunctions; diff --git a/src/tclsqlite.c b/src/tclsqlite.c index d80c25251c..2206bca321 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -2600,7 +2600,7 @@ static int SQLITE_TCLAPI DbObjCmd( ** Reopen DATABASE (default "main") using the content in $VALUE */ case DB_DESERIALIZE: { -#ifndef SQLITE_ENABLE_DESERIALIZE +#ifdef SQLITE_OMIT_DESERIALIZE Tcl_AppendResult(interp, "MEMDB not available in this build", (char*)0); rc = TCL_ERROR; @@ -3167,7 +3167,7 @@ deserialize_error: ** Return a serialization of a database. */ case DB_SERIALIZE: { -#ifndef SQLITE_ENABLE_DESERIALIZE +#ifdef SQLITE_OMIT_DESERIALIZE Tcl_AppendResult(interp, "MEMDB not available in this build", (char*)0); rc = TCL_ERROR; diff --git a/src/test1.c b/src/test1.c index 99bfecb0f8..22dfec9896 100644 --- a/src/test1.c +++ b/src/test1.c @@ -3825,9 +3825,11 @@ static int SQLITE_TCLAPI test_bind_text( ){ sqlite3_stmt *pStmt; int idx; + int trueLength = 0; int bytes; char *value; int rc; + char *toFree = 0; if( objc!=5 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", @@ -3837,13 +3839,23 @@ static int SQLITE_TCLAPI test_bind_text( if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; - value = (char*)Tcl_GetByteArrayFromObj(objv[3], &bytes); + value = (char*)Tcl_GetByteArrayFromObj(objv[3], &trueLength); if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; - + if( bytes<0 ){ + toFree = malloc( trueLength + 1 ); + if( toFree==0 ){ + Tcl_AppendResult(interp, "out of memory", (void*)0); + return TCL_ERROR; + } + memcpy(toFree, value, trueLength); + toFree[trueLength] = 0; + value = toFree; + } rc = sqlite3_bind_text(pStmt, idx, value, bytes, SQLITE_TRANSIENT); + free(toFree); if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; if( rc!=SQLITE_OK ){ - Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); + Tcl_AppendResult(interp, sqlite3ErrName(rc), (void*)0); return TCL_ERROR; } @@ -3869,7 +3881,9 @@ static int SQLITE_TCLAPI test_bind_text16( int idx; int bytes; char *value; + char *toFree = 0; int rc; + int trueLength = 0; void (*xDel)(void*) = (objc==6?SQLITE_STATIC:SQLITE_TRANSIENT); Tcl_Obj *oStmt = objv[objc-4]; @@ -3885,10 +3899,20 @@ static int SQLITE_TCLAPI test_bind_text16( if( getStmtPointer(interp, Tcl_GetString(oStmt), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, oN, &idx) ) return TCL_ERROR; - value = (char*)Tcl_GetByteArrayFromObj(oString, 0); + value = (char*)Tcl_GetByteArrayFromObj(oString, &trueLength); if( Tcl_GetIntFromObj(interp, oBytes, &bytes) ) return TCL_ERROR; - + if( bytes<0 && xDel==SQLITE_TRANSIENT ){ + toFree = malloc( trueLength + 3 ); + if( toFree==0 ){ + Tcl_AppendResult(interp, "out of memory", (void*)0); + return TCL_ERROR; + } + memcpy(toFree, value, trueLength); + memset(toFree+trueLength, 0, 3); + value = toFree; + } rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, xDel); + free(toFree); if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); @@ -6490,6 +6514,42 @@ static int SQLITE_TCLAPI file_control_tempfilename( return TCL_OK; } +/* +** tclcmd: file_control_external_reader DB ?AUXDB? +** +** Return a string that is a temporary filename +*/ +static int SQLITE_TCLAPI file_control_external_reader( + ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3 *db; + const char *zName = "main"; + int iRes = 0; + int rc = SQLITE_OK; + + if( objc!=2 && objc!=3 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", + Tcl_GetStringFromObj(objv[0], 0), " DB ?AUXDB?", 0); + return TCL_ERROR; + } + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ + return TCL_ERROR; + } + if( objc==3 ){ + zName = Tcl_GetString(objv[2]); + } + rc = sqlite3_file_control(db, zName, SQLITE_FCNTL_EXTERNAL_READER, &iRes); + if( rc!=SQLITE_OK ){ + Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); + return TCL_ERROR; + } + Tcl_SetObjResult(interp, Tcl_NewIntObj(iRes)); + return TCL_OK; +} + /* ** tclcmd: sqlite3_vfs_list @@ -8463,6 +8523,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "file_control_vfsname", file_control_vfsname, 0 }, { "file_control_reservebytes", file_control_reservebytes, 0 }, { "file_control_tempfilename", file_control_tempfilename, 0 }, + { "file_control_external_reader", file_control_external_reader, 0 }, { "sqlite3_vfs_list", vfs_list, 0 }, { "sqlite3_create_function_v2", test_create_function_v2, 0 }, diff --git a/src/test8.c b/src/test8.c index f984c2e5f2..7a532346ed 100644 --- a/src/test8.c +++ b/src/test8.c @@ -389,6 +389,7 @@ static int echoDestructor(sqlite3_vtab *pVtab){ typedef struct EchoModule EchoModule; struct EchoModule { Tcl_Interp *interp; + sqlite3 *db; }; /* @@ -1352,6 +1353,9 @@ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); extern const char *sqlite3ErrName(int); static void moduleDestroy(void *p){ + EchoModule *pMod = (EchoModule*)p; + sqlite3_create_function(pMod->db, "function_that_does_not_exist_0982ma98", + SQLITE_ANY, 1, 0, 0, 0, 0); sqlite3_free(p); } @@ -1376,6 +1380,7 @@ static int SQLITE_TCLAPI register_echo_module( /* Virtual table module "echo" */ pMod = sqlite3_malloc(sizeof(EchoModule)); pMod->interp = interp; + pMod->db = db; rc = sqlite3_create_module_v2( db, "echo", &echoModule, (void*)pMod, moduleDestroy ); @@ -1384,6 +1389,7 @@ static int SQLITE_TCLAPI register_echo_module( if( rc==SQLITE_OK ){ pMod = sqlite3_malloc(sizeof(EchoModule)); pMod->interp = interp; + pMod->db = db; rc = sqlite3_create_module_v2(db, "echo_v2", &echoModuleV2, (void*)pMod, moduleDestroy ); diff --git a/src/test_config.c b/src/test_config.c index de7ea9bb91..74484b6562 100644 --- a/src/test_config.c +++ b/src/test_config.c @@ -65,6 +65,13 @@ static void set_options(Tcl_Interp *interp){ Tcl_SetVar2(interp, "sqlite_options","casesensitivelike","0",TCL_GLOBAL_ONLY); #endif +#ifdef CONFIG_SLOWDOWN_FACTOR + Tcl_SetVar2(interp, "sqlite_options","configslower", + STRINGVALUE(CONFIG_SLOWDOWN_FACTOR),TCL_GLOBAL_ONLY); +#else + Tcl_SetVar2(interp, "sqlite_options","configslower","1.0",TCL_GLOBAL_ONLY); +#endif + #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT Tcl_SetVar2(interp, "sqlite_options", "curdir", "1", TCL_GLOBAL_ONLY); #else @@ -148,7 +155,7 @@ static void set_options(Tcl_Interp *interp){ Tcl_SetVar2(interp, "sqlite_options", "hiddencolumns", "0", TCL_GLOBAL_ONLY); #endif -#ifdef SQLITE_ENABLE_DESERIALIZE +#ifndef SQLITE_OMIT_DESERIALIZE Tcl_SetVar2(interp, "sqlite_options", "deserialize", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "deserialize", "0", TCL_GLOBAL_ONLY); @@ -226,6 +233,12 @@ static void set_options(Tcl_Interp *interp){ Tcl_SetVar2(interp, "sqlite_options", "atomicwrite", "0", TCL_GLOBAL_ONLY); #endif +#ifdef SQLITE_ENABLE_GEOPOLY + Tcl_SetVar2(interp, "sqlite_options", "geopoly", "1", TCL_GLOBAL_ONLY); +#else + Tcl_SetVar2(interp, "sqlite_options", "geopoly", "0", TCL_GLOBAL_ONLY); +#endif + #ifdef SQLITE_ENABLE_JSON1 Tcl_SetVar2(interp, "sqlite_options", "json1", "1", TCL_GLOBAL_ONLY); #else diff --git a/src/tokenize.c b/src/tokenize.c index 5e01de2b90..5d250e6f6a 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -56,6 +56,7 @@ #define CC_ID 27 /* unicode characters usable in IDs */ #define CC_ILLEGAL 28 /* Illegal character */ #define CC_NUL 29 /* 0x00 */ +#define CC_BOM 30 /* First byte of UTF8 BOM: 0xEF 0xBB 0xBF */ static const unsigned char aiClass[] = { #ifdef SQLITE_ASCII @@ -68,14 +69,14 @@ static const unsigned char aiClass[] = { /* 5x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 9, 28, 28, 28, 2, /* 6x */ 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 28, 10, 28, 25, 28, -/* 8x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -/* 9x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -/* Ax */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -/* Bx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -/* Cx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -/* Dx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -/* Ex */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -/* Fx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 +/* 8x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +/* 9x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +/* Ax */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +/* Bx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +/* Cx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +/* Dx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +/* Ex */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 30, +/* Fx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27 #endif #ifdef SQLITE_EBCDIC /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */ @@ -535,6 +536,14 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){ i = 1; break; } + case CC_BOM: { + if( z[1]==0xbb && z[2]==0xbf ){ + *tokenType = TK_SPACE; + return 3; + } + i = 1; + break; + } case CC_NUL: { *tokenType = TK_ILLEGAL; return 0; diff --git a/src/treeview.c b/src/treeview.c index b696d764e0..12a6b21a87 100644 --- a/src/treeview.c +++ b/src/treeview.c @@ -134,19 +134,12 @@ void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){ StrAccum x; char zLine[100]; sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); - sqlite3_str_appendf(&x, "{%d:*}", pItem->iCursor); - if( pItem->zDatabase ){ - sqlite3_str_appendf(&x, " %s.%s", pItem->zDatabase, pItem->zName); - }else if( pItem->zName ){ - sqlite3_str_appendf(&x, " %s", pItem->zName); - } + x.printfFlags |= SQLITE_PRINTF_INTERNAL; + sqlite3_str_appendf(&x, "{%d:*} %!S", pItem->iCursor, pItem); if( pItem->pTab ){ sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx", pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab, pItem->colUsed); } - if( pItem->zAlias ){ - sqlite3_str_appendf(&x, " (AS %s)", pItem->zAlias); - } if( pItem->fg.jointype & JT_LEFT ){ sqlite3_str_appendf(&x, " LEFT-JOIN"); } diff --git a/src/trigger.c b/src/trigger.c index 689c7c741e..90e6ef4a72 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -57,29 +57,41 @@ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){ } pTmpSchema = pParse->db->aDb[1].pSchema; p = sqliteHashFirst(&pTmpSchema->trigHash); - if( p==0 ){ - return pTab->pTrigger; - } pList = pTab->pTrigger; - if( pTmpSchema!=pTab->pSchema ){ - while( p ){ - Trigger *pTrig = (Trigger *)sqliteHashData(p); - if( pTrig->pTabSchema==pTab->pSchema - && 0==sqlite3StrICmp(pTrig->table, pTab->zName) - ){ - pTrig->pNext = pList; - pList = pTrig; - }else if( pTrig->op==TK_RETURNING ){ - assert( pParse->bReturning ); - assert( &(pParse->u1.pReturning->retTrig) == pTrig ); - pTrig->table = pTab->zName; - pTrig->pTabSchema = pTab->pSchema; - pTrig->pNext = pList; - pList = pTrig; - } - p = sqliteHashNext(p); - } + while( p ){ + Trigger *pTrig = (Trigger *)sqliteHashData(p); + if( pTrig->pTabSchema==pTab->pSchema + && pTrig->table + && 0==sqlite3StrICmp(pTrig->table, pTab->zName) + && pTrig->pTabSchema!=pTmpSchema + ){ + pTrig->pNext = pList; + pList = pTrig; + }else if( pTrig->op==TK_RETURNING +#ifndef SQLITE_OMIT_VIRTUALTABLE + && pParse->db->pVtabCtx==0 +#endif + ){ + assert( pParse->bReturning ); + assert( &(pParse->u1.pReturning->retTrig) == pTrig ); + pTrig->table = pTab->zName; + pTrig->pTabSchema = pTab->pSchema; + pTrig->pNext = pList; + pList = pTrig; + } + p = sqliteHashNext(p); } +#if 0 + if( pList ){ + Trigger *pX; + printf("Triggers for %s:", pTab->zName); + for(pX=pList; pX; pX=pX->pNext){ + printf(" %s", pX->zName); + } + printf("\n"); + fflush(stdout); + } +#endif return pList; } @@ -209,12 +221,12 @@ void sqlite3BeginTrigger( */ if( pTab->pSelect && tr_tm!=TK_INSTEAD ){ sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S", - (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0); + (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName->a); goto trigger_orphan_error; } if( !pTab->pSelect && tr_tm==TK_INSTEAD ){ sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF" - " trigger on table: %S", pTableName, 0); + " trigger on table: %S", pTableName->a); goto trigger_orphan_error; } @@ -611,7 +623,7 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){ } if( !pTrigger ){ if( !noErr ){ - sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0); + sqlite3ErrorMsg(pParse, "no such trigger: %S", pName->a); }else{ sqlite3CodeVerifyNamedSchema(pParse, zDb); } @@ -823,6 +835,25 @@ SrcList *sqlite3TriggerStepSrc( return pSrc; } +/* +** Return true if the pExpr term from the RETURNING clause argument +** list is of the form "*". Raise an error if the terms if of the +** form "table.*". +*/ +static int isAsteriskTerm( + Parse *pParse, /* Parsing context */ + Expr *pTerm /* A term in the RETURNING clause */ +){ + assert( pTerm!=0 ); + if( pTerm->op==TK_ASTERISK ) return 1; + if( pTerm->op!=TK_DOT ) return 0; + assert( pTerm->pRight!=0 ); + assert( pTerm->pLeft!=0 ); + if( pTerm->pRight->op!=TK_ASTERISK ) return 0; + sqlite3ErrorMsg(pParse, "RETURNING may not use \"TABLE.*\" wildcards"); + return 1; +} + /* The input list pList is the list of result set terms from a RETURNING ** clause. The table that we are returning from is pTab. ** @@ -840,7 +871,8 @@ static ExprList *sqlite3ExpandReturning( for(i=0; inExpr; i++){ Expr *pOldExpr = pList->a[i].pExpr; - if( ALWAYS(pOldExpr!=0) && pOldExpr->op==TK_ASTERISK ){ + if( NEVER(pOldExpr==0) ) continue; + if( isAsteriskTerm(pParse, pOldExpr) ){ int jj; for(jj=0; jjnCol; jj++){ Expr *pNewExpr; @@ -863,15 +895,6 @@ static ExprList *sqlite3ExpandReturning( } } } - if( !db->mallocFailed ){ - Vdbe *v = pParse->pVdbe; - assert( v!=0 ); - sqlite3VdbeSetNumCols(v, pNew->nExpr); - for(i=0; inExpr; i++){ - sqlite3VdbeSetColName(v, i, COLNAME_NAME, pNew->a[i].zEName, - SQLITE_TRANSIENT); - } - } return pNew; } @@ -887,13 +910,27 @@ static void codeReturningTrigger( int regIn /* The first in an array of registers */ ){ Vdbe *v = pParse->pVdbe; + sqlite3 *db = pParse->db; ExprList *pNew; Returning *pReturning; + Select sSelect; + SrcList sFrom; assert( v!=0 ); assert( pParse->bReturning ); pReturning = pParse->u1.pReturning; assert( pTrigger == &(pReturning->retTrig) ); + memset(&sSelect, 0, sizeof(sSelect)); + memset(&sFrom, 0, sizeof(sFrom)); + sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0); + sSelect.pSrc = &sFrom; + sFrom.nSrc = 1; + sFrom.a[0].pTab = pTab; + 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 ){ NameContext sNC; @@ -914,13 +951,14 @@ static void codeReturningTrigger( pParse->nMem += nCol+2; pReturning->iRetReg = reg; for(i=0; ia[i].pExpr, reg+i); + Expr *pCol = pNew->a[i].pExpr; + 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(pParse->db, pNew); + sqlite3ExprListDelete(db, pNew); pParse->eTriggerOp = 0; pParse->pTriggerTab = 0; } @@ -1123,8 +1161,8 @@ static TriggerPrg *codeRowTrigger( ** OP_Halt inserted at the end of the program. */ if( pTrigger->pWhen ){ pWhen = sqlite3ExprDup(db, pTrigger->pWhen, 0); - if( SQLITE_OK==sqlite3ResolveExprNames(&sNC, pWhen) - && db->mallocFailed==0 + if( db->mallocFailed==0 + && SQLITE_OK==sqlite3ResolveExprNames(&sNC, pWhen) ){ iEndTrigger = sqlite3VdbeMakeLabel(pSubParse); sqlite3ExprIfFalse(pSubParse, pWhen, iEndTrigger, SQLITE_JUMPIFNULL); diff --git a/src/update.c b/src/update.c index 8c37456948..15ebb77179 100644 --- a/src/update.c +++ b/src/update.c @@ -220,6 +220,7 @@ static void updateFromSelect( assert( pTabList->nSrc>1 ); if( pSrc ){ + pSrc->a[0].fg.notCte = 1; pSrc->a[0].iCursor = -1; pSrc->a[0].pTab->nTabRef--; pSrc->a[0].pTab = 0; @@ -249,7 +250,8 @@ static void updateFromSelect( } #endif } - if( ALWAYS(pChanges) ){ + assert( pChanges!=0 || pParse->db->mallocFailed ); + if( pChanges ){ for(i=0; inExpr; i++){ pList = sqlite3ExprListAppend(pParse, pList, sqlite3ExprDup(db, pChanges->a[i].pExpr, 0) @@ -810,7 +812,12 @@ void sqlite3Update( /* Top of the update loop */ if( eOnePass!=ONEPASS_OFF ){ - if( !isView && aiCurOnePass[0]!=iDataCur && aiCurOnePass[1]!=iDataCur ){ + if( aiCurOnePass[0]!=iDataCur + && aiCurOnePass[1]!=iDataCur +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + && !isView +#endif + ){ assert( pPk ); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey,nKey); VdbeCoverage(v); diff --git a/src/vdbe.c b/src/vdbe.c index 8a8d8854e0..a212734507 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -275,18 +275,36 @@ static VdbeCursor *allocateCursor( sqlite3VdbeFreeCursor(p, p->apCsr[iCur]); p->apCsr[iCur] = 0; } - if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){ - p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z; - memset(pCx, 0, offsetof(VdbeCursor,pAltCursor)); - pCx->eCurType = eCurType; - pCx->iDb = iDb; - pCx->nField = nField; - pCx->aOffset = &pCx->aType[nField]; - if( eCurType==CURTYPE_BTREE ){ - pCx->uc.pCursor = (BtCursor*) - &pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField]; - sqlite3BtreeCursorZero(pCx->uc.pCursor); + + /* There used to be a call to sqlite3VdbeMemClearAndResize() to make sure + ** the pMem used to hold space for the cursor has enough storage available + ** in pMem->zMalloc. But for the special case of the aMem[] entries used + ** to hold cursors, it is faster to in-line the logic. */ + assert( pMem->flags==MEM_Undefined ); + assert( (pMem->flags & MEM_Dyn)==0 ); + assert( pMem->szMalloc==0 || pMem->z==pMem->zMalloc ); + if( pMem->szMallocszMalloc>0 ){ + sqlite3DbFreeNN(pMem->db, pMem->zMalloc); } + pMem->z = pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, nByte); + if( pMem->zMalloc==0 ){ + pMem->szMalloc = 0; + return 0; + } + pMem->szMalloc = nByte; + } + + p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->zMalloc; + memset(pCx, 0, offsetof(VdbeCursor,pAltCursor)); + pCx->eCurType = eCurType; + pCx->iDb = iDb; + pCx->nField = nField; + pCx->aOffset = &pCx->aType[nField]; + if( eCurType==CURTYPE_BTREE ){ + pCx->uc.pCursor = (BtCursor*) + &pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField]; + sqlite3BtreeCursorZero(pCx->uc.pCursor); } return pCx; } @@ -433,7 +451,10 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){ sqlite3_int64 ix; assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 ); assert( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ); - ExpandBlob(pMem); + if( ExpandBlob(pMem) ){ + pMem->u.i = 0; + return MEM_Int; + } rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); if( rc<=0 ){ if( rc==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1 ){ @@ -571,6 +592,11 @@ static void registerTrace(int iReg, Mem *p){ printf("\n"); sqlite3VdbeCheckMemInvariants(p); } +/**/ void sqlite3PrintMem(Mem *pMem){ + memTracePrint(pMem); + printf("\n"); + fflush(stdout); +} #endif #ifdef SQLITE_DEBUG @@ -1473,7 +1499,7 @@ case OP_ResultRow: { Mem *pMem; int i; assert( p->nResColumn==pOp->p2 ); - assert( pOp->p1>0 ); + assert( pOp->p1>0 || CORRUPT_DB ); assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 ); /* Invalidate all ephemeral cursor row caches */ @@ -1915,8 +1941,7 @@ case OP_Cast: { /* in1 */ ** Synopsis: IF r[P3]==r[P1] ** ** Compare the values in register P1 and P3. If reg(P3)==reg(P1) then -** jump to address P2. Or if the SQLITE_STOREP2 flag is set in P5, then -** store the result of comparison in register P2. +** jump to address P2. ** ** The SQLITE_AFF_MASK portion of P5 must be an affinity character - ** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made @@ -1942,9 +1967,8 @@ case OP_Cast: { /* in1 */ ** If neither operand is NULL the result is the same as it would be if ** the SQLITE_NULLEQ flag were omitted from P5. ** -** If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the -** content of r[P2] is only changed if the new value is NULL or 0 (false). -** In other words, a prior r[P2] value will not be overwritten by 1 (true). +** This opcode saves the result of comparison for use by the new +** OP_Jump opcode. */ /* Opcode: Ne P1 P2 P3 P4 P5 ** Synopsis: IF r[P3]!=r[P1] @@ -1952,17 +1976,12 @@ case OP_Cast: { /* in1 */ ** This works just like the Eq opcode except that the jump is taken if ** the operands in registers P1 and P3 are not equal. See the Eq opcode for ** additional information. -** -** If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the -** content of r[P2] is only changed if the new value is NULL or 1 (true). -** In other words, a prior r[P2] value will not be overwritten by 0 (false). */ /* Opcode: Lt P1 P2 P3 P4 P5 ** Synopsis: IF r[P3]p3]; flags1 = pIn1->flags; flags3 = pIn3->flags; + if( (flags1 & flags3 & MEM_Int)!=0 ){ + assert( (pOp->p5 & SQLITE_AFF_MASK)!=SQLITE_AFF_TEXT || CORRUPT_DB ); + /* Common case of comparison of two integers */ + if( pIn3->u.i > pIn1->u.i ){ + iCompare = +1; + if( sqlite3aGTb[pOp->opcode] ){ + VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3); + goto jump_to_p2; + } + }else if( pIn3->u.i < pIn1->u.i ){ + iCompare = -1; + if( sqlite3aLTb[pOp->opcode] ){ + VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3); + goto jump_to_p2; + } + }else{ + iCompare = 0; + if( sqlite3aEQb[pOp->opcode] ){ + VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3); + goto jump_to_p2; + } + } + VdbeBranchTaken(0, (pOp->p5 & SQLITE_NULLEQ)?2:3); + break; + } if( (flags1 | flags3)&MEM_Null ){ /* One or both operands are NULL */ if( pOp->p5 & SQLITE_NULLEQ ){ @@ -2044,22 +2091,16 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ ** then the result is always NULL. ** The jump is taken if the SQLITE_JUMPIFNULL bit is set. */ - if( pOp->p5 & SQLITE_STOREP2 ){ - pOut = &aMem[pOp->p2]; - iCompare = 1; /* Operands are not equal */ - memAboutToChange(p, pOut); - MemSetTypeFlag(pOut, MEM_Null); - REGISTER_TRACE(pOp->p2, pOut); - }else{ - VdbeBranchTaken(2,3); - if( pOp->p5 & SQLITE_JUMPIFNULL ){ - goto jump_to_p2; - } + iCompare = 1; /* Operands are not equal */ + VdbeBranchTaken(2,3); + if( pOp->p5 & SQLITE_JUMPIFNULL ){ + goto jump_to_p2; } break; } }else{ - /* Neither operand is NULL. Do a comparison. */ + /* Neither operand is NULL and we couldn't do the special high-speed + ** integer comparison case. So do a general-case comparison. */ affinity = pOp->p5 & SQLITE_AFF_MASK; if( affinity>=SQLITE_AFF_NUMERIC ){ if( (flags1 | flags3)&MEM_Str ){ @@ -2072,14 +2113,6 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ applyNumericAffinity(pIn3,0); } } - /* Handle the common case of integer comparison here, as an - ** optimization, to avoid a call to sqlite3MemCompare() */ - if( (pIn1->flags & pIn3->flags & MEM_Int)!=0 ){ - if( pIn3->u.i > pIn1->u.i ){ res = +1; goto compare_op; } - if( pIn3->u.i < pIn1->u.i ){ res = -1; goto compare_op; } - res = 0; - goto compare_op; - } }else if( affinity==SQLITE_AFF_TEXT ){ if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ testcase( pIn1->flags & MEM_Int ); @@ -2102,7 +2135,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 ); res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl); } -compare_op: + /* At this point, res is negative, zero, or positive if reg[P1] is ** less than, equal to, or greater than reg[P3], respectively. Compute ** the answer to this operator in res2, depending on what the comparison @@ -2111,16 +2144,14 @@ compare_op: ** order: NE, EQ, GT, LE, LT, GE */ assert( OP_Eq==OP_Ne+1 ); assert( OP_Gt==OP_Ne+2 ); assert( OP_Le==OP_Ne+3 ); assert( OP_Lt==OP_Ne+4 ); assert( OP_Ge==OP_Ne+5 ); - if( res<0 ){ /* ne, eq, gt, le, lt, ge */ - static const unsigned char aLTb[] = { 1, 0, 0, 1, 1, 0 }; - res2 = aLTb[pOp->opcode - OP_Ne]; + if( res<0 ){ + res2 = sqlite3aLTb[pOp->opcode]; }else if( res==0 ){ - static const unsigned char aEQb[] = { 0, 1, 0, 1, 0, 1 }; - res2 = aEQb[pOp->opcode - OP_Ne]; + res2 = sqlite3aEQb[pOp->opcode]; }else{ - static const unsigned char aGTb[] = { 1, 0, 1, 0, 0, 1 }; - res2 = aGTb[pOp->opcode - OP_Ne]; + res2 = sqlite3aGTb[pOp->opcode]; } + iCompare = res; /* Undo any changes made by applyAffinity() to the input registers. */ assert( (pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn) ); @@ -2128,67 +2159,39 @@ compare_op: assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) ); pIn1->flags = flags1; - if( pOp->p5 & SQLITE_STOREP2 ){ - pOut = &aMem[pOp->p2]; - iCompare = res; - if( (pOp->p5 & SQLITE_KEEPNULL)!=0 ){ - /* The KEEPNULL flag prevents OP_Eq from overwriting a NULL with 1 - ** and prevents OP_Ne from overwriting NULL with 0. This flag - ** is only used in contexts where either: - ** (1) op==OP_Eq && (r[P2]==NULL || r[P2]==0) - ** (2) op==OP_Ne && (r[P2]==NULL || r[P2]==1) - ** Therefore it is not necessary to check the content of r[P2] for - ** NULL. */ - assert( pOp->opcode==OP_Ne || pOp->opcode==OP_Eq ); - assert( res2==0 || res2==1 ); - testcase( res2==0 && pOp->opcode==OP_Eq ); - testcase( res2==1 && pOp->opcode==OP_Eq ); - testcase( res2==0 && pOp->opcode==OP_Ne ); - testcase( res2==1 && pOp->opcode==OP_Ne ); - if( (pOp->opcode==OP_Eq)==res2 ) break; - } - memAboutToChange(p, pOut); - MemSetTypeFlag(pOut, MEM_Int); - pOut->u.i = res2; - REGISTER_TRACE(pOp->p2, pOut); - }else{ - VdbeBranchTaken(res2!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3); - if( res2 ){ - goto jump_to_p2; - } + VdbeBranchTaken(res2!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3); + if( res2 ){ + goto jump_to_p2; } break; } -/* Opcode: ElseNotEq * P2 * * * +/* Opcode: ElseEq * P2 * * * ** ** This opcode must follow an OP_Lt or OP_Gt comparison operator. There ** can be zero or more OP_ReleaseReg opcodes intervening, but no other ** opcodes are allowed to occur between this instruction and the previous -** OP_Lt or OP_Gt. Furthermore, the prior OP_Lt or OP_Gt must have the -** SQLITE_STOREP2 bit set in the P5 field. +** OP_Lt or OP_Gt. ** ** If result of an OP_Eq comparison on the same two operands as the -** prior OP_Lt or OP_Gt would have been NULL or false (0), then then -** jump to P2. If the result of an OP_Eq comparison on the two previous -** operands would have been true (1), then fall through. +** prior OP_Lt or OP_Gt would have been true, then jump to P2. +** If the result of an OP_Eq comparison on the two previous +** operands would have been false or NULL, then fall through. */ -case OP_ElseNotEq: { /* same as TK_ESCAPE, jump */ +case OP_ElseEq: { /* same as TK_ESCAPE, jump */ #ifdef SQLITE_DEBUG /* Verify the preconditions of this opcode - that it follows an OP_Lt or - ** OP_Gt with the SQLITE_STOREP2 flag set, with zero or more intervening - ** OP_ReleaseReg opcodes */ + ** OP_Gt with zero or more intervening OP_ReleaseReg opcodes */ int iAddr; for(iAddr = (int)(pOp - aOp) - 1; ALWAYS(iAddr>=0); iAddr--){ if( aOp[iAddr].opcode==OP_ReleaseReg ) continue; assert( aOp[iAddr].opcode==OP_Lt || aOp[iAddr].opcode==OP_Gt ); - assert( aOp[iAddr].p5 & SQLITE_STOREP2 ); break; } #endif /* SQLITE_DEBUG */ - VdbeBranchTaken(iCompare!=0, 2); - if( iCompare!=0 ) goto jump_to_p2; + VdbeBranchTaken(iCompare==0, 2); + if( iCompare==0 ) goto jump_to_p2; break; } @@ -2499,6 +2502,24 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */ break; } +/* Opcode: ZeroOrNull P1 P2 P3 * * +** Synopsis: r[P2] = 0 OR NULL +** +** If all both registers P1 and P3 are NOT NULL, then store a zero in +** register P2. If either registers P1 or P3 are NULL then put +** a NULL in register P2. +*/ +case OP_ZeroOrNull: { /* in1, in2, out2, in3 */ + if( (aMem[pOp->p1].flags & MEM_Null)!=0 + || (aMem[pOp->p3].flags & MEM_Null)!=0 + ){ + sqlite3VdbeMemSetNull(aMem + pOp->p2); + }else{ + sqlite3VdbeMemSetInt64(aMem + pOp->p2, 0); + } + break; +} + /* Opcode: NotNull P1 P2 * * * ** Synopsis: if r[P1]!=NULL goto P2 ** @@ -4591,8 +4612,18 @@ case OP_SeekHit: { assert( pC!=0 ); assert( pOp->p3>=pOp->p2 ); if( pC->seekHitp2 ){ +#ifdef SQLITE_DEBUG + if( db->flags&SQLITE_VdbeTrace ){ + printf("seekHit changes from %d to %d\n", pC->seekHit, pOp->p2); + } +#endif pC->seekHit = pOp->p2; }else if( pC->seekHit>pOp->p3 ){ +#ifdef SQLITE_DEBUG + if( db->flags&SQLITE_VdbeTrace ){ + printf("seekHit changes from %d to %d\n", pC->seekHit, pOp->p3); + } +#endif pC->seekHit = pOp->p3; } break; @@ -4707,6 +4738,11 @@ case OP_IfNoHope: { /* jump, in3 */ assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); +#ifdef SQLITE_DEBUG + if( db->flags&SQLITE_VdbeTrace ){ + printf("seekHit is %d\n", pC->seekHit); + } +#endif if( pC->seekHit>=pOp->p4.i ) break; /* Fall through into OP_NotFound */ /* no break */ deliberate_fall_through @@ -5136,7 +5172,7 @@ case OP_Insert: { /* Invoke the pre-update hook, if any */ if( pTab ){ if( db->xPreUpdateCallback && !(pOp->p5 & OPFLAG_ISUPDATE) ){ - sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, x.nKey,pOp->p2); + sqlite3VdbePreUpdateHook(p,pC,SQLITE_INSERT,zDb,pTab,x.nKey,pOp->p2,-1); } if( db->xUpdateCallback==0 || pTab->aCol==0 ){ /* Prevent post-update hook from running in cases when it should not */ @@ -5296,7 +5332,7 @@ case OP_Delete: { sqlite3VdbePreUpdateHook(p, pC, (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE, zDb, pTab, pC->movetoTarget, - pOp->p3 + pOp->p3, -1 ); } if( opflags & OPFLAG_ISNOOP ) break; @@ -6365,7 +6401,7 @@ case OP_ParseSchema: { iDb = pOp->p1; assert( iDb>=0 && iDbnDb ); - assert( DbHasProperty(db, iDb, DB_SchemaLoaded) ); + assert( DbHasProperty(db, iDb, DB_SchemaLoaded) || db->mallocFailed ); #ifndef SQLITE_OMIT_ALTERTABLE if( pOp->p4.z==0 ){ @@ -7248,6 +7284,7 @@ case OP_JournalMode: { /* out2 */ pPager = sqlite3BtreePager(pBt); eOld = sqlite3PagerGetJournalMode(pPager); if( eNew==PAGER_JOURNALMODE_QUERY ) eNew = eOld; + assert( sqlite3BtreeHoldsMutex(pBt) ); if( !sqlite3PagerOkToChangeJournalMode(pPager) ) eNew = eOld; #ifndef SQLITE_OMIT_WAL diff --git a/src/vdbeInt.h b/src/vdbeInt.h index cb423f20a1..5e3e523f92 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -472,6 +472,7 @@ struct PreUpdate { UnpackedRecord *pUnpacked; /* Unpacked version of aRecord[] */ UnpackedRecord *pNewUnpacked; /* Unpacked version of new.* record */ int iNewReg; /* Register for new.* values */ + int iBlobWrite; /* Value returned by preupdate_blobwrite() */ i64 iKey1; /* First key value passed to hook */ i64 iKey2; /* Second key value passed to hook */ Mem *aNew; /* Array of new.* values */ @@ -560,7 +561,8 @@ void sqlite3VdbeFrameMemDel(void*); /* Destructor on Mem */ void sqlite3VdbeFrameDelete(VdbeFrame*); /* Actually deletes the Frame */ int sqlite3VdbeFrameRestore(VdbeFrame *); #ifdef SQLITE_ENABLE_PREUPDATE_HOOK -void sqlite3VdbePreUpdateHook(Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int); +void sqlite3VdbePreUpdateHook( + Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int,int); #endif int sqlite3VdbeTransferError(Vdbe *p); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index ba3bdf6a5f..b21634dc80 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -1905,6 +1905,17 @@ int sqlite3_preupdate_depth(sqlite3 *db){ } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK +/* +** This function is designed to be called from within a pre-update callback +** only. +*/ +int sqlite3_preupdate_blobwrite(sqlite3 *db){ + PreUpdate *p = db->pPreUpdate; + return (p ? p->iBlobWrite : -1); +} +#endif + #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** This function is called from within a pre-update callback to retrieve diff --git a/src/vdbeaux.c b/src/vdbeaux.c index be0d3f9bb5..3ea07d3c07 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1487,11 +1487,7 @@ char *sqlite3VdbeDisplayComment( char c; zSynopsis = zOpName += nOpName + 1; if( strncmp(zSynopsis,"IF ",3)==0 ){ - if( pOp->p5 & SQLITE_STOREP2 ){ - sqlite3_snprintf(sizeof(zAlt), zAlt, "r[P2] = (%s)", zSynopsis+3); - }else{ - sqlite3_snprintf(sizeof(zAlt), zAlt, "if %s goto P2", zSynopsis+3); - } + sqlite3_snprintf(sizeof(zAlt), zAlt, "if %s goto P2", zSynopsis+3); zSynopsis = zAlt; } for(ii=0; (c = zSynopsis[ii])!=0; ii++){ @@ -5213,7 +5209,8 @@ void sqlite3VdbePreUpdateHook( const char *zDb, /* Database name */ Table *pTab, /* Modified table */ i64 iKey1, /* Initial key value */ - int iReg /* Register for new.* record */ + int iReg, /* Register for new.* record */ + int iBlobWrite ){ sqlite3 *db = v->db; i64 iKey2; @@ -5249,6 +5246,7 @@ void sqlite3VdbePreUpdateHook( preupdate.iKey1 = iKey1; preupdate.iKey2 = iKey2; preupdate.pTab = pTab; + preupdate.iBlobWrite = iBlobWrite; db->pPreUpdate = &preupdate; db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2); diff --git a/src/vdbeblob.c b/src/vdbeblob.c index d34e3cf9f4..a4e79bf89b 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -420,7 +420,7 @@ static int blobReadWrite( sqlite3_int64 iKey; iKey = sqlite3BtreeIntegerKey(p->pCsr); sqlite3VdbePreUpdateHook( - v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1 + v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1, p->iCol ); } #endif @@ -491,6 +491,7 @@ int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ rc = SQLITE_ABORT; }else{ char *zErr; + ((Vdbe*)p->pStmt)->rc = SQLITE_OK; rc = blobSeekToRow(p, iRow, &zErr); if( rc!=SQLITE_OK ){ sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr); diff --git a/src/vdbemem.c b/src/vdbemem.c index 384eacc015..fd5212c8a9 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -75,7 +75,9 @@ int sqlite3VdbeCheckMemInvariants(Mem *p){ /* The szMalloc field holds the correct memory allocation size */ assert( p->szMalloc==0 - || p->szMalloc==sqlite3DbMallocSize(p->db,p->zMalloc) ); + || (p->flags==MEM_Undefined + && p->szMalloc<=sqlite3DbMallocSize(p->db,p->zMalloc)) + || p->szMalloc==sqlite3DbMallocSize(p->db,p->zMalloc)); /* If p holds a string or blob, the Mem.z must point to exactly ** one of the following: @@ -239,7 +241,9 @@ SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ testcase( bPreserve && pMem->z==0 ); assert( pMem->szMalloc==0 - || pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) ); + || (pMem->flags==MEM_Undefined + && pMem->szMalloc<=sqlite3DbMallocSize(pMem->db,pMem->zMalloc)) + || pMem->szMalloc==sqlite3DbMallocSize(pMem->db,pMem->zMalloc)); if( pMem->szMalloc>0 && bPreserve && pMem->z==pMem->zMalloc ){ if( pMem->db ){ pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n); diff --git a/src/vtab.c b/src/vtab.c index ded12c13bb..c9dcadae4b 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -1221,6 +1221,7 @@ int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){ pTab->pSchema = db->aDb[0].pSchema; assert( pTab->nModuleArg==0 ); pTab->iPKey = -1; + pTab->tabFlags |= TF_Eponymous; addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName)); addModuleArgument(pParse, pTab, 0); addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName)); diff --git a/src/wal.c b/src/wal.c index ed7da63fd7..371312ffad 100644 --- a/src/wal.c +++ b/src/wal.c @@ -1315,7 +1315,6 @@ static void walCleanupHash(Wal *pWal){ int iLimit = 0; /* Zero values greater than this */ int nByte; /* Number of bytes to zero in aPgno[] */ int i; /* Used to iterate through aHash[] */ - int rc; /* Return code form walHashGet() */ int iWal = walidxGetFile(&pWal->hdr); u32 mxFrame = walidxGetMxFrame(&pWal->hdr, iWal); @@ -1340,8 +1339,8 @@ static void walCleanupHash(Wal *pWal){ */ assert( pWal->nWiData>walFramePage(iExternal) ); assert( pWal->apWiData[walFramePage(iExternal)] ); - rc = walHashGet(pWal, walFramePage(iExternal), &sLoc); - if( NEVER(rc) ) return; /* Defense-in-depth, in case (1) above is wrong */ + i = walHashGet(pWal, walFramePage(iExternal), &sLoc); + if( NEVER(i) ) return; /* Defense-in-depth, in case (1) above is wrong */ /* Zero all hash-table entries that correspond to frame numbers greater ** than pWal->hdr.mxFrame. diff --git a/src/walker.c b/src/walker.c index 927f7e52d7..8c0308473a 100644 --- a/src/walker.c +++ b/src/walker.c @@ -32,15 +32,10 @@ static int walkWindowList(Walker *pWalker, Window *pList, int bOneOnly){ if( rc ) return WRC_Abort; rc = sqlite3WalkExpr(pWalker, pWin->pFilter); if( rc ) return WRC_Abort; - - /* The next two are purely for calls to sqlite3RenameExprUnmap() - ** within sqlite3WindowOffsetExpr(). Because of constraints imposed - ** by sqlite3WindowOffsetExpr(), they can never fail. The results do - ** not matter anyhow. */ rc = sqlite3WalkExpr(pWalker, pWin->pStart); - if( NEVER(rc) ) return WRC_Abort; + if( rc ) return WRC_Abort; rc = sqlite3WalkExpr(pWalker, pWin->pEnd); - if( NEVER(rc) ) return WRC_Abort; + if( rc ) return WRC_Abort; if( bOneOnly ) break; } return WRC_Continue; @@ -117,6 +112,16 @@ int sqlite3WalkExprList(Walker *pWalker, ExprList *p){ return WRC_Continue; } +/* +** This is a no-op callback for Walker->xSelectCallback2. If this +** callback is set, then the Select->pWinDefn list is traversed. +*/ +void sqlite3WalkWinDefnDummyCallback(Walker *pWalker, Select *p){ + UNUSED_PARAMETER(pWalker); + UNUSED_PARAMETER(p); + /* No-op */ +} + /* ** Walk all expressions associated with SELECT statement p. Do ** not invoke the SELECT callback on p, but do (of course) invoke @@ -130,10 +135,15 @@ int sqlite3WalkSelectExpr(Walker *pWalker, Select *p){ if( sqlite3WalkExpr(pWalker, p->pHaving) ) return WRC_Abort; if( sqlite3WalkExprList(pWalker, p->pOrderBy) ) return WRC_Abort; if( sqlite3WalkExpr(pWalker, p->pLimit) ) return WRC_Abort; -#if !defined(SQLITE_OMIT_WINDOWFUNC) && !defined(SQLITE_OMIT_ALTERTABLE) - { - Parse *pParse = pWalker->pParse; - if( pParse && IN_RENAME_OBJECT ){ +#if !defined(SQLITE_OMIT_WINDOWFUNC) + if( p->pWinDefn ){ + Parse *pParse; + if( pWalker->xSelectCallback2==sqlite3WalkWinDefnDummyCallback + || ((pParse = pWalker->pParse)!=0 && IN_RENAME_OBJECT) +#ifndef SQLITE_OMIT_CTE + || pWalker->xSelectCallback2==sqlite3SelectPopWith +#endif + ){ /* The following may return WRC_Abort if there are unresolvable ** symbols (e.g. a table that does not exist) in a window definition. */ int rc = walkWindowList(pWalker, p->pWinDefn, 0); @@ -157,7 +167,7 @@ int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){ SrcItem *pItem; pSrc = p->pSrc; - if( pSrc ){ + if( ALWAYS(pSrc) ){ for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){ return WRC_Abort; @@ -170,7 +180,7 @@ int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){ } } return WRC_Continue; -} +} /* ** Call sqlite3WalkExpr() for every expression in Select statement p. diff --git a/src/where.c b/src/where.c index 75b3ceff87..4062de7eab 100644 --- a/src/where.c +++ b/src/where.c @@ -261,7 +261,9 @@ static void createMask(WhereMaskSet *pMaskSet, int iCursor){ */ static Expr *whereRightSubexprIsColumn(Expr *p){ p = sqlite3ExprSkipCollateAndLikely(p->pRight); - if( ALWAYS(p!=0) && p->op==TK_COLUMN ) return p; + if( ALWAYS(p!=0) && p->op==TK_COLUMN && !ExprHasProperty(p, EP_FixedCol) ){ + return p; + } return 0; } @@ -336,6 +338,18 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ } pScan->pWC = pWC; pScan->k = k+1; +#ifdef WHERETRACE_ENABLED + if( sqlite3WhereTrace & 0x20000 ){ + int ii; + sqlite3DebugPrintf("SCAN-TERM %p: nEquiv=%d", + pTerm, pScan->nEquiv); + for(ii=0; iinEquiv; ii++){ + sqlite3DebugPrintf(" {%d:%d}", + pScan->aiCur[ii], pScan->aiColumn[ii]); + } + sqlite3DebugPrintf("\n"); + } +#endif return pTerm; } } @@ -492,7 +506,7 @@ static int findIndexCol( for(i=0; inExpr; i++){ Expr *p = sqlite3ExprSkipCollateAndLikely(pList->a[i].pExpr); if( ALWAYS(p!=0) - && p->op==TK_COLUMN + && (p->op==TK_COLUMN || p->op==TK_AGG_COLUMN) && p->iColumn==pIdx->aiColumn[iCol] && p->iTable==iBase ){ @@ -557,7 +571,8 @@ static int isDistinctRedundant( for(i=0; inExpr; i++){ Expr *p = sqlite3ExprSkipCollateAndLikely(pDistinct->a[i].pExpr); if( NEVER(p==0) ) continue; - if( p->op==TK_COLUMN && p->iTable==iBase && p->iColumn<0 ) return 1; + if( p->op!=TK_COLUMN && p->op!=TK_AGG_COLUMN ) continue; + if( p->iTable==iBase && p->iColumn<0 ) return 1; } /* Loop through all indices on the table, checking each to see if it makes @@ -575,6 +590,7 @@ static int isDistinctRedundant( */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( !IsUniqueIndex(pIdx) ) continue; + if( pIdx->pPartIdxWhere ) continue; for(i=0; inKeyCol; i++){ if( 0==sqlite3WhereFindTerm(pWC, iBase, i, ~(Bitmask)0, WO_EQ, pIdx) ){ if( findIndexCol(pParse, pDistinct, iBase, pIdx, i)<0 ) break; @@ -629,14 +645,14 @@ static void translateColumnToCopy( pOp->p2 = pOp->p3; pOp->p3 = 0; }else if( pOp->opcode==OP_Rowid ){ - if( iAutoidxCur ){ - pOp->opcode = OP_Sequence; - pOp->p1 = iAutoidxCur; - }else{ + pOp->opcode = OP_Sequence; + pOp->p1 = iAutoidxCur; +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + if( iAutoidxCur==0 ){ pOp->opcode = OP_Null; - pOp->p1 = 0; pOp->p3 = 0; } +#endif } } } @@ -801,7 +817,7 @@ static void constructAutomaticIndex( } } } - assert( nKeyCol>0 ); + assert( nKeyCol>0 || pParse->db->mallocFailed ); pLoop->u.btree.nEq = pLoop->nLTerm = nKeyCol; pLoop->wsFlags = WHERE_COLUMN_EQ | WHERE_IDX_ONLY | WHERE_INDEXED | WHERE_AUTO_INDEX; @@ -1938,7 +1954,7 @@ static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){ whereLoopClearUnion(db, pTo); if( whereLoopResize(db, pTo, pFrom->nLTerm) ){ - memset(&pTo->u, 0, sizeof(pTo->u)); + memset(pTo, 0, WHERE_LOOP_XFER_SZ); return SQLITE_NOMEM_BKPT; } memcpy(pTo, pFrom, WHERE_LOOP_XFER_SZ); @@ -1981,6 +1997,17 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ sqlite3DbFreeNN(db, pWInfo); } +/* Undo all Expr node modifications +*/ +static void whereUndoExprMods(WhereInfo *pWInfo){ + while( pWInfo->pExprMods ){ + WhereExprMod *p = pWInfo->pExprMods; + pWInfo->pExprMods = p->pNext; + memcpy(p->pExpr, &p->orig, sizeof(p->orig)); + sqlite3DbFree(pWInfo->pParse->db, p); + } +} + /* ** Return TRUE if all of the following are true: ** @@ -2486,6 +2513,8 @@ static int whereLoopAddBtreeIndex( if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); assert( pNew->u.btree.nEqnColumn ); + assert( pNew->u.btree.nEqnKeyCol + || pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY ); saved_nEq = pNew->u.btree.nEq; saved_nBtm = pNew->u.btree.nBtm; @@ -2619,6 +2648,7 @@ static int whereLoopAddBtreeIndex( pNew->wsFlags |= WHERE_UNQ_WANTED; } } + if( scan.iEquiv>1 ) pNew->wsFlags |= WHERE_TRANSCONS; }else if( eOp & WO_ISNULL ){ pNew->wsFlags |= WHERE_COLUMN_NULL; }else if( eOp & (WO_GT|WO_GE) ){ @@ -2762,6 +2792,8 @@ static int whereLoopAddBtreeIndex( if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 && pNew->u.btree.nEqnColumn + && (pNew->u.btree.nEqnKeyCol || + pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY) ){ whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul+nIn); } @@ -3593,7 +3625,9 @@ static int whereLoopAddOr( if( rc==SQLITE_OK ){ rc = whereLoopAddOr(&sSubBuild, mPrereq, mUnusable); } - assert( rc==SQLITE_OK || rc==SQLITE_DONE || sCur.n==0 ); + assert( rc==SQLITE_OK || rc==SQLITE_DONE || sCur.n==0 + || rc==SQLITE_NOMEM ); + testcase( rc==SQLITE_NOMEM && sCur.n>0 ); testcase( rc==SQLITE_DONE ); if( sCur.n==0 ){ sSum.n = 0; @@ -3822,7 +3856,7 @@ static i8 wherePathSatisfiesOrderBy( if( MASKBIT(i) & obSat ) continue; pOBExpr = sqlite3ExprSkipCollateAndLikely(pOrderBy->a[i].pExpr); if( NEVER(pOBExpr==0) ) continue; - if( pOBExpr->op!=TK_COLUMN ) continue; + if( pOBExpr->op!=TK_COLUMN && pOBExpr->op!=TK_AGG_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn, ~ready, eqOpMask, 0); @@ -3862,6 +3896,10 @@ static i8 wherePathSatisfiesOrderBy( assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) ); assert( pIndex->aiColumn[nColumn-1]==XN_ROWID || !HasRowid(pIndex->pTable)); + /* All relevant terms of the index must also be non-NULL in order + ** for isOrderDistinct to be true. So the isOrderDistint value + ** computed here might be a false positive. Corrections will be + ** made at tag-20210426-1 below */ isOrderDistinct = IsUniqueIndex(pIndex) && (pLoop->wsFlags & WHERE_SKIPSCAN)==0; } @@ -3929,15 +3967,19 @@ static i8 wherePathSatisfiesOrderBy( } /* An unconstrained column that might be NULL means that this - ** WhereLoop is not well-ordered + ** WhereLoop is not well-ordered. tag-20210426-1 */ - if( isOrderDistinct - && iColumn>=0 - && j>=pLoop->u.btree.nEq - && pIndex->pTable->aCol[iColumn].notNull==0 - ){ - isOrderDistinct = 0; - } + if( isOrderDistinct ){ + if( iColumn>=0 + && j>=pLoop->u.btree.nEq + && pIndex->pTable->aCol[iColumn].notNull==0 + ){ + isOrderDistinct = 0; + } + if( iColumn==XN_EXPR ){ + isOrderDistinct = 0; + } + } /* Find the ORDER BY term that corresponds to the j-th column ** of the index and mark that ORDER BY term off @@ -3951,7 +3993,7 @@ static i8 wherePathSatisfiesOrderBy( if( NEVER(pOBExpr==0) ) continue; if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0; if( iColumn>=XN_ROWID ){ - if( pOBExpr->op!=TK_COLUMN ) continue; + if( pOBExpr->op!=TK_COLUMN && pOBExpr->op!=TK_AGG_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; if( pOBExpr->iColumn!=iColumn ) continue; }else{ @@ -4120,7 +4162,7 @@ static LogEst whereSortingCost( }else if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT) ){ /* TUNING: In the sort for a DISTINCT operator, assume that the DISTINCT ** reduces the number of output rows by a factor of 2 */ - if( nRow>10 ) nRow -= 10; assert( 10==sqlite3LogEst(2) ); + if( nRow>10 ){ nRow -= 10; assert( 10==sqlite3LogEst(2) ); } } rSortCost += estLog(nRow); return rSortCost; @@ -5052,7 +5094,8 @@ WhereInfo *sqlite3WhereBegin( */ notReady = ~(Bitmask)0; if( pWInfo->nLevel>=2 - && pResultSet!=0 /* guarantees condition (1) above */ + && pResultSet!=0 /* these two combine to guarantee */ + && 0==(wctrlFlags & WHERE_AGG_DISTINCT) /* condition (1) above */ && OptimizationEnabled(db, SQLITE_OmitNoopJoin) ){ int i; @@ -5311,6 +5354,8 @@ WhereInfo *sqlite3WhereBegin( /* Jump here if malloc fails */ whereBeginError: if( pWInfo ){ + testcase( pWInfo->pExprMods!=0 ); + whereUndoExprMods(pWInfo); pParse->nQueryLoop = pWInfo->savedNQueryLoop; whereInfoFree(db, pWInfo); } @@ -5407,6 +5452,8 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ int j; sqlite3VdbeResolveLabel(v, pLevel->addrNxt); for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){ + assert( sqlite3VdbeGetOp(v, pIn->addrInTop+1)->opcode==OP_IsNull + || pParse->db->mallocFailed ); sqlite3VdbeJumpHere(v, pIn->addrInTop+1); if( pIn->eEndLoopOp!=OP_Noop ){ if( pIn->nPrefix ){ @@ -5431,6 +5478,11 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ sqlite3VdbeCurrentAddr(v)+2, pIn->iBase, pIn->nPrefix); VdbeCoverage(v); + /* Retarget the OP_IsNull against the left operand of IN so + ** it jumps past the OP_IfNoHope. This is because the + ** OP_IsNull also bypasses the OP_Affinity opcode that is + ** required by OP_IfNoHope. */ + sqlite3VdbeJumpHere(v, pIn->addrInTop+1); } } sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop); @@ -5565,7 +5617,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ #endif pOp = sqlite3VdbeGetOp(v, k); pLastOp = pOp + (last - k); - assert( pOpnErr>0 && pOp==pLastOp) ); + assert( pOp<=pLastOp ); do{ if( pOp->p1!=pLevel->iTabCur ){ /* no-op */ @@ -5610,16 +5662,9 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ } } - /* Undo all Expr node modifications */ - while( pWInfo->pExprMods ){ - WhereExprMod *p = pWInfo->pExprMods; - pWInfo->pExprMods = p->pNext; - memcpy(p->pExpr, &p->orig, sizeof(p->orig)); - sqlite3DbFree(db, p); - } - /* Final cleanup */ + if( pWInfo->pExprMods ) whereUndoExprMods(pWInfo); pParse->nQueryLoop = pWInfo->savedNQueryLoop; whereInfoFree(db, pWInfo); return; diff --git a/src/whereInt.h b/src/whereInt.h index 8896da0271..c5dd83cc8e 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -293,8 +293,8 @@ struct WhereScan { const char *zCollName; /* Required collating sequence, if not NULL */ Expr *pIdxExpr; /* Search for this index expression */ char idxaff; /* Must match this affinity, if zCollName!=NULL */ - unsigned char nEquiv; /* Number of entries in aEquiv[] */ - unsigned char iEquiv; /* Next unused slot in aEquiv[] */ + unsigned char nEquiv; /* Number of entries in aiCur[] and aiColumn[] */ + unsigned char iEquiv; /* Next unused slot in aiCur[] and aiColumn[] */ u32 opMask; /* Acceptable operators */ int k; /* Resume scanning at this->pWC->a[this->k] */ int aiCur[11]; /* Cursors in the equivalence class */ @@ -603,5 +603,6 @@ void sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereClause*); #define WHERE_IN_EARLYOUT 0x00040000 /* Perhaps quit IN loops early */ #define WHERE_BIGNULL_SORT 0x00080000 /* Column nEq of index is BIGNULL */ #define WHERE_IN_SEEKSCAN 0x00100000 /* Seek-scan optimization for IN */ +#define WHERE_TRANSCONS 0x00200000 /* Uses a transitive constraint */ #endif /* !defined(SQLITE_WHEREINT_H) */ diff --git a/src/wherecode.c b/src/wherecode.c index a7a76fb704..4d0ba880d1 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -148,16 +148,8 @@ int sqlite3WhereExplainOneScan( || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); - sqlite3_str_appendall(&str, isSearch ? "SEARCH" : "SCAN"); - if( pItem->pSelect ){ - sqlite3_str_appendf(&str, " SUBQUERY %u", pItem->pSelect->selId); - }else{ - sqlite3_str_appendf(&str, " TABLE %s", pItem->zName); - } - - if( pItem->zAlias ){ - sqlite3_str_appendf(&str, " AS %s", pItem->zAlias); - } + str.printfFlags = SQLITE_PRINTF_INTERNAL; + sqlite3_str_appendf(&str, "%s %S", isSearch ? "SEARCH" : "SCAN", pItem); if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){ const char *zFmt = 0; Index *pIdx; @@ -305,6 +297,12 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ }else{ pTerm->wtFlags |= TERM_CODED; } +#ifdef WHERETRACE_ENABLED + if( sqlite3WhereTrace & 0x20000 ){ + sqlite3DebugPrintf("DISABLE-"); + sqlite3WhereTermPrint(pTerm, (int)(pTerm - (pTerm->pWC->a))); + } +#endif if( pTerm->iParent<0 ) break; pTerm = &pTerm->pWC->a[pTerm->iParent]; assert( pTerm!=0 ); @@ -622,7 +620,22 @@ static int codeEqualityTerm( sqlite3DbFree(pParse->db, aiMap); #endif } - disableTerm(pLevel, pTerm); + + /* As an optimization, try to disable the WHERE clause term that is + ** driving the index as it will always be true. The correct answer is + ** obtained regardless, but we might get the answer with fewer CPU cycles + ** by omitting the term. + ** + ** But do not disable the term unless we are certain that the term is + ** not a transitive constraint. For an example of where that does not + ** work, see https://sqlite.org/forum/forumpost/eb8613976a (2021-05-04) + */ + if( (pLevel->pWLoop->wsFlags & WHERE_TRANSCONS)==0 + || (pTerm->eOperator & WO_EQUIV)==0 + ){ + disableTerm(pLevel, pTerm); + } + return iReg; } @@ -708,6 +721,7 @@ static int codeAllEqualityTerms( if( nSkip ){ int iIdxCur = pLevel->iIdxCur; + sqlite3VdbeAddOp3(v, OP_Null, 0, regBase, regBase+nSkip-1); sqlite3VdbeAddOp1(v, (bRev?OP_Last:OP_Rewind), iIdxCur); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); @@ -759,7 +773,7 @@ static int codeAllEqualityTerms( sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk); VdbeCoverage(v); } - if( zAff ){ + if( pParse->db->mallocFailed==0 ){ if( sqlite3CompareAffinity(pRight, zAff[j])==SQLITE_AFF_BLOB ){ zAff[j] = SQLITE_AFF_BLOB; } @@ -1735,9 +1749,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( ** a forward order scan on a descending index, interchange the ** start and end terms (pRangeStart and pRangeEnd). */ - if( (nEqnKeyCol && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC)) - || (bRev && pIdx->nKeyCol==nEq) - ){ + if( (nEqnColumn && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC)) ){ SWAP(WhereTerm *, pRangeEnd, pRangeStart); SWAP(u8, bSeekPastNull, bStopAtNull); SWAP(u8, nBtm, nTop); @@ -2158,7 +2170,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( /* The extra 0x10000 bit on the opcode is masked off and does not ** become part of the new Expr.op. However, it does make the ** op==TK_AND comparison inside of sqlite3PExpr() false, and this - ** prevents sqlite3PExpr() from implementing AND short-circuit + ** prevents sqlite3PExpr() from applying the AND short-circuit ** optimization, which we do not want here. */ pAndExpr = sqlite3PExpr(pParse, TK_AND|0x10000, 0, pAndExpr); } @@ -2174,10 +2186,16 @@ Bitmask sqlite3WhereCodeOneLoopStart( if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ WhereInfo *pSubWInfo; /* Info for single OR-term scan */ Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */ + Expr *pDelete; /* Local copy of OR clause term */ int jmp1 = 0; /* Address of jump operation */ testcase( (pTabItem[0].fg.jointype & JT_LEFT)!=0 && !ExprHasProperty(pOrExpr, EP_FromJoin) ); /* See TH3 vtab25.400 and ticket 614b25314c766238 */ + pDelete = pOrExpr = sqlite3ExprDup(db, pOrExpr, 0); + if( db->mallocFailed ){ + sqlite3ExprDelete(db, pDelete); + continue; + } if( pAndExpr ){ pAndExpr->pLeft = pOrExpr; pOrExpr = pAndExpr; @@ -2292,6 +2310,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( sqlite3WhereEnd(pSubWInfo); ExplainQueryPlanPop(pParse); } + sqlite3ExprDelete(db, pDelete); } } ExplainQueryPlanPop(pParse); @@ -2456,6 +2475,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( sEAlt = *pAlt->pExpr; sEAlt.pLeft = pE->pLeft; sqlite3ExprIfFalse(pParse, &sEAlt, addrCont, SQLITE_JUMPIFNULL); + pAlt->wtFlags |= TERM_CODED; } /* For a LEFT OUTER JOIN, generate code that will record the fact that diff --git a/src/whereexpr.c b/src/whereexpr.c index 7b80c41393..31f2ea438e 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -511,6 +511,7 @@ static void whereCombineDisjuncts( int op; /* Operator for the combined expression */ int idxNew; /* Index in pWC of the next virtual term */ + if( (pOne->wtFlags | pTwo->wtFlags) & TERM_VNULL ) return; if( (pOne->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return; if( (pTwo->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return; if( (eOp & (WO_EQ|WO_LT|WO_LE))!=eOp @@ -871,7 +872,7 @@ static void exprAnalyzeOrTerm( idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew==0 ); exprAnalyze(pSrc, pWC, idxNew); - /* pTerm = &pWC->a[idxTerm]; // would be needed if pTerm where used again */ + /* pTerm = &pWC->a[idxTerm]; // would be needed if pTerm where reused */ markTermAsChild(pWC, idxNew, idxTerm); }else{ sqlite3ExprListDelete(db, pList); @@ -995,6 +996,7 @@ static int exprMightBeIndexed( assert( op<=TK_GE ); if( pExpr->op==TK_VECTOR && (op>=TK_GT && ALWAYS(op<=TK_GE)) ){ pExpr = pExpr->x.pList->a[0].pExpr; + } if( pExpr->op==TK_COLUMN ){ @@ -1007,275 +1009,6 @@ static int exprMightBeIndexed( return exprMightBeIndexed2(pFrom,mPrereq,aiCurCol,pExpr); } -/* -** Expression callback for exprUsesSrclist(). -*/ -static int exprUsesSrclistCb(Walker *p, Expr *pExpr){ - if( pExpr->op==TK_COLUMN ){ - SrcList *pSrc = p->u.pSrcList; - int iCsr = pExpr->iTable; - int ii; - for(ii=0; iinSrc; ii++){ - if( pSrc->a[ii].iCursor==iCsr ){ - return p->eCode ? WRC_Abort : WRC_Continue; - } - } - return p->eCode ? WRC_Continue : WRC_Abort; - } - return WRC_Continue; -} - -/* -** Select callback for exprUsesSrclist(). -*/ -static int exprUsesSrclistSelectCb(Walker *NotUsed1, Select *NotUsed2){ - UNUSED_PARAMETER(NotUsed1); - UNUSED_PARAMETER(NotUsed2); - return WRC_Abort; -} - -/* -** This function always returns true if expression pExpr contains -** a sub-select. -** -** If there is no sub-select in pExpr, then return true if pExpr -** contains a TK_COLUMN node for a table that is (bUses==1) -** or is not (bUses==0) in pSrc. -** -** Said another way: -** -** bUses Return Meaning -** -------- ------ ------------------------------------------------ -** -** bUses==1 true pExpr contains either a sub-select or a -** TK_COLUMN referencing pSrc. -** -** bUses==1 false pExpr contains no sub-selects and all TK_COLUMN -** nodes reference tables not found in pSrc -** -** bUses==0 true pExpr contains either a sub-select or a TK_COLUMN -** that references a table not in pSrc. -** -** bUses==0 false pExpr contains no sub-selects and all TK_COLUMN -** nodes reference pSrc -*/ -static int exprUsesSrclist(SrcList *pSrc, Expr *pExpr, int bUses){ - Walker sWalker; - memset(&sWalker, 0, sizeof(Walker)); - sWalker.eCode = bUses; - sWalker.u.pSrcList = pSrc; - sWalker.xExprCallback = exprUsesSrclistCb; - sWalker.xSelectCallback = exprUsesSrclistSelectCb; - return (sqlite3WalkExpr(&sWalker, pExpr)==WRC_Abort); -} - -/* -** Context object used by exprExistsToInIter() as it iterates through an -** expression tree. -*/ -struct ExistsToInCtx { - SrcList *pSrc; /* The tables in an EXISTS(SELECT ... FROM ...) */ - Expr *pInLhs; /* OUT: Use this as the LHS of the IN operator */ - Expr *pEq; /* OUT: The == term that include pInLhs */ - Expr **ppAnd; /* OUT: The AND operator that includes pEq as a child */ - Expr **ppParent; /* The AND operator currently being examined */ -}; - -/* -** Iterate through all AND connected nodes in the expression tree -** headed by (*ppExpr), populating the structure passed as the first -** argument with the values required by exprAnalyzeExistsFindEq(). -** -** This function returns non-zero if the expression tree does not meet -** the two conditions described by the header comment for -** exprAnalyzeExistsFindEq(), or zero if it does. -*/ -static int exprExistsToInIter(struct ExistsToInCtx *p, Expr **ppExpr){ - Expr *pExpr = *ppExpr; - switch( pExpr->op ){ - case TK_AND: - p->ppParent = ppExpr; - if( exprExistsToInIter(p, &pExpr->pLeft) ) return 1; - p->ppParent = ppExpr; - if( exprExistsToInIter(p, &pExpr->pRight) ) return 1; - break; - case TK_EQ: { - int bLeft = exprUsesSrclist(p->pSrc, pExpr->pLeft, 0); - int bRight = exprUsesSrclist(p->pSrc, pExpr->pRight, 0); - if( bLeft || bRight ){ - if( (bLeft && bRight) || p->pInLhs ) return 1; - p->pInLhs = bLeft ? pExpr->pLeft : pExpr->pRight; - if( exprUsesSrclist(p->pSrc, p->pInLhs, 1) ) return 1; - p->pEq = pExpr; - p->ppAnd = p->ppParent; - } - break; - } - default: - if( exprUsesSrclist(p->pSrc, pExpr, 0) ){ - return 1; - } - break; - } - - return 0; -} - -/* -** This function is used by exprAnalyzeExists() when creating virtual IN(...) -** terms equivalent to user-supplied EXIST(...) clauses. It splits the WHERE -** clause of the Select object passed as the first argument into one or more -** expressions joined by AND operators, and then tests if the following are -** true: -** -** 1. Exactly one of the AND separated terms refers to the outer -** query, and it is an == (TK_EQ) expression. -** -** 2. Only one side of the == expression refers to the outer query, and -** it does not refer to any columns from the inner query. -** -** If both these conditions are true, then a pointer to the side of the == -** expression that refers to the outer query is returned. The caller will -** use this expression as the LHS of the IN(...) virtual term. Or, if one -** or both of the above conditions are not true, NULL is returned. -** -** If non-NULL is returned and ppEq is non-NULL, *ppEq is set to point -** to the == expression node before returning. If pppAnd is non-NULL and -** the == node is not the root of the WHERE clause, then *pppAnd is set -** to point to the pointer to the AND node that is the parent of the == -** node within the WHERE expression tree. -*/ -static Expr *exprAnalyzeExistsFindEq( - Select *pSel, /* The SELECT of the EXISTS */ - Expr **ppEq, /* OUT: == node from WHERE clause */ - Expr ***pppAnd /* OUT: Pointer to parent of ==, if any */ -){ - struct ExistsToInCtx ctx; - memset(&ctx, 0, sizeof(ctx)); - ctx.pSrc = pSel->pSrc; - if( exprExistsToInIter(&ctx, &pSel->pWhere) ){ - return 0; - } - if( ppEq ) *ppEq = ctx.pEq; - if( pppAnd ) *pppAnd = ctx.ppAnd; - return ctx.pInLhs; -} - -/* -** Term idxTerm of the WHERE clause passed as the second argument is an -** EXISTS expression with a correlated SELECT statement on the RHS. -** This function analyzes the SELECT statement, and if possible adds an -** equivalent "? IN(SELECT...)" virtual term to the WHERE clause. -** -** For an EXISTS term such as the following: -** -** EXISTS (SELECT ... FROM WHERE = AND ) -** -** The virtual IN() term added is: -** -** IN (SELECT FROM WHERE ) -** -** The virtual term is only added if the following conditions are met: -** -** 1. The sub-select must not be an aggregate or use window functions, -** -** 2. The sub-select must not be a compound SELECT, -** -** 3. Expression must refer to at least one column from the outer -** query, and must not refer to any column from the inner query -** (i.e. from ). -** -** 4. and must not refer to any values from the outer query. -** In other words, once has been removed, the inner query -** must not be correlated. -** -*/ -static void exprAnalyzeExists( - SrcList *pSrc, /* the FROM clause */ - WhereClause *pWC, /* the WHERE clause */ - int idxTerm /* Index of the term to be analyzed */ -){ - Parse *pParse = pWC->pWInfo->pParse; - WhereTerm *pTerm = &pWC->a[idxTerm]; - Expr *pExpr = pTerm->pExpr; - Select *pSel = pExpr->x.pSelect; - Expr *pDup = 0; - Expr *pEq = 0; - Expr *pRet = 0; - Expr *pInLhs = 0; - Expr **ppAnd = 0; - int idxNew; - sqlite3 *db = pParse->db; - - assert( pExpr->op==TK_EXISTS ); - assert( (pExpr->flags & EP_VarSelect) && (pExpr->flags & EP_xIsSelect) ); - - if( pSel->selFlags & SF_Aggregate ) return; -#ifndef SQLITE_OMIT_WINDOWFUNC - if( pSel->pWin ) return; -#endif - if( pSel->pPrior ) return; - if( pSel->pWhere==0 ) return; - if( 0==exprAnalyzeExistsFindEq(pSel, 0, 0) ) return; - - pDup = sqlite3ExprDup(db, pExpr, 0); - if( db->mallocFailed ){ - sqlite3ExprDelete(db, pDup); - return; - } - pSel = pDup->x.pSelect; - sqlite3ExprListDelete(db, pSel->pEList); - pSel->pEList = 0; - - pInLhs = exprAnalyzeExistsFindEq(pSel, &pEq, &ppAnd); - assert( pInLhs && pEq ); - assert( pEq==pSel->pWhere || ppAnd ); - if( pInLhs==pEq->pLeft ){ - pRet = pEq->pRight; - }else{ - CollSeq *p = sqlite3ExprCompareCollSeq(pParse, pEq); - pInLhs = sqlite3ExprAddCollateString(pParse, pInLhs, p?p->zName:"BINARY"); - pRet = pEq->pLeft; - } - - assert( pDup->pLeft==0 ); - pDup->op = TK_IN; - pDup->pLeft = pInLhs; - pDup->flags &= ~EP_VarSelect; - if( pRet->op==TK_VECTOR ){ - pSel->pEList = pRet->x.pList; - pRet->x.pList = 0; - sqlite3ExprDelete(db, pRet); - }else{ - pSel->pEList = sqlite3ExprListAppend(pParse, 0, pRet); - } - pEq->pLeft = 0; - pEq->pRight = 0; - if( ppAnd ){ - Expr *pAnd = *ppAnd; - Expr *pOther = (pAnd->pLeft==pEq) ? pAnd->pRight : pAnd->pLeft; - pAnd->pLeft = pAnd->pRight = 0; - sqlite3ExprDelete(db, pAnd); - *ppAnd = pOther; - }else{ - assert( pSel->pWhere==pEq ); - pSel->pWhere = 0; - } - sqlite3ExprDelete(db, pEq); - -#ifdef WHERETRACE_ENABLED /* 0x20 */ - if( sqlite3WhereTrace & 0x20 ){ - sqlite3DebugPrintf("Convert EXISTS:\n"); - sqlite3TreeViewExpr(0, pExpr, 0); - sqlite3DebugPrintf("into IN:\n"); - sqlite3TreeViewExpr(0, pDup, 0); - } -#endif - idxNew = whereClauseInsert(pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC); - exprAnalyze(pSrc, pWC, idxNew); - markTermAsChild(pWC, idxNew, idxTerm); - pWC->a[idxTerm].wtFlags |= TERM_COPIED; -} /* ** The input to this routine is an WhereTerm structure with only the @@ -1375,6 +1108,7 @@ static void exprAnalyze( if( op==TK_IS ) pTerm->wtFlags |= TERM_IS; if( pRight && exprMightBeIndexed(pSrc, pTerm->prereqRight, aiCurCol, pRight, op) + && !ExprHasProperty(pRight, EP_FixedCol) ){ WhereTerm *pNew; Expr *pDup; @@ -1467,16 +1201,6 @@ static void exprAnalyze( pTerm = &pWC->a[idxTerm]; } #endif /* SQLITE_OMIT_OR_OPTIMIZATION */ - - else if( pExpr->op==TK_EXISTS ){ - /* Perhaps treat an EXISTS operator as an IN operator */ - if( (pExpr->flags & EP_VarSelect)!=0 - && OptimizationEnabled(db, SQLITE_ExistsToIN) - ){ - exprAnalyzeExists(pSrc, pWC, idxTerm); - } - } - /* The form "x IS NOT NULL" can sometimes be evaluated more efficiently ** as "x>NULL" if x is not an INTEGER PRIMARY KEY. So construct a ** virtual term of that form. diff --git a/src/window.c b/src/window.c index 26a82a9e33..a997b9c6c9 100644 --- a/src/window.c +++ b/src/window.c @@ -788,6 +788,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){ case TK_AGG_FUNCTION: case TK_COLUMN: { int iCol = -1; + if( pParse->db->mallocFailed ) return WRC_Abort; if( p->pSub ){ int i; for(i=0; ipSub->nExpr; i++){ @@ -897,9 +898,14 @@ static ExprList *exprListAppendList( int i; int nInit = pList ? pList->nExpr : 0; for(i=0; inExpr; i++){ - Expr *pDup = sqlite3ExprDup(pParse->db, pAppend->a[i].pExpr, 0); + sqlite3 *db = pParse->db; + Expr *pDup = sqlite3ExprDup(db, pAppend->a[i].pExpr, 0); assert( pDup==0 || !ExprHasProperty(pDup, EP_MemToken) ); - if( bIntToNull && pDup ){ + if( db->mallocFailed ){ + sqlite3ExprDelete(db, pDup); + break; + } + if( bIntToNull ){ int iDummy; Expr *pSub; for(pSub=pDup; ExprHasProperty(pSub, EP_Skip); pSub=pSub->pLeft){ @@ -935,6 +941,14 @@ static int sqlite3WindowExtraAggFuncDepth(Walker *pWalker, Expr *pExpr){ return WRC_Continue; } +static int disallowAggregatesInOrderByCb(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_AGG_FUNCTION && pExpr->pAggInfo==0 ){ + sqlite3ErrorMsg(pWalker->pParse, + "misuse of aggregate: %s()", pExpr->u.zToken); + } + return WRC_Continue; +} + /* ** If the SELECT statement passed as the second argument does not invoke ** any SQL window functions, this function is a no-op. Otherwise, it @@ -968,6 +982,11 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){ } sqlite3AggInfoPersistWalkerInit(&w, pParse); sqlite3WalkSelect(&w, p); + if( (p->selFlags & SF_Aggregate)==0 ){ + w.xExprCallback = disallowAggregatesInOrderByCb; + w.xSelectCallback = 0; + sqlite3WalkExprList(&w, p->pOrderBy); + } p->pSrc = 0; p->pWhere = 0; @@ -1469,6 +1488,7 @@ static void windowCheckValue(Parse *pParse, int reg, int eCond){ VdbeCoverageIf(v, eCond==2); } sqlite3VdbeAddOp3(v, aOp[eCond], regZero, sqlite3VdbeCurrentAddr(v)+2, reg); + sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC); VdbeCoverageNeverNullIf(v, eCond==0); /* NULL case captured by */ VdbeCoverageNeverNullIf(v, eCond==1); /* the OP_MustBeInt */ VdbeCoverageNeverNullIf(v, eCond==2); @@ -1563,6 +1583,7 @@ struct WindowCodeArg { int regGosub; /* Register used with OP_Gosub(addrGosub) */ int regArg; /* First in array of accumulator registers */ int eDelete; /* See above */ + int regRowid; WindowCsrAndReg start; WindowCsrAndReg current; @@ -1679,15 +1700,15 @@ static void windowAggStep( } if( pWin->bExprArgs ){ - int iStart = sqlite3VdbeCurrentAddr(v); - VdbeOp *pOp, *pEnd; + int iOp = sqlite3VdbeCurrentAddr(v); + int iEnd; nArg = pWin->pOwner->x.pList->nExpr; regArg = sqlite3GetTempRange(pParse, nArg); sqlite3ExprCodeExprList(pParse, pWin->pOwner->x.pList, regArg, 0, 0); - pEnd = sqlite3VdbeGetOp(v, -1); - for(pOp=sqlite3VdbeGetOp(v, iStart); pOp<=pEnd; pOp++){ + for(iEnd=sqlite3VdbeCurrentAddr(v); iOpopcode==OP_Column && pOp->p1==pWin->iEphCsr ){ pOp->p1 = csr; } @@ -2046,7 +2067,7 @@ static void windowIfNewPeer( ** if( csr1.peerVal - regVal <= csr2.peerVal ) goto lbl; ** ** A special type of arithmetic is used such that if csr1.peerVal is not -** a numeric type (real or integer), then the result of the addition addition +** a numeric type (real or integer), then the result of the addition ** or subtraction is a a copy of csr1.peerVal. */ static void windowCodeRangeTest( @@ -2065,8 +2086,13 @@ static void windowCodeRangeTest( int regString = ++pParse->nMem; /* Reg. for constant value '' */ int arith = OP_Add; /* OP_Add or OP_Subtract */ int addrGe; /* Jump destination */ + int addrDone = sqlite3VdbeMakeLabel(pParse); /* Address past OP_Ge */ CollSeq *pColl; + /* Read the peer-value from each cursor into a register */ + windowReadPeerValues(p, csr1, reg1); + windowReadPeerValues(p, csr2, reg2); + assert( op==OP_Ge || op==OP_Gt || op==OP_Le ); assert( pOrderBy && pOrderBy->nExpr==1 ); if( pOrderBy->a[0].sortFlags & KEYINFO_ORDER_DESC ){ @@ -2078,34 +2104,11 @@ static void windowCodeRangeTest( arith = OP_Subtract; } - /* Read the peer-value from each cursor into a register */ - windowReadPeerValues(p, csr1, reg1); - windowReadPeerValues(p, csr2, reg2); - VdbeModuleComment((v, "CodeRangeTest: if( R%d %s R%d %s R%d ) goto lbl", reg1, (arith==OP_Add ? "+" : "-"), regVal, ((op==OP_Ge) ? ">=" : (op==OP_Le) ? "<=" : (op==OP_Gt) ? ">" : "<"), reg2 )); - /* Register reg1 currently contains csr1.peerVal (the peer-value from csr1). - ** This block adds (or subtracts for DESC) the numeric value in regVal - ** from it. Or, if reg1 is not numeric (it is a NULL, a text value or a blob), - ** then leave reg1 as it is. In pseudo-code, this is implemented as: - ** - ** if( reg1>='' ) goto addrGe; - ** reg1 = reg1 +/- regVal - ** addrGe: - ** - ** Since all strings and blobs are greater-than-or-equal-to an empty string, - ** the add/subtract is skipped for these, as required. If reg1 is a NULL, - ** then the arithmetic is performed, but since adding or subtracting from - ** NULL is always NULL anyway, this case is handled as required too. */ - sqlite3VdbeAddOp4(v, OP_String8, 0, regString, 0, "", P4_STATIC); - addrGe = sqlite3VdbeAddOp3(v, OP_Ge, regString, 0, reg1); - VdbeCoverage(v); - sqlite3VdbeAddOp3(v, arith, regVal, reg1, reg1); - sqlite3VdbeJumpHere(v, addrGe); - /* If the BIGNULL flag is set for the ORDER BY, then it is required to ** consider NULL values to be larger than all other values, instead of ** the usual smaller. The VDBE opcodes OP_Ge and so on do not handle this @@ -2142,16 +2145,38 @@ static void windowCodeRangeTest( break; default: assert( op==OP_Lt ); /* no-op */ break; } - sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+3); + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrDone); /* This block runs if reg1 is not NULL, but reg2 is. */ sqlite3VdbeJumpHere(v, addr); sqlite3VdbeAddOp2(v, OP_IsNull, reg2, lbl); VdbeCoverage(v); if( op==OP_Gt || op==OP_Ge ){ - sqlite3VdbeChangeP2(v, -1, sqlite3VdbeCurrentAddr(v)+1); + sqlite3VdbeChangeP2(v, -1, addrDone); } } + /* Register reg1 currently contains csr1.peerVal (the peer-value from csr1). + ** This block adds (or subtracts for DESC) the numeric value in regVal + ** from it. Or, if reg1 is not numeric (it is a NULL, a text value or a blob), + ** then leave reg1 as it is. In pseudo-code, this is implemented as: + ** + ** if( reg1>='' ) goto addrGe; + ** reg1 = reg1 +/- regVal + ** addrGe: + ** + ** Since all strings and blobs are greater-than-or-equal-to an empty string, + ** the add/subtract is skipped for these, as required. If reg1 is a NULL, + ** then the arithmetic is performed, but since adding or subtracting from + ** NULL is always NULL anyway, this case is handled as required too. */ + sqlite3VdbeAddOp4(v, OP_String8, 0, regString, 0, "", P4_STATIC); + addrGe = sqlite3VdbeAddOp3(v, OP_Ge, regString, 0, reg1); + VdbeCoverage(v); + if( (op==OP_Ge && arith==OP_Add) || (op==OP_Le && arith==OP_Subtract) ){ + sqlite3VdbeAddOp3(v, op, reg2, lbl, reg1); VdbeCoverage(v); + } + sqlite3VdbeAddOp3(v, arith, regVal, reg1, reg1); + sqlite3VdbeJumpHere(v, addrGe); + /* Compare registers reg2 and reg1, taking the jump if required. Note that ** control skips over this test if the BIGNULL flag is set and either ** reg1 or reg2 contain a NULL value. */ @@ -2159,6 +2184,7 @@ static void windowCodeRangeTest( pColl = sqlite3ExprNNCollSeq(pParse, pOrderBy->a[0].pExpr); sqlite3VdbeAppendP4(v, (void*)pColl, P4_COLLSEQ); sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); + sqlite3VdbeResolveLabel(v, addrDone); assert( op==OP_Ge || op==OP_Gt || op==OP_Lt || op==OP_Le ); testcase(op==OP_Ge); VdbeCoverageIf(v, op==OP_Ge); @@ -2234,16 +2260,24 @@ static int windowCodeOp( /* If this is a (RANGE BETWEEN a FOLLOWING AND b FOLLOWING) or ** (RANGE BETWEEN b PRECEDING AND a PRECEDING) frame, ensure the ** start cursor does not advance past the end cursor within the - ** temporary table. It otherwise might, if (a>b). */ + ** temporary table. It otherwise might, if (a>b). Also ensure that, + ** if the input cursor is still finding new rows, that the end + ** cursor does not go past it to EOF. */ if( pMWin->eStart==pMWin->eEnd && regCountdown - && pMWin->eFrmType==TK_RANGE && op==WINDOW_AGGINVERSE + && pMWin->eFrmType==TK_RANGE ){ int regRowid1 = sqlite3GetTempReg(pParse); int regRowid2 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp2(v, OP_Rowid, p->start.csr, regRowid1); - sqlite3VdbeAddOp2(v, OP_Rowid, p->end.csr, regRowid2); - sqlite3VdbeAddOp3(v, OP_Ge, regRowid2, lblDone, regRowid1); - VdbeCoverage(v); + if( op==WINDOW_AGGINVERSE ){ + sqlite3VdbeAddOp2(v, OP_Rowid, p->start.csr, regRowid1); + sqlite3VdbeAddOp2(v, OP_Rowid, p->end.csr, regRowid2); + sqlite3VdbeAddOp3(v, OP_Ge, regRowid2, lblDone, regRowid1); + VdbeCoverage(v); + }else if( p->regRowid ){ + sqlite3VdbeAddOp2(v, OP_Rowid, p->end.csr, regRowid1); + sqlite3VdbeAddOp3(v, OP_Ge, p->regRowid, lblDone, regRowid1); + VdbeCoverageNeverNull(v); + } sqlite3ReleaseTempReg(pParse, regRowid1); sqlite3ReleaseTempReg(pParse, regRowid2); assert( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_FOLLOWING ); @@ -2740,7 +2774,6 @@ void sqlite3WindowCodeStep( int addrEmpty; /* Address of OP_Rewind in flush: */ int regNew; /* Array of registers holding new input row */ int regRecord; /* regNew array in record form */ - int regRowid; /* Rowid for regRecord in eph table */ int regNewPeer = 0; /* Peer values for new row (part of regNew) */ int regPeer = 0; /* Peer values for current row */ int regFlushPart = 0; /* Register for "Gosub flush_partition" */ @@ -2812,7 +2845,7 @@ void sqlite3WindowCodeStep( regNew = pParse->nMem+1; pParse->nMem += nInput; regRecord = ++pParse->nMem; - regRowid = ++pParse->nMem; + s.regRowid = ++pParse->nMem; /* If the window frame contains an " PRECEDING" or " FOLLOWING" ** clause, allocate registers to store the results of evaluating each @@ -2868,9 +2901,9 @@ void sqlite3WindowCodeStep( } /* Insert the new row into the ephemeral table */ - sqlite3VdbeAddOp2(v, OP_NewRowid, csrWrite, regRowid); - sqlite3VdbeAddOp3(v, OP_Insert, csrWrite, regRecord, regRowid); - addrNe = sqlite3VdbeAddOp3(v, OP_Ne, pMWin->regOne, 0, regRowid); + sqlite3VdbeAddOp2(v, OP_NewRowid, csrWrite, s.regRowid); + sqlite3VdbeAddOp3(v, OP_Insert, csrWrite, regRecord, s.regRowid); + addrNe = sqlite3VdbeAddOp3(v, OP_Ne, pMWin->regOne, 0, s.regRowid); VdbeCoverageNeverNull(v); /* This block is run for the first row of each partition */ @@ -2988,6 +3021,7 @@ void sqlite3WindowCodeStep( sqlite3VdbeJumpHere(v, addrGosubFlush); } + s.regRowid = 0; addrEmpty = sqlite3VdbeAddOp1(v, OP_Rewind, csrWrite); VdbeCoverage(v); if( pMWin->eEnd==TK_PRECEDING ){ diff --git a/test/alter4.test b/test/alter4.test index 3aca7df338..c63ba6b072 100644 --- a/test/alter4.test +++ b/test/alter4.test @@ -318,16 +318,16 @@ ifcapable trigger&&tempdb { END; INSERT INTO t1 VALUES(1, 2); - SELECT * FROM log; + SELECT * FROM log ORDER BY trig, a, b; } - } {b 1 2 a 1 2} + } {a 1 2 b 1 2} do_test alter4-6.2 { execsql { ALTER TABLE t1 ADD COLUMN c DEFAULT 'c'; INSERT INTO t1(a, b) VALUES(3, 4); - SELECT * FROM log; + SELECT * FROM log ORDER BY trig, a, b; } - } {b 1 2 a 1 2 b 3 4 a 3 4} + } {a 1 2 a 3 4 b 1 2 b 3 4} } # Ticket #1183 - Make sure adding columns to large tables does not cause diff --git a/test/alterauth2.test b/test/alterauth2.test index a411408b58..27ded1c3ea 100644 --- a/test/alterauth2.test +++ b/test/alterauth2.test @@ -82,6 +82,7 @@ do_auth_test 1.2 { {SQLITE_ALTER_TABLE main t2 {} {}} {SQLITE_FUNCTION {} like {} {}} {SQLITE_FUNCTION {} sqlite_rename_column {} {}} + {SQLITE_FUNCTION {} sqlite_rename_quotefix {} {}} {SQLITE_FUNCTION {} sqlite_rename_test {} {}} {SQLITE_READ sqlite_master name main {}} {SQLITE_READ sqlite_master sql main {}} @@ -100,6 +101,7 @@ do_auth_test 1.3 { } { {SQLITE_FUNCTION {} like {} {}} {SQLITE_FUNCTION {} sqlite_drop_column {} {}} + {SQLITE_FUNCTION {} sqlite_rename_quotefix {} {}} {SQLITE_FUNCTION {} sqlite_rename_test {} {}} {SQLITE_READ sqlite_master name main {}} {SQLITE_READ sqlite_master sql main {}} @@ -110,6 +112,7 @@ do_auth_test 1.3 { {SQLITE_READ sqlite_temp_master type temp {}} {SQLITE_SELECT {} {} {} {}} {SQLITE_UPDATE sqlite_master sql main {}} + {SQLITE_UPDATE sqlite_temp_master sql temp {}} } finish_test diff --git a/test/altercol.test b/test/altercol.test index 047917e5a1..d0c5c40ea6 100644 --- a/test/altercol.test +++ b/test/altercol.test @@ -567,7 +567,7 @@ do_execsql_test 13.1.6 { do_catchsql_test 13.1.7 { ALTER TABLE x1 RENAME COLUMN t TO ttt; -} {1 {database disk image is malformed}} +} {1 {error in index x1i: }} do_execsql_test 13.1.8 { DELETE FROM sqlite_master WHERE name = 'x1i'; @@ -835,5 +835,29 @@ do_execsql_test 22.0 { {CREATE TABLE t2(c, othername, extra AS (c + 1))} } +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 22.0 { + CREATE TABLE t1(a, b); + CREATE INDEX x1 on t1("c"=b); + INSERT INTO t1 VALUES('a', 'a'); + INSERT INTO t1 VALUES('b', 'b'); + INSERT INTO t1 VALUES('c', 'c'); + ALTER TABLE t1 RENAME COLUMN a TO "c"; + PRAGMA integrity_check; +} {ok} + +reset_db +do_execsql_test 23.0 { + CREATE TABLE t1('a'"b",c); + CREATE INDEX i1 ON t1('a'); + INSERT INTO t1 VALUES(1,2), (3,4); + ALTER TABLE t1 RENAME COLUMN a TO x; + PRAGMA integrity_check; + SELECT sql FROM sqlite_schema WHERE name='t1'; + +} {ok {CREATE TABLE t1("x" "b",c)}} + finish_test diff --git a/test/alterdropcol.test b/test/alterdropcol.test index 3cca664151..8674e981a3 100644 --- a/test/alterdropcol.test +++ b/test/alterdropcol.test @@ -276,4 +276,64 @@ do_catchsql_test 6.1 { ALTER TABLE t2 DROP COLUMN z; } {1 {database disk image is malformed}} +# 2021-04-06 dbsqlfuzz crash-331c5c29bb76257b198f1318eef3288f9624c8ce +reset_db +do_execsql_test 7.0 { + CREATE TABLE t1(a, b, c, PRIMARY KEY(a COLLATE nocase, a)) WITHOUT ROWID; + INSERT INTO t1 VALUES(1, 2, 3); + INSERT INTO t1 VALUES(4, 5, 6); +} +do_execsql_test 7.1 { + ALTER TABLE t1 DROP COLUMN c; +} +do_execsql_test 7.2 { + SELECT sql FROM sqlite_schema; +} {{CREATE TABLE t1(a, b, PRIMARY KEY(a COLLATE nocase, a)) WITHOUT ROWID}} +do_execsql_test 7.3 { + SELECT * FROM t1; +} {1 2 4 5} + +reset_db +do_execsql_test 8.0 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b); + PRAGMA writable_schema = 1; + UPDATE sqlite_schema + SET sql = 'CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b)' +} +db close +sqlite3 db test.db +do_execsql_test 8.1 { + ALTER TABLE t1 DROP COLUMN b; +} +do_execsql_test 8.2 { + SELECT sql FROM sqlite_schema; +} {{CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT)}} + +#------------------------------------------------------------------------- + +foreach {tn wo} { + 1 {} + 2 {WITHOUT ROWID} +} { + reset_db + do_execsql_test 9.$tn.0 " + CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c) $wo; + " + do_execsql_test 9.$tn.1 { + WITH s(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<50000 + ) + INSERT INTO t1(a, b, c) SELECT i, 123, 456 FROM s; + } + do_execsql_test 9.$tn.2 { + ALTER TABLE t1 DROP COLUMN b; + } + + do_execsql_test 9.$tn.3 { + SELECT count(*), c FROM t1 GROUP BY c; + } {50000 456} +} + + + finish_test diff --git a/test/altermalloc3.test b/test/altermalloc3.test index d84f6bbc94..5e4e75149d 100644 --- a/test/altermalloc3.test +++ b/test/altermalloc3.test @@ -22,6 +22,14 @@ 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); } @@ -37,4 +45,3 @@ do_faultsim_test 1 -prep { finish_test - diff --git a/test/alterqf.test b/test/alterqf.test new file mode 100644 index 0000000000..ce00f3b596 --- /dev/null +++ b/test/alterqf.test @@ -0,0 +1,111 @@ +# 2021 March 16 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. This +# script focuses on testing internal function sqlite_rename_quotefix(). +# + + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix alterqf + +sqlite3_test_control SQLITE_TESTCTRL_INTERNAL_FUNCTIONS db + +do_execsql_test 1.0 { + CREATE TABLE t1(a, b, c); +} + +foreach {tn before after} { + 1 {CREATE VIEW v1 AS SELECT "a", "b", "notacolumn!", "c" FROM t1} + {CREATE VIEW v1 AS SELECT "a", "b", 'notacolumn!', "c" FROM t1} + + 2 {CREATE VIEW v1 AS SELECT "a", "b", "not'a'column!", "c" FROM t1} + {CREATE VIEW v1 AS SELECT "a", "b", 'not''a''column!', "c" FROM t1} + + 3 {CREATE VIEW v1 AS SELECT "a", "b", "not""a""column!", "c" FROM t1} + {CREATE VIEW v1 AS SELECT "a", "b", 'not"a"column!', "c" FROM t1} + + 4 {CREATE VIEW v1 AS SELECT "val", count("b") FROM t1 GROUP BY "abc"} + {CREATE VIEW v1 AS SELECT 'val', count("b") FROM t1 GROUP BY 'abc'} + + 5 {CREATE TABLE xyz(a CHECK (a!="str"), b AS (a||"str"))} + {CREATE TABLE xyz(a CHECK (a!='str'), b AS (a||'str'))} + + 6 {CREATE INDEX i1 ON t1(a || "str", "b", "val")} + {CREATE INDEX i1 ON t1(a || 'str', "b", 'val')} + + 7 {CREATE TRIGGER tr AFTER INSERT ON t1 BEGIN SELECT "abcd"; END} + {CREATE TRIGGER tr AFTER INSERT ON t1 BEGIN SELECT 'abcd'; END} + + 8 {CREATE VIEW v1 AS SELECT "string"'alias' FROM t1} + {CREATE VIEW v1 AS SELECT 'string' 'alias' FROM t1} + + 9 {CREATE INDEX i1 ON t1(a) WHERE "b"="bb"} + {CREATE INDEX i1 ON t1(a) WHERE "b"='bb'} + + 10 {CREATE TABLE t2(abc, xyz CHECK (xyz != "123"))} + {CREATE TABLE t2(abc, xyz CHECK (xyz != '123'))} + + 11 { + CREATE TRIGGER ott AFTER UPDATE ON t1 BEGIN + SELECT max("str", new."a") FROM t1 + WHERE group_concat("b", ",") OVER (ORDER BY c||"str"); + UPDATE t1 SET c= b + "str"; + DELETE FROM t1 WHERE EXISTS ( + SELECT 1 FROM t1 AS o WHERE o."a" = "o.a" AND t1.b IN("t1.b") + ); + END; + } { + CREATE TRIGGER ott AFTER UPDATE ON t1 BEGIN + SELECT max('str', new."a") FROM t1 + WHERE group_concat("b", ',') OVER (ORDER BY c||'str'); + UPDATE t1 SET c= b + 'str'; + DELETE FROM t1 WHERE EXISTS ( + SELECT 1 FROM t1 AS o WHERE o."a" = 'o.a' AND t1.b IN('t1.b') + ); + END; + } + +} { + do_execsql_test 1.$tn { + SELECT sqlite_rename_quotefix('main', $before) + } [list $after] +} + +#------------------------------------------------------------------------- +reset_db +do_execsql_test 2.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; +} + +do_execsql_test 2.1 { + ALTER TABLE x1 RENAME two TO 'four'; + SELECT sql FROM sqlite_schema; + SELECT sql FROM sqlite_temp_schema; +} {{CREATE TABLE x1( + one, "four", three, PRIMARY KEY(one), + CHECK (three!='xyz'), CHECK ("four"!="one") + ) WITHOUT ROWID} + {CREATE INDEX x1i ON x1(one+"four"+'four') WHERE 'five'} + {CREATE TRIGGER AFTER INSERT ON x1 BEGIN + UPDATE x1 SET "four"=new.three || 'new' WHERE one=new.one||''; + END} +} + + +finish_test diff --git a/test/altertab.test b/test/altertab.test index 0ed8fe5962..576d391ced 100644 --- a/test/altertab.test +++ b/test/altertab.test @@ -736,6 +736,67 @@ do_catchsql_test 24.2.1 { ALTER TABLE t1 RENAME TO t2; } {1 {error in trigger AFTER: no such table: main.nosuchtable}} +#-------------------------------------------------------------------------- +# +reset_db +do_execsql_test 25.1 { + CREATE TABLE xx(x); + CREATE VIEW v3(b) AS WITH b AS (SELECT b FROM (SELECT * FROM t2)) VALUES(1); +} + +ifcapable json1&&vtab { + do_catchsql_test 25.2 { + ALTER TABLE json_each RENAME TO t4; + } {1 {table json_each may not be altered}} +} + +# 2021-05-01 dbsqlfuzz bc17a306a09329bba0ecc61547077f6178bcf321 +# Remove a NEVER() inserted on 2019-12-09 that is reachable after all. +# +reset_db +do_execsql_test 26.1 { + CREATE TABLE t1(k,v); + CREATE TABLE t2_a(k,v); + CREATE VIEW t2 AS SELECT * FROM t2_a; + CREATE TRIGGER r2 AFTER INSERT ON t1 BEGIN + UPDATE t1 + SET (k,v)=((WITH cte1(a) AS (SELECT 1 FROM t2) SELECT t2.k FROM t2, cte1),1); + END; + ALTER TABLE t1 RENAME TO t1x; + INSERT INTO t2_a VALUES(2,3); + INSERT INTO t1x VALUES(98,99); + SELECT * FROM t1x; +} {2 1} + +#------------------------------------------------------------------------- +reset_db + +do_execsql_test 27.1 { + + create table t_sa ( + c_muyat INTEGER NOT NULL, + c_d4u TEXT + ); + + create table t2 ( abc ); + + CREATE TRIGGER trig AFTER DELETE ON t_sa + BEGIN + DELETE FROM t_sa WHERE ( + SELECT 123 FROM t2 + WINDOW oamat7fzf AS ( PARTITION BY t_sa.c_d4u ) + ); + END; +} + + +breakpoint +do_execsql_test 27.2 { + alter table t_sa rename column c_muyat to c_dg; +} + + + + finish_test - diff --git a/test/analyze3.test b/test/analyze3.test index 1f4a2722b0..7469c537c0 100644 --- a/test/analyze3.test +++ b/test/analyze3.test @@ -124,10 +124,10 @@ do_execsql_test analyze3-1.1.x { # do_eqp_test analyze3-1.1.2 { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 -} {SEARCH TABLE t1 USING INDEX i1 (x>? AND x? AND x0 AND x<1100 -} {SCAN TABLE t1} +} {SCAN t1} # 2017-06-26: Verify that the SQLITE_DBCONFIG_ENABLE_QPSG setting disables # the use of bound parameters by STAT4 @@ -137,27 +137,27 @@ unset -nocomplain l unset -nocomplain u do_eqp_test analyze3-1.1.3.100 { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u -} {SEARCH TABLE t1 USING INDEX i1 (x>? AND x? AND x$l AND x<$u -} {SEARCH TABLE t1 USING INDEX i1 (x>? AND x? AND x$l AND x<$u -} {SCAN TABLE t1} +} {SCAN t1} db cache flush sqlite3_db_config db ENABLE_QPSG 1 do_eqp_test analyze3-1.1.3.103 { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u -} {SEARCH TABLE t1 USING INDEX i1 (x>? AND x? AND x$l AND x<$u -} {SCAN TABLE t1} +} {SCAN t1} do_test analyze3-1.1.4 { sf_execsql { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 } @@ -207,10 +207,10 @@ do_execsql_test analyze3-2.1.x { } {200 990} do_eqp_test analyze3-1.2.2 { SELECT sum(y) FROM t2 WHERE x>1 AND x<2 -} {SEARCH TABLE t2 USING INDEX i2 (x>? AND x? AND x0 AND x<99 -} {SCAN TABLE t2} +} {SCAN t2} do_test analyze3-1.2.4 { sf_execsql { SELECT sum(y) FROM t2 WHERE x>12 AND x<20 } @@ -259,10 +259,10 @@ do_execsql_test analyze3-1.3.x { } {99 1000} do_eqp_test analyze3-1.3.2 { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 -} {SEARCH TABLE t3 USING INDEX i3 (x>? AND x? AND x0 AND x<1100 -} {SCAN TABLE t3} +} {SCAN t3} do_test analyze3-1.3.4 { sf_execsql { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 } @@ -314,10 +314,10 @@ do_test analyze3-2.1 { } {} do_eqp_test analyze3-2.2 { SELECT count(a) FROM t1 WHERE b LIKE 'a%' -} {SEARCH TABLE t1 USING INDEX i1 (b>? AND b? AND b 'w' AND c = 13; -} {SEARCH TABLE t1 USING INDEX i2 (c=?)} +} {SEARCH t1 USING INDEX i2 (c=?)} #----------------------------------------------------------------------------- # 2015-04-20. diff --git a/test/analyze4.test b/test/analyze4.test index 9fc98aa8f2..e3b0d23f6f 100644 --- a/test/analyze4.test +++ b/test/analyze4.test @@ -38,7 +38,7 @@ do_test analyze4-1.0 { # Should choose the t1a index since it is more specific than t1b. db eval {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=5 AND b IS NULL} -} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} +} {/*SEARCH t1 USING INDEX t1a (a=?)*/} # Verify that the t1b index shows that it does not narrow down the # search any at all. diff --git a/test/analyze6.test b/test/analyze6.test index b6353f2668..807fec132a 100644 --- a/test/analyze6.test +++ b/test/analyze6.test @@ -61,7 +61,7 @@ do_test analyze6-1.0 { # do_test analyze6-1.1 { eqp {SELECT count(*) FROM ev, cat WHERE x=y} -} {/*SCAN TABLE cat USING COVERING INDEX catx*SEARCH TABLE ev USING COVERING INDEX evy (y=?)*/} +} {/*SCAN cat USING COVERING INDEX catx*SEARCH ev USING COVERING INDEX evy (y=?)*/} # The same plan is chosen regardless of the order of the tables in the # FROM clause. @@ -70,8 +70,8 @@ do_eqp_test analyze6-1.2 { SELECT count(*) FROM cat, ev WHERE x=y } { QUERY PLAN - |--SCAN TABLE cat USING COVERING INDEX catx - `--SEARCH TABLE ev USING COVERING INDEX evy (y=?) + |--SCAN cat USING COVERING INDEX catx + `--SEARCH ev USING COVERING INDEX evy (y=?) } @@ -86,26 +86,26 @@ do_test analyze6-2.1 { ANALYZE; } eqp {SELECT * FROM t201 WHERE z=5} -} {/*SEARCH TABLE t201 USING INDEX t201z (z=?)*/} +} {/*SEARCH t201 USING INDEX t201z (z=?)*/} do_test analyze6-2.2 { eqp {SELECT * FROM t201 WHERE y=5} -} {/*SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?)*/} +} {/*SEARCH t201 USING INDEX sqlite_autoindex_t201_1 (y=?)*/} do_test analyze6-2.3 { eqp {SELECT * FROM t201 WHERE x=5} -} {/*SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?)*/} +} {/*SEARCH t201 USING INTEGER PRIMARY KEY (rowid=?)*/} do_test analyze6-2.4 { execsql { INSERT INTO t201 VALUES(1,2,3),(2,3,4),(3,4,5); ANALYZE t201; } eqp {SELECT * FROM t201 WHERE z=5} -} {/*SEARCH TABLE t201 USING INDEX t201z (z=?)*/} +} {/*SEARCH t201 USING INDEX t201z (z=?)*/} do_test analyze6-2.5 { eqp {SELECT * FROM t201 WHERE y=5} -} {/*SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?)*/} +} {/*SEARCH t201 USING INDEX sqlite_autoindex_t201_1 (y=?)*/} do_test analyze6-2.6 { eqp {SELECT * FROM t201 WHERE x=5} -} {/*SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?)*/} +} {/*SEARCH t201 USING INTEGER PRIMARY KEY (rowid=?)*/} do_test analyze6-2.7 { execsql { INSERT INTO t201 VALUES(4,5,7); @@ -115,12 +115,12 @@ do_test analyze6-2.7 { ANALYZE t201; } eqp {SELECT * FROM t201 WHERE z=5} -} {/*SEARCH TABLE t201 USING INDEX t201z (z=?)*/} +} {/*SEARCH t201 USING INDEX t201z (z=?)*/} do_test analyze6-2.8 { eqp {SELECT * FROM t201 WHERE y=5} -} {/*SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?)*/} +} {/*SEARCH t201 USING INDEX sqlite_autoindex_t201_1 (y=?)*/} do_test analyze6-2.9 { eqp {SELECT * FROM t201 WHERE x=5} -} {/*SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?)*/} +} {/*SEARCH t201 USING INTEGER PRIMARY KEY (rowid=?)*/} finish_test diff --git a/test/analyze7.test b/test/analyze7.test index b3dba02563..53a80f6419 100644 --- a/test/analyze7.test +++ b/test/analyze7.test @@ -37,13 +37,13 @@ do_test analyze7-1.0 { WHERE value BETWEEN 1 AND 256; EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123; } -} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} +} {/*SEARCH t1 USING INDEX t1a (a=?)*/} do_test analyze7-1.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;} -} {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/} +} {/*SEARCH t1 USING INDEX t1b (b=?)*/} do_test analyze7-1.2 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} -} {/*SEARCH TABLE t1 USING INDEX t1cd (c=?)*/} +} {/*SEARCH t1 USING INDEX t1cd (c=?)*/} # Run an analyze on one of the three indices. Verify that this # effects the row-count estimate on the one query that uses that @@ -53,20 +53,20 @@ do_test analyze7-2.0 { execsql {ANALYZE t1a;} db cache flush execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123;} -} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} +} {/*SEARCH t1 USING INDEX t1a (a=?)*/} do_test analyze7-2.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;} -} {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/} +} {/*SEARCH t1 USING INDEX t1b (b=?)*/} do_test analyze7-2.2 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} -} {/*SEARCH TABLE t1 USING INDEX t1cd (c=?)*/} +} {/*SEARCH t1 USING INDEX t1cd (c=?)*/} # Verify that since the query planner now things that t1a is more # selective than t1b, it prefers to use t1a. # do_test analyze7-2.3 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND b=123} -} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} +} {/*SEARCH t1 USING INDEX t1a (a=?)*/} # Run an analysis on another of the three indices. Verify that this # new analysis works and does not disrupt the previous analysis. @@ -75,40 +75,40 @@ do_test analyze7-3.0 { execsql {ANALYZE t1cd;} db cache flush; execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123;} -} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} +} {/*SEARCH t1 USING INDEX t1a (a=?)*/} do_test analyze7-3.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;} -} {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/} +} {/*SEARCH t1 USING INDEX t1b (b=?)*/} do_test analyze7-3.2.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=?;} -} {/*SEARCH TABLE t1 USING INDEX t1cd (c=?)*/} +} {/*SEARCH t1 USING INDEX t1cd (c=?)*/} ifcapable stat4 { # If ENABLE_STAT4 is defined, SQLite comes up with a different estimated # row count for (c=2) than it does for (c=?). do_test analyze7-3.2.2 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} - } {/*SEARCH TABLE t1 USING INDEX t1cd (c=?)*/} + } {/*SEARCH t1 USING INDEX t1cd (c=?)*/} } else { # If ENABLE_STAT4 is not defined, the expected row count for (c=2) is the # same as that for (c=?). do_test analyze7-3.2.3 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} - } {/*SEARCH TABLE t1 USING INDEX t1cd (c=?)*/} + } {/*SEARCH t1 USING INDEX t1cd (c=?)*/} } do_test analyze7-3.3 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND b=123} -} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} +} {/*SEARCH t1 USING INDEX t1a (a=?)*/} ifcapable {!stat4} { do_test analyze7-3.4 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND b=123} - } {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/} + } {/*SEARCH t1 USING INDEX t1b (b=?)*/} do_test analyze7-3.5 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND c=123} - } {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} + } {/*SEARCH t1 USING INDEX t1a (a=?)*/} } do_test analyze7-3.6 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND d=123 AND b=123} -} {/*SEARCH TABLE t1 USING INDEX t1cd (c=? AND d=?)*/} +} {/*SEARCH t1 USING INDEX t1cd (c=? AND d=?)*/} finish_test diff --git a/test/analyze8.test b/test/analyze8.test index 7c61652e51..69605fd6f7 100644 --- a/test/analyze8.test +++ b/test/analyze8.test @@ -61,25 +61,25 @@ do_test 1.0 { # do_test 1.1 { eqp {SELECT * FROM t1 WHERE a=100 AND b=55} -} {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/} +} {/*SEARCH t1 USING INDEX t1b (b=?)*/} do_test 1.2 { eqp {SELECT * FROM t1 WHERE a=99 AND b=55} -} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} +} {/*SEARCH t1 USING INDEX t1a (a=?)*/} do_test 1.3 { eqp {SELECT * FROM t1 WHERE a=101 AND b=55} -} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} +} {/*SEARCH t1 USING INDEX t1a (a=?)*/} do_test 1.4 { eqp {SELECT * FROM t1 WHERE a=100 AND b=56} -} {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/} +} {/*SEARCH t1 USING INDEX t1b (b=?)*/} do_test 1.5 { eqp {SELECT * FROM t1 WHERE a=99 AND b=56} -} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} +} {/*SEARCH t1 USING INDEX t1a (a=?)*/} do_test 1.6 { eqp {SELECT * FROM t1 WHERE a=101 AND b=56} -} {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} +} {/*SEARCH t1 USING INDEX t1a (a=?)*/} do_test 2.1 { eqp {SELECT * FROM t1 WHERE a=100 AND b BETWEEN 50 AND 54} -} {/*SEARCH TABLE t1 USING INDEX t1b (b>? AND b? AND b? AND b? AND b? AND c? AND c? AND c? AND c? AND b? AND b=? term. Better than # (a<20) but not as good as (a<10). do_eqp_test 25.4.1 { SELECT * FROM t6 WHERE a < 10 AND (b BETWEEN ? AND 60) - } {SEARCH TABLE t6 USING INDEX aa (a? AND b? AND b25 AND z=?; -} {SEARCH TABLE t1 USING INDEX i1 (x=? AND y>?)} +} {SEARCH t1 USING INDEX i1 (x=? AND y>?)} finish_test diff --git a/test/analyzeC.test b/test/analyzeC.test index 2a0a897810..2f43d57a1e 100644 --- a/test/analyzeC.test +++ b/test/analyzeC.test @@ -50,7 +50,7 @@ do_execsql_test 1.2 { do_execsql_test 1.3 { EXPLAIN QUERY PLAN SELECT c FROM t1 ORDER BY a; -} {/.*SCAN TABLE t1 USING INDEX t1a.*/} +} {/.*SCAN t1 USING INDEX t1a.*/} do_execsql_test 1.3x { EXPLAIN QUERY PLAN SELECT c FROM t1 ORDER BY a; diff --git a/test/analyzeD.test b/test/analyzeD.test index 9c7ed7586d..7a51785a1c 100644 --- a/test/analyzeD.test +++ b/test/analyzeD.test @@ -63,7 +63,7 @@ do_test 1.1 { # do_eqp_test 1.2 { SELECT * FROM t1 WHERE a=3001 AND c=150; -} {SEARCH TABLE t1 USING INDEX t1_c (c=?)} +} {SEARCH t1 USING INDEX t1_c (c=?)} do_test 1.3 { execsql { DELETE FROM sqlite_stat1 } @@ -78,7 +78,7 @@ do_test 1.3 { # do_eqp_test 1.4 { SELECT * FROM t1 WHERE a=3001 AND c=150; -} {SEARCH TABLE t1 USING INDEX t1_ab (a=?)} +} {SEARCH t1 USING INDEX t1_ab (a=?)} do_test 1.5 { execsql { @@ -89,7 +89,7 @@ do_test 1.5 { do_eqp_test 1.6 { SELECT * FROM t1 WHERE a=13 AND c=150; -} {SEARCH TABLE t1 USING INDEX t1_c (c=?)} +} {SEARCH t1 USING INDEX t1_c (c=?)} do_test 1.7 { execsql { DELETE FROM sqlite_stat1 } @@ -102,6 +102,6 @@ do_test 1.7 { # gets this right, even without stat1 data. do_eqp_test 1.8 { SELECT * FROM t1 WHERE a=13 AND c=150; -} {SEARCH TABLE t1 USING INDEX t1_c (c=?)} +} {SEARCH t1 USING INDEX t1_c (c=?)} finish_test diff --git a/test/analyzeE.test b/test/analyzeE.test index 66db1e122c..733b79367f 100644 --- a/test/analyzeE.test +++ b/test/analyzeE.test @@ -36,47 +36,47 @@ do_execsql_test analyzeE-1.0 { do_execsql_test analyzeE-1.1 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 500 AND 2500; -} {/SCAN TABLE t1/} +} {/SCAN t1/} do_execsql_test analyzeE-1.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 2900 AND 3000; -} {/SEARCH TABLE t1 USING INDEX t1a/} +} {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-1.3 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 1700 AND 1750; -} {/SEARCH TABLE t1 USING INDEX t1a/} +} {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-1.4 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 1 AND 500 -} {/SEARCH TABLE t1 USING INDEX t1a/} +} {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-1.5 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 3000 AND 3000000 -} {/SEARCH TABLE t1 USING INDEX t1a/} +} {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-1.6 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<500 -} {/SEARCH TABLE t1 USING INDEX t1a/} +} {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-1.7 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>2500 -} {/SEARCH TABLE t1 USING INDEX t1a/} +} {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-1.8 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1900 -} {/SEARCH TABLE t1 USING INDEX t1a/} +} {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-1.9 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1100 -} {/SCAN TABLE t1/} +} {/SCAN t1/} do_execsql_test analyzeE-1.10 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1100 -} {/SEARCH TABLE t1 USING INDEX t1a/} +} {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-1.11 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1900 -} {/SCAN TABLE t1/} +} {/SCAN t1/} # Verify that everything works the same on a DESCENDING index. # @@ -88,47 +88,47 @@ do_execsql_test analyzeE-2.0 { do_execsql_test analyzeE-2.1 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 500 AND 2500; -} {/SCAN TABLE t1/} +} {/SCAN t1/} do_execsql_test analyzeE-2.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 2900 AND 3000; -} {/SEARCH TABLE t1 USING INDEX t1a/} +} {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-2.3 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 1700 AND 1750; -} {/SEARCH TABLE t1 USING INDEX t1a/} +} {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-2.4 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 1 AND 500 -} {/SEARCH TABLE t1 USING INDEX t1a/} +} {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-2.5 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 3000 AND 3000000 -} {/SEARCH TABLE t1 USING INDEX t1a/} +} {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-2.6 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<500 -} {/SEARCH TABLE t1 USING INDEX t1a/} +} {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-2.7 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>2500 -} {/SEARCH TABLE t1 USING INDEX t1a/} +} {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-2.8 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1900 -} {/SEARCH TABLE t1 USING INDEX t1a/} +} {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-2.9 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1100 -} {/SCAN TABLE t1/} +} {/SCAN t1/} do_execsql_test analyzeE-2.10 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1100 -} {/SEARCH TABLE t1 USING INDEX t1a/} +} {/SEARCH t1 USING INDEX t1a/} do_execsql_test analyzeE-2.11 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1900 -} {/SCAN TABLE t1/} +} {/SCAN t1/} # Now do a range query on the second term of an ASCENDING index # where the first term is constrained by equality. @@ -145,47 +145,47 @@ do_execsql_test analyzeE-3.0 { do_execsql_test analyzeE-3.1 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 500 AND 2500 AND c=123; -} {/SCAN TABLE t1/} +} {/SCAN t1/} do_execsql_test analyzeE-3.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 2900 AND 3000 AND c=123; -} {/SEARCH TABLE t1 USING INDEX t1ca/} +} {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-3.3 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 1700 AND 1750 AND c=123; -} {/SEARCH TABLE t1 USING INDEX t1ca/} +} {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-3.4 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 1 AND 500 AND c=123 -} {/SEARCH TABLE t1 USING INDEX t1ca/} +} {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-3.5 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 3000 AND 3000000 AND c=123 -} {/SEARCH TABLE t1 USING INDEX t1ca/} +} {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-3.6 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<500 AND c=123 -} {/SEARCH TABLE t1 USING INDEX t1ca/} +} {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-3.7 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>2500 AND c=123 -} {/SEARCH TABLE t1 USING INDEX t1ca/} +} {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-3.8 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1900 AND c=123 -} {/SEARCH TABLE t1 USING INDEX t1ca/} +} {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-3.9 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1100 AND c=123 -} {/SCAN TABLE t1/} +} {/SCAN t1/} do_execsql_test analyzeE-3.10 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1100 AND c=123 -} {/SEARCH TABLE t1 USING INDEX t1ca/} +} {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-3.11 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1900 AND c=123 -} {/SCAN TABLE t1/} +} {/SCAN t1/} # Repeat the 3.x tests using a DESCENDING index # @@ -197,46 +197,46 @@ do_execsql_test analyzeE-4.0 { do_execsql_test analyzeE-4.1 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 500 AND 2500 AND c=123; -} {/SCAN TABLE t1/} +} {/SCAN t1/} do_execsql_test analyzeE-4.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 2900 AND 3000 AND c=123; -} {/SEARCH TABLE t1 USING INDEX t1ca/} +} {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-4.3 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 1700 AND 1750 AND c=123; -} {/SEARCH TABLE t1 USING INDEX t1ca/} +} {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-4.4 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 1 AND 500 AND c=123 -} {/SEARCH TABLE t1 USING INDEX t1ca/} +} {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-4.5 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 3000 AND 3000000 AND c=123 -} {/SEARCH TABLE t1 USING INDEX t1ca/} +} {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-4.6 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<500 AND c=123 -} {/SEARCH TABLE t1 USING INDEX t1ca/} +} {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-4.7 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>2500 AND c=123 -} {/SEARCH TABLE t1 USING INDEX t1ca/} +} {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-4.8 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1900 AND c=123 -} {/SEARCH TABLE t1 USING INDEX t1ca/} +} {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-4.9 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1100 AND c=123 -} {/SCAN TABLE t1/} +} {/SCAN t1/} do_execsql_test analyzeE-4.10 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1100 AND c=123 -} {/SEARCH TABLE t1 USING INDEX t1ca/} +} {/SEARCH t1 USING INDEX t1ca/} do_execsql_test analyzeE-4.11 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1900 AND c=123 -} {/SCAN TABLE t1/} +} {/SCAN t1/} finish_test diff --git a/test/analyzeF.test b/test/analyzeF.test index 143cecdf57..00107993eb 100644 --- a/test/analyzeF.test +++ b/test/analyzeF.test @@ -62,7 +62,7 @@ foreach {tn where idx} { 11 "x = nullif('19', 0) AND y = nullif('4', 0)" {t1y (y=?)} 12 "x = nullif('4', 0) AND y = nullif('19', 0)" {t1y (y=?)} } { - set res "SEARCH TABLE t1 USING INDEX $idx" + set res "SEARCH t1 USING INDEX $idx" do_eqp_test 1.$tn "SELECT * FROM t1 WHERE $where" $res } @@ -92,7 +92,7 @@ foreach {tn where idx} { 3 "x = nondet4() AND y = nondet19()" {t1y (y=?)} 4 "x = nondet19() AND y = nondet4()" {t1y (y=?)} } { - set res "SEARCH TABLE t1 USING INDEX $idx" + set res "SEARCH t1 USING INDEX $idx" do_eqp_test 3.$tn "SELECT * FROM t1 WHERE $where" $res } diff --git a/test/analyzeG.test b/test/analyzeG.test index eb1853b1dc..ca65bc3b96 100644 --- a/test/analyzeG.test +++ b/test/analyzeG.test @@ -20,16 +20,6 @@ ifcapable !stat4 { } set testprefix analyzeG -proc do_scan_order_test {tn sql expect} { - uplevel [list do_test $tn [subst -nocommands { - set res "" - db eval "explain query plan $sql" { - lappend res [set detail] - } - set res - }] [list {*}$expect]] -} - #------------------------------------------------------------------------- # Test cases 1.* seek to verify that even if an index is not used, its # stat4 data may be used by the planner to estimate the number of @@ -54,15 +44,17 @@ do_execsql_test 1.0 { # know this, so it has no preference as to which order the tables are # scanned in. In practice this means that tables are scanned in the order # they are specified in in the FROM clause. -do_scan_order_test 1.1.1 { +do_eqp_test 1.1.1 { SELECT * FROM t1, t2 WHERE a=44 AND b=44; } { - {SCAN TABLE t1} {SCAN TABLE t2} + } -do_scan_order_test 1.1.2 { +do_eqp_test 1.1.2 { SELECT * FROM t2, t1 WHERE a=44 AND b=44 } { - {SCAN TABLE t2} {SCAN TABLE t1} + QUERY PLAN + |--SCAN t2 + `--SCAN t1 } do_execsql_test 1.2 { @@ -73,15 +65,19 @@ do_execsql_test 1.2 { # Now, with the ANALYZE data, the planner knows that (b=44) matches a # large number of rows. So it elects to scan table "t1" first, regardless # of the order in which the tables are specified in the FROM clause. -do_scan_order_test 1.3.1 { +do_eqp_test 1.3.1 { SELECT * FROM t1, t2 WHERE a=44 AND b=44; } { - {SCAN TABLE t1} {SCAN TABLE t2} + QUERY PLAN + |--SCAN t1 + `--SCAN t2 } -do_scan_order_test 1.3.2 { +do_eqp_test 1.3.2 { SELECT * FROM t2, t1 WHERE a=44 AND b=44 } { - {SCAN TABLE t1} {SCAN TABLE t2} + QUERY PLAN + |--SCAN t1 + `--SCAN t2 } diff --git a/test/attach4.test b/test/attach4.test index 87911814a0..9d54e7df57 100644 --- a/test/attach4.test +++ b/test/attach4.test @@ -135,4 +135,3 @@ do_execsql_test 2.2 { } finish_test - diff --git a/test/autoindex1.test b/test/autoindex1.test index b08f8cfeb6..6b437f1867 100644 --- a/test/autoindex1.test +++ b/test/autoindex1.test @@ -183,18 +183,18 @@ do_eqp_test autoindex1-500.1 { WHERE t501.a IN (SELECT x FROM t502 WHERE y=?); } { QUERY PLAN - |--SEARCH TABLE t501 USING INTEGER PRIMARY KEY (rowid=?) + |--SEARCH t501 USING INTEGER PRIMARY KEY (rowid=?) `--LIST SUBQUERY xxxxxx - `--SCAN TABLE t502 + `--SCAN t502 } do_eqp_test autoindex1-501 { SELECT b FROM t501 WHERE t501.a IN (SELECT x FROM t502 WHERE y=t501.b); } { QUERY PLAN - |--SCAN TABLE t501 + |--SCAN t501 `--CORRELATED LIST SUBQUERY xxxxxx - `--SEARCH TABLE t502 USING AUTOMATIC COVERING INDEX (y=?) + `--SEARCH t502 USING AUTOMATIC COVERING INDEX (y=?) } do_eqp_test autoindex1-502 { SELECT b FROM t501 @@ -202,9 +202,9 @@ do_eqp_test autoindex1-502 { AND t501.a IN (SELECT x FROM t502 WHERE y=t501.b); } { QUERY PLAN - |--SEARCH TABLE t501 USING INTEGER PRIMARY KEY (rowid=?) + |--SEARCH t501 USING INTEGER PRIMARY KEY (rowid=?) `--CORRELATED LIST SUBQUERY xxxxxx - `--SCAN TABLE t502 + `--SCAN t502 } # The following code checks a performance regression reported on the @@ -277,13 +277,13 @@ do_eqp_test autoindex1-600a { ORDER BY x.registering_flock; } { QUERY PLAN - |--MATERIALIZE xxxxxx - | |--SCAN TABLE sheep AS s - | |--SEARCH TABLE flock_owner AS prev USING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date? AND owner_change_date? AND owner_change_date?) -# 0|1|0|SEARCH TABLE u USING COVERING INDEX uab (ANY(a) AND b=?) +# 0|0|1|SEARCH v USING INDEX ve (e>?) +# 0|1|0|SEARCH u USING COVERING INDEX uab (ANY(a) AND b=?) # # on the basis that the real index "uab" must be better than the automatic # index. This is not right - a skip-scan is not necessarily better than an @@ -85,8 +85,8 @@ do_eqp_test 220 { select count(*) from u, v where u.b = v.b and v.e > 34; } { QUERY PLAN - |--SEARCH TABLE v USING INDEX ve (e>?) - `--SEARCH TABLE u USING AUTOMATIC COVERING INDEX (b=?) + |--SEARCH v USING INDEX ve (e>?) + `--SEARCH u USING AUTOMATIC COVERING INDEX (b=?) } diff --git a/test/autoindex5.test b/test/autoindex5.test index 94e220328c..36695d7f74 100644 --- a/test/autoindex5.test +++ b/test/autoindex5.test @@ -102,7 +102,7 @@ do_eqp_test autoindex5-1.1 { AND ( sp.release = 'sid' OR sp.release = 'stretch' OR sp.release = 'jessie' OR sp.release = 'wheezy' OR sp.release = 'squeeze' ) ORDER BY sp.name, st.bug_name, sp.release, sp.subrelease; -} {SEARCH SUBQUERY * USING AUTOMATIC COVERING INDEX (bug_name=?)} +} {SEARCH debian_cve USING AUTOMATIC COVERING INDEX (bug_name=?)} #------------------------------------------------------------------------- # Test that ticket [8a2adec1] has been fixed. @@ -123,7 +123,7 @@ do_execsql_test 2.1 { SELECT sum(z) FROM vvv WHERE x='aaa' ) FROM one; } {8.0} -do_execsql_test 2.2 { +do_catchsql_test 2.2 { DROP TABLE t1; CREATE TABLE t1(aaa); INSERT INTO t1(aaa) VALUES(9); @@ -136,7 +136,7 @@ do_execsql_test 2.2 { ) WHERE bbb = 1 ) ); -} {9} +} {1 {no such column: rowid}} # Ticket https://www.sqlite.org/src/info/787fa716be3a7f65 # Segfault due to multiple uses of the same subquery where the diff --git a/test/bestindex1.test b/test/bestindex1.test index b97af11140..0d69469943 100644 --- a/test/bestindex1.test +++ b/test/bestindex1.test @@ -51,11 +51,11 @@ do_execsql_test 1.0 { do_eqp_test 1.1 { SELECT * FROM x1 WHERE a = 'abc' -} {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:eq!} +} {SCAN x1 VIRTUAL TABLE INDEX 555:eq!} do_eqp_test 1.2 { SELECT * FROM x1 WHERE a IN ('abc', 'def'); -} {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:eq!} +} {SCAN x1 VIRTUAL TABLE INDEX 555:eq!} #------------------------------------------------------------------------- # @@ -141,17 +141,17 @@ foreach {tn mode} { set plan(use) { QUERY PLAN - |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%' + |--SCAN t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%' `--USE TEMP B-TREE FOR ORDER BY } set plan(omit) { QUERY PLAN - |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%' + |--SCAN t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%' `--USE TEMP B-TREE FOR ORDER BY } set plan(use2) { QUERY PLAN - |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x + |--SCAN t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x `--USE TEMP B-TREE FOR ORDER BY } diff --git a/test/bestindex2.test b/test/bestindex2.test index c17665f6f5..81ed9ebf61 100644 --- a/test/bestindex2.test +++ b/test/bestindex2.test @@ -89,40 +89,40 @@ do_execsql_test 1.0 { do_eqp_test 1.1 { SELECT * FROM t1 WHERE a='abc' -} {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=?)} +} {SCAN t1 VIRTUAL TABLE INDEX 0:indexed(a=?)} do_eqp_test 1.2 { SELECT * FROM t1 WHERE a='abc' AND b='def' -} {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=? AND b=?)} +} {SCAN t1 VIRTUAL TABLE INDEX 0:indexed(a=? AND b=?)} do_eqp_test 1.3 { SELECT * FROM t1 WHERE a='abc' AND a='def' -} {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=?)} +} {SCAN t1 VIRTUAL TABLE INDEX 0:indexed(a=?)} do_eqp_test 1.4 { SELECT * FROM t1,t2 WHERE c=a } { QUERY PLAN - |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0: - `--SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?) + |--SCAN t1 VIRTUAL TABLE INDEX 0: + `--SCAN t2 VIRTUAL TABLE INDEX 0:indexed(c=?) } do_eqp_test 1.5 { SELECT * FROM t1, t2 CROSS JOIN t3 WHERE t2.c = +t1.b AND t3.e=t2.d } { QUERY PLAN - |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0: - |--SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?) - `--SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?) + |--SCAN t1 VIRTUAL TABLE INDEX 0: + |--SCAN t2 VIRTUAL TABLE INDEX 0:indexed(c=?) + `--SCAN t3 VIRTUAL TABLE INDEX 0:indexed(e=?) } do_eqp_test 1.6 { SELECT * FROM t1, t2, t3 WHERE t2.c = +t1.b AND t3.e = t2.d } { QUERY PLAN - |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0: - |--SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?) - `--SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?) + |--SCAN t1 VIRTUAL TABLE INDEX 0: + |--SCAN t2 VIRTUAL TABLE INDEX 0:indexed(c=?) + `--SCAN t3 VIRTUAL TABLE INDEX 0:indexed(e=?) } do_execsql_test 1.7.1 { @@ -133,10 +133,10 @@ do_eqp_test 1.7.2 { WHERE t1.a = t2.c AND t1.b = t3.e } { QUERY PLAN - |--SCAN TABLE x1 - |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0: - |--SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?) - `--SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?) + |--SCAN x1 + |--SCAN t1 VIRTUAL TABLE INDEX 0: + |--SCAN t2 VIRTUAL TABLE INDEX 0:indexed(c=?) + `--SCAN t3 VIRTUAL TABLE INDEX 0:indexed(e=?) } finish_test diff --git a/test/bestindex3.test b/test/bestindex3.test index 80038e2855..1ee3975f8b 100644 --- a/test/bestindex3.test +++ b/test/bestindex3.test @@ -79,11 +79,11 @@ do_execsql_test 1.0 { do_eqp_test 1.1 { SELECT * FROM t1 WHERE a LIKE 'abc'; -} {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ?} +} {SCAN t1 VIRTUAL TABLE INDEX 0:a LIKE ?} do_eqp_test 1.2 { SELECT * FROM t1 WHERE a = 'abc'; -} {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a EQ ?} +} {SCAN t1 VIRTUAL TABLE INDEX 0:a EQ ?} do_eqp_test 1.3 { SELECT * FROM t1 WHERE a = 'abc' OR b = 'def'; @@ -91,9 +91,9 @@ do_eqp_test 1.3 { QUERY PLAN `--MULTI-INDEX OR |--INDEX 1 - | `--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a EQ ? + | `--SCAN t1 VIRTUAL TABLE INDEX 0:a EQ ? `--INDEX 2 - `--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ? + `--SCAN t1 VIRTUAL TABLE INDEX 0:b EQ ? } do_eqp_test 1.4 { @@ -102,9 +102,9 @@ do_eqp_test 1.4 { QUERY PLAN `--MULTI-INDEX OR |--INDEX 1 - | `--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ? + | `--SCAN t1 VIRTUAL TABLE INDEX 0:a LIKE ? `--INDEX 2 - `--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ? + `--SCAN t1 VIRTUAL TABLE INDEX 0:b EQ ? } do_execsql_test 1.5 { @@ -155,9 +155,9 @@ ifcapable !icu { QUERY PLAN `--MULTI-INDEX OR |--INDEX 1 - | `--SEARCH TABLE t2 USING INDEX t2x (x>? AND x? AND x? AND b? AND b? AND x? AND x? AND b? AND b? AND b? AND b=0} + } $use_eph + + do_execsql_test 3.$tn.2 $sql $res +} + +do_execsql_test 3.10 { + SELECT a, count(DISTINCT b) FROM t1 GROUP BY a; +} { + 1 1 2 2 3 2 4 1 5 2 +} + +#-------------------------------------------------------------------------- +reset_db +do_execsql_test 3.0 { + CREATE TABLE t1(a, b, c); + CREATE INDEX t1a ON t1(a); + CREATE INDEX t1bc ON t1(b, c); + + INSERT INTO t1 VALUES(1, 'A', 1); + INSERT INTO t1 VALUES(1, 'A', 1); + INSERT INTO t1 VALUES(2, 'A', 2); + INSERT INTO t1 VALUES(2, 'A', 2); + INSERT INTO t1 VALUES(1, 'B', 1); + INSERT INTO t1 VALUES(2, 'B', 2); + INSERT INTO t1 VALUES(3, 'B', 3); + INSERT INTO t1 VALUES(NULL, 'B', NULL); + INSERT INTO t1 VALUES(NULL, 'C', NULL); + INSERT INTO t1 VALUES('d', 'D', 'd'); + + CREATE TABLE t2(d, e, f); + CREATE INDEX t2def ON t2(d, e, f); + + INSERT INTO t2 VALUES(1, 1, 'a'); + INSERT INTO t2 VALUES(1, 1, 'a'); + INSERT INTO t2 VALUES(1, 2, 'a'); + INSERT INTO t2 VALUES(1, 2, 'a'); + INSERT INTO t2 VALUES(1, 2, 'b'); + INSERT INTO t2 VALUES(1, 3, 'b'); + INSERT INTO t2 VALUES(1, 3, 'a'); + INSERT INTO t2 VALUES(1, 3, 'b'); + INSERT INTO t2 VALUES(2, 3, 'x'); + INSERT INTO t2 VALUES(2, 3, 'y'); + INSERT INTO t2 VALUES(2, 3, 'z'); + + CREATE TABLE t3(x, y, z); + INSERT INTO t3 VALUES(1,1,1); + INSERT INTO t3 VALUES(2,2,2); +} + +foreach {tn use_eph sql res} { + 1 0 "SELECT count(DISTINCT c) FROM t1 GROUP BY b" {2 3 0 1} + 2 1 "SELECT count(DISTINCT a) FROM t1 GROUP BY b" {2 3 0 1} + 3 1 "SELECT count(DISTINCT a) FROM t1 GROUP BY b+c" {0 1 1 1 1} + + 4 0 "SELECT count(DISTINCT f) FROM t2 GROUP BY d, e" {1 2 2 3} + 5 1 "SELECT count(DISTINCT f) FROM t2 GROUP BY d" {2 3} + 6 0 "SELECT count(DISTINCT f) FROM t2 WHERE d IS 1 GROUP BY e" {1 2 2} +} { + do_test 4.$tn.1 { + set prg [db eval "EXPLAIN $sql"] + set idx [lsearch $prg OpenEphemeral] + expr {$idx>=0} + } $use_eph + + do_execsql_test 4.$tn.2 $sql $res +} + + +set t3root [db one {SELECT rootpage FROM sqlite_schema WHERE name='t3'}] +foreach {tn use_t3 sql res} { + 1 1 "SELECT count(*) FROM t3" 2 + 2 0 "SELECT count(*) FROM t1" 10 + 2 1 "SELECT count(DISTINCT a) FROM t1, t3" 4 + 3 1 "SELECT count(DISTINCT a) FROM t1 LEFT JOIN t3" 4 + 4 1 "SELECT count(DISTINCT a) FROM t1 LEFT JOIN t3 WHERE t3.x=1" 4 + 5 1 "SELECT count(DISTINCT a) FROM t1 LEFT JOIN t3 WHERE t3.x=0" 0 + 6 1 "SELECT count(DISTINCT a) FROM t1 LEFT JOIN t3 ON (t3.x=0)" 4 + 7 1 "SELECT count(DISTINCT x) FROM t1 LEFT JOIN t3" 2 + 8 1 "SELECT count(DISTINCT x) FROM t1 LEFT JOIN t3 WHERE t3.x=1" 1 + 9 1 "SELECT count(DISTINCT x) FROM t1 LEFT JOIN t3 WHERE t3.x=0" 0 + 10 1 "SELECT count(DISTINCT x) FROM t1 LEFT JOIN t3 ON (t3.x=0)" 0 + +} { + do_test 5.$tn.1 { + set bUse 0 + db eval "EXPLAIN $sql" a { + if {$a(opcode)=="OpenRead" && $a(p2)==$t3root} {set bUse 1} + } + set bUse + } $use_t3 + + do_execsql_test 5.$tn.2 $sql $res +} + +#------------------------------------------------------------------------- +reset_db +do_execsql_test 6.0 { + CREATE TABLE t1(a, b); + CREATE TABLE t2(c, d); + INSERT INTO t1 VALUES(123,456); + INSERT INTO t2 VALUES(123,456); +} +do_execsql_test 6.1 { + SELECT count(DISTINCT c) FROM t1 LEFT JOIN t2; +} {1} + +do_execsql_test 7.0 { + CREATE TABLE v1 ( v2 UNIQUE, v3 AS( TYPEOF ( NULL ) ) UNIQUE ); + SELECT COUNT ( DISTINCT TRUE ) FROM v1 GROUP BY likelihood ( v3 , 0.100000 ); +} + + finish_test + diff --git a/test/e_createtable.test b/test/e_createtable.test index e83e5cca1c..c2cd1bc2c1 100644 --- a/test/e_createtable.test +++ b/test/e_createtable.test @@ -1393,13 +1393,13 @@ do_execsql_test 4.10.0 { } do_createtable_tests 4.10 { 1 "EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b = 5" - {/*SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (b=?)*/} + {/*SEARCH t1 USING INDEX sqlite_autoindex_t1_1 (b=?)*/} 2 "EXPLAIN QUERY PLAN SELECT * FROM t2 ORDER BY b, c" - {/*SCAN TABLE t2 USING INDEX sqlite_autoindex_t2_1*/} + {/*SCAN t2 USING INDEX sqlite_autoindex_t2_1*/} 3 "EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE b=10 AND c>10" - {/*SEARCH TABLE t2 USING INDEX sqlite_autoindex_t2_1 (b=? AND c>?)*/} + {/*SEARCH t2 USING INDEX sqlite_autoindex_t2_1 (b=? AND c>?)*/} } # EVIDENCE-OF: R-45493-35653 A CHECK constraint may be attached to a diff --git a/test/e_fkey.test b/test/e_fkey.test index 40fa075df3..e5eb0d49c1 100644 --- a/test/e_fkey.test +++ b/test/e_fkey.test @@ -992,15 +992,15 @@ do_detail_test e_fkey-25.2 { EXPLAIN QUERY PLAN DELETE FROM artist WHERE 1; EXPLAIN QUERY PLAN SELECT rowid FROM track WHERE trackartist = ?; } { - {SCAN TABLE artist} - {SCAN TABLE track} + {SCAN artist} + {SCAN track} } do_detail_test e_fkey-25.3 { PRAGMA foreign_keys = ON; EXPLAIN QUERY PLAN DELETE FROM artist WHERE 1; } { - {SCAN TABLE artist} - {SCAN TABLE track} + {SCAN artist} + {SCAN track} } do_test e_fkey-25.4 { execsql { @@ -1117,15 +1117,15 @@ do_test e_fkey-27.2 { do_detail_test e_fkey-27.3 { EXPLAIN QUERY PLAN UPDATE artist SET artistid = ?, artistname = ? } { - {SCAN TABLE artist} - {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)} - {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)} + {SCAN artist} + {SEARCH track USING COVERING INDEX trackindex (trackartist=?)} + {SEARCH track USING COVERING INDEX trackindex (trackartist=?)} } do_detail_test e_fkey-27.4 { EXPLAIN QUERY PLAN DELETE FROM artist } { - {SCAN TABLE artist} - {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)} + {SCAN artist} + {SEARCH track USING COVERING INDEX trackindex (trackartist=?)} } ########################################################################### diff --git a/test/eqp.test b/test/eqp.test index f931f8f340..19d6ea91ae 100644 --- a/test/eqp.test +++ b/test/eqp.test @@ -46,111 +46,131 @@ do_eqp_test 1.2 { QUERY PLAN |--MULTI-INDEX OR | |--INDEX 1 - | | `--SEARCH TABLE t1 USING INDEX i1 (a=?) + | | `--SEARCH t1 USING INDEX i1 (a=?) | `--INDEX 2 - | `--SEARCH TABLE t1 USING INDEX i2 (b=?) - `--SCAN TABLE t2 + | `--SEARCH t1 USING INDEX i2 (b=?) + `--SCAN t2 } do_eqp_test 1.3 { SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a=1 OR t1.b=2; } { QUERY PLAN - |--SCAN TABLE t2 + |--SCAN t2 `--MULTI-INDEX OR |--INDEX 1 - | `--SEARCH TABLE t1 USING INDEX i1 (a=?) + | `--SEARCH t1 USING INDEX i1 (a=?) `--INDEX 2 - `--SEARCH TABLE t1 USING INDEX i2 (b=?) + `--SEARCH t1 USING INDEX i2 (b=?) } do_eqp_test 1.3 { SELECT a FROM t1 ORDER BY a } { QUERY PLAN - `--SCAN TABLE t1 USING COVERING INDEX i1 + `--SCAN t1 USING COVERING INDEX i1 } do_eqp_test 1.4 { SELECT a FROM t1 ORDER BY +a } { QUERY PLAN - |--SCAN TABLE t1 USING COVERING INDEX i1 + |--SCAN t1 USING COVERING INDEX i1 `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 1.5 { SELECT a FROM t1 WHERE a=4 } { QUERY PLAN - `--SEARCH TABLE t1 USING COVERING INDEX i1 (a=?) + `--SEARCH t1 USING COVERING INDEX i1 (a=?) } do_eqp_test 1.6 { SELECT DISTINCT count(*) FROM t3 GROUP BY a; } { QUERY PLAN - |--SCAN TABLE t3 + |--SCAN t3 |--USE TEMP B-TREE FOR GROUP BY `--USE TEMP B-TREE FOR DISTINCT } -do_eqp_test 1.7 { +do_eqp_test 1.7.1 { SELECT * FROM t3 JOIN (SELECT 1) } { QUERY PLAN - |--MATERIALIZE xxxxxx + |--MATERIALIZE SUBQUERY xxxxxx | `--SCAN CONSTANT ROW |--SCAN SUBQUERY xxxxxx - `--SCAN TABLE t3 + `--SCAN t3 } +do_eqp_test 1.7.2 { + SELECT * FROM t3 JOIN (SELECT 1) AS v1 +} { + QUERY PLAN + |--MATERIALIZE v1 + | `--SCAN CONSTANT ROW + |--SCAN v1 + `--SCAN t3 +} +do_eqp_test 1.7.3 { + SELECT * FROM t3 AS xx JOIN (SELECT 1) AS yy +} { + QUERY PLAN + |--MATERIALIZE yy + | `--SCAN CONSTANT ROW + |--SCAN yy + `--SCAN xx +} + + do_eqp_test 1.8 { SELECT * FROM t3 JOIN (SELECT 1 UNION SELECT 2) } { QUERY PLAN - |--MATERIALIZE xxxxxx + |--MATERIALIZE SUBQUERY xxxxxx | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SCAN CONSTANT ROW | `--UNION USING TEMP B-TREE | `--SCAN CONSTANT ROW |--SCAN SUBQUERY xxxxxx - `--SCAN TABLE t3 + `--SCAN t3 } do_eqp_test 1.9 { - SELECT * FROM t3 JOIN (SELECT 1 EXCEPT SELECT a FROM t3 LIMIT 17) + SELECT * FROM t3 JOIN (SELECT 1 EXCEPT SELECT a FROM t3 LIMIT 17) AS abc } { QUERY PLAN - |--MATERIALIZE xxxxxx + |--MATERIALIZE abc | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SCAN CONSTANT ROW | `--EXCEPT USING TEMP B-TREE - | `--SCAN TABLE t3 - |--SCAN SUBQUERY xxxxxx - `--SCAN TABLE t3 + | `--SCAN t3 + |--SCAN abc + `--SCAN t3 } do_eqp_test 1.10 { - SELECT * FROM t3 JOIN (SELECT 1 INTERSECT SELECT a FROM t3 LIMIT 17) + SELECT * FROM t3 JOIN (SELECT 1 INTERSECT SELECT a FROM t3 LIMIT 17) AS abc } { QUERY PLAN - |--MATERIALIZE xxxxxx + |--MATERIALIZE abc | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SCAN CONSTANT ROW | `--INTERSECT USING TEMP B-TREE - | `--SCAN TABLE t3 - |--SCAN SUBQUERY xxxxxx - `--SCAN TABLE t3 + | `--SCAN t3 + |--SCAN abc + `--SCAN t3 } do_eqp_test 1.11 { - SELECT * FROM t3 JOIN (SELECT 1 UNION ALL SELECT a FROM t3 LIMIT 17) + SELECT * FROM t3 JOIN (SELECT 1 UNION ALL SELECT a FROM t3 LIMIT 17) abc } { QUERY PLAN - |--MATERIALIZE xxxxxx + |--MATERIALIZE abc | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SCAN CONSTANT ROW | `--UNION ALL - | `--SCAN TABLE t3 - |--SCAN SUBQUERY xxxxxx - `--SCAN TABLE t3 + | `--SCAN t3 + |--SCAN abc + `--SCAN t3 } #------------------------------------------------------------------------- @@ -166,57 +186,57 @@ do_execsql_test 2.1 { det 2.2.1 "SELECT DISTINCT min(x), max(x) FROM t1 GROUP BY x ORDER BY 1" { QUERY PLAN - |--SCAN TABLE t1 + |--SCAN t1 |--USE TEMP B-TREE FOR GROUP BY |--USE TEMP B-TREE FOR DISTINCT `--USE TEMP B-TREE FOR ORDER BY } det 2.2.2 "SELECT DISTINCT min(x), max(x) FROM t2 GROUP BY x ORDER BY 1" { QUERY PLAN - |--SCAN TABLE t2 USING COVERING INDEX t2i1 + |--SCAN t2 USING COVERING INDEX t2i1 |--USE TEMP B-TREE FOR DISTINCT `--USE TEMP B-TREE FOR ORDER BY } det 2.2.3 "SELECT DISTINCT * FROM t1" { QUERY PLAN - |--SCAN TABLE t1 + |--SCAN t1 `--USE TEMP B-TREE FOR DISTINCT } det 2.2.4 "SELECT DISTINCT * FROM t1, t2" { QUERY PLAN - |--SCAN TABLE t1 - |--SCAN TABLE t2 + |--SCAN t1 + |--SCAN t2 `--USE TEMP B-TREE FOR DISTINCT } det 2.2.5 "SELECT DISTINCT * FROM t1, t2 ORDER BY t1.x" { QUERY PLAN - |--SCAN TABLE t1 - |--SCAN TABLE t2 + |--SCAN t1 + |--SCAN t2 |--USE TEMP B-TREE FOR DISTINCT `--USE TEMP B-TREE FOR ORDER BY } det 2.2.6 "SELECT DISTINCT t2.x FROM t1, t2 ORDER BY t2.x" { QUERY PLAN - |--SCAN TABLE t2 USING COVERING INDEX t2i1 - `--SCAN TABLE t1 + |--SCAN t2 USING COVERING INDEX t2i1 + `--SCAN t1 } det 2.3.1 "SELECT max(x) FROM t2" { QUERY PLAN - `--SEARCH TABLE t2 USING COVERING INDEX t2i1 + `--SEARCH t2 USING COVERING INDEX t2i1 } det 2.3.2 "SELECT min(x) FROM t2" { QUERY PLAN - `--SEARCH TABLE t2 USING COVERING INDEX t2i1 + `--SEARCH t2 USING COVERING INDEX t2i1 } det 2.3.3 "SELECT min(x), max(x) FROM t2" { QUERY PLAN - `--SCAN TABLE t2 USING COVERING INDEX t2i1 + `--SCAN t2 USING COVERING INDEX t2i1 } det 2.4.1 "SELECT * FROM t1 WHERE rowid=?" { QUERY PLAN - `--SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?) + `--SEARCH t1 USING INTEGER PRIMARY KEY (rowid=?) } @@ -228,42 +248,42 @@ do_eqp_test 3.1.1 { SELECT (SELECT x FROM t1 AS sub) FROM t1; } { QUERY PLAN - |--SCAN TABLE t1 + |--SCAN t1 `--SCALAR SUBQUERY xxxxxx - `--SCAN TABLE t1 AS sub + `--SCAN sub } do_eqp_test 3.1.2 { SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub); } { QUERY PLAN - |--SCAN TABLE t1 + |--SCAN t1 `--SCALAR SUBQUERY xxxxxx - `--SCAN TABLE t1 AS sub + `--SCAN sub } do_eqp_test 3.1.3 { SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub ORDER BY y); } { QUERY PLAN - |--SCAN TABLE t1 + |--SCAN t1 `--SCALAR SUBQUERY xxxxxx - |--SCAN TABLE t1 AS sub + |--SCAN sub `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 3.1.4 { SELECT * FROM t1 WHERE (SELECT x FROM t2 ORDER BY x); } { QUERY PLAN - |--SCAN TABLE t1 + |--SCAN t1 `--SCALAR SUBQUERY xxxxxx - `--SCAN TABLE t2 USING COVERING INDEX t2i1 + `--SCAN t2 USING COVERING INDEX t2i1 } det 3.2.1 { SELECT * FROM (SELECT * FROM t1 ORDER BY x LIMIT 10) ORDER BY y LIMIT 5 } { QUERY PLAN - |--CO-ROUTINE xxxxxx - | |--SCAN TABLE t1 + |--CO-ROUTINE SUBQUERY xxxxxx + | |--SCAN t1 | `--USE TEMP B-TREE FOR ORDER BY |--SCAN SUBQUERY xxxxxx `--USE TEMP B-TREE FOR ORDER BY @@ -275,13 +295,13 @@ det 3.2.2 { ORDER BY x2.y LIMIT 5 } { QUERY PLAN - |--MATERIALIZE xxxxxx - | |--SCAN TABLE t1 + |--MATERIALIZE x1 + | |--SCAN t1 | `--USE TEMP B-TREE FOR ORDER BY - |--MATERIALIZE xxxxxx - | `--SCAN TABLE t2 USING INDEX t2i1 - |--SCAN SUBQUERY xxxxxx AS x1 - |--SCAN SUBQUERY xxxxxx AS x2 + |--MATERIALIZE x2 + | `--SCAN t2 USING INDEX t2i1 + |--SCAN x1 + |--SCAN x2 `--USE TEMP B-TREE FOR ORDER BY } @@ -289,25 +309,25 @@ det 3.3.1 { SELECT * FROM t1 WHERE y IN (SELECT y FROM t2) } { QUERY PLAN - |--SCAN TABLE t1 + |--SCAN t1 `--LIST SUBQUERY xxxxxx - `--SCAN TABLE t2 + `--SCAN t2 } det 3.3.2 { SELECT * FROM t1 WHERE y IN (SELECT y FROM t2 WHERE t1.x!=t2.x) } { QUERY PLAN - |--SCAN TABLE t1 + |--SCAN t1 `--CORRELATED LIST SUBQUERY xxxxxx - `--SCAN TABLE t2 + `--SCAN t2 } det 3.3.3 { SELECT * FROM t1 WHERE EXISTS (SELECT y FROM t2 WHERE t1.x!=t2.x) } { QUERY PLAN - |--SCAN TABLE t1 + |--SCAN t1 `--CORRELATED SCALAR SUBQUERY xxxxxx - `--SCAN TABLE t2 + `--SCAN t2 } #------------------------------------------------------------------------- @@ -319,9 +339,9 @@ do_eqp_test 4.1.1 { QUERY PLAN `--COMPOUND QUERY |--LEFT-MOST SUBQUERY - | `--SCAN TABLE t1 + | `--SCAN t1 `--UNION ALL - `--SCAN TABLE t2 + `--SCAN t2 } do_eqp_test 4.1.2 { SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 2 @@ -329,10 +349,10 @@ do_eqp_test 4.1.2 { QUERY PLAN `--MERGE (UNION ALL) |--LEFT - | |--SCAN TABLE t1 + | |--SCAN t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT - |--SCAN TABLE t2 + |--SCAN t2 `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 4.1.3 { @@ -341,10 +361,10 @@ do_eqp_test 4.1.3 { QUERY PLAN `--MERGE (UNION) |--LEFT - | |--SCAN TABLE t1 + | |--SCAN t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT - |--SCAN TABLE t2 + |--SCAN t2 `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 4.1.4 { @@ -353,10 +373,10 @@ do_eqp_test 4.1.4 { QUERY PLAN `--MERGE (INTERSECT) |--LEFT - | |--SCAN TABLE t1 + | |--SCAN t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT - |--SCAN TABLE t2 + |--SCAN t2 `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 4.1.5 { @@ -365,10 +385,10 @@ do_eqp_test 4.1.5 { QUERY PLAN `--MERGE (EXCEPT) |--LEFT - | |--SCAN TABLE t1 + | |--SCAN t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT - |--SCAN TABLE t2 + |--SCAN t2 `--USE TEMP B-TREE FOR ORDER BY } @@ -378,10 +398,10 @@ do_eqp_test 4.2.2 { QUERY PLAN `--MERGE (UNION ALL) |--LEFT - | |--SCAN TABLE t1 + | |--SCAN t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT - `--SCAN TABLE t2 USING INDEX t2i1 + `--SCAN t2 USING INDEX t2i1 } do_eqp_test 4.2.3 { SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 1 @@ -389,10 +409,10 @@ do_eqp_test 4.2.3 { QUERY PLAN `--MERGE (UNION) |--LEFT - | |--SCAN TABLE t1 + | |--SCAN t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT - |--SCAN TABLE t2 USING INDEX t2i1 + |--SCAN t2 USING INDEX t2i1 `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY } do_eqp_test 4.2.4 { @@ -401,10 +421,10 @@ do_eqp_test 4.2.4 { QUERY PLAN `--MERGE (INTERSECT) |--LEFT - | |--SCAN TABLE t1 + | |--SCAN t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT - |--SCAN TABLE t2 USING INDEX t2i1 + |--SCAN t2 USING INDEX t2i1 `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY } do_eqp_test 4.2.5 { @@ -413,10 +433,10 @@ do_eqp_test 4.2.5 { QUERY PLAN `--MERGE (EXCEPT) |--LEFT - | |--SCAN TABLE t1 + | |--SCAN t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT - |--SCAN TABLE t2 USING INDEX t2i1 + |--SCAN t2 USING INDEX t2i1 `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY } @@ -426,9 +446,9 @@ do_eqp_test 4.3.1 { QUERY PLAN `--COMPOUND QUERY |--LEFT-MOST SUBQUERY - | `--SCAN TABLE t1 + | `--SCAN t1 `--UNION USING TEMP B-TREE - `--SCAN TABLE t2 USING COVERING INDEX t2i1 + `--SCAN t2 USING COVERING INDEX t2i1 } do_eqp_test 4.3.2 { @@ -437,11 +457,11 @@ do_eqp_test 4.3.2 { QUERY PLAN `--COMPOUND QUERY |--LEFT-MOST SUBQUERY - | `--SCAN TABLE t1 + | `--SCAN t1 |--UNION USING TEMP B-TREE - | `--SCAN TABLE t2 USING COVERING INDEX t2i1 + | `--SCAN t2 USING COVERING INDEX t2i1 `--UNION USING TEMP B-TREE - `--SCAN TABLE t1 + `--SCAN t1 } do_eqp_test 4.3.3 { SELECT x FROM t1 UNION SELECT x FROM t2 UNION SELECT x FROM t1 ORDER BY 1 @@ -451,12 +471,12 @@ do_eqp_test 4.3.3 { |--LEFT | `--MERGE (UNION) | |--LEFT - | | |--SCAN TABLE t1 + | | |--SCAN t1 | | `--USE TEMP B-TREE FOR ORDER BY | `--RIGHT - | `--SCAN TABLE t2 USING COVERING INDEX t2i1 + | `--SCAN t2 USING COVERING INDEX t2i1 `--RIGHT - |--SCAN TABLE t1 + |--SCAN t1 `--USE TEMP B-TREE FOR ORDER BY } @@ -469,145 +489,145 @@ drop_all_tables # XVIDENCE-OF: R-47779-47605 sqlite> EXPLAIN QUERY PLAN SELECT a, b # FROM t1 WHERE a=1; -# 0|0|0|SCAN TABLE t1 +# 0|0|0|SCAN t1 # do_execsql_test 5.1.0 { CREATE TABLE t1(a INT, b INT, ex TEXT) } det 5.1.1 "SELECT a, b FROM t1 WHERE a=1" { - 0 0 0 {SCAN TABLE t1} + 0 0 0 {SCAN t1} } # XVIDENCE-OF: R-55852-17599 sqlite> CREATE INDEX i1 ON t1(a); # sqlite> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1; -# 0|0|0|SEARCH TABLE t1 USING INDEX i1 +# 0|0|0|SEARCH t1 USING INDEX i1 # do_execsql_test 5.2.0 { CREATE INDEX i1 ON t1(a) } det 5.2.1 "SELECT a, b FROM t1 WHERE a=1" { - 0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)} + 0 0 0 {SEARCH t1 USING INDEX i1 (a=?)} } # XVIDENCE-OF: R-21179-11011 sqlite> CREATE INDEX i2 ON t1(a, b); # sqlite> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1; -# 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) +# 0|0|0|SEARCH t1 USING COVERING INDEX i2 (a=?) # do_execsql_test 5.3.0 { CREATE INDEX i2 ON t1(a, b) } det 5.3.1 "SELECT a, b FROM t1 WHERE a=1" { - 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)} + 0 0 0 {SEARCH t1 USING COVERING INDEX i2 (a=?)} } # XVIDENCE-OF: R-09991-48941 sqlite> EXPLAIN QUERY PLAN # SELECT t1.*, t2.* FROM t1, t2 WHERE t1.a=1 AND t1.b>2; -# 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?) -# 0|1|1|SCAN TABLE t2 +# 0|0|0|SEARCH t1 USING COVERING INDEX i2 (a=? AND b>?) +# 0|1|1|SCAN t2 # do_execsql_test 5.4.0 {CREATE TABLE t2(c INT, d INT, ex TEXT)} det 5.4.1 "SELECT t1.a, t2.c FROM t1, t2 WHERE t1.a=1 AND t1.b>2" { - 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)} - 0 1 1 {SCAN TABLE t2} + 0 0 0 {SEARCH t1 USING COVERING INDEX i2 (a=? AND b>?)} + 0 1 1 {SCAN t2} } # XVIDENCE-OF: R-33626-61085 sqlite> EXPLAIN QUERY PLAN # SELECT t1.*, t2.* FROM t2, t1 WHERE t1.a=1 AND t1.b>2; -# 0|0|1|SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?) -# 0|1|0|SCAN TABLE t2 +# 0|0|1|SEARCH t1 USING COVERING INDEX i2 (a=? AND b>?) +# 0|1|0|SCAN t2 # det 5.5 "SELECT t1.a, t2.c FROM t2, t1 WHERE t1.a=1 AND t1.b>2" { - 0 0 1 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)} - 0 1 0 {SCAN TABLE t2} + 0 0 1 {SEARCH t1 USING COVERING INDEX i2 (a=? AND b>?)} + 0 1 0 {SCAN t2} } # XVIDENCE-OF: R-04002-25654 sqlite> CREATE INDEX i3 ON t1(b); # sqlite> EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=1 OR b=2; -# 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) -# 0|0|0|SEARCH TABLE t1 USING INDEX i3 (b=?) +# 0|0|0|SEARCH t1 USING COVERING INDEX i2 (a=?) +# 0|0|0|SEARCH t1 USING INDEX i3 (b=?) # do_execsql_test 5.5.0 {CREATE INDEX i3 ON t1(b)} det 5.6.1 "SELECT a, b FROM t1 WHERE a=1 OR b=2" { - 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)} - 0 0 0 {SEARCH TABLE t1 USING INDEX i3 (b=?)} + 0 0 0 {SEARCH t1 USING COVERING INDEX i2 (a=?)} + 0 0 0 {SEARCH t1 USING INDEX i3 (b=?)} } # XVIDENCE-OF: R-24577-38891 sqlite> EXPLAIN QUERY PLAN # SELECT c, d FROM t2 ORDER BY c; -# 0|0|0|SCAN TABLE t2 +# 0|0|0|SCAN t2 # 0|0|0|USE TEMP B-TREE FOR ORDER BY # det 5.7 "SELECT c, d FROM t2 ORDER BY c" { - 0 0 0 {SCAN TABLE t2} + 0 0 0 {SCAN t2} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } # XVIDENCE-OF: R-58157-12355 sqlite> CREATE INDEX i4 ON t2(c); # sqlite> EXPLAIN QUERY PLAN SELECT c, d FROM t2 ORDER BY c; -# 0|0|0|SCAN TABLE t2 USING INDEX i4 +# 0|0|0|SCAN t2 USING INDEX i4 # do_execsql_test 5.8.0 {CREATE INDEX i4 ON t2(c)} det 5.8.1 "SELECT c, d FROM t2 ORDER BY c" { - 0 0 0 {SCAN TABLE t2 USING INDEX i4} + 0 0 0 {SCAN t2 USING INDEX i4} } # XVIDENCE-OF: R-13931-10421 sqlite> EXPLAIN QUERY PLAN SELECT # (SELECT b FROM t1 WHERE a=0), (SELECT a FROM t1 WHERE b=t2.c) FROM t2; -# 0|0|0|SCAN TABLE t2 +# 0|0|0|SCAN t2 # 0|0|0|EXECUTE SCALAR SUBQUERY 1 -# 1|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) +# 1|0|0|SEARCH t1 USING COVERING INDEX i2 (a=?) # 0|0|0|EXECUTE CORRELATED SCALAR SUBQUERY 2 -# 2|0|0|SEARCH TABLE t1 USING INDEX i3 (b=?) +# 2|0|0|SEARCH t1 USING INDEX i3 (b=?) # det 5.9 { SELECT (SELECT b FROM t1 WHERE a=0), (SELECT a FROM t1 WHERE b=t2.c) FROM t2 } { - 0 0 0 {SCAN TABLE t2 USING COVERING INDEX i4} + 0 0 0 {SCAN t2 USING COVERING INDEX i4} 0 0 0 {EXECUTE SCALAR SUBQUERY 1} - 1 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)} + 1 0 0 {SEARCH t1 USING COVERING INDEX i2 (a=?)} 0 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 2} - 2 0 0 {SEARCH TABLE t1 USING INDEX i3 (b=?)} + 2 0 0 {SEARCH t1 USING INDEX i3 (b=?)} } # XVIDENCE-OF: R-50892-45943 sqlite> EXPLAIN QUERY PLAN # SELECT count(*) FROM (SELECT max(b) AS x FROM t1 GROUP BY a) GROUP BY x; -# 1|0|0|SCAN TABLE t1 USING COVERING INDEX i2 +# 1|0|0|SCAN t1 USING COVERING INDEX i2 # 0|0|0|SCAN SUBQUERY 1 # 0|0|0|USE TEMP B-TREE FOR GROUP BY # det 5.10 { SELECT count(*) FROM (SELECT max(b) AS x FROM t1 GROUP BY a) GROUP BY x } { - 1 0 0 {SCAN TABLE t1 USING COVERING INDEX i2} + 1 0 0 {SCAN t1 USING COVERING INDEX i2} 0 0 0 {SCAN SUBQUERY 1} 0 0 0 {USE TEMP B-TREE FOR GROUP BY} } # XVIDENCE-OF: R-46219-33846 sqlite> EXPLAIN QUERY PLAN # SELECT * FROM (SELECT * FROM t2 WHERE c=1), t1; -# 0|0|0|SEARCH TABLE t2 USING INDEX i4 (c=?) -# 0|1|1|SCAN TABLE t1 +# 0|0|0|SEARCH t2 USING INDEX i4 (c=?) +# 0|1|1|SCAN t1 # det 5.11 "SELECT a, b FROM (SELECT * FROM t2 WHERE c=1), t1" { - 0 0 0 {SEARCH TABLE t2 USING INDEX i4 (c=?)} - 0 1 1 {SCAN TABLE t1 USING COVERING INDEX i2} + 0 0 0 {SEARCH t2 USING INDEX i4 (c=?)} + 0 1 1 {SCAN t1 USING COVERING INDEX i2} } # XVIDENCE-OF: R-37879-39987 sqlite> EXPLAIN QUERY PLAN # SELECT a FROM t1 UNION SELECT c FROM t2; -# 1|0|0|SCAN TABLE t1 -# 2|0|0|SCAN TABLE t2 +# 1|0|0|SCAN t1 +# 2|0|0|SCAN t2 # 0|0|0|COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION) # det 5.12 "SELECT a,b FROM t1 UNION SELECT c, 99 FROM t2" { - 1 0 0 {SCAN TABLE t1 USING COVERING INDEX i2} - 2 0 0 {SCAN TABLE t2 USING COVERING INDEX i4} + 1 0 0 {SCAN t1 USING COVERING INDEX i2} + 2 0 0 {SCAN t2 USING COVERING INDEX i4} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)} } # XVIDENCE-OF: R-44864-63011 sqlite> EXPLAIN QUERY PLAN # SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1; -# 1|0|0|SCAN TABLE t1 USING COVERING INDEX i2 -# 2|0|0|SCAN TABLE t2 2|0|0|USE TEMP B-TREE FOR ORDER BY +# 1|0|0|SCAN t1 USING COVERING INDEX i2 +# 2|0|0|SCAN t2 2|0|0|USE TEMP B-TREE FOR ORDER BY # 0|0|0|COMPOUND SUBQUERIES 1 AND 2 (EXCEPT) # det 5.13 "SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1" { - 1 0 0 {SCAN TABLE t1 USING COVERING INDEX i1} - 2 0 0 {SCAN TABLE t2} + 1 0 0 {SCAN t1 USING COVERING INDEX i1} + 2 0 0 {SCAN t2} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)} } @@ -647,8 +667,8 @@ if {![nonzero_reserved_bytes]} { do_peqp_test 6.1 { SELECT a, b FROM t1 EXCEPT SELECT d, 99 FROM t2 ORDER BY 1 } [string trimleft { -1 0 0 SCAN TABLE t1 USING COVERING INDEX i2 -2 0 0 SCAN TABLE t2 +1 0 0 SCAN t1 USING COVERING INDEX i2 +2 0 0 SCAN t2 2 0 0 USE TEMP B-TREE FOR ORDER BY 0 0 0 COMPOUND SUBQUERIES 1 AND 2 (EXCEPT) }] @@ -669,12 +689,12 @@ do_execsql_test 7.0 { det 7.1 "SELECT count(*) FROM t1" { QUERY PLAN - `--SCAN TABLE t1 + `--SCAN t1 } det 7.2 "SELECT count(*) FROM t2" { QUERY PLAN - `--SCAN TABLE t2 USING COVERING INDEX i1 + `--SCAN t2 USING COVERING INDEX i1 } do_execsql_test 7.3 { @@ -693,12 +713,12 @@ sqlite3 db test.db det 7.4 "SELECT count(*) FROM t1" { QUERY PLAN - `--SCAN TABLE t1 + `--SCAN t1 } det 7.5 "SELECT count(*) FROM t2" { QUERY PLAN - `--SCAN TABLE t2 USING COVERING INDEX i1 + `--SCAN t2 USING COVERING INDEX i1 } #------------------------------------------------------------------------- @@ -714,37 +734,37 @@ do_execsql_test 8.0 { det 8.1.1 "SELECT * FROM t2" { QUERY PLAN - `--SCAN TABLE t2 + `--SCAN t2 } det 8.1.2 "SELECT * FROM t2 WHERE rowid=?" { QUERY PLAN - `--SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?) + `--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?) } det 8.1.3 "SELECT count(*) FROM t2" { QUERY PLAN - `--SCAN TABLE t2 + `--SCAN t2 } det 8.2.1 "SELECT * FROM t1" { QUERY PLAN - `--SCAN TABLE t1 + `--SCAN t1 } det 8.2.2 "SELECT * FROM t1 WHERE b=?" { QUERY PLAN - `--SEARCH TABLE t1 USING PRIMARY KEY (b=?) + `--SEARCH t1 USING PRIMARY KEY (b=?) } det 8.2.3 "SELECT * FROM t1 WHERE b=? AND c=?" { QUERY PLAN - `--SEARCH TABLE t1 USING PRIMARY KEY (b=? AND c=?) + `--SEARCH t1 USING PRIMARY KEY (b=? AND c=?) } det 8.2.4 "SELECT count(*) FROM t1" { QUERY PLAN - `--SCAN TABLE t1 + `--SCAN t1 } # 2018-08-16: While working on Fossil I discovered that EXPLAIN QUERY PLAN @@ -814,16 +834,16 @@ do_eqp_test 9.1 { ORDER BY 1; } { QUERY PLAN - |--MATERIALIZE xxxxxx - | |--SCAN TABLE forumpost AS x USING INDEX forumthread + |--MATERIALIZE thread + | |--SCAN x USING INDEX forumthread | |--USING ROWID SEARCH ON TABLE private FOR IN-OPERATOR | |--CORRELATED SCALAR SUBQUERY xxxxxx - | | |--SEARCH TABLE forumpost USING COVERING INDEX forumthread (froot=?) + | | |--SEARCH forumpost USING COVERING INDEX forumthread (froot=?) | | `--USING ROWID SEARCH ON TABLE private FOR IN-OPERATOR | `--USE TEMP B-TREE FOR ORDER BY - |--SCAN SUBQUERY xxxxxx - |--SEARCH TABLE blob USING INTEGER PRIMARY KEY (rowid=?) - |--SEARCH TABLE event USING INTEGER PRIMARY KEY (rowid=?) + |--SCAN thread + |--SEARCH blob USING INTEGER PRIMARY KEY (rowid=?) + |--SEARCH event USING INTEGER PRIMARY KEY (rowid=?) `--USE TEMP B-TREE FOR ORDER BY } diff --git a/test/exists2.test b/test/exists2.test deleted file mode 100644 index c4fc9dc373..0000000000 --- a/test/exists2.test +++ /dev/null @@ -1,188 +0,0 @@ -# 2021 January 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 cases where EXISTS expressions are -# transformed to IN() expressions by where.c -# - -set testdir [file dirname $argv0] -source $testdir/tester.tcl -set testprefix exists2 - -do_execsql_test 1.0 { - CREATE TABLE t1(a INTEGER PRIMARY KEY, b); - INSERT INTO t1 VALUES(1, 'one'); - INSERT INTO t1 VALUES(2, 'two'); - INSERT INTO t1 VALUES(3, 'three'); - INSERT INTO t1 VALUES(4, 'four'); - INSERT INTO t1 VALUES(5, 'five'); - INSERT INTO t1 VALUES(6, 'six'); - INSERT INTO t1 VALUES(7, 'seven'); - - CREATE TABLE t2(c INTEGER, d INTEGER); - INSERT INTO t2 VALUES(1, 1); - INSERT INTO t2 VALUES(3, 2); - INSERT INTO t2 VALUES(5, 3); - INSERT INTO t2 VALUES(7, 4); -} - -proc do_execsql_eqp_test {tn sql eqp res} { - uplevel [list do_eqp_test $tn.1 $sql [string trim $eqp]] - uplevel [list do_execsql_test $tn.2 $sql $res] -} - -do_execsql_eqp_test 1.1 { - SELECT t1.* FROM t1 WHERE EXISTS(SELECT * FROM t2 WHERE t1.a=t2.c); -} { - USING INTEGER PRIMARY KEY -} { - 1 one 3 three 5 five 7 seven -} - -do_execsql_eqp_test 1.2 { - SELECT t1.* FROM t1 WHERE EXISTS(SELECT * FROM t2 WHERE t2.c=t1.a); -} { - SEARCH TABLE t1 USING INTEGER PRIMARY KEY -} { - 1 one 3 three 5 five 7 seven -} - -do_execsql_eqp_test 1.3 { - SELECT t1.* FROM t1 WHERE EXISTS(SELECT * FROM t2 WHERE t2.c+1=t1.a); -} { - SEARCH TABLE t1 USING INTEGER PRIMARY KEY -} { - 2 two 4 four 6 six -} - -do_execsql_eqp_test 1.4 { - SELECT t1.* FROM t1 WHERE EXISTS(SELECT * FROM t2 WHERE t2.c+1=t1.a+1); -} { - SCAN TABLE t1 -} { - 1 one 3 three 5 five 7 seven -} - -do_execsql_eqp_test 1.5 { - SELECT t1.* FROM t1 WHERE EXISTS( - SELECT * FROM t2 WHERE t1.a=t2.c AND d IN (1, 2, 3) - ); -} { - SEARCH TABLE t1 USING INTEGER PRIMARY KEY -} { - 1 one 3 three 5 five -} - -do_execsql_eqp_test 1.6 { - SELECT t1.* FROM t1 WHERE EXISTS( - SELECT * FROM t2 WHERE d IN (1, 2, 3)AND t1.a=t2.c - ); -} { - SEARCH TABLE t1 USING INTEGER PRIMARY KEY -} { - 1 one 3 three 5 five -} - -do_execsql_eqp_test 1.7 { - SELECT t1.* FROM t1 WHERE EXISTS( - SELECT * FROM t2 WHERE d IN (1, 2, 3)AND t1.a=t2.c - ); -} { - SEARCH TABLE t1 USING INTEGER PRIMARY KEY -} { - 1 one 3 three 5 five -} - -#------------------------------------------------------------------------- -# -reset_db -do_execsql_test 2.0 { - CREATE TABLE t3(a TEXT PRIMARY KEY, b TEXT, x INT) WITHOUT ROWID; - CREATE TABLE t4(c TEXT COLLATE nocase, y INT); - - INSERT INTO t3 VALUES('one', 'i', 1); - INSERT INTO t3 VALUES('two', 'ii', 2); - INSERT INTO t3 VALUES('three', 'iii', 3); - INSERT INTO t3 VALUES('four', 'iv', 4); - INSERT INTO t3 VALUES('five', 'v', 5); - - INSERT INTO t4 VALUES('FIVE',5), ('four',4), ('TWO',2), ('one',1); -} - -do_execsql_test 2.1 { SELECT a FROM t3, t4 WHERE a=c } {four one} -do_execsql_test 2.2 { SELECT a FROM t3, t4 WHERE c=a } {five four one two} - -do_execsql_eqp_test 2.3 { - SELECT a FROM t3 WHERE EXISTS (SELECT 1 FROM t4 WHERE a=c) -} { - SEARCH TABLE t3 USING PRIMARY KEY -} { - four one -} - -do_execsql_eqp_test 2.4 { - SELECT a FROM t3 WHERE EXISTS (SELECT 1 FROM t4 WHERE c=a) -} { - SCAN TABLE t3 -} { - five four one two -} - -do_execsql_test 2.5 { - CREATE INDEX t3anc ON t3(a COLLATE nocase, x); -} - -do_execsql_eqp_test 2.6 { - SELECT a FROM t3 WHERE EXISTS (SELECT 1 FROM t4 WHERE c=a) -} { - SEARCH TABLE t3 USING COVERING INDEX t3anc -} { - five four one two -} -do_execsql_test 2.6a { - SELECT a FROM t3 WHERE EXISTS (SELECT 1 FROM t4 WHERE (c,y)=(a,x)) -} {five four one two} - -do_execsql_eqp_test 2.7 { - SELECT a FROM t3 WHERE EXISTS (SELECT 1 FROM t4 WHERE a=c) -} { - SEARCH TABLE t3 USING PRIMARY KEY -} { - four one -} -do_execsql_test 2.7a { - SELECT a FROM t3 WHERE EXISTS (SELECT 1 FROM t4 WHERE (a,x)=(c,y)) -} { - four one -} - -# EXISTS clauses using vector expressions in the WHERE clause. -# -reset_db -do_execsql_test 3.0 { - CREATE TABLE t1(a,b); - INSERT INTO t1(a,b) VALUES(1,111),(2,222),(8,888); - CREATE TABLE t2(x INTEGER PRIMARY KEY, y); - INSERT INTO t2(x,y) VALUES(2,222),(3,333),(7,333); - SELECT y FROM t2 WHERE EXISTS(SELECT 1 FROM t1 WHERE (x,y)=(a,b)); -} {222} -do_execsql_test 3.1 { - SELECT y FROM t2 WHERE EXISTS(SELECT 1 FROM t1 WHERE (a,b)=(x,y)); -} {222} -do_execsql_test 3.2 { - SELECT y FROM t2 WHERE EXISTS(SELECT 1 FROM t1 WHERE (x,b)=(a,y)); -} {222} - - - - - -finish_test diff --git a/test/existsfault.test b/test/existsfault.test deleted file mode 100644 index 24e44a7b58..0000000000 --- a/test/existsfault.test +++ /dev/null @@ -1,52 +0,0 @@ -# 2021 January 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 cases where EXISTS expressions are -# transformed to IN() expressions by where.c -# - -set testdir [file dirname $argv0] -source $testdir/tester.tcl -set testprefix existsfault - -do_execsql_test 1 { - CREATE TABLE t1(a PRIMARY KEY, b); - INSERT INTO t1 VALUES(1, 'one'); - INSERT INTO t1 VALUES(2, 'two'); - INSERT INTO t1 VALUES(3, 'three'); - INSERT INTO t1 VALUES(4, 'four'); - INSERT INTO t1 VALUES(5, 'five'); - INSERT INTO t1 VALUES(6, 'six'); - INSERT INTO t1 VALUES(7, 'seven'); - - CREATE TABLE t2(c INTEGER, d INTEGER); - INSERT INTO t2 VALUES(1, 1); - INSERT INTO t2 VALUES(3, 2); - INSERT INTO t2 VALUES(5, 3); - INSERT INTO t2 VALUES(7, 4); -} -faultsim_save_and_close - -do_faultsim_test 1 -prep { - faultsim_restore_and_reopen -} -body { - execsql { - SELECT t1.* FROM t1 WHERE EXISTS( - SELECT * FROM t2 WHERE t2.c=t1.a AND d IN (1, 2, 3) - ) - } -} -test { - faultsim_test_result {0 {1 one 3 three 5 five}} -} - - -finish_test - diff --git a/test/exprfault.test b/test/exprfault.test new file mode 100644 index 0000000000..9e5977e1d2 --- /dev/null +++ b/test/exprfault.test @@ -0,0 +1,35 @@ +# 2021 April 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. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix exprfault + +do_execsql_test 1.0 { + CREATE TABLE t1(a); + CREATE TABLE t2(d); +} +faultsim_save_and_close + +do_faultsim_test 1.1 -faults oom* -prep { + faultsim_restore_and_reopen +} -body { + execsql { + SELECT a = ( SELECT d FROM (SELECT d FROM t2) ) FROM t1 + } +} -test { + faultsim_test_result {0 {}} +} + + +finish_test diff --git a/test/external_reader.test b/test/external_reader.test new file mode 100644 index 0000000000..5d293981c5 --- /dev/null +++ b/test/external_reader.test @@ -0,0 +1,74 @@ +# 2021 April 2 +# +# 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/lock_common.tcl +set testprefix external_reader + +ifcapable !wal { + finish_test + return +} +if {$::tcl_platform(platform)!="unix"} { + finish_test + return +} + +do_multiclient_test tn { + + set bExternal 1 + if {[info commands db3]!=""} { set bExternal 0 } + + do_test 1.$tn.0 { + sql1 { + PRAGMA journal_mode = wal; + CREATE TABLE t1(a, b); + INSERT INTO t1 VALUES(1, 2); + } + } {wal} + + do_test 1.$tn.1 { + sql2 { SELECT * FROM t1 } + } {1 2} + + do_test 1.$tn.2 { + code1 { + file_control_external_reader db + } + } {0} + + do_test 1.$tn.3 { + sql2 { + BEGIN; + SELECT * FROM t1; + } + } {1 2} + + do_test 1.$tn.4 { + code1 { + file_control_external_reader db + } + } $bExternal + + do_test 1.$tn.5 { + sql2 { COMMIT } + } {} + + do_test 1.$tn.6 { + code1 { file_control_external_reader db } + } 0 + +} + + +finish_test diff --git a/test/fts3aux1.test b/test/fts3aux1.test index c7e1ac1a5c..1524d6d30f 100644 --- a/test/fts3aux1.test +++ b/test/fts3aux1.test @@ -105,10 +105,10 @@ db func rec rec # do_execsql_test 2.1.1.1 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term='braid' -} {/*SCAN TABLE terms VIRTUAL TABLE INDEX 1:*/} +} {/*SCAN terms VIRTUAL TABLE INDEX 1:*/} do_execsql_test 2.1.1.2 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term='braid' -} {/*SCAN TABLE terms VIRTUAL TABLE INDEX 0:*/} +} {/*SCAN terms VIRTUAL TABLE INDEX 0:*/} # Now show that using "term='braid'" means the virtual table returns # only 1 row to SQLite, but "+term='braid'" means all 19 are returned. @@ -154,24 +154,24 @@ do_execsql_test 2.1.5 { SELECT * FROM terms WHERE term=NULL } {} do_execsql_test 2.2.1.1 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term>'brain' -} {/*SCAN TABLE terms VIRTUAL TABLE INDEX 2:*/} +} {/*SCAN terms VIRTUAL TABLE INDEX 2:*/} do_execsql_test 2.2.1.2 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term>'brain' -} {/*SCAN TABLE terms VIRTUAL TABLE INDEX 0:*/} +} {/*SCAN terms VIRTUAL TABLE INDEX 0:*/} do_execsql_test 2.2.1.3 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term<'brain' -} {/*SCAN TABLE terms VIRTUAL TABLE INDEX 4:*/} +} {/*SCAN terms VIRTUAL TABLE INDEX 4:*/} do_execsql_test 2.2.1.4 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term<'brain' -} {/*SCAN TABLE terms VIRTUAL TABLE INDEX 0:*/} +} {/*SCAN terms VIRTUAL TABLE INDEX 0:*/} do_execsql_test 2.2.1.5 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term BETWEEN 'brags' AND 'brain' -} {/*SCAN TABLE terms VIRTUAL TABLE INDEX 6:*/} +} {/*SCAN terms VIRTUAL TABLE INDEX 6:*/} do_execsql_test 2.2.1.6 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term BETWEEN 'brags' AND 'brain' -} {/*SCAN TABLE terms VIRTUAL TABLE INDEX 0:*/} +} {/*SCAN terms VIRTUAL TABLE INDEX 0:*/} do_test 2.2.2.1 { set cnt 0 @@ -335,7 +335,7 @@ foreach {tn sort orderby} { 9 1 "ORDER BY occurrences DESC" } { - set res {SCAN TABLE terms VIRTUAL TABLE INDEX 0:} + set res {SCAN terms VIRTUAL TABLE INDEX 0:} if {$sort} { append res {*USE TEMP B-TREE FOR ORDER BY} } set res "/*$res*/" @@ -413,8 +413,8 @@ do_plansql_test 4.2 { SELECT y FROM x2, terms WHERE y = term AND col = '*' } { QUERY PLAN - |--SCAN TABLE x2 - `--SCAN TABLE terms VIRTUAL TABLE INDEX 1: + |--SCAN x2 + `--SCAN terms VIRTUAL TABLE INDEX 1: } { a b c d e f g h i j k l } @@ -423,8 +423,8 @@ do_plansql_test 4.3 { SELECT y FROM terms, x2 WHERE y = term AND col = '*' } { QUERY PLAN - |--SCAN TABLE x2 - `--SCAN TABLE terms VIRTUAL TABLE INDEX 1: + |--SCAN x2 + `--SCAN terms VIRTUAL TABLE INDEX 1: } { a b c d e f g h i j k l } @@ -433,8 +433,8 @@ do_plansql_test 4.4 { SELECT y FROM x3, terms WHERE y = term AND col = '*' } { QUERY PLAN - |--SCAN TABLE terms VIRTUAL TABLE INDEX 0: - `--SEARCH TABLE x3 USING COVERING INDEX i1 (y=?) + |--SCAN terms VIRTUAL TABLE INDEX 0: + `--SEARCH x3 USING COVERING INDEX i1 (y=?) } { a b c d e f g h i j k l } @@ -443,8 +443,8 @@ do_plansql_test 4.5 { SELECT y FROM terms, x3 WHERE y = term AND occurrences>1 AND col = '*' } { QUERY PLAN - |--SCAN TABLE terms VIRTUAL TABLE INDEX 0: - `--SEARCH TABLE x3 USING COVERING INDEX i1 (y=?) + |--SCAN terms VIRTUAL TABLE INDEX 0: + `--SEARCH x3 USING COVERING INDEX i1 (y=?) } { a k l } diff --git a/test/fts3corrupt4.test b/test/fts3corrupt4.test index 851119a2fe..51016ab19c 100644 --- a/test/fts3corrupt4.test +++ b/test/fts3corrupt4.test @@ -6385,5 +6385,208 @@ do_catchsql_test 48.1 { INSERT INTO x1(x1) VALUES( 'merge=3,4' ),('merge=3,4'); } {1 {database disk image is malformed}} +#------------------------------------------------------------------------- +# +reset_db +do_test 49.0 { + sqlite3 db {} + db deserialize [decode_hexdb { +.open --hexdb +| size 28672 pagesize 4096 filename crash-58821b8eae6883.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 00 00 00 00 00 00 00 00 06 00 00 00 04 ................ +| 96: 00 00 00 00 0d 0e ef 00 07 0d 4d 00 0f bd 0f 5f ..........M...._ +| 112: 0e f7 0e 06 0e bc 0d a4 0d 4d 00 00 00 00 00 00 .........M...... +| 3392: 00 00 00 00 00 00 00 00 00 00 00 00 00 55 07 07 .............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 54 45 47 45 52 2c 73 74 61 72 74 dx INTEGER,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 f9 52 49 4d 41 52 59 20 4b NTEGER .RIMARY 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 20 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 32 2c 32 27 29 (a,prefix='2,2') +| page 2 offset 4096 +| 0: 0d 00 00 00 08 0e 1f 00 0f c4 0f 7c 0f 34 0f 07 ...........|.4.. +| 16: 0e c3 0e 97 0e 00 00 00 00 00 00 00 00 00 00 00 ................ +| 3600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 42 ...............B +| 3616: 08 04 00 81 09 73 75 6e 74 20 69 6e 20 63 75 6c .....sunt in cul +| 3632: 70 61 20 71 75 69 20 6f 66 66 69 63 69 61 20 64 pa qui officia d +| 3648: 65 73 65 72 75 6e 74 20 6d 6f 6c 6c 69 74 20 61 eserunt mollit a +| 3664: 6e 69 6d 20 69 64 20 65 73 74 20 6c 61 62 6f 72 nim id est labor +| 3680: 75 6d 2e 32 07 03 00 6b 45 78 63 65 70 74 65 75 um.2...kExcepteu +| 3696: 72 20 73 69 6e 74 20 6f 63 63 61 65 63 61 74 20 r sint occaecat +| 3712: 63 75 70 69 64 61 74 61 74 20 6e 6f 6e 20 70 72 cupidatat non pr +| 3728: 6f 69 64 65 6e 74 2c 2a 06 03 00 5b 63 69 6c 6c oident,*...[cill +| 3744: 75 6d 20 64 6f 6c 6f 72 65 20 65 75 20 66 75 67 um dolore eu fug +| 3760: 69 61 74 20 6e 75 6c 6c 61 20 70 61 72 69 61 74 iat nulla pariat +| 3776: 75 72 2e 42 05 04 00 81 09 44 75 69 73 20 61 75 ur.B.....Duis au +| 3792: 74 65 20 69 72 75 72 65 20 64 6f 6c 6f 72 20 69 te irure dolor i +| 3808: 6e 20 72 65 70 72 65 68 65 6e 64 65 72 69 74 20 n reprehenderit +| 3824: 69 6e 20 76 6f 6c 75 70 74 61 74 65 20 76 65 6c in voluptate vel +| 3840: 69 74 20 65 73 73 65 2b 04 03 00 5d 6e 69 73 69 it esse+...]nisi +| 3856: 20 75 74 20 61 6c 69 71 75 69 70 20 65 78 20 65 ut aliquip ex e +| 3872: 61 20 63 6f 6d 6d 6f 64 6f 20 63 6f 6e 73 65 71 a commodo conseq +| 3888: 75 61 74 2e 46 03 04 00 81 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 74 61 74 69 6f 6e 20 75 6c 6c exercitation 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: 70 73 75 6d 20 64 6f 6c 6f 72 20 73 69 74 20 61 psum dolor sit a +| 4064: 6d 65 74 2c 20 63 6f 6e 73 65 63 74 65 74 75 72 met, consectetur +| 4080: 20 61 64 69 70 69 73 63 69 6e 67 20 65 00 01 00 adipiscing e... +| page 4 offset 12288 +| 0: 0d 00 00 00 03 0a a6 00 0d 57 0c 4a 0a a6 00 00 .........W.J.... +| 2720: 00 00 00 00 00 00 83 21 03 08 02 08 08 08 17 86 .......!........ +| 2736: 30 08 00 30 20 34 30 32 00 02 61 64 06 01 08 00 0..0 402..ad.... +| 2752: 02 04 00 01 01 6c 06 02 0c 00 02 04 00 01 01 6d .....l.........m +| 2768: 03 01 06 00 01 01 6e 03 08 09 00 01 01 75 03 05 ......n......u.. +| 2784: 03 00 00 02 63 69 03 06 02 00 01 01 6f 07 01 07 ....ci......o... +| 2800: 00 03 07 03 00 01 01 75 06 07 05 00 01 04 00 00 .......u........ +| 2816: 02 64 65 03 08 07 00 01 01 6f 0d 01 04 00 01 03 .de......o...... +| 2832: 09 00 03 05 00 01 03 00 01 01 75 03 05 02 00 00 ..........u..... +| 2848: 02 65 61 03 04 06 00 01 01 69 03 02 04 00 01 01 .ea......i...... +| 2864: 6c 03 01 09 00 01 01 6e 03 03 03 00 01 01 73 06 l......n......s. +| 2880: 05 0b 00 03 0b 00 01 01 74 03 02 09 00 01 01 75 ........t......u +| 2896: 03 06 04 00 01 01 78 09 03 09 00 01 05 00 03 02 ......x......... +| 2912: 00 00 02 66 75 03 06 05 00 00 02 69 64 03 08 0a ...fu......id... +| 2928: 00 01 01 6e 0a 02 06 00 03 06 04 00 03 03 00 01 ...n............ +| 2944: 01 70 03 01 03 00 01 01 72 03 05 04 00 00 02 6c .p......r......l +| 2960: 61 09 02 08 00 01 0b 00 05 0c 00 01 01 6f 03 01 a............o.. +| 2976: 02 00 00 02 6d 61 03 02 0b 00 01 01 69 03 03 05 ....ma......i... +| 2992: 00 01 01 6f 03 08 08 00 00 02 6e 69 03 04 02 00 ...o......ni.... +| 3008: 01 01 6f 06 03 08 00 04 06 00 01 01 75 03 06 06 ..o.........u... +| 3024: 00 00 02 6f 63 03 07 04 00 01 01 66 03 08 06 00 ...oc......f.... +| 3040: 00 02 70 61 03 06 07 00 01 01 72 03 07 07 00 00 ..pa......r..... +| 3056: 02 71 75 06 03 07 00 05 05 00 00 02 72 65 03 05 .qu.........re.. +| 3072: 07 00 00 02 73 65 03 02 02 00 01 01 69 06 01 05 ....se......i... +| 3088: 00 06 03 00 01 01 75 03 08 02 00 00 02 74 65 03 ......u......te. +| 3104: 02 05 00 00 02 75 6c 03 03 0a 00 01 01 74 09 02 .....ul......t.. +| 3120: 07 00 01 02 00 01 03 00 00 02 76 65 06 03 06 00 ..........ve.... +| 3136: 02 0a 00 01 01 6f 03 05 09 00 82 0a 02 08 02 08 .....o.......... +| 3152: 08 08 17 84 02 04 00 30 20 32 35 31 00 01 61 13 .......0 251..a. +| 3168: 01 06 04 00 01 0c 00 01 04 00 01 04 00 01 03 00 ................ +| 3184: 03 09 00 00 01 63 10 01 07 00 03 07 03 00 02 02 .....c.......... +| 3200: 00 01 05 00 01 04 00 00 01 64 11 01 04 00 01 03 .........d...... +| 3216: 09 00 03 02 05 00 01 03 00 02 07 00 00 01 65 1b ..............e. +| 3232: 01 09 00 01 04 07 00 01 03 08 00 01 05 03 00 01 ................ +| 3248: 0b 00 01 04 00 01 02 00 01 0b 00 00 01 66 03 06 .............f.. +| 3264: 05 00 00 01 69 0f 01 03 00 01 06 00 03 04 04 04 ....i........... +| 3280: 00 03 03 09 00 00 01 6c 0c 01 02 00 01 08 00 01 .......l........ +| 3296: 0b 00 05 0c 00 00 01 6d 09 02 0b 00 01 05 00 05 .......m........ +| 3312: 08 00 00 01 6e 0c 03 08 00 01 02 00 02 06 00 01 ....n........... +| 3328: 06 00 00 01 6f 06 07 04 00 01 06 00 00 01 70 06 ....o.........p. +| 3344: 06 07 00 01 07 00 00 01 71 06 03 07 00 05 05 00 ........q....... +| 3360: 00 01 72 03 05 07 00 00 01 73 0c 01 05 00 01 02 ..r......s...... +| 3376: 00 05 03 00 01 02 00 00 01 74 03 02 05 00 00 01 .........t...... +| 3392: 75 0a 02 07 00 01 02 0a 00 01 03 00 00 01 76 07 u.............v. +| 3408: 03 06 00 02 09 03 00 85 26 01 08 08 08 08 08 17 ........&....... +| 3424: 8a 3e 30 20 36 36 35 00 02 61 65 03 03 04 00 02 .>0 665..ae..... +| 3440: 08 69 70 69 73 63 69 6e 67 03 01 08 00 01 05 6c .ipiscing......l +| 3456: 69 71 75 61 03 02 0c 00 05 02 69 70 03 04 04 00 iqua......ip.... +| 3472: 01 03 6d 65 74 03 01 06 00 01 03 6e 69 6d 03 08 ..met......nim.. +| 3488: 09 00 01 03 75 74 65 03 05 03 00 00 06 63 69 6c ....ute......cil +| 3504: 6c 75 6d 03 06 02 00 01 06 6f 6d 6d 6f 64 6f 03 lum......ommodo. +| 3520: 04 07 00 02 09 6e 73 65 63 74 65 74 b5 72 03 01 .....nsectet.r.. +| 3536: 07 00 05 04 71 75 61 74 03 04 08 00 01 04 75 6c ....quat......ul +| 3552: 70 61 03 08 04 00 02 07 70 69 64 61 74 61 74 03 pa......pidatat. +| 3568: 07 05 00 00 08 64 65 73 65 72 75 6e 74 03 08 07 .....deserunt... +| 3584: 00 01 01 6f 03 02 03 00 02 03 6c 6f 72 06 01 04 ...o......lor... +| 3600: 00 04 05 00 05 01 65 06 02 0a 00 04 03 00 01 03 ......e......... +| 3616: 75 69 73 03 05 02 00 00 02 65 61 03 04 06 00 01 uis......ea..... +| 3632: 06 69 75 73 6d 6f 64 03 02 04 00 01 03 6c 69 74 .iusmod......lit +| 3648: 03 01 09 00 01 03 6e 69 6d 03 03 03 00 01 03 73 ......nim......s +| 3664: 73 65 03 05 0b 00 02 01 74 03 08 0b 00 01 01 74 se......t......t +| 3680: 03 02 09 00 01 01 75 03 06 04 00 01 01 78 03 04 ......u......x.. +| 3696: 05 00 02 07 63 65 70 74 65 75 72 03 07 02 00 02 ....cepteur..... +| 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 6d 03 01 03 00 01 04 72 75 72 65 03 05 04 00 um......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 05 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 02 00 01 03 t......sed...... +| 4000: 69 6e 74 03 07 03 00 02 01 74 03 01 05 00 01 03 int......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 0f eb 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 08 0f d0 00 0f fa 0f f4 0f ee 0f e8 ................ +| 16: 0f e2 0f dc 0f d6 0f d0 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 0e 0a 04 02 03 00 0e 0b 04 01 03 00 0e 08 ................ +| page 7 offset 24576 +| 0: 0d 00 00 00 01 0f f7 00 0f f7 00 00 00 00 01 00 ................ +| 4080: 00 00 00 00 00 00 00 07 00 03 00 14 08 45 b5 03 .............E.. +| end crash-58821b8eae6883.db +}]} {} + +do_catchsql_test 49.1 { + SAVEPOINT one; + DELETE FROM t1 WHERE t1 MATCH 'c*'; + SELECT matchinfo(t1,'pcx') IS NULL FROM t1 WHERE t1 MATCH 'f*e*'; +} {0 0} + + finish_test diff --git a/test/fts3corrupt6.test b/test/fts3corrupt6.test index 5cb0a18691..8788a61d67 100644 --- a/test/fts3corrupt6.test +++ b/test/fts3corrupt6.test @@ -64,5 +64,3 @@ do_execsql_test 2.1 { set sqlite_fts3_enable_parentheses $saved_sqlite_fts3_enable_parentheses finish_test - - diff --git a/test/fts3join.test b/test/fts3join.test index f3b9b3639a..9a7994193f 100644 --- a/test/fts3join.test +++ b/test/fts3join.test @@ -97,10 +97,10 @@ do_eqp_test 4.2 { WHERE t4.y = ?; } { QUERY PLAN - |--MATERIALIZE xxxxxx - | `--SCAN TABLE ft4 VIRTUAL TABLE INDEX 3: - |--SCAN TABLE t4 - `--SEARCH SUBQUERY xxxxxx AS rr USING AUTOMATIC COVERING INDEX (docid=?) + |--MATERIALIZE rr + | `--SCAN ft4 VIRTUAL TABLE INDEX 3: + |--SCAN t4 + `--SEARCH rr USING AUTOMATIC COVERING INDEX (docid=?) } finish_test diff --git a/test/fts3query.test b/test/fts3query.test index ca3ee6695a..70ee005291 100644 --- a/test/fts3query.test +++ b/test/fts3query.test @@ -119,29 +119,29 @@ do_eqp_test fts3query-4.2 { SELECT t1.number FROM t1, ft WHERE t1.number=ft.rowid ORDER BY t1.date } { QUERY PLAN - |--SCAN TABLE t1 USING COVERING INDEX i1 - `--SCAN TABLE ft VIRTUAL TABLE INDEX 1: + |--SCAN t1 USING COVERING INDEX i1 + `--SCAN ft VIRTUAL TABLE INDEX 1: } do_eqp_test fts3query-4.3 { SELECT t1.number FROM ft, t1 WHERE t1.number=ft.rowid ORDER BY t1.date } { QUERY PLAN - |--SCAN TABLE t1 USING COVERING INDEX i1 - `--SCAN TABLE ft VIRTUAL TABLE INDEX 1: + |--SCAN t1 USING COVERING INDEX i1 + `--SCAN ft VIRTUAL TABLE INDEX 1: } do_eqp_test fts3query-4.4 { SELECT t1.number FROM t1, bt WHERE t1.number=bt.rowid ORDER BY t1.date } { QUERY PLAN - |--SCAN TABLE t1 USING COVERING INDEX i1 - `--SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?) + |--SCAN t1 USING COVERING INDEX i1 + `--SEARCH bt USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test fts3query-4.5 { SELECT t1.number FROM bt, t1 WHERE t1.number=bt.rowid ORDER BY t1.date } { QUERY PLAN - |--SCAN TABLE t1 USING COVERING INDEX i1 - `--SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?) + |--SCAN t1 USING COVERING INDEX i1 + `--SEARCH bt USING INTEGER PRIMARY KEY (rowid=?) } diff --git a/test/fts3snippet2.test b/test/fts3snippet2.test index fc39941890..607b01e0f8 100644 --- a/test/fts3snippet2.test +++ b/test/fts3snippet2.test @@ -57,4 +57,3 @@ do_execsql_test 2.2 { set sqlite_fts3_enable_parentheses 0 finish_test - diff --git a/test/fts4upfrom.test b/test/fts4upfrom.test index b1b43a0374..889b64ad68 100644 --- a/test/fts4upfrom.test +++ b/test/fts4upfrom.test @@ -137,4 +137,3 @@ foreach {tn create_table} { } finish_test - diff --git a/test/fuzzcheck.c b/test/fuzzcheck.c index cb8509e23a..6ec2f8460c 100644 --- a/test/fuzzcheck.c +++ b/test/fuzzcheck.c @@ -936,7 +936,12 @@ int runCombinedDbSqlInput(const uint8_t *aData, size_t nByte, int iTimeout){ sqlite3_set_authorizer(cx.db, block_troublesome_sql, 0); /* Consistent PRNG seed */ +#ifdef SQLITE_TESTCTRL_PRNG_SEED + sqlite3_table_column_metadata(cx.db, 0, "x", 0, 0, 0, 0, 0, 0); + sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SEED, 1, cx.db); +#else sqlite3_randomness(0,0); +#endif zSql = sqlite3_malloc( nSql + 1 ); if( zSql==0 ){ @@ -980,6 +985,8 @@ testrun_finished: sqlite3_memory_used(), nAlloc); exit(1); } + sqlite3_hard_heap_limit64(0); + sqlite3_soft_heap_limit64(0); return 0; } @@ -1428,9 +1435,10 @@ static void showHelp(void){ " --limit-heap N Limit heap memory to N. Default: 100M\n" " --limit-mem N Limit memory used by test SQLite instance to N bytes\n" " --limit-vdbe Panic if any test runs for more than 100,000 cycles\n" -" --load-sql ARGS... Load SQL scripts fron files into SOURCE-DB\n" -" --load-db ARGS... Load template databases from files into SOURCE_DB\n" -" --load-dbsql ARGS.. Load dbsqlfuzz outputs into the xsql table\n" +" --load-sql FILE.. Load SQL scripts fron files into SOURCE-DB\n" +" --load-db FILE.. Load template databases from files into SOURCE_DB\n" +" --load-dbsql FILE.. Load dbsqlfuzz outputs into the xsql table\n" +" ^^^^------ Use \"-\" for FILE to read filenames from stdin\n" " -m TEXT Add a description to the database\n" " --native-vfs Use the native VFS for initially empty database files\n" " --native-malloc Turn off MEMSYS3/5 and Lookaside\n" @@ -1771,10 +1779,25 @@ int main(int argc, char **argv){ rc = sqlite3_exec(db, "BEGIN", 0, 0, 0); if( rc ) fatalError("cannot start a transaction"); for(i=iFirstInsArg; i0 && zLine[kk-1]<=' ' ) kk--; + sqlite3_bind_text(pStmt, 1, zLine, kk, SQLITE_STATIC); + if( verboseFlag ) printf("loading %.*s\n", (int)kk, zLine); + sqlite3_step(pStmt); + rc = sqlite3_reset(pStmt); + if( rc ) fatalError("insert failed for %s", zLine); + } + }else{ + sqlite3_bind_text(pStmt, 1, argv[i], -1, SQLITE_STATIC); + if( verboseFlag ) printf("loading %s\n", argv[i]); + sqlite3_step(pStmt); + rc = sqlite3_reset(pStmt); + if( rc ) fatalError("insert failed for %s", argv[i]); + } } sqlite3_finalize(pStmt); rc = sqlite3_exec(db, "COMMIT", 0, 0, 0); @@ -2043,7 +2066,8 @@ int main(int argc, char **argv){ } } if( bSpinner ){ - printf("\n"); + int nTotal = g.nDb*g.nSql; + printf("\r%s: %d/%d \n", zDbName, nTotal, nTotal); }else if( !quietFlag && !verboseFlag ){ printf(" 100%% - %d tests\n", g.nDb*g.nSql); } diff --git a/test/fuzzdata8.db b/test/fuzzdata8.db index a5e9084192..a552177591 100644 Binary files a/test/fuzzdata8.db and b/test/fuzzdata8.db differ diff --git a/test/hook.test b/test/hook.test index 0b72b2dcff..1dba87f272 100644 --- a/test/hook.test +++ b/test/hook.test @@ -1015,4 +1015,3 @@ do_catchsql_test 12.6 { } {1 {UNIQUE constraint failed: t4.a}} finish_test - diff --git a/test/in4.test b/test/in4.test index bbb32d8a7a..de8c2d6dbc 100644 --- a/test/in4.test +++ b/test/in4.test @@ -330,7 +330,7 @@ do_execsql_test in4-6.1 { do_execsql_test in4-6.1-eqp { EXPLAIN QUERY PLAN SELECT * FROM t6a, t6b WHERE a=3 AND b IN (c); -} {~/SCAN TABLE t6a/} +} {~/SCAN t6a/} do_execsql_test in4-6.2 { SELECT * FROM t6a, t6b WHERE a=3 AND c IN (b); } {3 4 4 44} diff --git a/test/in6.test b/test/in6.test index 3719a6cbf3..f477f60ef2 100644 --- a/test/in6.test +++ b/test/in6.test @@ -97,4 +97,23 @@ do_execsql_test in6-3.110 { SELECT quote(v5) FROM v0 LEFT JOIN v3 ON v4 = NULL AND v5 IN(0); } {NULL} +# 2021-04-29 forum https://sqlite.org/forum/forumpost/6a3ec138e9 +# An early OP_IsNull bypass might skip over the OP_Affinity and +# cause the OP_IfNoHope to jump on a false-positive, resulting in +# incomplete output. +# +reset_db +do_execsql_test in6-3.120 { + CREATE TABLE t1(a TEXT, b TEXT); + INSERT INTO t1 VALUES(null,10),(0,10),(10,10); + CREATE INDEX t1ab ON t1(a,b); + SELECT quote(a), quote(b), '|' FROM t1 WHERE b in (SELECT a FROM t1) AND a=0; +} {'0' '10' |} +do_execsql_test in6-3.130 { + CREATE TABLE t2(x TEXT); + INSERT INTO t2(x) VALUES(NULL),(0),(10); + SELECT quote(x), quote(a), quote(b), 'x' + FROM t2 LEFT JOIN t1 ON a=x AND b in (null,0,10); +} {NULL NULL NULL x '0' '0' '10' x '10' '10' '10' x} + finish_test diff --git a/test/incrvacuum.test b/test/incrvacuum.test index d2b505efe1..d06005c1f6 100644 --- a/test/incrvacuum.test +++ b/test/incrvacuum.test @@ -832,5 +832,61 @@ ifcapable mmap { set res } {1 2 3 4} } - + +# 2021-04-05 dbsqlfuzz cced0668cfd4da4eb2382cb9dd26c17c64aaff76 +# +# This is an incremental vacuum database that has one free page that +# needs to be filled. After removing the last page from the end of +# the database file to fill the free page slot, the last page that +# is left is the tail of an overflow chain. +# +# But the size of the database file is shorter than the actual data +# so that after incremental vacuum runs, the file is actually too +# small to hold the last page of the overflow chain. +# +# At one point this caused an assertion fault in +# sqlite3PagerTruncateImage(). +# +do_test incrvacuum-17.0 { + sqlite3 db {} + database_may_be_corrupt + db deserialize [decode_hexdb { +| size 20480 pagesize 4096 filename x2.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 05 00 00 00 07 .....@ ........ +| 32: 00 00 00 04 00 00 00 01 00 00 00 03 00 00 00 04 ................ +| 48: 00 00 00 00 00 00 00 03 00 00 00 01 00 00 00 00 ................ +| 64: 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 ................ +| 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 ................ +| 96: 00 2e 53 60 0d 0f dc 00 01 0f b8 00 0f b8 0f b8 ..S`............ +| 4016: 00 00 00 00 00 00 00 00 22 02 06 17 11 11 01 31 ...............1 +| 4032: 74 61 62 6c 65 74 32 74 32 03 43 52 45 41 54 45 tablet2t2.CREATE +| 4048: 20 54 41 42 4c 45 20 74 32 28 79 29 00 00 00 24 TABLE t2(y)...$ +| 4064: 11 11 01 31 74 61 62 6c 65 74 31 74 31 03 43 52 ...1tablet1t1.CR +| 4080: 45 41 54 45 20 54 41 42 4c 45 20 74 31 28 78 29 EATE TABLE t1(x) +| page 2 offset 4096 +| 0: 01 00 00 00 00 02 00 00 00 00 03 00 00 00 03 04 ................ +| 16: 00 00 00 05 03 00 00 00 03 00 00 00 00 00 00 00 ................ +| page 3 offset 8192 +| 0: 0d 00 00 00 02 05 47 00 08 dd 05 47 00 00 00 00 ......G....G.... +| 1344: 00 00 00 00 00 00 00 a7 0b 02 03 ce 1c 00 00 00 ................ +| 2256: 00 00 00 00 00 00 00 00 00 00 00 00 07 ce 14 01 ................ +| 2272: 04 81 9c 2c 00 00 00 00 00 00 00 00 00 00 00 00 ...,............ +| 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 ................ +| page 4 offset 12288 +| 0: 00 00 00 00 00 00 00 00 08 dd 05 47 00 00 00 00 ...........G.... +| 1344: 00 00 00 00 00 00 00 a7 0b 02 03 ce 1c 00 00 00 ................ +| 2256: 00 00 00 00 00 00 00 00 00 00 00 00 07 ce 14 01 ................ +| 2272: 04 81 9c 2c 00 00 00 00 00 00 00 00 00 00 00 00 ...,............ +| 4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 ................ +| page 5 offset 16384 +| 0: 00 00 00 06 00 00 00 00 00 00 00 00 00 00 00 00 ................ +| end x2.db +}]} {} +do_catchsql_test incrvacuum-17.1 { + PRAGMA writable_schema=ON; + PRAGMA incremental_vacuum(10); +} {0 {}} + finish_test diff --git a/test/index6.test b/test/index6.test index d385692584..d22c4d47df 100644 --- a/test/index6.test +++ b/test/index6.test @@ -158,7 +158,7 @@ do_test index6-2.2 { EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE a=5; } -} {/.* TABLE t2 USING INDEX t2a1 .*/} +} {/(SEARCH|SCAN) t2 USING INDEX t2a1 /} ifcapable stat4 { execsql ANALYZE do_test index6-2.3stat4 { @@ -166,21 +166,21 @@ ifcapable stat4 { EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE a IS NOT NULL; } - } {/.* TABLE t2 USING INDEX t2a1 .*/} + } {/(SEARCH|SCAN) t2 USING INDEX t2a1 /} } else { do_test index6-2.3stat4 { execsql { EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE a IS NOT NULL AND a>0; } - } {/.* TABLE t2 USING INDEX t2a1 .*/} + } {/(SEARCH|SCANE) t2 USING INDEX t2a1 /} } do_test index6-2.4 { execsql { EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE a IS NULL; } -} {~/.*INDEX t2a1.*/} +} {~/INDEX t2a1/} do_execsql_test index6-2.101 { DROP INDEX t2a1; @@ -319,8 +319,8 @@ do_eqp_test index6-8.1 { SELECT * FROM t8a LEFT JOIN t8b ON (x = 'value' AND y = a) } { QUERY PLAN - |--SCAN TABLE t8a - `--SEARCH TABLE t8b USING INDEX i8c (y=?) + |--SCAN t8a + `--SEARCH t8b USING INDEX i8c (y=?) } do_execsql_test index6-8.2 { diff --git a/test/index7.test b/test/index7.test index 084e8c3c7d..eeb36bab5c 100644 --- a/test/index7.test +++ b/test/index7.test @@ -113,7 +113,7 @@ do_execsql_test index7-1.7 { do_execsql_test index7-1.7eqp { EXPLAIN QUERY PLAN SELECT b FROM t1 WHERE a NOT LIKE 'abc%' AND a=7 ORDER BY +b; -} {/SEARCH TABLE t1 USING COVERING INDEX bad1 /} +} {/SEARCH t1 USING COVERING INDEX bad1 /} do_execsql_test index7-1.8 { DELETE FROM t1 WHERE c>=101; DROP INDEX IF EXISTS bad1; @@ -202,28 +202,28 @@ do_test index7-2.2 { EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE a=5; } -} {/.* TABLE t2 USING COVERING INDEX t2a1 .*/} +} {/(SCAN|SEARCH) t2 USING COVERING INDEX t2a1 /} ifcapable stat4 { do_test index7-2.3stat4 { execsql { EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE a IS NOT NULL; } - } {/.* TABLE t2 USING COVERING INDEX t2a1 .*/} + } {/(SCAN|SEARCH) t2 USING COVERING INDEX t2a1 /} } else { do_test index7-2.3stat4 { execsql { EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE a IS NOT NULL AND a>0; } - } {/.* TABLE t2 USING COVERING INDEX t2a1 .*/} + } {/(SCAN|SEARCH) t2 USING COVERING INDEX t2a1 /} } do_test index7-2.4 { execsql { EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE a IS NULL; } -} {~/.*INDEX t2a1.*/} +} {~/INDEX t2a1/} do_execsql_test index7-2.101 { DROP INDEX t2a1; @@ -321,7 +321,7 @@ do_execsql_test index7-6.3 { } do_eqp_test index7-6.4 { SELECT * FROM v4 WHERE d='xyz' AND c='def' -} {SEARCH TABLE t4 USING INDEX i4 (c=?)} +} {SEARCH t4 USING INDEX i4 (c=?)} do_catchsql_test index7-6.5 { CREATE INDEX t5a ON t5(a) WHERE a=#1; @@ -349,7 +349,7 @@ do_execsql_test index7-8.1 { INSERT INTO t1(x) VALUES(1),(2); ANALYZE; EXPLAIN QUERY PLAN SELECT 1 FROM t1 WHERE y=5; -} {/SEARCH TABLE t1 USING COVERING INDEX t1y/} +} {/SEARCH t1 USING COVERING INDEX t1y/} finish_test diff --git a/test/index8.test b/test/index8.test index bb58228527..41ccf4bbcf 100644 --- a/test/index8.test +++ b/test/index8.test @@ -41,7 +41,7 @@ do_execsql_test 1.0 { do_execsql_test 1.0eqp { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=4 ORDER BY a, b LIMIT 2; -} {/SCAN TABLE t1 USING INDEX t1abc/} +} {/SCAN t1 USING INDEX t1abc/} # If we change the index so that it no longer covers the WHERE clause, # then we should (correctly) revert to using a table scan. diff --git a/test/indexedby.test b/test/indexedby.test index 41a52d8224..6a371112b3 100644 --- a/test/indexedby.test +++ b/test/indexedby.test @@ -42,16 +42,16 @@ proc EQP {sql} { # do_eqp_test indexedby-1.2 { select * from t1 WHERE a = 10; -} {SEARCH TABLE t1 USING INDEX i1 (a=?)} +} {SEARCH t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-1.3 { select * from t1 ; -} {SCAN TABLE t1} +} {SCAN t1} do_eqp_test indexedby-1.4 { select * from t1, t2 WHERE c = 10; } { QUERY PLAN - |--SEARCH TABLE t2 USING INDEX i3 (c=?) - `--SCAN TABLE t1 + |--SEARCH t2 USING INDEX i3 (c=?) + `--SCAN t1 } # Parser tests. Test that an INDEXED BY or NOT INDEX clause can be @@ -118,21 +118,21 @@ do_test indexedby-2.7 { # do_eqp_test indexedby-3.1 { SELECT * FROM t1 WHERE a = 'one' AND b = 'two' -} {/SEARCH TABLE t1 USING INDEX/} +} {/SEARCH t1 USING INDEX/} do_eqp_test indexedby-3.1.1 { SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two' -} {SCAN TABLE t1} +} {SCAN t1} do_eqp_test indexedby-3.1.2 { SELECT * FROM t1 NOT INDEXED WHERE rowid=1 -} {/SEARCH TABLE t1 USING INTEGER PRIMARY KEY .rowid=/} +} {/SEARCH t1 USING INTEGER PRIMARY KEY .rowid=/} do_eqp_test indexedby-3.2 { SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two' -} {SEARCH TABLE t1 USING INDEX i1 (a=?)} +} {SEARCH t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-3.3 { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' AND b = 'two' -} {SEARCH TABLE t1 USING INDEX i2 (b=?)} +} {SEARCH t1 USING INDEX i2 (b=?)} do_test indexedby-3.4 { catchsql { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' } } {0 {}} @@ -148,10 +148,10 @@ do_test indexedby-3.7 { do_eqp_test indexedby-3.8 { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 ORDER BY e -} {SCAN TABLE t3 USING INDEX sqlite_autoindex_t3_1} +} {SCAN t3 USING INDEX sqlite_autoindex_t3_1} do_eqp_test indexedby-3.9 { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE e = 10 -} {SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (e=?)} +} {SEARCH t3 USING INDEX sqlite_autoindex_t3_1 (e=?)} do_test indexedby-3.10 { catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE f = 10 } } {0 {}} @@ -165,15 +165,15 @@ do_eqp_test indexedby-4.1 { SELECT * FROM t1, t2 WHERE a = c } { QUERY PLAN - |--SCAN TABLE t1 - `--SEARCH TABLE t2 USING INDEX i3 (c=?) + |--SCAN t1 + `--SEARCH t2 USING INDEX i3 (c=?) } do_eqp_test indexedby-4.2 { SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c } { QUERY PLAN - |--SCAN TABLE t1 USING INDEX i1 - `--SEARCH TABLE t2 USING INDEX i3 (c=?) + |--SCAN t1 USING INDEX i1 + `--SEARCH t2 USING INDEX i3 (c=?) } do_test indexedby-4.3 { catchsql { @@ -193,10 +193,10 @@ do_test indexedby-4.4 { do_execsql_test indexedby-5.1 { CREATE VIEW v2 AS SELECT * FROM t1 INDEXED BY i1 WHERE a > 5; EXPLAIN QUERY PLAN SELECT * FROM v2 -} {/*SEARCH TABLE t1 USING INDEX i1 (a>?)*/} +} {/*SEARCH t1 USING INDEX i1 (a>?)*/} do_execsql_test indexedby-5.2 { EXPLAIN QUERY PLAN SELECT * FROM v2 WHERE b = 10 -} {/*SEARCH TABLE t1 USING INDEX i1 (a>?)*/} +} {/*SEARCH t1 USING INDEX i1 (a>?)*/} do_test indexedby-5.3 { execsql { DROP INDEX i1 } catchsql { SELECT * FROM v2 } @@ -217,10 +217,10 @@ do_test indexedby-5.5 { # do_eqp_test indexedby-6.1 { SELECT * FROM t1 WHERE b = 10 ORDER BY rowid -} {SEARCH TABLE t1 USING INDEX i2 (b=?)} +} {SEARCH t1 USING INDEX i2 (b=?)} do_eqp_test indexedby-6.2 { SELECT * FROM t1 NOT INDEXED WHERE b = 10 ORDER BY rowid -} {SCAN TABLE t1} +} {SCAN t1} # EVIDENCE-OF: R-40297-14464 The INDEXED BY phrase forces the SQLite # query planner to use a particular named index on a DELETE, SELECT, or @@ -230,19 +230,19 @@ do_eqp_test indexedby-6.2 { # do_eqp_test indexedby-7.1 { DELETE FROM t1 WHERE a = 5 -} {SEARCH TABLE t1 USING INDEX i1 (a=?)} +} {SEARCH t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-7.2 { DELETE FROM t1 NOT INDEXED WHERE a = 5 -} {SCAN TABLE t1} +} {SCAN t1} do_eqp_test indexedby-7.3 { DELETE FROM t1 INDEXED BY i1 WHERE a = 5 -} {SEARCH TABLE t1 USING INDEX i1 (a=?)} +} {SEARCH t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-7.4 { DELETE FROM t1 INDEXED BY i1 WHERE a = 5 AND b = 10 -} {SEARCH TABLE t1 USING INDEX i1 (a=?)} +} {SEARCH t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-7.5 { DELETE FROM t1 INDEXED BY i2 WHERE a = 5 AND b = 10 -} {SEARCH TABLE t1 USING INDEX i2 (b=?)} +} {SEARCH t1 USING INDEX i2 (b=?)} do_test indexedby-7.6 { catchsql { DELETE FROM t1 INDEXED BY i2 WHERE a = 5} } {0 {}} @@ -251,19 +251,19 @@ do_test indexedby-7.6 { # do_eqp_test indexedby-8.1 { UPDATE t1 SET rowid=rowid+1 WHERE a = 5 -} {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)} +} {SEARCH t1 USING COVERING INDEX i1 (a=?)} do_eqp_test indexedby-8.2 { UPDATE t1 NOT INDEXED SET rowid=rowid+1 WHERE a = 5 -} {SCAN TABLE t1} +} {SCAN t1} do_eqp_test indexedby-8.3 { UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 -} {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)} +} {SEARCH t1 USING COVERING INDEX i1 (a=?)} do_eqp_test indexedby-8.4 { UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 AND b = 10 -} {SEARCH TABLE t1 USING INDEX i1 (a=?)} +} {SEARCH t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-8.5 { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5 AND b = 10 -} {SEARCH TABLE t1 USING INDEX i2 (b=?)} +} {SEARCH t1 USING INDEX i2 (b=?)} do_test indexedby-8.6 { catchsql { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5} } {0 {}} @@ -338,7 +338,7 @@ do_execsql_test 11.4 { } {1 1 3} do_eqp_test 11.5 { SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0'; -} {SEARCH TABLE x1 USING COVERING INDEX x1i (a=? AND b=? AND rowid=?)} +} {SEARCH x1 USING COVERING INDEX x1i (a=? AND b=? AND rowid=?)} do_execsql_test 11.6 { CREATE TABLE x2(c INTEGER PRIMARY KEY, a, b TEXT); @@ -359,7 +359,7 @@ do_execsql_test 11.9 { } {1 1 3} do_eqp_test 11.10 { SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0'; -} {SEARCH TABLE x2 USING COVERING INDEX x2i (a=? AND b=? AND rowid=?)} +} {SEARCH x2 USING COVERING INDEX x2i (a=? AND b=? AND rowid=?)} #------------------------------------------------------------------------- # Check INDEXED BY works (throws an exception) with partial indexes that diff --git a/test/indexexpr1.test b/test/indexexpr1.test index 19c2573509..a31b876955 100644 --- a/test/indexexpr1.test +++ b/test/indexexpr1.test @@ -97,14 +97,14 @@ do_execsql_test indexexpr1-170 { do_execsql_test indexexpr1-170eqp { EXPLAIN QUERY PLAN SELECT length(a) FROM t1 ORDER BY length(a); -} {/SCAN TABLE t1 USING INDEX t1alen/} +} {/SCAN t1 USING INDEX t1alen/} do_execsql_test indexexpr1-171 { SELECT length(a) FROM t1 ORDER BY length(a) DESC; } {52 38 29 27 25 20} do_execsql_test indexexpr1-171eqp { EXPLAIN QUERY PLAN SELECT length(a) FROM t1 ORDER BY length(a) DESC; -} {/SCAN TABLE t1 USING INDEX t1alen/} +} {/SCAN t1 USING INDEX t1alen/} do_execsql_test indexexpr1-200 { DROP TABLE t1; diff --git a/test/indexexpr2.test b/test/indexexpr2.test index 35caef3c24..8c1171e038 100644 --- a/test/indexexpr2.test +++ b/test/indexexpr2.test @@ -93,7 +93,7 @@ ifcapable json1 { ORDER BY json_extract(x, '$.b') COLLATE nocase; } [string map {"\n " \n} { QUERY PLAN - |--SCAN TABLE t2 + |--SCAN t2 `--USE TEMP B-TREE FOR GROUP BY }] @@ -108,7 +108,7 @@ ifcapable json1 { ORDER BY json_extract(x, '$.b') COLLATE nocase; } [string map {"\n " \n} { QUERY PLAN - |--SEARCH TABLE t3 USING INDEX i3 (=?) + |--SEARCH t3 USING INDEX i3 (=?) `--USE TEMP B-TREE FOR GROUP BY }] } @@ -154,7 +154,7 @@ do_execsql_test 3.4.5 { do_execsql_test 3.4.5eqp { EXPLAIN QUERY PLAN SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE nocase; -} {/SCAN TABLE t4 USING INDEX i4/} +} {/SCAN t4 USING INDEX i4/} do_execsql_test 3.4.6 { SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE binary; } {.ABC1 1 .ABC3 3 .abc2 2 .abc4 4} @@ -265,7 +265,7 @@ do_execsql_test 6.1.2 { } {1 123 2 123 3 123abc 4 123.0} do_eqp_test 6.1.3 { SELECT a, b FROM x1 WHERE CAST(b AS INTEGER) = 123; -} {SEARCH TABLE x1 USING INDEX x1i (=?)} +} {SEARCH x1 USING INDEX x1i (=?)} do_execsql_test 6.2.1 { SELECT a, b FROM x1 WHERE CAST(b AS TEXT) = 123; @@ -276,7 +276,7 @@ do_execsql_test 6.2.2 { } {1 123 2 123} do_eqp_test 6.2.3 { SELECT a, b FROM x1 WHERE CAST(b AS TEXT) = 123; -} {SEARCH TABLE x1 USING INDEX x1i2 (=?)} +} {SEARCH x1 USING INDEX x1i2 (=?)} do_execsql_test 7.0 { CREATE TABLE IF NOT EXISTS t0(c0); diff --git a/test/intpkey.test b/test/intpkey.test index a56cab4c69..d6b8833a27 100644 --- a/test/intpkey.test +++ b/test/intpkey.test @@ -129,7 +129,7 @@ do_test intpkey-1.12.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a==4; } -} {/SEARCH TABLE t1 /} +} {/SEARCH t1 /} # Try to insert a non-integer value into the primary key field. This # should result in a data type mismatch. diff --git a/test/join2.test b/test/join2.test index f004fda071..170000ca27 100644 --- a/test/join2.test +++ b/test/join2.test @@ -113,16 +113,16 @@ do_eqp_test 3.1 { SELECT v2 FROM t1 LEFT JOIN t2 USING (k2) LEFT JOIN t3_1 USING (k3); } { QUERY PLAN - |--SCAN TABLE t1 - `--SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?) + |--SCAN t1 + `--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test 3.2 { SELECT v2 FROM t1 LEFT JOIN t2 USING (k2) LEFT JOIN t3_2 USING (k3); } { QUERY PLAN - |--SCAN TABLE t1 - `--SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?) + |--SCAN t1 + `--SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?) } #------------------------------------------------------------------------- @@ -161,16 +161,16 @@ do_eqp_test 4.1.5 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v2); } { QUERY PLAN - |--SCAN TABLE c1 - |--SEARCH TABLE c2 USING INTEGER PRIMARY KEY (rowid=?) - `--SEARCH TABLE c3 USING INTEGER PRIMARY KEY (rowid=?) + |--SCAN c1 + |--SEARCH c2 USING INTEGER PRIMARY KEY (rowid=?) + `--SEARCH c3 USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test 4.1.6 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1); } { QUERY PLAN - |--SCAN TABLE c1 - `--SEARCH TABLE c3 USING INTEGER PRIMARY KEY (rowid=?) + |--SCAN c1 + `--SEARCH c3 USING INTEGER PRIMARY KEY (rowid=?) } do_execsql_test 4.2.0 { @@ -208,16 +208,16 @@ do_eqp_test 4.2.5 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v2); } { QUERY PLAN - |--SCAN TABLE c1 - |--SEARCH TABLE c2 USING INDEX sqlite_autoindex_c2_1 (k=?) - `--SEARCH TABLE c3 USING INDEX sqlite_autoindex_c3_1 (k=?) + |--SCAN c1 + |--SEARCH c2 USING INDEX sqlite_autoindex_c2_1 (k=?) + `--SEARCH c3 USING INDEX sqlite_autoindex_c3_1 (k=?) } do_eqp_test 4.2.6 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1); } { QUERY PLAN - |--SCAN TABLE c1 - `--SEARCH TABLE c3 USING INDEX sqlite_autoindex_c3_1 (k=?) + |--SCAN c1 + `--SEARCH c3 USING INDEX sqlite_autoindex_c3_1 (k=?) } # 2017-11-23 (Thanksgiving day) @@ -251,11 +251,11 @@ do_execsql_test 5.0 { } do_eqp_test 5.1 { SELECT s1.a FROM s1 left join s2 using (a); -} {SCAN TABLE s1} +} {SCAN s1} do_eqp_test 5.2 { SELECT s1.a FROM s1 left join s3 using (a); -} {SCAN TABLE s1} +} {SCAN s1} do_execsql_test 6.0 { CREATE TABLE u1(a INTEGER PRIMARY KEY, b, c); @@ -264,7 +264,7 @@ do_execsql_test 6.0 { } do_eqp_test 6.1 { SELECT u2.* FROM u2 LEFT JOIN u1 ON( u1.a=u2.a AND u1.b=u2.b AND u1.c=u2.c ); -} {SCAN TABLE u2} +} {SCAN u2} db close sqlite3 db :memory: diff --git a/test/join5.test b/test/join5.test index 6724419e6d..e2ff2f6c27 100644 --- a/test/join5.test +++ b/test/join5.test @@ -277,12 +277,12 @@ do_eqp_test 7.2 { ); } { QUERY PLAN - |--SCAN TABLE t1 + |--SCAN t1 `--MULTI-INDEX OR |--INDEX 1 - | `--SEARCH TABLE t2 USING INDEX t2xy (x=? AND y=?) + | `--SEARCH t2 USING INDEX t2xy (x=? AND y=?) `--INDEX 2 - `--SEARCH TABLE t2 USING INDEX t2xy (x=? AND y=?) + `--SEARCH t2 USING INDEX t2xy (x=? AND y=?) } do_execsql_test 7.3 { @@ -302,8 +302,8 @@ do_eqp_test 7.4 { SELECT * FROM t3 LEFT JOIN t4 ON (t4.x = t3.x) WHERE (t4.y = ? OR t4.z = ?); } { QUERY PLAN - |--SCAN TABLE t3 - `--SEARCH TABLE t4 USING INDEX t4xz (x=?) + |--SCAN t3 + `--SEARCH t4 USING INDEX t4xz (x=?) } reset_db diff --git a/test/like.test b/test/like.test index 8ea7cff782..e8662dc6c3 100644 --- a/test/like.test +++ b/test/like.test @@ -168,13 +168,13 @@ proc queryplan {sql} { set eqp [execsql "EXPLAIN QUERY PLAN $sql"] # puts eqp=$eqp foreach {a b c x} $eqp { - if {[regexp { TABLE (\w+ AS )?(\w+) USING COVERING INDEX (\w+)\y} \ - $x all as tab idx]} { + if {[regexp {(SCAN|SEARCH) (\w+ AS )?(\w+) USING COVERING INDEX (\w+)\y} \ + $x all ss as tab idx]} { lappend data {} $idx - } elseif {[regexp { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ - $x all as tab idx]} { + } elseif {[regexp {(SCAN|SEARCH) (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ + $x all ss as tab idx]} { lappend data $tab $idx - } elseif {[regexp { TABLE (\w+ AS )?(\w+)\y} $x all as tab]} { + } elseif {[regexp {(SCAN|SEARCH) (\w+ AS )?(\w+)\y} $x all ss as tab]} { lappend data $tab * } } @@ -726,7 +726,7 @@ ifcapable like_opt&&!icu { set res [sqlite3_exec_hex db { EXPLAIN QUERY PLAN SELECT x FROM t2 WHERE x LIKE '%ff%25' }] - regexp {SCAN TABLE t2} $res + regexp {SCAN t2} $res } {1} } do_test like-9.5.1 { @@ -1036,16 +1036,18 @@ do_test like-14.1 { set x [lindex [time { db one {SELECT 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaz'GLOB'*a*a*a*a*a*a*a*a*y'} }] 0] - puts -nonewline " ($x ms - want less than 1000) " - expr {$x<1000} + set tlimit [expr {1000 * $::sqlite_options(configslower)}] + puts -nonewline " ($x ms - want less than $tlimit) " + expr {$x<$tlimit} } {1} ifcapable !icu { do_test like-14.2 { set x [lindex [time { db one {SELECT 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaz'LIKE'%a%a%a%a%a%a%a%a%y'} }] 0] - puts -nonewline " ($x ms - want less than 1000) " - expr {$x<1000} + set tlimit [expr {1000 * $::sqlite_options(configslower)}] + puts -nonewline " ($x ms - want less than $tlimit) " + expr {$x<$tlimit} } {1} } diff --git a/test/like3.test b/test/like3.test index 3bfe30c318..a93e113d62 100644 --- a/test/like3.test +++ b/test/like3.test @@ -125,7 +125,7 @@ do_eqp_test like3-5.101 { SELECT x FROM t5a WHERE x LIKE '/%'; } { QUERY PLAN - `--SCAN TABLE t5a + `--SCAN t5a } do_execsql_test like3-5.110 { SELECT x FROM t5a WHERE x LIKE '/a%'; @@ -135,7 +135,7 @@ do_eqp_test like3-5.111 { SELECT x FROM t5a WHERE x LIKE '/a%'; } { QUERY PLAN - `--SEARCH TABLE t5a USING COVERING INDEX sqlite_autoindex_t5a_1 (x>? AND x? AND x? AND x? AND x? AND path? AND path? AND path? AND path? AND path? AND path? AND path? AND path? AND path? AND path? AND path? AND path? AND b? AND b'xray' RETURNING a, b, '@'; +} {1 9 @ happy glad @} +do_execsql_test 11.4 { + SELECT * FROM log; + DELETE FROM log; +} {I1 1 2 I1 happy glad U1 1 9 D1 1 9 D1 happy glad} +do_execsql_test 11.5 { + INSERT INTO t2 VALUES('bravo','charlie') RETURNING d, c, 'z'; +} {charlie bravo z} +do_execsql_test 11.6 { + SELECT * FROM log; + DELETE FROM log; +} {I2 bravo charlie} +do_execsql_test 11.7 { + INSERT INTO t3(e) VALUES(1),(2),(3) RETURNING 'I', e; + UPDATE t3 SET f=e+100 RETURNING 'U', e, f; + DELETE FROM t3 WHERE f>100 RETURNING 'D', e, f; +} {I 1 I 2 I 3 U 1 101 U 2 102 U 3 103 D 1 101 D 2 102 D 3 103} +do_execsql_test 11.6 { + SELECT * FROM log; + DELETE FROM log; +} {U3 1 101 U3 2 102 U3 3 103 D3 1 101 D3 2 102 D3 3 103} + +reset_db +do_execsql_test 11.11 { + CREATE TEMP TABLE t1(a,b); + CREATE TRIGGER r1 BEFORE INSERT ON t1 BEGIN SELECT 1; END; + DELETE FROM t1 RETURNING *; + DROP TRIGGER r1; + INSERT INTO t1 VALUES(5,30); +} {} +do_execsql_test 11.12 { + SELECT * FROM t1; +} {5 30} + +# RETURNING column names are dequoted. +# https://sqlite.org/forum/forumpost/033daf0b32 +# +reset_db +do_test 12.1 { + db eval {CREATE TABLE t1(x INT, y INT)} + unset -nocomplain cname + db eval {INSERT INTO t1(x) VALUES(1) RETURNING "x";} cname {} + lsort [array names cname] +} {* x} +do_test 12.2 { + unset -nocomplain cname + db eval {INSERT INTO t1(x) VALUES(2) RETURNING [x];} cname {} + lsort [array names cname] +} {* x} +do_test 12.3 { + unset -nocomplain cname + db eval {INSERT INTO t1(x) VALUES(3) RETURNING x AS [xyz];} cname {} + lsort [array names cname] +} {* xyz} +do_test 12.4 { + unset -nocomplain cname + db eval {INSERT INTO t1(x,y) VALUES(4,5) RETURNING "x"+"y";} cname {} + lsort [array names cname] +} {{"x"+"y"} *} + +finish_test diff --git a/test/rollback2.test b/test/rollback2.test index 70aecc3377..21ebdeaca0 100644 --- a/test/rollback2.test +++ b/test/rollback2.test @@ -101,7 +101,7 @@ do_rollback_test 2.2 -setup { # do_eqp_test 3.1 { SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h DESC; -} {SCAN TABLE t1 USING INDEX i1} +} {SCAN t1 USING INDEX i1} do_rollback_test 3.2 -setup { BEGIN; DELETE FROM t1 WHERE (i%2)==1; @@ -131,7 +131,7 @@ do_execsql_test 4.1 { UPDATE t1 SET h = $leader || h; } do_eqp_test 4.2 { SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC; -} {SCAN TABLE t1 USING INDEX i1} +} {SCAN t1 USING INDEX i1} do_rollback_test 4.3 -setup { BEGIN; DELETE FROM t1 WHERE (i%2)==1; diff --git a/test/rowvalue.test b/test/rowvalue.test index b9967a865a..79cde62762 100644 --- a/test/rowvalue.test +++ b/test/rowvalue.test @@ -175,19 +175,19 @@ do_execsql_test 7.0 { foreach {tn sql res eqp} { 1 "SELECT * FROM xy WHERE (i, j) IS (2, 2)" {2 2 2} - "SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid=?)" + "SEARCH xy USING INTEGER PRIMARY KEY (rowid=?)" 2 "SELECT * FROM xy WHERE (k, j) < (2, 3)" {1 1 1 2 2 2} - "SCAN TABLE xy" + "SCAN xy" 3 "SELECT * FROM xy WHERE (i, j) < (2, 3)" {1 1 1 2 2 2} - "SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid (2, 1)" {2 2 2 3 3 3 4 4 4} - "SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid>?)" + "SEARCH xy USING INTEGER PRIMARY KEY (rowid>?)" 5 "SELECT * FROM xy WHERE (i, j) > ('2', 1)" {2 2 2 3 3 3 4 4 4} - "SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid>?)" + "SEARCH xy USING INTEGER PRIMARY KEY (rowid>?)" } { do_eqp_test 7.$tn.1 $sql $eqp diff --git a/test/rowvalue4.test b/test/rowvalue4.test index 2929a97d10..784859cb19 100644 --- a/test/rowvalue4.test +++ b/test/rowvalue4.test @@ -185,31 +185,31 @@ ifcapable stat4 { } do_eqp_test 3.1.1 { SELECT * FROM c1 WHERE a=1 AND c=2 } \ - {SEARCH TABLE c1 USING INDEX c1cd (c=?)} + {SEARCH c1 USING INDEX c1cd (c=?)} do_eqp_test 3.1.2 { SELECT * FROM c1 WHERE a=1 AND b>'d' AND c=2 } \ - {SEARCH TABLE c1 USING INDEX c1cd (c=?)} + {SEARCH c1 USING INDEX c1cd (c=?)} do_eqp_test 3.1.3 { SELECT * FROM c1 WHERE a=1 AND b>'l' AND c=2 } \ - {SEARCH TABLE c1 USING INDEX c1ab (a=? AND b>?)} + {SEARCH c1 USING INDEX c1ab (a=? AND b>?)} do_eqp_test 3.2.1 { SELECT * FROM c1 WHERE a=1 AND c>1 } \ - {SEARCH TABLE c1 USING INDEX c1cd (c>?)} + {SEARCH c1 USING INDEX c1cd (c>?)} do_eqp_test 3.2.2 { SELECT * FROM c1 WHERE a=1 AND c>0 } \ - {SEARCH TABLE c1 USING INDEX c1ab (a=?)} + {SEARCH c1 USING INDEX c1ab (a=?)} do_eqp_test 3.2.3 { SELECT * FROM c1 WHERE a=1 AND c>=1 } \ - {SEARCH TABLE c1 USING INDEX c1ab (a=?)} + {SEARCH c1 USING INDEX c1ab (a=?)} do_eqp_test 3.2.4 { SELECT * FROM c1 WHERE a=1 AND (c, d)>(1, 'c') } \ - {SEARCH TABLE c1 USING INDEX c1ab (a=?)} + {SEARCH c1 USING INDEX c1ab (a=?)} do_eqp_test 3.2.5 { SELECT * FROM c1 WHERE a=1 AND (c, d)>(1, 'o') } \ - {SEARCH TABLE c1 USING INDEX c1cd ((c,d)>(?,?))} + {SEARCH c1 USING INDEX c1cd ((c,d)>(?,?))} do_eqp_test 3.2.6 { SELECT * FROM c1 WHERE a=1 AND (c, +b)>(1, 'c') } \ - {SEARCH TABLE c1 USING INDEX c1ab (a=?)} + {SEARCH c1 USING INDEX c1ab (a=?)} } @@ -234,11 +234,11 @@ do_eqp_test 5.1 { (c) IN (SELECT y FROM d1) } { QUERY PLAN - |--SEARCH TABLE d2 USING INDEX d2ab (a=? AND b=?) + |--SEARCH d2 USING INDEX d2ab (a=? AND b=?) |--LIST SUBQUERY xxxxxx - | `--SCAN TABLE d1 + | `--SCAN d1 `--LIST SUBQUERY xxxxxx - `--SCAN TABLE d1 + `--SCAN d1 } do_execsql_test 6.0 { @@ -249,23 +249,23 @@ do_execsql_test 6.0 { do_eqp_test 6.1 { SELECT * FROM e1 WHERE (a, b) > (?, ?) -} {SEARCH TABLE e1 USING INDEX e1ab ((a,b)>(?,?))} +} {SEARCH e1 USING INDEX e1ab ((a,b)>(?,?))} do_eqp_test 6.2 { SELECT * FROM e1 WHERE (a, b) < (?, ?) -} {SEARCH TABLE e1 USING INDEX e1ab ((a,b)<(?,?))} +} {SEARCH e1 USING INDEX e1ab ((a,b)<(?,?))} do_eqp_test 6.3 { SELECT * FROM e1 WHERE c = ? AND (d, e) > (?, ?) -} {SEARCH TABLE e1 USING INDEX e1cde (c=? AND (d,e)>(?,?))} +} {SEARCH e1 USING INDEX e1cde (c=? AND (d,e)>(?,?))} do_eqp_test 6.4 { SELECT * FROM e1 WHERE c = ? AND (d, e) < (?, ?) -} {SEARCH TABLE e1 USING INDEX e1cde (c=? AND (d,e)<(?,?))} +} {SEARCH e1 USING INDEX e1cde (c=? AND (d,e)<(?,?))} do_eqp_test 6.5 { SELECT * FROM e1 WHERE (d, e) BETWEEN (?, ?) AND (?, ?) AND c = ? -} {SEARCH TABLE e1 USING INDEX e1cde (c=? AND (d,e)>(?,?) AND (d,e)<(?,?))} +} {SEARCH e1 USING INDEX e1cde (c=? AND (d,e)>(?,?) AND (d,e)<(?,?))} #------------------------------------------------------------------------- diff --git a/test/scanstatus.test b/test/scanstatus.test index 1b92ef3fe1..46249f665d 100644 --- a/test/scanstatus.test +++ b/test/scanstatus.test @@ -45,8 +45,8 @@ proc do_scanstatus_test {tn res} { do_execsql_test 1.1 { SELECT count(*) FROM t1, t2; } 6 do_scanstatus_test 1.2 { - nLoop 1 nVisit 2 nEst 1048576.0 zName t1 zExplain {SCAN TABLE t1} - nLoop 2 nVisit 6 nEst 1048576.0 zName t2 zExplain {SCAN TABLE t2} + nLoop 1 nVisit 2 nEst 1048576.0 zName t1 zExplain {SCAN t1} + nLoop 2 nVisit 6 nEst 1048576.0 zName t2 zExplain {SCAN t2} } do_execsql_test 1.3 { @@ -54,8 +54,8 @@ do_execsql_test 1.3 { SELECT count(*) FROM t1, t2; } 6 do_scanstatus_test 1.4 { - nLoop 1 nVisit 2 nEst 2.0 zName t1 zExplain {SCAN TABLE t1} - nLoop 2 nVisit 6 nEst 3.0 zName t2 zExplain {SCAN TABLE t2} + nLoop 1 nVisit 2 nEst 2.0 zName t1 zExplain {SCAN t1} + nLoop 2 nVisit 6 nEst 3.0 zName t2 zExplain {SCAN t2} } do_execsql_test 1.5 { ANALYZE } @@ -64,8 +64,8 @@ do_execsql_test 1.6 { } 4 do_scanstatus_test 1.7 { nLoop 1 nVisit 2 nEst 2.0 zName t2 zExplain - {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} - nLoop 2 nVisit 4 nEst 2.0 zName t1 zExplain {SCAN TABLE t1} + {SEARCH t2 USING INTEGER PRIMARY KEY (rowid>?)} + nLoop 2 nVisit 4 nEst 2.0 zName t1 zExplain {SCAN t1} } do_execsql_test 1.8 { @@ -74,8 +74,8 @@ do_execsql_test 1.8 { do_scanstatus_test 1.9 { nLoop 2 nVisit 4 nEst 2.0 zName t2 zExplain - {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} - nLoop 4 nVisit 8 nEst 2.0 zName t1 zExplain {SCAN TABLE t1} + {SEARCH t2 USING INTEGER PRIMARY KEY (rowid>?)} + nLoop 4 nVisit 8 nEst 2.0 zName t1 zExplain {SCAN t1} } do_test 1.9 { @@ -84,8 +84,8 @@ do_test 1.9 { do_scanstatus_test 1.10 { nLoop 0 nVisit 0 nEst 2.0 zName t2 zExplain - {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} - nLoop 0 nVisit 0 nEst 2.0 zName t1 zExplain {SCAN TABLE t1} + {SEARCH t2 USING INTEGER PRIMARY KEY (rowid>?)} + nLoop 0 nVisit 0 nEst 2.0 zName t1 zExplain {SCAN t1} } #------------------------------------------------------------------------- @@ -105,7 +105,7 @@ do_execsql_test 2.1 { do_scanstatus_test 2.2 { nLoop 1 nVisit 1 nEst 1.0 zName x1 - zExplain {SEARCH TABLE x1 USING INTEGER PRIMARY KEY (rowid=?)} + zExplain {SEARCH x1 USING INTEGER PRIMARY KEY (rowid=?)} } do_execsql_test 2.3.1 { @@ -113,7 +113,7 @@ do_execsql_test 2.3.1 { } {2 two} do_scanstatus_test 2.3.2 { nLoop 1 nVisit 1 nEst 10.0 zName x1j - zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j=?)} + zExplain {SEARCH x1 USING COVERING INDEX x1j (j=?)} } do_execsql_test 2.4.1 { @@ -121,7 +121,7 @@ do_execsql_test 2.4.1 { } {4 four 1 one 3 three} do_scanstatus_test 2.4.2 { nLoop 1 nVisit 3 nEst 262144.0 zName x1j - zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j?)} + zExplain {SEARCH x1 USING COVERING INDEX x1j (j>?)} } do_execsql_test 2.6.1 { @@ -137,7 +137,7 @@ do_execsql_test 2.6.1 { } {3 three 2 two} do_scanstatus_test 2.6.2 { nLoop 1 nVisit 2 nEst 16384.0 zName x1j - zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j>? AND j? AND j? AND j? AND j? AND a? AND a? AND b? AND b? AND b? AND b? AND a? AND a5 GROUP BY x1.d) AS x2 ON t41.b=x2.d; -} {/*SEARCH SUBQUERY * AS x2 USING AUTOMATIC*/} +} {/SEARCH x2 USING AUTOMATIC/} finish_test diff --git a/test/skipscan1.test b/test/skipscan1.test index 367cd2a108..94062fb17e 100644 --- a/test/skipscan1.test +++ b/test/skipscan1.test @@ -341,7 +341,7 @@ optimization_control db skip-scan 0 do_execsql_test skipscan1-9.3 { EXPLAIN QUERY PLAN SELECT * FROM t9a WHERE b IN (SELECT x FROM t9b WHERE y!=5); -} {/{SCAN TABLE t9a}/} +} {/{SCAN t9a}/} optimization_control db skip-scan 1 do_execsql_test skipscan1-2.1 { @@ -394,7 +394,7 @@ do_eqp_test skipscan1-3.2 { FROM t1 WHERE t1.c3 = 1; } { QUERY PLAN - |--SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (ANY(c4) AND c3=?) + |--SEARCH t1 USING INDEX sqlite_autoindex_t1_1 (ANY(c4) AND c3=?) `--USE TEMP B-TREE FOR DISTINCT } diff --git a/test/skipscan2.test b/test/skipscan2.test index 6fa04d54c6..47b2b3fffa 100644 --- a/test/skipscan2.test +++ b/test/skipscan2.test @@ -199,7 +199,7 @@ do_test skipscan2-3.2 { } {} do_eqp_test skipscan2-3.3eqp { SELECT * FROM t3 WHERE b=42; -} {SEARCH TABLE t3 USING PRIMARY KEY (ANY(a) AND b=?)} +} {SEARCH t3 USING PRIMARY KEY (ANY(a) AND b=?)} diff --git a/test/skipscan5.test b/test/skipscan5.test index c128e614c1..026356e6c0 100644 --- a/test/skipscan5.test +++ b/test/skipscan5.test @@ -41,20 +41,20 @@ do_test 1.2 { foreach {tn q res} { 1 "b = 5" {/*ANY(a) AND b=?*/} 2 "b > 12 AND b < 16" {/*ANY(a) AND b>? AND b 2 AND b < 16" {/*SCAN TABLE t1*/} + 3 "b > 2 AND b < 16" {/*SCAN t1*/} 4 "b > 18 AND b < 25" {/*ANY(a) AND b>? AND b 16" {/*ANY(a) AND b>?*/} - 6 "b > 5" {/*SCAN TABLE t1*/} - 7 "b < 15" {/*SCAN TABLE t1*/} + 6 "b > 5" {/*SCAN t1*/} + 7 "b < 15" {/*SCAN t1*/} 8 "b < 5" {/*ANY(a) AND b b" {/*ANY(a) AND b '12' AND b < '16'" {/*ANY(a) AND b>? AND b '2' AND b < '16'" {/*SCAN TABLE t1*/} + 12 "b > '2' AND b < '16'" {/*SCAN t1*/} 13 "b > '18' AND b < '25'" {/*ANY(a) AND b>? AND b '16'" {/*ANY(a) AND b>?*/} - 15 "b > '5'" {/*SCAN TABLE t1*/} - 16 "b < '15'" {/*SCAN TABLE t1*/} + 15 "b > '5'" {/*SCAN t1*/} + 16 "b < '15'" {/*SCAN t1*/} 17 "b < '5'" {/*ANY(a) AND b b" {/*ANY(a) AND b? AND c 'q' } {/*ANY(a) AND ANY(b) AND c>?*/} - 4 { c > 'e' } {/*SCAN TABLE t2*/} - 5 { c < 'q' } {/*SCAN TABLE t2*/} + 4 { c > 'e' } {/*SCAN t2*/} + 5 { c < 'q' } {/*SCAN t2*/} 6 { c < 'b' } {/*ANY(a) AND ANY(b) AND c? AND b X'5555'" {/*ANY(a) AND b>?*/} 5 "b > 'zzz'" {/*ANY(a) AND b>?*/} - 6 "b < 'zzz'" {/*SCAN TABLE t3*/} + 6 "b < 'zzz'" {/*SCAN t3*/} } { set sql "EXPLAIN QUERY PLAN SELECT * FROM t3 WHERE $q" do_execsql_test 3.3.$tn $sql $res diff --git a/test/skipscan6.test b/test/skipscan6.test index a53be1d952..4f592bc0e0 100644 --- a/test/skipscan6.test +++ b/test/skipscan6.test @@ -179,13 +179,13 @@ do_execsql_test 3.0 { # do_eqp_test 3.1 { SELECT * FROM t3 WHERE a = ? AND c = ? -} {SEARCH TABLE t3 USING INDEX t3_a (a=?)} +} {SEARCH t3 USING INDEX t3_a (a=?)} # The same query on table t2. This should use index "t2_a", for the # same reason. At one point though, it was mistakenly using a skip-scan. # do_eqp_test 3.2 { SELECT * FROM t2 WHERE a = ? AND c = ? -} {SEARCH TABLE t2 USING INDEX t2_a (a=?)} +} {SEARCH t2 USING INDEX t2_a (a=?)} finish_test diff --git a/test/tabfunc01.test b/test/tabfunc01.test index 04bc6f42ad..797267b338 100644 --- a/test/tabfunc01.test +++ b/test/tabfunc01.test @@ -227,6 +227,50 @@ do_test tabfunc01-751 { } } {5.0 x5 | 7.0 x7 | 13.0 x13 | 17.0 x17 | 23.0 x23 |} +ifcapable altertable { + do_test tabfunc01-800 { + catchsql { + ALTER TABLE generate_series ADD COLUMN col2; + } + } {1 {virtual tables may not be altered}} + do_test tabfunc01-810 { + catchsql { + ALTER TABLE generate_series RENAME TO flubber; + } + } {1 {table generate_series may not be altered}} + do_test tabfunc01-820 { + catchsql { + ALTER TABLE generate_series RENAME start TO flubber; + } + } {1 {table generate_series may not be altered}} + do_test tabfunc01-830 { + catchsql { + ALTER TABLE generate_series DROP COLUMN start; + } + } {1 {table generate_series may not be altered}} + do_test tabfunc01-900 { + catchsql { + ALTER TABLE pragma_compile_options ADD COLUMN col2; + } + } {1 {virtual tables may not be altered}} + do_test tabfunc01-910 { + catchsql { + ALTER TABLE pragma_compile_options RENAME TO flubber; + } + } {1 {table pragma_compile_options may not be altered}} + do_test tabfunc01-920 { + catchsql { + ALTER TABLE pragma_compile_options RENAME start TO flubber; + } + } {1 {table pragma_compile_options may not be altered}} + do_test tabfunc01-930 { + catchsql { + ALTER TABLE pragma_compile_options DROP COLUMN start; + } + } {1 {table pragma_compile_options may not be altered}} +} + + # Free up memory allocations intarray_addr int64array_addr diff --git a/test/threadtest5.c b/test/threadtest5.c new file mode 100644 index 0000000000..6e6610ff66 --- /dev/null +++ b/test/threadtest5.c @@ -0,0 +1,339 @@ +/* +** 2021-05-12 +** +** 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. +** +************************************************************************* +** +** Testing threading behavior when multiple database connections in separate +** threads of the same process are all talking to the same database file. +** +** For best results, ensure that SQLite is compiled with HAVE_USLEEP=1 +** +** Only works on unix platforms. +** +** Usage: +** +** ./threadtest5 ?DATABASE? +** +** If DATABASE is omitted, it defaults to using file:/mem?vfs=memdb. +*/ +#include "sqlite3.h" +#include +#include +#include +#include +#include +#include + +/* Name of the in-memory database */ +static char *zDbName = 0; + +/* True for debugging */ +static int eVerbose = 0; + +/* If rc is not SQLITE_OK, then print an error message and stop +** the test. +*/ +static void error_out(int rc, const char *zCtx, int lineno){ + if( rc!=SQLITE_OK ){ + fprintf(stderr, "error %d at %d in \"%s\"\n", rc, lineno, zCtx); + exit(-1); + } +} + +#if 0 +/* Return the number of milliseconds since the Julian epoch (-4714-11-24). +*/ +static sqlite3_int64 gettime(void){ + sqlite3_int64 tm; + sqlite3_vfs *pVfs = sqlite3_vfs_find(0); + pVfs->xCurrentTimeInt64(pVfs, &tm); + return tm; +} +#endif + +/* Run the SQL in the second argument. +*/ +static int exec( + sqlite3 *db, + const char *zId, + int lineno, + const char *zFormat, + ... +){ + int rc; + va_list ap; + char *zSql; + va_start(ap, zFormat); + zSql = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + if( eVerbose){ + printf("%s:%d: [%s]\n", zId, lineno, zSql); + fflush(stdout); + } + rc = sqlite3_exec(db, zSql, 0, 0, 0); + if( rc && eVerbose ){ + printf("%s:%d: return-code %d\n", zId, lineno, rc); + fflush(stdout); + } + sqlite3_free(zSql); + return rc; +} + +/* Generate a perpared statement from the input SQL +*/ +static sqlite3_stmt *prepare( + sqlite3 *db, + const char *zId, + int lineno, + const char *zFormat, + ... +){ + int rc; + va_list ap; + char *zSql; + sqlite3_stmt *pStmt = 0; + va_start(ap, zFormat); + zSql = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + if( eVerbose){ + printf("%s:%d: [%s]\n", zId, lineno, zSql); + fflush(stdout); + } + + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + if( rc ){ + printf("%s:%d: ERROR - %s\n", zId, lineno, sqlite3_errmsg(db)); + exit(-1); + } + sqlite3_free(zSql); + return pStmt; +} + +/* +** Wait for table zTable to exist in the schema. +*/ +static void waitOnTable(sqlite3 *db, const char *zWorker, const char *zTable){ + while(1){ + int eFound = 0; + sqlite3_stmt *q = prepare(db, zWorker, __LINE__, + "SELECT 1 FROM sqlite_schema WHERE name=%Q", zTable); + if( sqlite3_step(q)==SQLITE_ROW && sqlite3_column_int(q,0)!=0 ){ + eFound = 1; + } + sqlite3_finalize(q); + if( eFound ) return; + sqlite3_sleep(1); + } +} + +/* +** Return true if x is a prime number +*/ +static int isPrime(int x){ + int i; + if( x<2 ) return 1; + for(i=2; i*i<=x; i++){ + if( (x%i)==0 ) return 0; + } + return 1; +} + +/* Each worker thread runs an instance of the following */ +static void *worker(void *pArg){ + int rc; + const char *zName = (const char*)pArg; + sqlite3 *db = 0; + + if( eVerbose ){ + printf("%s: startup\n", zName); + fflush(stdout); + } + + rc = sqlite3_open(zDbName, &db); + error_out(rc, "sqlite3_open", __LINE__); + sqlite3_busy_timeout(db, 2000); + + while( 1 ){ + sqlite3_stmt *q1; + int tid = -1; + q1 = prepare(db, zName, __LINE__, + "UPDATE task SET doneby=%Q" + " WHERE tid=(SELECT tid FROM task WHERE doneby IS NULL LIMIT 1)" + "RETURNING tid", zName + ); + if( sqlite3_step(q1)==SQLITE_ROW ){ + tid = sqlite3_column_int(q1,0); + } + sqlite3_finalize(q1); + if( tid<0 ) break; + if( eVerbose ){ + printf("%s: starting task %d\n", zName, tid); + fflush(stdout); + } + if( tid==1 ){ + exec(db, zName, __LINE__, + "CREATE TABLE IF NOT EXISTS p1(x INTEGER PRIMARY KEY);" + ); + }else if( tid>=2 && tid<=51 ){ + int a, b, i; + waitOnTable(db, zName, "p1"); + a = (tid-2)*200 + 1; + b = a+200; + for(i=a; i=53 && tid<=62 ){ + int a, b, i; + waitOnTable(db, zName, "p2"); + a = (tid-53)*10 + 2; + b = a+9; + for(i=a; i<=b; i++){ + exec(db, zName, __LINE__, + "DELETE FROM p2 WHERE x>%d AND (x %% %d)==0", i, i); + } + } + if( eVerbose ){ + printf("%s: completed task %d\n", zName, tid); + fflush(stdout); + } + sqlite3_sleep(1); + } + + sqlite3_close(db); + + if( eVerbose ){ + printf("%s: exit\n", zName); + fflush(stdout); + } + return 0; +} + +/* Print a usage comment and die */ +static void usage(const char *argv0){ + printf("Usage: %s [options]\n", argv0); + printf( + " -num-workers N Run N worker threads\n" + " -v Debugging output\n" + ); + exit(1); +} + +/* Maximum number of threads */ +#define MX_WORKER 100 + +/* +** Main routine +*/ +int main(int argc, char **argv){ + int i; + int nWorker = 4; + int rc; + sqlite3 *db = 0; + sqlite3_stmt *q; + pthread_t aWorker[MX_WORKER]; + char aWorkerName[MX_WORKER][8]; + + for(i=1; iMX_WORKER ){ + printf("number of threads must be between 1 and %d\n", MX_WORKER); + exit(1); + } + continue; + } + printf("unknown option: %s\n", argv[i]); + usage(argv[0]); + } + if( zDbName==0 ) zDbName = "file:/mem?vfs=memdb"; + + sqlite3_config(SQLITE_CONFIG_URI, (int)1); + rc = sqlite3_open(zDbName, &db); + error_out(rc, "sqlite3_open", __LINE__); + + rc = exec(db, "SETUP", __LINE__, + "DROP TABLE IF EXISTS task;\n" + "DROP TABLE IF EXISTS p1;\n" + "DROP TABLE IF EXISTS p2;\n" + "DROP TABLE IF EXISTS verify;\n" + "CREATE TABLE IF NOT EXISTS task(\n" + " tid INTEGER PRIMARY KEY,\n" + " doneby TEXT\n" + ");\n" + "WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)" + "INSERT INTO task(tid) SELECT x FROM c;\n" + ); + error_out(rc, "sqlite3_exec", __LINE__); + + for(i=0; i? AND O_ORDERDATE? AND O_ORDERDATE 100" - {SEARCH TABLE t1 USING INDEX i1 (a>?)} - {SCAN TABLE t1} + {SEARCH t1 USING INDEX i1 (a>?)} + {SCAN t1} 3 "SELECT * FROM t1 WHERE a = ? ORDER BY rowid" - {SEARCH TABLE t1 USING INDEX i1 (a=?)} - {SEARCH TABLE t1 USING INDEX i1 (a=?)*USE TEMP B-TREE FOR ORDER BY} + {SEARCH t1 USING INDEX i1 (a=?)} + {SEARCH t1 USING INDEX i1 (a=?)*USE TEMP B-TREE FOR ORDER BY} 4 "SELECT max(a) FROM t1" - {SEARCH TABLE t1 USING COVERING INDEX i1} - {SEARCH TABLE t1} + {SEARCH t1 USING COVERING INDEX i1} + {SEARCH t1} 5 "SELECT group_concat(b) FROM t1 GROUP BY a" - {SCAN TABLE t1 USING INDEX i1} - {SCAN TABLE t1*USE TEMP B-TREE FOR GROUP BY} + {SCAN t1 USING INDEX i1} + {SCAN t1*USE TEMP B-TREE FOR GROUP BY} 6 "SELECT * FROM t1 WHERE a = ?" - {SEARCH TABLE t1 USING INDEX i1 (a=?)} - {SEARCH TABLE t1 USING INDEX i1 (a=?)} + {SEARCH t1 USING INDEX i1 (a=?)} + {SEARCH t1 USING INDEX i1 (a=?)} 7 "SELECT count(*) FROM t1" - {SCAN TABLE t1 USING COVERING INDEX i1} - {SCAN TABLE t1} + {SCAN t1 USING COVERING INDEX i1} + {SCAN t1} } { do_eqp_test 1.$idxmode.$tn $sql $r($idxmode) } diff --git a/test/upfrom1.test b/test/upfrom1.test index 7996f97702..204f3512e5 100644 --- a/test/upfrom1.test +++ b/test/upfrom1.test @@ -175,4 +175,36 @@ do_execsql_test 3.1 { SELECT * FROM t0, t1; } {} +# Problem described by forum post https://sqlite.org/forum/forumpost/a274248080 +# +reset_db +do_execsql_test 4.1 { + CREATE TABLE t1(x INT); INSERT INTO t1 VALUES(1); + CREATE TABLE t2(y INT); INSERT INTO t2 VALUES(2); + WITH t1 AS (SELECT y+100 AS x FROM t2) + UPDATE t1 SET x=(SELECT x FROM t1); + SELECT x, y FROM t1, t2; +} {102 2} +do_execsql_test 4.2 { + WITH t1 AS (SELECT y+100 AS x FROM t2) + UPDATE t1 SET x=x+y FROM t2; + SELECT x, y FROM t1, t2; +} {104 2} + +# 2021-05-20 +# Forum https://sqlite.org/forum/forumpost/339f487de5 by Yu Liang +# A bad assert() +# +reset_db +do_execsql_test 5.1 { + CREATE TABLE t1(a); + INSERT INTO t1(a) VALUES(5); + CREATE VIEW t2 AS SELECT a FROM t1 UNION ALL SELECT a FROM t1; + CREATE TABLE t3(b,c); + INSERT INTO t3(b,c) VALUES(1,2); + UPDATE t3 SET (c,b) = (SELECT 3,4) FROM t1, t2; + SELECT * FROM t3; +} {4 3} + + finish_test diff --git a/test/upfrom2.test b/test/upfrom2.test index f903c1f4f7..81c847a604 100644 --- a/test/upfrom2.test +++ b/test/upfrom2.test @@ -367,5 +367,3 @@ foreach {tn update nm} { finish_test - - diff --git a/test/upfrom3.test b/test/upfrom3.test index d30b3fa28c..9936716b51 100644 --- a/test/upfrom3.test +++ b/test/upfrom3.test @@ -259,4 +259,3 @@ foreach {tn wo} { } finish_test - diff --git a/test/upfromfault.test b/test/upfromfault.test index fcb5956089..e876c071cb 100644 --- a/test/upfromfault.test +++ b/test/upfromfault.test @@ -137,4 +137,3 @@ do_faultsim_test 2.3 -prep { finish_test - diff --git a/test/view2.test b/test/view2.test new file mode 100644 index 0000000000..e5df1437fe --- /dev/null +++ b/test/view2.test @@ -0,0 +1,49 @@ +# 2021 May 20 +# +# 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 VIEW statements. +# +# $Id: view.test,v 1.39 2008/12/14 14:45:21 danielk1977 Exp $ +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# Omit this entire file if the library is not configured with views enabled. +ifcapable !view { + finish_test + return +} +set testprefix view2 + +do_execsql_test 1.0 { + CREATE TABLE t1(x, y); + INSERT INTO t1 VALUES(1, 2); + CREATE VIEW v1 AS SELECT * FROM ( + WITH x1 AS (SELECT y, x FROM t1) + SELECT * FROM x1 + ); +} + +do_execsql_test 1.1 { + SELECT * FROM v1 +} {2 1} + +do_execsql_test 1.2 { + CREATE VIEW v3 AS SELECT * FROM main.t1; + WITH t1(a, b) AS ( SELECT 3, 4 ) SELECT * FROM v3; +} {1 2} + +breakpoint +do_execsql_test 1.3 { + CREATE VIEW v2 AS SELECT * FROM t1; + WITH t1(a, b) AS ( SELECT 3, 4 ) SELECT * FROM v2; +} {1 2} + +finish_test diff --git a/test/vtab1.test b/test/vtab1.test index e8891a632c..3d2e233366 100644 --- a/test/vtab1.test +++ b/test/vtab1.test @@ -983,6 +983,7 @@ do_test vtab1.10-5 { proc match_func {args} {return ""} do_test vtab1.10-6 { set echo_module "" + sqlite_delete_function db match db function match match_func execsql { SELECT * FROM e WHERE match('pattern', rowid, 'pattern2'); diff --git a/test/walsetlk.test b/test/walsetlk.test index 66513ad2dc..8c0a9659f7 100644 --- a/test/walsetlk.test +++ b/test/walsetlk.test @@ -195,4 +195,3 @@ do_test 3.1 { } {1 {database is locked}} finish_test - diff --git a/test/where.test b/test/where.test index fa3bcd836c..298248a6ea 100644 --- a/test/where.test +++ b/test/where.test @@ -70,10 +70,10 @@ do_test where-1.1.1b { } {3 121 10 3} do_eqp_test where-1.1.2 { SELECT x, y, w FROM t1 WHERE w=10 -} {*SEARCH TABLE t1 USING INDEX i1w (w=?)*} +} {*SEARCH t1 USING INDEX i1w (w=?)*} do_eqp_test where-1.1.2b { SELECT x, y, w FROM t1 WHERE w IS 10 -} {*SEARCH TABLE t1 USING INDEX i1w (w=?)*} +} {*SEARCH t1 USING INDEX i1w (w=?)*} do_test where-1.1.3 { db status step } {0} @@ -85,13 +85,13 @@ do_test where-1.1.5 { } {99} do_eqp_test where-1.1.6 { SELECT x, y, w FROM t1 WHERE +w=10 -} {*SCAN TABLE t1*} +} {*SCAN t1*} do_test where-1.1.7 { count {SELECT x, y, w AS abc FROM t1 WHERE abc=10} } {3 121 10 3} do_eqp_test where-1.1.8 { SELECT x, y, w AS abc FROM t1 WHERE abc=10 -} {*SEARCH TABLE t1 USING INDEX i1w (w=?)*} +} {*SEARCH t1 USING INDEX i1w (w=?)*} do_test where-1.1.9 { db status step } {0} @@ -118,22 +118,22 @@ do_test where-1.4.1b { } {11 3 144 3} do_eqp_test where-1.4.2 { SELECT w, x, y FROM t1 WHERE 11=w AND x>2 -} {*SEARCH TABLE t1 USING INDEX i1w (w=?)*} +} {*SEARCH t1 USING INDEX i1w (w=?)*} do_eqp_test where-1.4.2b { SELECT w, x, y FROM t1 WHERE 11 IS w AND x>2 -} {*SEARCH TABLE t1 USING INDEX i1w (w=?)*} +} {*SEARCH t1 USING INDEX i1w (w=?)*} do_test where-1.4.3 { count {SELECT w AS a, x AS b, y FROM t1 WHERE 11=a AND b>2} } {11 3 144 3} do_eqp_test where-1.4.4 { SELECT w AS a, x AS b, y FROM t1 WHERE 11=a AND b>2 -} {*SEARCH TABLE t1 USING INDEX i1w (w=?)*} +} {*SEARCH t1 USING INDEX i1w (w=?)*} do_test where-1.5 { count {SELECT x, y FROM t1 WHERE y<200 AND w=11 AND x>2} } {3 144 3} do_eqp_test where-1.5.2 { SELECT x, y FROM t1 WHERE y<200 AND w=11 AND x>2 -} {*SEARCH TABLE t1 USING INDEX i1w (w=?)*} +} {*SEARCH t1 USING INDEX i1w (w=?)*} do_test where-1.6 { count {SELECT x, y FROM t1 WHERE y<200 AND x>2 AND w=11} } {3 144 3} @@ -145,10 +145,10 @@ do_test where-1.8 { } {3 144 3} do_eqp_test where-1.8.2 { SELECT x, y FROM t1 WHERE w>10 AND y=144 AND x=3 -} {*SEARCH TABLE t1 USING INDEX i1xy (x=? AND y=?)*} +} {*SEARCH t1 USING INDEX i1xy (x=? AND y=?)*} do_eqp_test where-1.8.3 { SELECT x, y FROM t1 WHERE y=144 AND x=3 -} {*SEARCH TABLE t1 USING COVERING INDEX i1xy (x=? AND y=?)*} +} {*SEARCH t1 USING COVERING INDEX i1xy (x=? AND y=?)*} do_test where-1.9 { count {SELECT x, y FROM t1 WHERE y=144 AND w>10 AND x=3} } {3 144 3} diff --git a/test/where2.test b/test/where2.test index 0a0533506a..7a7e9b92ed 100644 --- a/test/where2.test +++ b/test/where2.test @@ -76,10 +76,12 @@ proc queryplan {sql} { set eqp [execsql "EXPLAIN QUERY PLAN $sql"] # puts eqp=$eqp foreach {a b c x} $eqp { - if {[regexp { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ - $x all as tab idx]} { + if {[regexp {SCAN CONSTANT} $x]} { + # noop + } elseif {[regexp {(SCAN|SEARCH) (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ + $x all ss as tab idx]} { lappend data $tab $idx - } elseif {[regexp { TABLE (\w+ AS )?(\w+)\y} $x all as tab]} { + } elseif {[regexp {(SCAN|SEARCH) (\w+ AS )?(\w+)\y} $x all ss as tab]} { lappend data $tab * } } @@ -753,7 +755,7 @@ do_execsql_test where2-12.1 { SELECT a.x, b.x FROM t12 AS a JOIN t12 AS b ON a.y=b.x WHERE (b.x=$abc OR b.y=$abc); -} {/.*SEARCH TABLE t12 AS b .*SEARCH TABLE t12 AS b .*/} +} {/SEARCH b .*SEARCH b /} } # Verify that all necessary OP_OpenRead opcodes occur in the OR optimization. diff --git a/test/where3.test b/test/where3.test index 4d4ea3ee68..20af995cfe 100644 --- a/test/where3.test +++ b/test/where3.test @@ -111,10 +111,12 @@ proc queryplan {sql} { set eqp [execsql "EXPLAIN QUERY PLAN $sql"] # puts eqp=$eqp foreach {a b c x} $eqp { - if {[regexp { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ - $x all as tab idx]} { + if {[regexp {SCAN CONSTANT} $x]} { + # noop + } elseif {[regexp {(SCAN|SEARCH) (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ + $x all ss as tab idx]} { lappend data $tab $idx - } elseif {[regexp { TABLE (\w+ AS )?(\w+)\y} $x all as tab]} { + } elseif {[regexp {(SCAN|SEARCH) (\w+ AS )?(\w+)\y} $x all ss as tab]} { lappend data $tab * } } @@ -240,15 +242,15 @@ do_eqp_test where3-3.0a { SELECT * FROM t302, t301 WHERE t302.x=5 AND t301.a=t302.y; } { QUERY PLAN - |--SCAN TABLE t302 - `--SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?) + |--SCAN t302 + `--SEARCH t301 USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test where3-3.1 { SELECT * FROM t301, t302 WHERE t302.x=5 AND t301.a=t302.y; } { QUERY PLAN - |--SCAN TABLE t302 - `--SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?) + |--SCAN t302 + `--SEARCH t301 USING INTEGER PRIMARY KEY (rowid=?) } do_execsql_test where3-3.2 { SELECT * FROM t301 WHERE c=3 AND a IS NULL; @@ -269,25 +271,25 @@ do_execsql_test where3-4.0 { EXPLAIN QUERY PLAN SELECT * FROM t400, t401, t402 WHERE t402.z GLOB 'abc*'; } { - 0 0 2 {SCAN TABLE t402} - 0 1 0 {SCAN TABLE t400} - 0 2 1 {SCAN TABLE t401} + 0 0 2 {SCAN t402} + 0 1 0 {SCAN t400} + 0 2 1 {SCAN t401} } do_execsql_test where3-4.1 { EXPLAIN QUERY PLAN SELECT * FROM t400, t401, t402 WHERE t401.r GLOB 'abc*'; } { - 0 0 1 {SCAN TABLE t401} - 0 1 0 {SCAN TABLE t400} - 0 2 2 {SCAN TABLE t402} + 0 0 1 {SCAN t401} + 0 1 0 {SCAN t400} + 0 2 2 {SCAN t402} } do_execsql_test where3-4.2 { EXPLAIN QUERY PLAN SELECT * FROM t400, t401, t402 WHERE t400.c GLOB 'abc*'; } { - 0 0 0 {SCAN TABLE t400} - 0 1 1 {SCAN TABLE t401} - 0 2 2 {SCAN TABLE t402} + 0 0 0 {SCAN t400} + 0 1 1 {SCAN t401} + 0 2 2 {SCAN t402} } } ;# endif @@ -321,8 +323,8 @@ do_eqp_test where3-5.0a { ORDER BY bbb.title COLLATE NOCASE ASC; } { QUERY PLAN - |--SEARCH TABLE aaa USING INDEX aaa_333 (fk=?) - |--SEARCH TABLE bbb USING INTEGER PRIMARY KEY (rowid=?) + |--SEARCH aaa USING INDEX aaa_333 (fk=?) + |--SEARCH bbb USING INTEGER PRIMARY KEY (rowid=?) `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test where3-5.1 { @@ -334,8 +336,8 @@ do_eqp_test where3-5.1 { ORDER BY bbb.title COLLATE NOCASE ASC; } { QUERY PLAN - |--SEARCH TABLE aaa USING INDEX aaa_333 (fk=?) - |--SEARCH TABLE aaa AS bbb USING INTEGER PRIMARY KEY (rowid=?) + |--SEARCH aaa USING INDEX aaa_333 (fk=?) + |--SEARCH bbb USING INTEGER PRIMARY KEY (rowid=?) `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test where3-5.2 { @@ -347,8 +349,8 @@ do_eqp_test where3-5.2 { ORDER BY bbb.title COLLATE NOCASE ASC; } { QUERY PLAN - |--SEARCH TABLE aaa USING INDEX aaa_333 (fk=?) - |--SEARCH TABLE bbb USING INTEGER PRIMARY KEY (rowid=?) + |--SEARCH aaa USING INDEX aaa_333 (fk=?) + |--SEARCH bbb USING INTEGER PRIMARY KEY (rowid=?) `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test where3-5.3 { @@ -360,8 +362,8 @@ do_eqp_test where3-5.3 { ORDER BY bbb.title COLLATE NOCASE ASC; } { QUERY PLAN - |--SEARCH TABLE aaa USING INDEX aaa_333 (fk=?) - |--SEARCH TABLE aaa AS bbb USING INTEGER PRIMARY KEY (rowid=?) + |--SEARCH aaa USING INDEX aaa_333 (fk=?) + |--SEARCH bbb USING INTEGER PRIMARY KEY (rowid=?) `--USE TEMP B-TREE FOR ORDER BY } diff --git a/test/where7.test b/test/where7.test index 81111a9de4..830530634f 100644 --- a/test/where7.test +++ b/test/where7.test @@ -23354,10 +23354,10 @@ do_eqp_test where7-3.2 { QUERY PLAN |--MULTI-INDEX OR | |--INDEX 1 - | | `--SEARCH TABLE t301 USING COVERING INDEX t301_c4 (c4=?) + | | `--SEARCH t301 USING COVERING INDEX t301_c4 (c4=?) | `--INDEX 2 - | `--SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?) - |--SEARCH TABLE t302 USING INDEX t302_c8_c3 (c8=? AND c3>?) + | `--SEARCH t301 USING INTEGER PRIMARY KEY (rowid=?) + |--SEARCH t302 USING INDEX t302_c8_c3 (c8=? AND c3>?) `--USE TEMP B-TREE FOR ORDER BY } diff --git a/test/where9.test b/test/where9.test index 0f770dfee8..429708f1fe 100644 --- a/test/where9.test +++ b/test/where9.test @@ -362,12 +362,12 @@ ifcapable explain { WHERE t1.a=80 AND ((t1.c=t2.c AND t1.d=t2.d) OR t1.f=t2.f) } [string map {"\n " \n} { QUERY PLAN - |--SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?) + |--SEARCH t1 USING INTEGER PRIMARY KEY (rowid=?) `--MULTI-INDEX OR |--INDEX 1 - | `--SEARCH TABLE t2 USING INDEX t2d (d=?) + | `--SEARCH t2 USING INDEX t2d (d=?) `--INDEX 3 - `--SEARCH TABLE t2 USING COVERING INDEX t2f (f=?) + `--SEARCH t2 USING COVERING INDEX t2f (f=?) }] do_eqp_test where9-3.2 { SELECT coalesce(t2.a,9999) @@ -375,12 +375,12 @@ ifcapable explain { WHERE t1.a=80 } [string map {"\n " \n} { QUERY PLAN - |--SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?) + |--SEARCH t1 USING INTEGER PRIMARY KEY (rowid=?) `--MULTI-INDEX OR |--INDEX 1 - | `--SEARCH TABLE t2 USING INDEX t2d (d=?) + | `--SEARCH t2 USING INDEX t2d (d=?) `--INDEX 2 - `--SEARCH TABLE t2 USING COVERING INDEX t2f (f=?) + `--SEARCH t2 USING COVERING INDEX t2f (f=?) }] } @@ -461,23 +461,23 @@ do_eqp_test where9-5.1 { QUERY PLAN `--MULTI-INDEX OR |--INDEX 1 - | `--SEARCH TABLE t1 USING INDEX t1c (c=?) + | `--SEARCH t1 USING INDEX t1c (c=?) `--INDEX 2 - `--SEARCH TABLE t1 USING INDEX t1d (d=?) + `--SEARCH t1 USING INDEX t1d (d=?) } # In contrast, b=1000 is preferred over any OR-clause. # do_eqp_test where9-5.2 { SELECT a FROM t1 WHERE b=1000 AND (c=31031 OR d IS NULL) -} {SEARCH TABLE t1 USING INDEX t1b (b=?)} +} {SEARCH t1 USING INDEX t1b (b=?)} # Likewise, inequalities in an AND are preferred over inequalities in # an OR. # do_eqp_test where9-5.3 { SELECT a FROM t1 WHERE b>1000 AND (c>=31031 OR d IS NULL) -} {SEARCH TABLE t1 USING INDEX t1b (b>?)} +} {SEARCH t1 USING INDEX t1b (b>?)} ############################################################################ # Make sure OR-clauses work correctly on UPDATE and DELETE statements. @@ -982,6 +982,23 @@ do_test where9-10.2 { } } {1 {} 1} - +# dbsqlfuzz 9df1d53c24c4c96af0dae15ee764897af415ac76 +# The MULTI-INDEX OR processing evaluates the same WHERE-clause sub-expression +# twice. But if that sub-expression contains a UNION ALL SELECT statement +# subject to query flattening, the sub-expression might be transformed in a +# way that it can only be code-generated once. An assert() will fail on +# the second attempt to generate code from the same sub-expression. +# The solution is to make a copy of sub-expressions used by MULTI-INDEX OR +# +reset_db +do_execsql_test where9-11.1 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT); + CREATE TABLE t2_a(k INTEGER PRIMARY KEY, v TEXT); + CREATE TABLE t2_b(k INTEGER PRIMARY KEY, v TEXT); + CREATE VIEW t2 AS SELECT * FROM t2_a UNION ALL SELECT * FROM t2_b; + SELECT 1 FROM t1 JOIN t1 USING(a) + WHERE (a=1) + OR (a=2 AND (SELECT 4 FROM t2,(SELECT 5 FROM t1 ORDER BY a) WHERE a)); +} {} finish_test diff --git a/test/whereE.test b/test/whereE.test index a6b8f481b2..31086b2492 100644 --- a/test/whereE.test +++ b/test/whereE.test @@ -47,16 +47,16 @@ do_execsql_test 1.1 { CREATE UNIQUE INDEX t2zx ON t2(z,x); EXPLAIN QUERY PLAN SELECT x FROM t1, t2 WHERE a=z AND c=x; -} {/.*SCAN TABLE t1.*SEARCH TABLE t2.*/} +} {/.*SCAN t1.*SEARCH t2.*/} do_execsql_test 1.2 { EXPLAIN QUERY PLAN SELECT x FROM t2, t1 WHERE a=z AND c=x; -} {/.*SCAN TABLE t1.*SEARCH TABLE t2.*/} +} {/.*SCAN t1.*SEARCH t2.*/} do_execsql_test 1.3 { ANALYZE; EXPLAIN QUERY PLAN SELECT x FROM t1, t2 WHERE a=z AND c=x; -} {/.*SCAN TABLE t1.*SEARCH TABLE t2.*/} +} {/.*SCAN t1.*SEARCH t2.*/} do_execsql_test 1.4 { EXPLAIN QUERY PLAN SELECT x FROM t2, t1 WHERE a=z AND c=x; -} {/.*SCAN TABLE t1.*SEARCH TABLE t2.*/} +} {/.*SCAN t1.*SEARCH t2.*/} finish_test diff --git a/test/whereF.test b/test/whereF.test index 121cc3cf22..ac7fd807b8 100644 --- a/test/whereF.test +++ b/test/whereF.test @@ -63,7 +63,7 @@ foreach {tn sql} { } { do_test 1.$tn { db eval "EXPLAIN QUERY PLAN $sql" - } {/.*SCAN TABLE t2\y.*SEARCH TABLE t1\y.*/} + } {/.*SCAN t2\y.*SEARCH t1\y.*/} } do_execsql_test 2.0 { @@ -84,7 +84,7 @@ foreach {tn sql} { } { do_test 2.$tn { db eval "EXPLAIN QUERY PLAN $sql" - } {/.*SCAN TABLE t2\y.*SEARCH TABLE t1\y.*/} + } {/.*SCAN t2\y.*SEARCH t1\y.*/} } do_execsql_test 3.0 { @@ -109,7 +109,7 @@ foreach {tn sql} { } { do_test 3.$tn { db eval "EXPLAIN QUERY PLAN $sql" - } {/.*SCAN TABLE t2\y.*SEARCH TABLE t1\y.*/} + } {/.*SCAN t2\y.*SEARCH t1\y.*/} } do_execsql_test 4.0 { diff --git a/test/whereG.test b/test/whereG.test index abff2270b7..f39f3e8fce 100644 --- a/test/whereG.test +++ b/test/whereG.test @@ -156,16 +156,16 @@ do_execsql_test whereG-3.0 { } {} do_eqp_test whereG-3.1 { SELECT * FROM a, b WHERE b1=a1 AND a2=5; -} {/.*SCAN TABLE a.*SEARCH TABLE b USING INDEX .*b_1 .b1=..*/} +} {/.*SCAN a.*SEARCH b USING INDEX .*b_1 .b1=..*/} do_eqp_test whereG-3.2 { SELECT * FROM a, b WHERE a1=b1 AND a2=5; -} {/.*SCAN TABLE a.*SEARCH TABLE b USING INDEX .*b_1 .b1=..*/} +} {/.*SCAN a.*SEARCH b USING INDEX .*b_1 .b1=..*/} do_eqp_test whereG-3.3 { SELECT * FROM a, b WHERE a2=5 AND b1=a1; -} {/.*SCAN TABLE a.*SEARCH TABLE b USING INDEX .*b_1 .b1=..*/} +} {/.*SCAN a.*SEARCH b USING INDEX .*b_1 .b1=..*/} do_eqp_test whereG-3.4 { SELECT * FROM a, b WHERE a2=5 AND a1=b1; -} {/.*SCAN TABLE a.*SEARCH TABLE b USING INDEX .*b_1 .b1=..*/} +} {/.*SCAN a.*SEARCH b USING INDEX .*b_1 .b1=..*/} # Ticket [1e64dd782a126f48d78c43a664844a41d0e6334e]: # Incorrect result in a nested GROUP BY/DISTINCT due to the use of an OP_SCopy @@ -195,13 +195,13 @@ do_execsql_test 5.1 { } do_eqp_test 5.1.2 { SELECT * FROM t1 WHERE a>? -} {SEARCH TABLE t1 USING INDEX i1 (a>?)} +} {SEARCH t1 USING INDEX i1 (a>?)} do_eqp_test 5.1.3 { SELECT * FROM t1 WHERE likelihood(a>?, 0.9) -} {SCAN TABLE t1} +} {SCAN t1} do_eqp_test 5.1.4 { SELECT * FROM t1 WHERE likely(a>?) -} {SCAN TABLE t1} +} {SCAN t1} do_test 5.2 { for {set i 0} {$i < 100} {incr i} { @@ -212,29 +212,29 @@ do_test 5.2 { } {} do_eqp_test 5.2.2 { SELECT * FROM t1 WHERE likelihood(b>?, 0.01) -} {SEARCH TABLE t1 USING INDEX i1 (ANY(a) AND b>?)} +} {SEARCH t1 USING INDEX i1 (ANY(a) AND b>?)} do_eqp_test 5.2.3 { SELECT * FROM t1 WHERE likelihood(b>?, 0.9) -} {SCAN TABLE t1} +} {SCAN t1} do_eqp_test 5.2.4 { SELECT * FROM t1 WHERE likely(b>?) -} {SCAN TABLE t1} +} {SCAN t1} ifcapable stat4 { do_eqp_test 5.3.1.stat4 { SELECT * FROM t1 WHERE a=? - } {SCAN TABLE t1} + } {SCAN t1} } else { do_eqp_test 5.3.1 { SELECT * FROM t1 WHERE a=? - } {SEARCH TABLE t1 USING INDEX i1} + } {SEARCH t1 USING INDEX i1} } do_eqp_test 5.3.2 { SELECT * FROM t1 WHERE likelihood(a=?, 0.9) -} {SCAN TABLE t1} +} {SCAN t1} do_eqp_test 5.3.3 { SELECT * FROM t1 WHERE likely(a=?) -} {SCAN TABLE t1} +} {SCAN t1} # 2015-06-18 # Ticket [https://www.sqlite.org/see/tktview/472f0742a1868fb58862bc588ed70] @@ -334,4 +334,37 @@ do_execsql_test 10.1 { SELECT g = g FROM f GROUP BY h; } {1} +reset_db +do_execsql_test 11.0 { + CREATE TABLE t1(x PRIMARY KEY, y); + INSERT INTO t1 VALUES('AAA', 'BBB'); + + CREATE TABLE t2(z); + INSERT INTO t2 VALUES('t2'); + + CREATE TABLE t3(x PRIMARY KEY, y); + INSERT INTO t3 VALUES('AAA', 'AAA'); +} + +do_execsql_test 11.1.1 { + SELECT * FROM t1 JOIN t2 ON unlikely(x=y) AND y='AAA' +} +do_execsql_test 11.1.2 { + SELECT * FROM t1 JOIN t2 ON likely(x=y) AND y='AAA' +} +do_execsql_test 11.1.3 { + SELECT * FROM t1 JOIN t2 ON x=y AND y='AAA' +} + +do_execsql_test 11.2.1 { + SELECT * FROM t3 JOIN t2 ON unlikely(x=y) AND y='AAA' +} {AAA AAA t2} +do_execsql_test 11.2.2 { + SELECT * FROM t3 JOIN t2 ON likely(x=y) AND y='AAA' +} {AAA AAA t2} +do_execsql_test 11.2.3 { + SELECT * FROM t3 JOIN t2 ON x=y AND y='AAA' +} {AAA AAA t2} + + finish_test diff --git a/test/whereI.test b/test/whereI.test index 7bb4ba39de..38e0148844 100644 --- a/test/whereI.test +++ b/test/whereI.test @@ -32,9 +32,9 @@ do_eqp_test 1.1 { QUERY PLAN `--MULTI-INDEX OR |--INDEX 1 - | `--SEARCH TABLE t1 USING INDEX i1 (b=?) + | `--SEARCH t1 USING INDEX i1 (b=?) `--INDEX 2 - `--SEARCH TABLE t1 USING INDEX i2 (c=?) + `--SEARCH t1 USING INDEX i2 (c=?) } do_execsql_test 1.2 { @@ -64,9 +64,9 @@ do_eqp_test 2.1 { QUERY PLAN `--MULTI-INDEX OR |--INDEX 1 - | `--SEARCH TABLE t2 USING INDEX i3 (b=?) + | `--SEARCH t2 USING INDEX i3 (b=?) `--INDEX 2 - `--SEARCH TABLE t2 USING INDEX i4 (c=?) + `--SEARCH t2 USING INDEX i4 (c=?) } do_execsql_test 2.2 { diff --git a/test/whereJ.test b/test/whereJ.test index af6ffafb3f..c31ab8c370 100644 --- a/test/whereJ.test +++ b/test/whereJ.test @@ -402,7 +402,7 @@ do_eqp_test 3.4 { a = 4 AND b BETWEEN 20 AND 80 -- Matches 80 rows AND c BETWEEN 150 AND 160 -- Matches 10 rows -} {SEARCH TABLE t1 USING INDEX idx_c (c>? AND c? AND c? AND b? AND b9 OR b=9 ORDER BY +a; -} {/SEARCH TABLE t1 USING INDEX t1bc/} +} {/SEARCH t1 USING INDEX t1bc/} do_execsql_test 1.2 { SELECT a FROM t1 WHERE b>8 OR (b=8 AND c>7) ORDER BY +a; @@ -41,7 +41,7 @@ do_execsql_test 1.2 { do_execsql_test 1.2eqp { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>8 OR (b=8 AND c>7) ORDER BY +a; -} {/SEARCH TABLE t1 USING INDEX t1bc/} +} {/SEARCH t1 USING INDEX t1bc/} do_execsql_test 1.3 { SELECT a FROM t1 WHERE (b=8 AND c>7) OR b>8 ORDER BY +a; @@ -49,7 +49,7 @@ do_execsql_test 1.3 { do_execsql_test 1.3eqp { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE (b=8 AND c>7) OR b>8 ORDER BY +a; -} {/SEARCH TABLE t1 USING INDEX t1bc/} +} {/SEARCH t1 USING INDEX t1bc/} do_execsql_test 1.4 { SELECT a FROM t1 WHERE (b=8 AND c>7) OR 87) OR 87) OR (b>8 AND c NOT IN (4,5,6)) @@ -67,6 +67,6 @@ do_execsql_test 1.5eqp { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE (b=8 AND c>7) OR (b>8 AND c NOT IN (4,5,6)) ORDER BY +a; -} {/SEARCH TABLE t1 USING INDEX t1bc/} +} {/SEARCH t1 USING INDEX t1bc/} finish_test diff --git a/test/whereL.test b/test/whereL.test index c78ae160b3..b6f86fc2d2 100644 --- a/test/whereL.test +++ b/test/whereL.test @@ -28,11 +28,11 @@ do_eqp_test 110 { QUERY PLAN `--COMPOUND QUERY |--LEFT-MOST SUBQUERY - | |--SEARCH TABLE t2 USING INDEX sqlite_autoindex_t2_1 (a=?) - | `--SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (a=?) + | |--SEARCH t1 USING INDEX sqlite_autoindex_t1_1 (a=?) + | `--SEARCH t2 USING INDEX sqlite_autoindex_t2_1 (a=?) `--UNION ALL - |--SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (a=?) - `--SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (a=?) + |--SEARCH t1 USING INDEX sqlite_autoindex_t1_1 (a=?) + `--SEARCH t3 USING INDEX sqlite_autoindex_t3_1 (a=?) } # The scan of the t1 table goes first since that enables the ORDER BY @@ -45,9 +45,9 @@ do_eqp_test 120 { ORDER BY t1.a; } { QUERY PLAN - |--SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (a=?) - |--SEARCH TABLE t2 USING INDEX sqlite_autoindex_t2_1 (a=?) - `--SCAN TABLE t3 + |--SEARCH t1 USING INDEX sqlite_autoindex_t1_1 (a=?) + |--SEARCH t2 USING INDEX sqlite_autoindex_t2_1 (a=?) + `--SCAN t3 } # Constant propagation in the face of collating sequences: diff --git a/test/wherefault.test b/test/wherefault.test index 60330a92dd..7f07ad5f53 100644 --- a/test/wherefault.test +++ b/test/wherefault.test @@ -56,4 +56,28 @@ do_malloc_test 2 -tclprep { SELECT count(*) FROM t1 WHERE a BETWEEN 5 AND 995 OR b BETWEEN 5 AND 900000; } +reset_db +do_execsql_test 3.0 { + PRAGMA writable_schema = 1; + BEGIN TRANSACTION; + CREATE TABLE t1( + a INT AS (c*11), + b TEXT AS (substr(d,1,3)) STORED, + c INTEGEB PRIMARI KEY, d TEXT + ); + CREATE INDEX t1a ON t1(a); + COMMIT; +} +faultsim_save_and_close + +do_faultsim_test 3.1 -faults oom* -prep { + faultsim_restore_and_reopen +} -body { + execsql { + SELECT * FROM (SELECT a FROM t1 NATURAL JOIN t1 WHERE a IN (SELECT b FROM t1 ORDER BY b)) WHERE (SELECT a FROM t1 NATURAL JOIN (SELECT * FROM (SELECT a FROM t1 NATURAL JOIN t1 WHERE a IN (SELECT CASE b WHEN 82 THEN 207 WHEN 869 THEN 406 WHEN 85 THEN 83 WHEN 705 THEN 698 ELSE 1992229051 END%5 FROM t1 ORDER BY b)) WHERE (SELECT a FROM t1 NATURAL JOIN (SELECT b FROM t1 ORDER BY b) WHERE a IN (SELECT b FROM t1 ORDER BY b))) WHERE a ); + } +} -test { + faultsim_test_result {0 {}} +} + finish_test diff --git a/test/wherelimit.test b/test/wherelimit.test index aeadc6f39b..f6efab6682 100644 --- a/test/wherelimit.test +++ b/test/wherelimit.test @@ -237,8 +237,8 @@ ifcapable {update_delete_limit} { } {11} create_test_data 6 do_test wherelimit-3.2 { - execsql {UPDATE t1 SET y=1 WHERE x=1 RETURNING x, old.y, '|' LIMIT 5} - } {1 1 | 1 2 | 1 3 | 1 4 | 1 5 |} + execsql {UPDATE t1 SET y=1 WHERE x=1 RETURNING x, y, '|' LIMIT 5} + } {1 1 | 1 1 | 1 1 | 1 1 | 1 1 |} do_test wherelimit-3.2cnt { execsql {SELECT count(*) FROM t1 WHERE y=1} } {10} diff --git a/test/window1.test b/test/window1.test index dbaf4388fb..f4b573d298 100644 --- a/test/window1.test +++ b/test/window1.test @@ -374,6 +374,38 @@ do_execsql_test 9.3 { SELECT *, min(z) OVER (ORDER BY x) FROM aaa ORDER BY 1; } {1 g g g 2 i i g 3 l l g 4 g l g 5 a l g 6 m m g} +do_catchsql_test 9.4 { + -- 2021-04-17 dbsqlfuzz d9cf66100064952b66951845dfab41de1c124611 + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(a,b,c,d); + DROP TABLE IF EXISTS t2; + CREATE TABLE t2(x,y); + CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN + INSERT INTO t2(x,y) + SELECT a, max(d) OVER w1 FROM t1 + WINDOW w1 AS (PARTITION BY EXISTS(SELECT 1 FROM t1 WHERE c=?1) ); + END; +} {1 {trigger cannot use variables}} + +do_catchsql_test 9.4.2 { + CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN + INSERT INTO t1(a,b) + SELECT a, max(d) OVER w1 FROM t1 + WINDOW w1 AS ( + ORDER BY a ROWS BETWEEN ? PRECEDING AND UNBOUNDED FOLLOWING + ); + END; +} {1 {trigger cannot use variables}} +do_catchsql_test 9.4.3 { + CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN + INSERT INTO t1(a,b) + SELECT a, max(d) OVER w1 FROM t1 + WINDOW w1 AS ( + ORDER BY a ROWS BETWEEN UNBOUNDED PRECEDING AND ? FOLLOWING + ); + END; +} {1 {trigger cannot use variables}} + #------------------------------------------------------------------------- # do_execsql_test 10.0 { @@ -1883,11 +1915,59 @@ do_execsql_test 60.1 { # the Parse object is destroyed. # reset_db -do_execsql_test 61.1 { +do_catchsql_test 61.1 { CREATE TABLE t1(a); INSERT INTO t1 VALUES(5),(NULL),('seventeen'); SELECT (SELECT max(x)OVER(ORDER BY x) % min(x)OVER(ORDER BY CASE x WHEN 889 THEN x WHEN x THEN x END)) FROM (SELECT (SELECT sum(CAST(a IN(SELECT (SELECT max(x)OVER(ORDER BY CASE x WHEN 889 THEN 299 WHEN 863 THEN 863 END)) FROM (SELECT (SELECT sum(CAST((SELECT (SELECT max(x)OVER(ORDER BY x) / min(x)OVER(ORDER BY CASE x WHEN 889 THEN 299 WHEN -true THEN 863 END)) FROM (SELECT (SELECT sum(CAST(a IN(SELECT (SELECT max(x) & sum ( a )OVER(ORDER BY CASE x WHEN -8 THEN 299 WHEN 863 THEN 863 END)) FROM (SELECT (SELECT sum(CAST(a AS )) FROM t1) AS x FROM t1)) AS t1 )) FROM t1) AS x FROM t1)) AS x )) FROM t1) AS x FROM t1)) AS real)) FROM t1) AS x FROM t1); -} {{} {} {}} +} {0 {{} {} {}}} + +foreach tn {1 2} { + if {$tn==2} { optimization_control db query-flattener 0 } + do_catchsql_test 61.2.$tn { + SELECT + (SELECT max(x)OVER(ORDER BY x) / min(x) OVER() ) + FROM ( + SELECT (SELECT sum(a) FROM t1 ) AS x FROM t1 + ) + + } {0 {1.0 1.0 1.0}} +} + +reset_db +optimization_control db all 0 +do_execsql_test 61.3.0 { + CREATE TABLE t1(a); + CREATE TABLE t2(y); +} + +do_execsql_test 61.3.1 { + SELECT ( + SELECT count(a) OVER ( ORDER BY (SELECT sum(y) FROM t2) ) + + total(a) OVER() + ) + FROM t1 +} {} +do_execsql_test 61.4.2 { + SELECT ( + SELECT count(a) OVER ( ORDER BY sum(a) ) + + total(a) OVER() + ) + FROM t1 +} {0.0} + +do_catchsql_test 61.4.3 { + SELECT + sum(a) OVER ( ORDER BY a ) + FROM t1 + ORDER BY (SELECT sum(a) FROM t2) +} {1 {misuse of aggregate: sum()}} +do_execsql_test 61.4.4 { + SELECT + sum(a) OVER ( ORDER BY a ) + FROM t1 + ORDER BY (SELECT sum(y) FROM t2) +} + #------------------------------------------------------------------------- reset_db @@ -2001,4 +2081,82 @@ do_execsql_test 65.4 { FROM t1; } {{}} +#------------------------------------------------------------------------- +reset_db + +do_execsql_test 66.1 { + CREATE TABLE t1(a INTEGER); + INSERT INTO t1 VALUES(3578824042033200656); + INSERT INTO t1 VALUES(3029012920382354029); +} + +foreach {tn spec} { + 1 "ORDER BY a RANGE BETWEEN 0.3 PRECEDING AND 10 FOLLOWING" + 2 "ORDER BY a RANGE BETWEEN 0.3 PRECEDING AND 0.1 PRECEDING" + 3 "ORDER BY a RANGE BETWEEN 0.3 FOLLOWING AND 10 FOLLOWING" + 4 "ORDER BY a DESC RANGE BETWEEN 0.3 PRECEDING AND 10 FOLLOWING" + 5 "ORDER BY a NULLS LAST RANGE BETWEEN 0.3 PRECEDING AND 10 FOLLOWING" + 6 "ORDER BY a RANGE BETWEEN 1.0 PRECEDING AND 2.0 PRECEDING" +} { + do_execsql_test 66.2.$tn " + SELECT total(a) OVER ( $spec ) FROM t1 ORDER BY a + " { + 3.02901292038235e+18 3.5788240420332e+18 + } +} + + +do_execsql_test 66.3 { + CREATE TABLE t2(a INTEGER); + INSERT INTO t2 VALUES(45); + INSERT INTO t2 VALUES(30); +} + +foreach {tn spec res} { + 1 "ORDER BY a RANGE BETWEEN 0.3 PRECEDING AND 10 FOLLOWING" {30.0 45.0} + 2 "ORDER BY a RANGE BETWEEN 0.3 PRECEDING AND 0.1 PRECEDING" {0.0 0.0} + 3 "ORDER BY a RANGE BETWEEN 0.3 FOLLOWING AND 10 FOLLOWING" {0.0 0.0} + 4 "ORDER BY a DESC RANGE BETWEEN 0.3 PRECEDING AND 10 FOLLOWING" {30.0 45.0} + 5 "ORDER BY a NULLS LAST RANGE BETWEEN 0.3 PRECEDING AND 10 FOLLOWING" {30.0 45.0} + 6 "ORDER BY a RANGE BETWEEN 1.0 PRECEDING AND 2.0 PRECEDING" {0.0 0.0} +} { + do_execsql_test 66.2.$tn " + SELECT total(a) OVER ( $spec ) FROM t2 ORDER BY a + " $res +} + + +#------------------------------------------------------------------------- +reset_db +do_execsql_test 67.0 { + CREATE TABLE t1(a, b, c); + CREATE TABLE t2(a, b, c); +} + +do_catchsql_test 67.1 { + SELECT a,c,b FROM t1 INTERSECT SELECT a,b,c FROM t1 ORDER BY ( + SELECT nth_value(a,2) OVER w1 + WINDOW w1 AS ( ORDER BY ((SELECT 1 FROM v1)) ) + ) +} {1 {no such table: v1}} + +do_catchsql_test 67.2 { + SELECT a,c,b FROM t1 INTERSECT SELECT a,b,c FROM t1 ORDER BY ( + SELECT nth_value(a,2) OVER w1 + WINDOW w1 AS ( ORDER BY ((SELECT 1 FROM t2)) ) + ) +} {1 {1st ORDER BY term does not match any column in the result set}} + +# 2021-05-07 +# Do not allow aggregate functions in the ORDER BY clause even if +# there are window functions in the result set. +# Forum: /forumpost/540fdfef77 +# +reset_db +do_catchsql_test 68.0 { + CREATE TABLE t1(a,b); + INSERT INTO t1(a,b) VALUES(0,0),(1,1),(2,4),(3,9),(4,99); + SELECT rowid, a, b, sum(a)OVER() FROM t1 ORDER BY count(b); +} {1 {misuse of aggregate: count()}} + finish_test diff --git a/test/window8.tcl b/test/window8.tcl index a8333f1907..69ad0ad263 100644 --- a/test/window8.tcl +++ b/test/window8.tcl @@ -418,6 +418,76 @@ execsql_test 7.$tn.9 " " } +========== + +execsql_test 8.0 { + DROP TABLE IF EXISTS tx; + CREATE TABLE tx(a INTEGER PRIMARY KEY); + INSERT INTO tx VALUES(1), (2), (3), (4), (5), (6); + + DROP TABLE IF EXISTS map; + CREATE TABLE map(v INTEGER PRIMARY KEY, t TEXT); + INSERT INTO map VALUES + (1, 'odd'), (2, 'even'), (3, 'odd'), + (4, 'even'), (5, 'odd'), (6, 'even'); +} + +execsql_test 8.1 { + SELECT sum(a) OVER ( + PARTITION BY ( + SELECT t FROM map WHERE v=a + ) ORDER BY a + ) FROM tx; +} + +execsql_test 8.2 { + SELECT sum(a) OVER win FROM tx + WINDOW win AS ( + PARTITION BY ( + SELECT t FROM map WHERE v=a + ) ORDER BY a + ); +} + +execsql_test 8.3 { + WITH map2 AS ( + SELECT * FROM map + ) + SELECT sum(a) OVER ( + PARTITION BY ( + SELECT t FROM map2 WHERE v=a + ) ORDER BY a + ) FROM tx; +} + +execsql_test 8.4 { + WITH map2 AS ( + SELECT * FROM map + ) + SELECT sum(a) OVER win FROM tx + WINDOW win AS ( + PARTITION BY ( + SELECT t FROM map2 WHERE v=a + ) ORDER BY a + ); +} + +========== + +execsql_test 9.1 { + DROP TABLE IF EXISTS t1; + DROP TABLE IF EXISTS t2; + CREATE TABLE t1(a INTEGER); + CREATE TABLE t2(y INTEGER); +} + +execsql_test 9.2 { + SELECT ( + SELECT max(a) OVER ( ORDER BY (SELECT sum(a) FROM t1) ) + + min(a) OVER() + ) + FROM t1 +} finish_test diff --git a/test/window8.test b/test/window8.test index ed720ebd41..0c5d39badb 100644 --- a/test/window8.test +++ b/test/window8.test @@ -6469,4 +6469,75 @@ do_execsql_test 7.4.9 { ); } {4 4 4 {} {} {}} +#========================================================================== + +do_execsql_test 8.0 { + DROP TABLE IF EXISTS tx; + CREATE TABLE tx(a INTEGER PRIMARY KEY); + INSERT INTO tx VALUES(1), (2), (3), (4), (5), (6); + + DROP TABLE IF EXISTS map; + CREATE TABLE map(v INTEGER PRIMARY KEY, t TEXT); + INSERT INTO map VALUES + (1, 'odd'), (2, 'even'), (3, 'odd'), + (4, 'even'), (5, 'odd'), (6, 'even'); +} {} + +do_execsql_test 8.1 { + SELECT sum(a) OVER ( + PARTITION BY ( + SELECT t FROM map WHERE v=a + ) ORDER BY a + ) FROM tx; +} {2 6 12 1 4 9} + +do_execsql_test 8.2 { + SELECT sum(a) OVER win FROM tx + WINDOW win AS ( + PARTITION BY ( + SELECT t FROM map WHERE v=a + ) ORDER BY a + ); +} {2 6 12 1 4 9} + +do_execsql_test 8.3 { + WITH map2 AS ( + SELECT * FROM map + ) + SELECT sum(a) OVER ( + PARTITION BY ( + SELECT t FROM map2 WHERE v=a + ) ORDER BY a + ) FROM tx; +} {2 6 12 1 4 9} + +do_execsql_test 8.4 { + WITH map2 AS ( + SELECT * FROM map + ) + SELECT sum(a) OVER win FROM tx + WINDOW win AS ( + PARTITION BY ( + SELECT t FROM map2 WHERE v=a + ) ORDER BY a + ); +} {2 6 12 1 4 9} + +#========================================================================== + +do_execsql_test 9.1 { + DROP TABLE IF EXISTS t1; + DROP TABLE IF EXISTS t2; + CREATE TABLE t1(a INTEGER); + CREATE TABLE t2(y INTEGER); +} {} + +do_execsql_test 9.2 { + SELECT ( + SELECT max(a) OVER ( ORDER BY (SELECT sum(a) FROM t1) ) + + min(a) OVER() + ) + FROM t1 +} {} + finish_test diff --git a/test/window9.test b/test/window9.test index c342a4d790..4b8e4fa58f 100644 --- a/test/window9.test +++ b/test/window9.test @@ -265,4 +265,21 @@ do_execsql_test 8.4 { FROM v1; } {0.0 0.0} +#-------------------------------------------------------------------------- +reset_db +do_execsql_test 9.0 { + CREATE TABLE t1(a, b, c); + INSERT INTO t1 VALUES(NULL,'bb',356); + INSERT INTO t1 VALUES('CB','aa',158); + INSERT INTO t1 VALUES('BB','aa',399); + INSERT INTO t1 VALUES('FF','bb',938); +} + +do_catchsql_test 9.1 { + SELECT sum(c) OVER ( + ORDER BY c RANGE BETWEEN 0 PRECEDING AND '-700' PRECEDING + ) + FROM t1 +} {1 {frame ending offset must be a non-negative number}} + finish_test diff --git a/test/windowfault.test b/test/windowfault.test index 27c7742b30..b5d7433112 100644 --- a/test/windowfault.test +++ b/test/windowfault.test @@ -284,7 +284,7 @@ do_faultsim_test 12 -faults oom* -prep { } -body { execsql { WITH v(a, b, row_number) AS ( - SELECT a, b, row_number() OVER (PARTITION BY a ORDER BY b) FROM t1 + SELECT a, b, row_number() OVER (PARTITION BY a COLLATE nocase ORDER BY b) FROM t1 ) SELECT * FROM v WHERE a=2 } diff --git a/test/windowpushd.test b/test/windowpushd.test index 4462a0b4b4..f2e04d72fb 100644 --- a/test/windowpushd.test +++ b/test/windowpushd.test @@ -51,7 +51,7 @@ do_execsql_test 1.3 { do_eqp_test 1.4 { SELECT * FROM lll WHERE grp_id=2 -} {SEARCH TABLE t1 USING COVERING INDEX i1 (grp_id=?)} +} {SEARCH t1 USING COVERING INDEX i1 (grp_id=?)} #------------------------------------------------------------------------- reset_db @@ -158,10 +158,10 @@ foreach tn {0 1} { if {$tn==1} { do_eqp_test 2.$tn.3.3 { SELECT * FROM v3 WHERE b='E' - } {SEARCH TABLE t1 USING INDEX i2 (b=?)} + } {SEARCH t1 USING INDEX i2 (b=?)} do_eqp_test 2.$tn.3.4 { SELECT * FROM v3 WHERE b>'C' - } {SEARCH TABLE t1 USING INDEX i2 (b>?)} + } {SEARCH t1 USING INDEX i2 (b>?)} } do_execsql_test 2.$tn.3.5 { SELECT * FROM v3 WHERE d<0.55; } { @@ -172,7 +172,7 @@ foreach tn {0 1} { if {$tn==1} { do_eqp_test 2.$tn.3.6 { SELECT * FROM v3 WHERE d<0.55 - } {SCAN TABLE t1 USING INDEX i2} + } {SCAN t1 USING INDEX i2} } do_execsql_test 2.$tn.4.1 { @@ -234,4 +234,3 @@ foreach tn {0 1} { finish_test - diff --git a/test/with1.test b/test/with1.test index 74997c1db0..5765399d10 100644 --- a/test/with1.test +++ b/test/with1.test @@ -1025,10 +1025,10 @@ do_eqp_test 19.1b { SELECT * FROM t1; } { QUERY PLAN - |--MATERIALIZE xxxxxx + |--MATERIALIZE x1 | `--SCAN CONSTANT ROW - |--SCAN SUBQUERY xxxxxx - `--SCAN SUBQUERY xxxxxx + |--SCAN x1 + `--SCAN x1 } # 2017-10-28. @@ -1149,20 +1149,26 @@ do_execsql_test 24.2 { # had to continue to recognize "true" and "false" as identifiers for # backwards compatibility. # -reset_db -do_execsql_test 25.1 { - CREATE TABLE dual(dummy); - INSERT INTO dual(dummy) VALUES('X'); - WITH cte1 AS ( - SELECT TRUE, ( - WITH cte2 AS (SELECT avg(DISTINCT TRUE) FROM dual) - SELECT 2571 FROM cte2 - ) AS subquery1 - FROM dual - GROUP BY 1 - ) - SELECT (SELECT 1324 FROM cte1) FROM cte1; -} {1324} +foreach {id dual} { + 1 {CREATE TABLE dual AS SELECT 'X' AS dummy} + 2 {CREATE TEMP TABLE dual AS SELECT 'X' AS dummy} + 3 {CREATE VIEW dual(dummy) AS VALUES('X')} + 4 {CREATE TEMP VIEW dual(dummy) AS VALUES('X')} +} { + reset_db + db eval $dual + do_execsql_test 25.$id { + WITH cte1 AS ( + SELECT TRUE, ( + WITH cte2 AS (SELECT avg(DISTINCT TRUE) FROM dual) + SELECT 2571 FROM cte2 + ) AS subquery1 + FROM dual + GROUP BY 1 + ) + SELECT (SELECT 1324 FROM cte1) FROM cte1; + } {1324} +} do_catchsql_test 26.0 { WITH i(x) AS ( @@ -1207,4 +1213,28 @@ do_execsql_test 26.3 { SELECT * FROM cte ORDER BY +label, +step; } {a 1 a 2 a 3 b 1 b 2 b 3} +# 2021-05-20 +# forum post https://sqlite.org/forum/forumpost/8590e3f6dc +# +reset_db +do_execsql_test 27.1 { + CREATE TABLE t1(k); + CREATE TABLE log(k, cte_map, main_map); + CREATE TABLE map(k, v); + INSERT INTO map VALUES(1, 'main1'), (2, 'main2'); + + CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN + INSERT INTO log + WITH map(k,v) AS (VALUES(1,'cte1'),(2,'cte2')) + SELECT + new.k, + (SELECT v FROM map WHERE k=new.k), + (SELECT v FROM main.map WHERE k=new.k); + END; + + INSERT INTO t1 VALUES(1); + INSERT INTO t1 VALUES(2); + SELECT k, cte_map, main_map, '|' FROM log ORDER BY k; +} {1 cte1 main1 | 2 cte2 main2 |} + finish_test diff --git a/test/with3.test b/test/with3.test index 6dffb84077..8e8eba89f6 100644 --- a/test/with3.test +++ b/test/with3.test @@ -89,13 +89,13 @@ ifcapable analyze { SELECT * FROM cnt, y1 WHERE i=a } [string map {"\n " \n} { QUERY PLAN - |--MATERIALIZE xxxxxx + |--MATERIALIZE cnt | |--SETUP | | `--SCAN CONSTANT ROW | `--RECURSIVE STEP - | `--SCAN TABLE cnt - |--SCAN SUBQUERY xxxxxx - `--SEARCH TABLE y1 USING INDEX y1a (a=?) + | `--SCAN cnt + |--SCAN cnt + `--SEARCH y1 USING INDEX y1a (a=?) }] do_eqp_test 3.1.3 { @@ -103,13 +103,13 @@ ifcapable analyze { SELECT * FROM cnt, y1 WHERE i=a } [string map {"\n " \n} { QUERY PLAN - |--MATERIALIZE xxxxxx + |--MATERIALIZE cnt | |--SETUP | | `--SCAN CONSTANT ROW | `--RECURSIVE STEP - | `--SCAN TABLE cnt - |--SCAN TABLE y1 - `--SEARCH SUBQUERY xxxxxx USING AUTOMATIC COVERING INDEX (i=?) + | `--SCAN cnt + |--SCAN y1 + `--SEARCH cnt USING AUTOMATIC COVERING INDEX (i=?) }] } @@ -125,17 +125,17 @@ do_eqp_test 3.2.2 { WHERE c.id=w2.pk AND c.id=w1.pk; } { QUERY PLAN - |--MATERIALIZE xxxxxx + |--MATERIALIZE c | |--SETUP | | |--SCAN CONSTANT ROW | | `--SCALAR SUBQUERY xxxxxx - | | `--SCAN TABLE w2 + | | `--SCAN w2 | `--RECURSIVE STEP - | |--SCAN TABLE w1 - | `--SCAN TABLE c - |--SCAN SUBQUERY xxxxxx - |--SEARCH TABLE w2 USING INTEGER PRIMARY KEY (rowid=?) - `--SEARCH TABLE w1 USING INTEGER PRIMARY KEY (rowid=?) + | |--SCAN w1 + | `--SCAN c + |--SCAN c + |--SEARCH w2 USING INTEGER PRIMARY KEY (rowid=?) + `--SEARCH w1 USING INTEGER PRIMARY KEY (rowid=?) } do_execsql_test 4.0 { @@ -207,15 +207,15 @@ do_eqp_test 5.1 { ORDER BY 1; } { QUERY PLAN - |--MATERIALIZE xxxxxx + |--MATERIALIZE c | |--SETUP | | `--SCAN CONSTANT ROW | `--RECURSIVE STEP - | `--SCAN TABLE c - |--SCAN SUBQUERY xxxxxx AS x1 - |--SCAN SUBQUERY xxxxxx AS x2 - |--SCAN SUBQUERY xxxxxx AS x3 - |--SCAN SUBQUERY xxxxxx AS x4 + | `--SCAN c + |--SCAN x1 + |--SCAN x2 + |--SCAN x3 + |--SCAN x4 `--USE TEMP B-TREE FOR ORDER BY } do_execsql_test 5.2 { diff --git a/test/with6.test b/test/with6.test index ef63ec8bee..333147d8be 100644 --- a/test/with6.test +++ b/test/with6.test @@ -30,11 +30,11 @@ do_eqp_test 101 { SELECT c1.x||c2.x||c3.x FROM c c1, c c2, c c3; } { QUERY PLAN - |--MATERIALIZE xxxxxx + |--MATERIALIZE c | `--SCAN 2 CONSTANT ROWS - |--SCAN SUBQUERY xxxxxx AS c1 - |--SCAN SUBQUERY xxxxxx AS c2 - `--SCAN SUBQUERY xxxxxx AS c3 + |--SCAN c1 + |--SCAN c2 + `--SCAN c3 } do_execsql_test 110 { @@ -46,11 +46,11 @@ do_eqp_test 111 { SELECT c1.x||c2.x||c3.x FROM c c1, c c2, c c3; } { QUERY PLAN - |--MATERIALIZE xxxxxx + |--MATERIALIZE c | `--SCAN 2 CONSTANT ROWS - |--SCAN SUBQUERY xxxxxx AS c1 - |--SCAN SUBQUERY xxxxxx AS c2 - `--SCAN SUBQUERY xxxxxx AS c3 + |--SCAN c1 + |--SCAN c2 + `--SCAN c3 } # Even though the CTE is not materialized, the self-join optimization @@ -65,11 +65,11 @@ do_eqp_test 121 { SELECT c1.x||c2.x||c3.x FROM c c1, c c2, c c3; } { QUERY PLAN - |--MATERIALIZE xxxxxx + |--MATERIALIZE c | `--SCAN 2 CONSTANT ROWS - |--SCAN SUBQUERY xxxxxx AS c1 - |--SCAN SUBQUERY xxxxxx AS c2 - `--SCAN SUBQUERY xxxxxx AS c3 + |--SCAN c1 + |--SCAN c2 + `--SCAN c3 } do_execsql_test 130 { @@ -87,21 +87,21 @@ do_eqp_test 131 { (SELECT x FROM c LIMIT 5) AS c3; } { QUERY PLAN - |--MATERIALIZE xxxxxx - | |--CO-ROUTINE xxxxxx + |--MATERIALIZE c1 + | |--CO-ROUTINE c | | `--SCAN 2 CONSTANT ROWS - | `--SCAN SUBQUERY xxxxxx - |--MATERIALIZE xxxxxx - | |--CO-ROUTINE xxxxxx + | `--SCAN c + |--MATERIALIZE c2 + | |--CO-ROUTINE c | | `--SCAN 2 CONSTANT ROWS - | `--SCAN SUBQUERY xxxxxx - |--MATERIALIZE xxxxxx - | |--CO-ROUTINE xxxxxx + | `--SCAN c + |--MATERIALIZE c3 + | |--CO-ROUTINE c | | `--SCAN 2 CONSTANT ROWS - | `--SCAN SUBQUERY xxxxxx - |--SCAN SUBQUERY xxxxxx AS c1 - |--SCAN SUBQUERY xxxxxx AS c2 - `--SCAN SUBQUERY xxxxxx AS c3 + | `--SCAN c + |--SCAN c1 + |--SCAN c2 + `--SCAN c3 } # The (SELECT x FROM c LIMIT N) subqueries get materialized once each. @@ -123,17 +123,17 @@ do_eqp_test 141 { (SELECT x FROM c LIMIT 7) AS c3; } { QUERY PLAN - |--MATERIALIZE xxxxxx - | |--MATERIALIZE xxxxxx + |--MATERIALIZE c1 + | |--MATERIALIZE c | | `--SCAN 2 CONSTANT ROWS - | `--SCAN SUBQUERY xxxxxx - |--MATERIALIZE xxxxxx - | `--SCAN SUBQUERY xxxxxx - |--MATERIALIZE xxxxxx - | `--SCAN SUBQUERY xxxxxx - |--SCAN SUBQUERY xxxxxx AS c1 - |--SCAN SUBQUERY xxxxxx AS c2 - `--SCAN SUBQUERY xxxxxx AS c3 + | `--SCAN c + |--MATERIALIZE c2 + | `--SCAN c + |--MATERIALIZE c3 + | `--SCAN c + |--SCAN c1 + |--SCAN c2 + `--SCAN c3 } do_execsql_test 150 { @@ -151,17 +151,17 @@ do_eqp_test 151 { (SELECT x FROM c LIMIT 7) AS c3; } { QUERY PLAN - |--MATERIALIZE xxxxxx - | |--MATERIALIZE xxxxxx + |--MATERIALIZE c1 + | |--MATERIALIZE c | | `--SCAN 2 CONSTANT ROWS - | `--SCAN SUBQUERY xxxxxx - |--MATERIALIZE xxxxxx - | `--SCAN SUBQUERY xxxxxx - |--MATERIALIZE xxxxxx - | `--SCAN SUBQUERY xxxxxx - |--SCAN SUBQUERY xxxxxx AS c1 - |--SCAN SUBQUERY xxxxxx AS c2 - `--SCAN SUBQUERY xxxxxx AS c3 + | `--SCAN c + |--MATERIALIZE c2 + | `--SCAN c + |--MATERIALIZE c3 + | `--SCAN c + |--SCAN c1 + |--SCAN c2 + `--SCAN c3 } do_execsql_test 160 { @@ -175,11 +175,11 @@ do_eqp_test 161 { FROM c AS c2 WHERE c2.x<10; } { QUERY PLAN - |--MATERIALIZE xxxxxx + |--MATERIALIZE c | `--SCAN 2 CONSTANT ROWS - |--SCAN SUBQUERY xxxxxx AS c2 + |--SCAN c2 `--CORRELATED SCALAR SUBQUERY xxxxxx - `--SCAN SUBQUERY xxxxxx + `--SCAN c } do_execsql_test 170 { @@ -193,13 +193,13 @@ do_eqp_test 171 { FROM c AS c2 WHERE c2.x<10; } { QUERY PLAN - |--CO-ROUTINE xxxxxx + |--CO-ROUTINE c | `--SCAN 2 CONSTANT ROWS - |--SCAN SUBQUERY xxxxxx AS c2 + |--SCAN c2 `--CORRELATED SCALAR SUBQUERY xxxxxx - |--CO-ROUTINE xxxxxx + |--CO-ROUTINE c | `--SCAN 2 CONSTANT ROWS - `--SCAN SUBQUERY xxxxxx + `--SCAN c } @@ -228,15 +228,15 @@ do_eqp_test 211 { SELECT y FROM t2 ORDER BY y; } { QUERY PLAN - |--MATERIALIZE xxxxxx - | |--MATERIALIZE xxxxxx + |--MATERIALIZE c1 + | |--MATERIALIZE c | | `--SCAN 3 CONSTANT ROWS - | `--SCAN SUBQUERY xxxxxx - |--MATERIALIZE xxxxxx - | `--SCAN SUBQUERY xxxxxx - |--SCAN SUBQUERY xxxxxx AS c1 - |--SCAN SUBQUERY xxxxxx AS c2 - |--SCAN TABLE t1 + | `--SCAN c + |--MATERIALIZE c2 + | `--SCAN c + |--SCAN c1 + |--SCAN c2 + |--SCAN t1 `--USE TEMP B-TREE FOR ORDER BY } do_execsql_test 220 { diff --git a/test/without_rowid1.test b/test/without_rowid1.test index 02a089610d..e4e69eb727 100644 --- a/test/without_rowid1.test +++ b/test/without_rowid1.test @@ -452,5 +452,18 @@ do_execsql_test 13.10 { PRAGMA integrity_check; SELECT * FROM t0, t1; } {ok abc xyz abc xyz} + +# 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=/} finish_test diff --git a/test/without_rowid6.test b/test/without_rowid6.test index 567acfaed6..06fc7435b0 100644 --- a/test/without_rowid6.test +++ b/test/without_rowid6.test @@ -64,7 +64,7 @@ do_execsql_test_if_vtab without_rowid6-201 { do_execsql_test without_rowid6-210 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>3 ORDER BY b; -} {/SEARCH TABLE t1 USING PRIMARY KEY .b>../} +} {/SEARCH t1 USING PRIMARY KEY .b>../} do_execsql_test without_rowid6-220 { PRAGMA index_list(t1); } {/sqlite_autoindex_t1_2 1 pk/} @@ -83,7 +83,7 @@ do_execsql_test without_rowid6-300 { do_execsql_test without_rowid6-310 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>3 ORDER BY b; -} {/SEARCH TABLE t1 USING PRIMARY KEY .b>../} +} {/SEARCH t1 USING PRIMARY KEY .b>../} do_execsql_test without_rowid6-320 { PRAGMA index_list(t1); } {/sqlite_autoindex_t1_2 1 pk/} @@ -101,7 +101,7 @@ do_execsql_test without_rowid6-400 { do_execsql_test without_rowid6-410 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>3 ORDER BY b; -} {/SEARCH TABLE t1 USING PRIMARY KEY .b>../} +} {/SEARCH t1 USING PRIMARY KEY .b>../} do_execsql_test without_rowid6-420 { PRAGMA index_list(t1); } {/sqlite_autoindex_t1_2 1 pk/} @@ -121,7 +121,7 @@ do_execsql_test_if_vtab without_rowid6-501 { do_execsql_test without_rowid6-510 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>3 ORDER BY b; -} {/SEARCH TABLE t1 USING PRIMARY KEY .b>../} +} {/SEARCH t1 USING PRIMARY KEY .b>../} do_execsql_test without_rowid6-520 { PRAGMA index_list(t1); } {/sqlite_autoindex_t1_1 1 pk/} diff --git a/test/zipfile.test b/test/zipfile.test index 79298a0506..8749f17c38 100644 --- a/test/zipfile.test +++ b/test/zipfile.test @@ -843,4 +843,16 @@ do_catchsql_test 16.20 { REPLACE INTO zipfile VALUES(null,null,null,null,null,123,null); } {1 {zipfile: missing filename}} +# 2021-04-22 forum https://sqlite.org/forum/forumpost/d82289d69f +do_execsql_test 17.1 { + WITH vlist(x) AS ( + VALUES(9223372036854775807), + (-9223372036854775808), + (9223372036854775806), + (-9223372036854775807) + ) + SELECT DISTINCT typeof(zipfile(0,0,x,0)) FROM vlist; +} {blob} + + finish_test diff --git a/tool/lemon.c b/tool/lemon.c index 06ba1be2bd..75fc7aa2fb 100644 --- a/tool/lemon.c +++ b/tool/lemon.c @@ -2708,7 +2708,7 @@ static void parseonetoken(struct pstate *psp) ** in order to control their assigned integer number. The number for ** each token is assigned when it is first seen. So by including ** - ** %token ONE TWO THREE + ** %token ONE TWO THREE. ** ** early in the grammar file, that assigns small consecutive values ** to each of the tokens ONE TWO and THREE. diff --git a/tool/mkctimec.tcl b/tool/mkctimec.tcl index 499d5a5639..2f15ac9fb7 100644 --- a/tool/mkctimec.tcl +++ b/tool/mkctimec.tcl @@ -4,16 +4,28 @@ # # const char **azCompileOpt[] # -# declaration used in src/ctime.c, run this script. +# definition used in src/ctime.c, run this script from +# the checkout root. It alters src/ctime.c in-place. # -# All Boolean compile time options. +# All Boolean compile time options which default to something +# other than 0 or empty. The default is paired with the PP +# symbol so that a differing define can be detected. # -set boolean_options { +set boolean_defnnz_options { + {SQLITE_HOMEGROWN_RECURSIVE_MUTEX 1} + {SQLITE_POWERSAFE_OVERWRITE 1} + {SQLITE_DEFAULT_MEMSTATUS 1} + {SQLITE_OMIT_TRACE 1} + {SQLITE_ALLOW_COVERING_INDEX_SCAN 1} +} + +# All Boolean compile time options which default to 0 or empty. +# +set boolean_defnil_options { SQLITE_32BIT_ROWID SQLITE_4_BYTE_ALIGNED_MALLOC SQLITE_64BIT_STATS - SQLITE_ALLOW_COVERING_INDEX_SCAN SQLITE_ALLOW_URI_AUTHORITY SQLITE_BUG_COMPATIBLE_20160819 SQLITE_CASE_SENSITIVE_LIKE @@ -25,7 +37,6 @@ set boolean_options { SQLITE_DEFAULT_CKPTFULLFSYNC SQLITE_DEFAULT_FOREIGN_KEYS SQLITE_DEFAULT_LOCKING_MODE - SQLITE_DEFAULT_MEMSTATUS SQLITE_DEFAULT_RECURSIVE_TRIGGERS SQLITE_DEFAULT_SYNCHRONOUS SQLITE_DEFAULT_WAL_SYNCHRONOUS @@ -40,40 +51,49 @@ set boolean_options { SQLITE_ENABLE_8_3_NAMES SQLITE_ENABLE_API_ARMOR SQLITE_ENABLE_ATOMIC_WRITE - SQLITE_ENABLE_CEROD + SQLITE_ENABLE_BATCH_ATOMIC_WRITE + SQLITE_ENABLE_BYTECODE_VTAB SQLITE_ENABLE_COLUMN_METADATA SQLITE_ENABLE_COLUMN_USED_MASK SQLITE_ENABLE_COSTMULT SQLITE_ENABLE_CURSOR_HINTS + SQLITE_ENABLE_DBPAGE_VTAB SQLITE_ENABLE_DBSTAT_VTAB SQLITE_ENABLE_EXPENSIVE_ASSERT - SQLITE_ENABLE_FTS1 - SQLITE_ENABLE_FTS2 + SQLITE_ENABLE_EXPLAIN_COMMENTS SQLITE_ENABLE_FTS3 SQLITE_ENABLE_FTS3_PARENTHESIS SQLITE_ENABLE_FTS3_TOKENIZER SQLITE_ENABLE_FTS4 SQLITE_ENABLE_FTS5 + SQLITE_ENABLE_GEOPOLY SQLITE_ENABLE_HIDDEN_COLUMNS SQLITE_ENABLE_ICU SQLITE_ENABLE_IOTRACE SQLITE_ENABLE_JSON1 SQLITE_ENABLE_LOAD_EXTENSION SQLITE_ENABLE_LOCKING_STYLE + SQLITE_ENABLE_MATH_FUNCTIONS SQLITE_ENABLE_MEMORY_MANAGEMENT SQLITE_ENABLE_MEMSYS3 SQLITE_ENABLE_MEMSYS5 SQLITE_ENABLE_MULTIPLEX + SQLITE_ENABLE_NORMALIZE SQLITE_ENABLE_NULL_TRIM + SQLITE_ENABLE_OFFSET_SQL_FUNC SQLITE_ENABLE_OVERSIZE_CELL_CHECK SQLITE_ENABLE_PREUPDATE_HOOK + SQLITE_ENABLE_QPSG SQLITE_ENABLE_RBU SQLITE_ENABLE_RTREE SQLITE_ENABLE_SELECTTRACE SQLITE_ENABLE_SESSION SQLITE_ENABLE_SNAPSHOT + SQLITE_ENABLE_SORTER_REFERENCES SQLITE_ENABLE_SQLLOG + SQLITE_ENABLE_STAT4 SQLITE_ENABLE_STMT_SCANSTATUS + SQLITE_ENABLE_STMTVTAB SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION SQLITE_ENABLE_UNLOCK_NOTIFY SQLITE_ENABLE_UPDATE_DELETE_LIMIT @@ -85,8 +105,6 @@ set boolean_options { SQLITE_EXTRA_IFNULLROW SQLITE_FTS5_ENABLE_TEST_MI SQLITE_FTS5_NO_WITHOUT_ROWID - SQLITE_HAS_CODEC - SQLITE_HOMEGROWN_RECURSIVE_MUTEX SQLITE_IGNORE_AFP_LOCK_ERRORS SQLITE_IGNORE_FLOCK_LOCK_ERRORS SQLITE_INLINE_MEMCPY @@ -98,7 +116,6 @@ set boolean_options { SQLITE_MIXED_ENDIAN_64BIT_FLOAT SQLITE_MMAP_READWRITE SQLITE_MUTEX_NOOP - SQLITE_MUTEX_NREF SQLITE_MUTEX_OMIT SQLITE_MUTEX_PTHREADS SQLITE_MUTEX_W32 @@ -116,16 +133,15 @@ set boolean_options { SQLITE_OMIT_AUTOVACUUM SQLITE_OMIT_BETWEEN_OPTIMIZATION SQLITE_OMIT_BLOB_LITERAL - SQLITE_OMIT_BTREECOUNT SQLITE_OMIT_CAST SQLITE_OMIT_CHECK SQLITE_OMIT_COMPLETE SQLITE_OMIT_COMPOUND_SELECT SQLITE_OMIT_CONFLICT_CLAUSE SQLITE_OMIT_CTE - SQLITE_OMIT_DATETIME_FUNCS SQLITE_OMIT_DECLTYPE SQLITE_OMIT_DEPRECATED + SQLITE_OMIT_DESERIALIZE SQLITE_OMIT_DISKIO SQLITE_OMIT_EXPLAIN SQLITE_OMIT_FLAG_PRAGMAS @@ -135,6 +151,7 @@ set boolean_options { SQLITE_OMIT_HEX_INTEGER SQLITE_OMIT_INCRBLOB SQLITE_OMIT_INTEGRITY_CHECK + SQLITE_OMIT_INTROSPECTION_PRAGMAS SQLITE_OMIT_LIKE_OPTIMIZATION SQLITE_OMIT_LOAD_EXTENSION SQLITE_OMIT_LOCALTIME @@ -156,7 +173,6 @@ set boolean_options { SQLITE_OMIT_TCL_VARIABLE SQLITE_OMIT_TEMPDB SQLITE_OMIT_TEST_CONTROL - SQLITE_OMIT_TRACE SQLITE_OMIT_TRIGGER SQLITE_OMIT_TRUNCATE_OPTIMIZATION SQLITE_OMIT_UTF16 @@ -168,7 +184,6 @@ set boolean_options { SQLITE_OMIT_XFER_OPT SQLITE_PCACHE_SEPARATE_HEADER SQLITE_PERFORMANCE_TRACE - SQLITE_POWERSAFE_OVERWRITE SQLITE_PREFER_PROXY_LOCKING SQLITE_PROXY_DEBUG SQLITE_REVERSE_UNORDERED_SELECTS @@ -177,7 +192,6 @@ set boolean_options { SQLITE_SMALL_STACK SQLITE_SOUNDEX SQLITE_SUBSTR_COMPATIBILITY - SQLITE_SYSTEM_MALLOC SQLITE_TCL SQLITE_TEST SQLITE_UNLINK_AFTER_CLOSE @@ -191,7 +205,15 @@ set boolean_options { SQLITE_ZERO_MALLOC } -# All compile time options for which the assigned value is other than boolean. +# All compile time options for which the assigned value is other than boolean +# and is a comma-separated scalar pair. +# +set value2_options { + SQLITE_DEFAULT_LOOKASIDE +} + +# All compile time options for which the assigned value is other than boolean +# and is a single scalar. # set value_options { SQLITE_BITMASK_TYPE @@ -200,7 +222,6 @@ set value_options { SQLITE_DEFAULT_FILE_PERMISSIONS SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT SQLITE_DEFAULT_LOCKING_MODE - SQLITE_DEFAULT_LOOKASIDE SQLITE_DEFAULT_MMAP_SIZE SQLITE_DEFAULT_PAGE_SIZE SQLITE_DEFAULT_PCACHE_INITSZ @@ -212,6 +233,7 @@ set value_options { SQLITE_DEFAULT_WAL_SYNCHRONOUS SQLITE_DEFAULT_WORKER_THREADS SQLITE_ENABLE_8_3_NAMES + SQLITE_ENABLE_CEROD SQLITE_ENABLE_LOCKING_STYLE SQLITE_EXTRA_INIT SQLITE_EXTRA_SHUTDOWN @@ -245,13 +267,6 @@ set value_options { # Options that require custom code. # -set options(ENABLE_STAT3) { -#if defined(SQLITE_ENABLE_STAT4) - "ENABLE_STAT4", -#elif defined(SQLITE_ENABLE_STAT3) - "ENABLE_STAT3", -#endif -} set options(COMPILER) { #if defined(__clang__) && defined(__clang_major__) "COMPILER=clang-" CTIMEOPT_VAL(__clang_major__) "." @@ -268,13 +283,26 @@ set options(HAVE_ISNAN) { "HAVE_ISNAN", #endif } +set options(OMIT_DATETIME_FUNCS) { +#if defined(SQLITE_OMIT_DATETIME_FUNCS) || defined(SQLITE_OMIT_FLOATING_POINT) + "OMIT_DATETIME_FUNCS", +#endif +} +set options(SYSTEM_MALLOC) "\ +#if (!defined(SQLITE_WIN32_MALLOC) \\ + && !defined(SQLITE_ZERO_MALLOC) \\ + && !defined(SQLITE_MEMDEBUG) \\ + ) || defined(SQLITE_SYSTEM_MALLOC) + \"SYSTEM_MALLOC\", +#endif +" set options(THREADSAFE) { #if defined(SQLITE_THREADSAFE) "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE), #elif defined(THREADSAFE) "THREADSAFE=" CTIMEOPT_VAL(THREADSAFE), #else - "THREADSAFE=1" + "THREADSAFE=1", #endif } @@ -286,7 +314,20 @@ proc trim_name {in} { return $ret } -foreach b $boolean_options { +foreach name_defval $boolean_defnnz_options { + set b [lindex $name_defval 0] + set defval [lindex $name_defval 1] + set name [trim_name $b] + set options($name) [subst { +#ifdef $b +# if $b != $defval + "$name=" CTIMEOPT_VAL($b), +# endif +#endif +}] +} + +foreach b $boolean_defnil_options { set name [trim_name $b] set options($name) [subst { #if $b @@ -303,9 +344,70 @@ foreach v $value_options { #endif }] } + +foreach v $value2_options { + set name [trim_name $v] + set options($name) [subst { +#ifdef $v + "$name=" CTIMEOPT_VAL2($v), +#endif +}] +} -foreach o [lsort [array names options]] { - puts [string trim $options($o)] +# Split a string on a regex, return all parts in order. +# Any elements with an even index may be empty. +# Elements with odd indices will match the regex. +proc split_on_re {re str {nrepps 1}} { + set chunks {} + set cix 0 + set resm [regexp -all -inline -indices $re $str] + if {[llength $resm]==0} { + return $str + } + set rix 0 + while {$rix < [llength $resm]} { + set mre [lindex $resm $rix] + incr rix $nrepps + set mbx [lindex $mre 0] + set mex [lindex $mre 1] + lappend chunks [string range $str $cix [expr $mbx - 1]] + lappend chunks [string range $str $mbx $mex] + set cix [expr $mex + 1] + } + lappend chunks [string range $str $cix end] + return $chunks } +set ctime_c "src/ctime.c" +if {[catch {set cfd [open $ctime_c r]}]!=0} { + puts stderr "File '$ctime_c' unreadable. Run this script from checkout root." + exit 1; +} + +set ctfc [read $cfd] +close $cfd + +set re {/\*\s+\*+\s*((BEGIN)|(END)) CODE GENERATED BY (\S+)\s+\*/\s+} +set renpp 5 + +set ctfcChunks [split_on_re $re $ctfc $renpp] +if {[llength $ctfcChunks] != 5} { + puts stderr "File '$ctime_c' has too few generated code markers." + exit 1; +} + +if {[catch {set cfd [open $ctime_c w]}]!=0} { + puts stderr "File '$ctime_c' unwritable." + exit 1; +} + +puts -nonewline $cfd [lindex $ctfcChunks 0] +puts -nonewline $cfd [lindex $ctfcChunks 1] +foreach o [lsort [array names options]] { + puts $cfd [string trim $options($o)] +} +puts -nonewline $cfd [lindex $ctfcChunks 3] +puts -nonewline $cfd [lindex $ctfcChunks 4] + +close $cfd diff --git a/tool/mkopcodeh.tcl b/tool/mkopcodeh.tcl index 57017364a0..cc372e404a 100644 --- a/tool/mkopcodeh.tcl +++ b/tool/mkopcodeh.tcl @@ -145,7 +145,9 @@ foreach name {OP_Noop OP_Explain OP_Abortable} { incr nOp } -# The following are the opcodes that are processed by resolveP2Values() +# The following are the opcodes that receive special processing in the +# resolveP2Values() routine. Update this list whenever new cases are +# added to the pOp->opcode switch within resolveP2Values(). # set rp2v_ops { OP_Transaction @@ -157,13 +159,11 @@ set rp2v_ops { OP_VUpdate OP_VFilter OP_Next - OP_NextIfOpen OP_SorterNext OP_Prev - OP_PrevIfOpen } -# Assign small values to opcodes that are processed by resolveP2Values() +# Assign the smallest values to opcodes that are processed by resolveP2Values() # to make code generation for the switch() statement smaller and faster. # set cnt -1 @@ -177,6 +177,7 @@ for {set i 0} {$i<$nOp} {incr i} { set def($cnt) $name } } +set mxCase1 $cnt # Assign the next group of values to JUMP opcodes # @@ -311,7 +312,7 @@ for {set i 0} {$i<=$max} {incr i} { } puts "\175" puts "" -puts "/* The sqlite3P2Values() routine is able to run faster if it knows" +puts "/* The resolve3P2Values() routine is able to run faster if it knows" puts "** the value of the largest JUMP opcode. The smaller the maximum" puts "** JUMP opcode the better, so the mkopcodeh.tcl script that" puts "** generated this include file strives to group all JUMP opcodes" diff --git a/tool/omittest.tcl b/tool/omittest.tcl index 120fc2afdd..9f24d6d3d3 100644 --- a/tool/omittest.tcl +++ b/tool/omittest.tcl @@ -206,6 +206,7 @@ proc main {argv} { SQLITE_OMIT_DATETIME_FUNCS \ SQLITE_OMIT_DECLTYPE \ SQLITE_OMIT_DEPRECATED \ + SQLITE_OMIT_DESERIALIZE \ SQLITE_OMIT_DISKIO \ SQLITE_OMIT_EXPLAIN \ SQLITE_OMIT_FLAG_PRAGMAS \ @@ -254,6 +255,7 @@ proc main {argv} { ] set ::ENABLE_SYMBOLS [list \ + SQLITE_ALLOW_ROWID_IN_VIEW \ SQLITE_DISABLE_DIRSYNC \ SQLITE_DISABLE_LFS \ SQLITE_ENABLE_ATOMIC_WRITE \ diff --git a/tool/showdb.c b/tool/showdb.c index 09c4d9de44..5e949939e1 100644 --- a/tool/showdb.c +++ b/tool/showdb.c @@ -912,10 +912,19 @@ static void page_usage_btree( int cellstart = hdr+12; u32 child; for(i=0; i= g.pagesize ){ + printf("ERROR: page %d too many cells (%d)\n", pgno, nCell); + break; + } + ofst = a[cellidx]*256 + a[cellidx+1]; + if( ofst=g.pagesize ){ + printf("ERROR: page %d cell %d out of bounds\n", pgno, i); + continue; + } child = decodeInt32(a+ofst); page_usage_btree(child, pgno, i, zName); }