ADDED LICENSE.md Index: LICENSE.md ================================================================== --- /dev/null +++ LICENSE.md @@ -0,0 +1,6 @@ +The author disclaims copyright to this source code. In place of +a legal notice, here is a blessing: + + * May you do good and not evil. + * May you find forgiveness for yourself and forgive others. + * May you share freely, never taking more than you give. Index: Makefile.in ================================================================== --- Makefile.in +++ Makefile.in @@ -1148,14 +1148,14 @@ $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_write.c rtree.lo: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c -sqlite3session.lo: $(TOP)/ext/userauth/userauth.c $(HDR) $(EXTHDR) +userauth.lo: $(TOP)/ext/userauth/userauth.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/userauth/userauth.c -userauth.lo: $(TOP)/ext/session/sqlite3session.c $(HDR) $(EXTHDR) +sqlite3session.lo: $(TOP)/ext/session/sqlite3session.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/session/sqlite3session.c json1.lo: $(TOP)/ext/misc/json1.c $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/misc/json1.c Index: README.md ================================================================== --- README.md +++ README.md @@ -3,20 +3,32 @@ This repository contains the complete source code for the [SQLite database engine](https://sqlite.org/). Some test scripts are also included. However, many other test scripts and most of the documentation are managed separately. -SQLite [does not use Git](https://sqlite.org/whynotgit.html). -If you are reading this on GitHub, then you are looking at an -unofficial mirror. See for the official -repository. - -## Obtaining The Code +## Version Control SQLite sources are managed using the [Fossil](https://www.fossil-scm.org/), a distributed version control system -that was specifically designed to support SQLite development. +that was specifically designed and written to support SQLite development. +The [Fossil repository](https://sqlite.org/src/timeline) contains the urtext. + +If you are reading this on GitHub or some other Git repository or service, +then you are looking at a mirror. The names of check-ins and +other artifacts in a Git mirror are different from the official +names for those objects. The offical names for check-ins are +found in a footer on the check-in comment for authorized mirrors. +The official check-in name can also be seen in the `manifest.uuid` file +in the root of the tree. Always use the official name, not the +Git-name, when communicating about an SQLite check-in. + +If you pulled your SQLite source code from a secondary source and want to +verify its integrity, there are hints on how to do that in the +[Verifying Code Authenticity](#vauth) section below. + +## Obtaining The Code + If you do not want to use Fossil, you can download tarballs or ZIP archives or [SQLite archives](https://sqlite.org/cli.html#sqlar) as follows: * Lastest trunk check-in as [Tarball](https://www.sqlite.org/src/tarball/sqlite.tar.gz), @@ -292,12 +304,39 @@ that are build into SQLite. There are many other source files. Each has a succinct header comment that describes its purpose and role within the larger system. + +## Verifying Code Authenticity + +If you obtained an SQLite source tree from a secondary source, such as a +GitHub mirror, and you want to verify that it has not been altered, there +are a couple of ways to do that. + +If you have an official release version of SQLite, and you are using the +`sqlite3.c` amalgamation, then SHA3-256 hashes for the amalgamation are +available in the [change log](https://www.sqlite.org/changes.html) on +the official website. After building the `sqlite3.c` file, you can check +that is authentic by comparing the hash. This does not ensure that the +test scripts are unaltered, but it does validate the deliverable part of +the code and only involves computing and comparing a single hash. + +For versions other than an official release, or if you are building the +`sqlite3.c` amalgamation using non-standard build options, the verification +process is a little more involved. The `manifest` file at the root directory +of the source tree ([example](https://sqlite.org/src/artifact/bd49a8271d650fa8)) +contains either a SHA3-256 hash (for newer files) or a SHA1 hash (for +older files) for every source file in the repository. You can write a script +to extracts hashes from `manifest` and verifies the hashes against the +corresponding files in the source tree. The SHA3-256 hash of the `manifest` +file itself is the official name of the version of the source tree that you +have. The `manifest.uuid` file should contain the SHA3-256 hash of the +`manifest` file. If all of the above hash comparisons are correct, then +you can be confident that your source tree is authentic and unadulterated. ## Contacts The main SQLite webpage is [http://www.sqlite.org/](http://www.sqlite.org/) with geographically distributed backups at [http://www2.sqlite.org/](http://www2.sqlite.org) and [http://www3.sqlite.org/](http://www3.sqlite.org). Index: configure ================================================================== --- configure +++ configure @@ -861,10 +861,11 @@ htmldir infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir @@ -962,10 +963,11 @@ datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' @@ -1213,10 +1215,19 @@ psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) @@ -1351,11 +1362,11 @@ # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) @@ -1504,10 +1515,11 @@ --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] @@ -3932,17 +3944,17 @@ if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:3937: $ac_compile\"" >&5) + (eval echo "\"\$as_me:3949: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 - (eval echo "\"\$as_me:3940: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval echo "\"\$as_me:3952: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 - (eval echo "\"\$as_me:3943: output\"" >&5) + (eval echo "\"\$as_me:3955: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* @@ -5144,11 +5156,11 @@ fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 5149 "configure"' > conftest.$ac_ext + echo '#line 5161 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then @@ -6669,15 +6681,15 @@ # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:6674: $lt_compile\"" >&5) + (eval echo "\"\$as_me:6686: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:6678: \$? = $ac_status" >&5 + echo "$as_me:6690: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 @@ -7008,15 +7020,15 @@ # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7013: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7025: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7017: \$? = $ac_status" >&5 + echo "$as_me:7029: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 @@ -7113,15 +7125,15 @@ # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7118: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7130: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7122: \$? = $ac_status" >&5 + echo "$as_me:7134: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp @@ -7168,15 +7180,15 @@ # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7173: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7185: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7177: \$? = $ac_status" >&5 + echo "$as_me:7189: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp @@ -9548,11 +9560,11 @@ lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 9553 "configure" +#line 9565 "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif @@ -9644,11 +9656,11 @@ lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 9649 "configure" +#line 9661 "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif @@ -9993,11 +10005,11 @@ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () @@ -10039,11 +10051,11 @@ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () @@ -10063,11 +10075,11 @@ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () @@ -10108,11 +10120,11 @@ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () @@ -10132,11 +10144,11 @@ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () Index: ext/fts3/fts3_term.c ================================================================== --- ext/fts3/fts3_term.c +++ ext/fts3/fts3_term.c @@ -96,11 +96,11 @@ if( rc!=SQLITE_OK ) return rc; nByte = sizeof(Fts3termTable) + sizeof(Fts3Table) + nDb + nFts3 + 2; p = (Fts3termTable *)sqlite3_malloc64(nByte); if( !p ) return SQLITE_NOMEM; - memset(p, 0, nByte); + memset(p, 0, (size_t)nByte); p->pFts3Tab = (Fts3Table *)&p[1]; p->pFts3Tab->zDb = (char *)&p->pFts3Tab[1]; p->pFts3Tab->zName = &p->pFts3Tab->zDb[nDb+1]; p->pFts3Tab->db = db; Index: ext/fts3/unicode/mkunicode.tcl ================================================================== --- ext/fts3/unicode/mkunicode.tcl +++ ext/fts3/unicode/mkunicode.tcl @@ -736,11 +736,11 @@ int iTbl = 0; while( i<128 ){ int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ]; int n = (aFts5UnicodeData[iTbl] >> 5) + i; for(; i<128 && inDocsize ) iAdj = nDocsize - nToken; if( iAdj<0 ) iAdj = 0; - *piPos = iAdj; + *piPos = (int)iAdj; } return rc; } @@ -579,11 +579,11 @@ nByte = sizeof(Fts5Bm25Data) + nPhrase*2*sizeof(double); p = (Fts5Bm25Data*)sqlite3_malloc64(nByte); if( p==0 ){ rc = SQLITE_NOMEM; }else{ - memset(p, 0, nByte); + memset(p, 0, (size_t)nByte); p->nPhrase = nPhrase; p->aIDF = (double*)&p[1]; p->aFreq = &p->aIDF[nPhrase]; } Index: ext/fts5/fts5_buffer.c ================================================================== --- ext/fts5/fts5_buffer.c +++ ext/fts5/fts5_buffer.c @@ -25,11 +25,11 @@ pNew = sqlite3_realloc64(pBuf->p, nNew); if( pNew==0 ){ *pRc = SQLITE_NOMEM; return 1; }else{ - pBuf->nSpace = nNew; + pBuf->nSpace = (int)nNew; pBuf->p = pNew; } } return 0; } @@ -249,11 +249,11 @@ if( *pRc==SQLITE_OK ){ pRet = sqlite3_malloc64(nByte); if( pRet==0 ){ if( nByte>0 ) *pRc = SQLITE_NOMEM; }else{ - memset(pRet, 0, nByte); + memset(pRet, 0, (size_t)nByte); } } return pRet; } Index: ext/fts5/fts5_config.c ================================================================== --- ext/fts5/fts5_config.c +++ ext/fts5/fts5_config.c @@ -323,11 +323,11 @@ if( p==0 ){ *pzErr = sqlite3_mprintf("parse error in tokenize directive"); rc = SQLITE_ERROR; }else{ rc = sqlite3Fts5GetTokenizer(pGlobal, - (const char**)azArg, nArg, &pConfig->pTok, &pConfig->pTokApi, + (const char**)azArg, (int)nArg, &pConfig->pTok, &pConfig->pTokApi, pzErr ); } } } @@ -433,11 +433,11 @@ *pzOut = 0; if( zOut==0 ){ *pRc = SQLITE_NOMEM; }else{ - memcpy(zOut, zIn, nIn+1); + memcpy(zOut, zIn, (size_t)(nIn+1)); if( fts5_isopenquote(zOut[0]) ){ int ii = fts5Dequote(zOut); zRet = &zIn[ii]; *pbQuoted = 1; }else{ Index: ext/fts5/fts5_expr.c ================================================================== --- ext/fts5/fts5_expr.c +++ ext/fts5/fts5_expr.c @@ -1485,11 +1485,11 @@ nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*); pRet = sqlite3_malloc64(nByte); if( pRet==0 ){ pParse->rc = SQLITE_NOMEM; }else{ - memset(pRet, 0, nByte); + memset(pRet, 0, (size_t)nByte); } }else if( (pNear->nPhrase % SZALLOC)==0 ){ int nNew = pNear->nPhrase + SZALLOC; sqlite3_int64 nByte; @@ -1561,11 +1561,11 @@ sqlite3_int64 nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1; pSyn = (Fts5ExprTerm*)sqlite3_malloc64(nByte); if( pSyn==0 ){ rc = SQLITE_NOMEM; }else{ - memset(pSyn, 0, nByte); + memset(pSyn, 0, (size_t)nByte); pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer); memcpy(pSyn->zTerm, pToken, nToken); pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym; pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn; } @@ -1721,11 +1721,11 @@ sqlite3_int64 nByte; Fts5Colset *pColset; nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int); pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte); if( pColset ){ - memcpy(pColset, pColsetOrig, nByte); + memcpy(pColset, pColsetOrig, (size_t)nByte); } pNew->pRoot->pNear->pColset = pColset; } } @@ -1938,11 +1938,11 @@ Fts5Colset *pRet; if( pOrig ){ sqlite3_int64 nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int); pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte); if( pRet ){ - memcpy(pRet, pOrig, nByte); + memcpy(pRet, pOrig, (size_t)nByte); } }else{ pRet = 0; } return pRet; Index: ext/fts5/fts5_hash.c ================================================================== --- ext/fts5/fts5_hash.c +++ ext/fts5/fts5_hash.c @@ -101,11 +101,11 @@ if( pNew->aSlot==0 ){ sqlite3_free(pNew); *ppNew = 0; rc = SQLITE_NOMEM; }else{ - memset(pNew->aSlot, 0, nByte); + memset(pNew->aSlot, 0, (size_t)nByte); } } return rc; } @@ -185,40 +185,51 @@ pHash->nSlot = nNew; pHash->aSlot = apNew; return SQLITE_OK; } -static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){ +static int fts5HashAddPoslistSize( + Fts5Hash *pHash, + Fts5HashEntry *p, + Fts5HashEntry *p2 +){ + int nRet = 0; if( p->iSzPoslist ){ - u8 *pPtr = (u8*)p; + u8 *pPtr = p2 ? (u8*)p2 : (u8*)p; + int nData = p->nData; if( pHash->eDetail==FTS5_DETAIL_NONE ){ - assert( p->nData==p->iSzPoslist ); + assert( nData==p->iSzPoslist ); if( p->bDel ){ - pPtr[p->nData++] = 0x00; + pPtr[nData++] = 0x00; if( p->bContent ){ - pPtr[p->nData++] = 0x00; + pPtr[nData++] = 0x00; } } }else{ - int nSz = (p->nData - p->iSzPoslist - 1); /* Size in bytes */ + int nSz = (nData - p->iSzPoslist - 1); /* Size in bytes */ int nPos = nSz*2 + p->bDel; /* Value of nPos field */ assert( p->bDel==0 || p->bDel==1 ); if( nPos<=127 ){ pPtr[p->iSzPoslist] = (u8)nPos; }else{ int nByte = sqlite3Fts5GetVarintLen((u32)nPos); memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz); sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos); - p->nData += (nByte-1); + nData += (nByte-1); } } - p->iSzPoslist = 0; - p->bDel = 0; - p->bContent = 0; + nRet = nData - p->nData; + if( p2==0 ){ + p->iSzPoslist = 0; + p->bDel = 0; + p->bContent = 0; + p->nData = nData; + } } + return nRet; } /* ** Add an entry to the in-memory hash table. The key is the concatenation ** of bByte and (pToken/nToken). The value is (iRowid/iCol/iPos). @@ -271,11 +282,11 @@ /* Allocate new Fts5HashEntry and add it to the hash table. */ p = (Fts5HashEntry*)sqlite3_malloc64(nByte); if( !p ) return SQLITE_NOMEM; memset(p, 0, sizeof(Fts5HashEntry)); - p->nAlloc = nByte; + p->nAlloc = (int)nByte; zKey = fts5EntryKey(p); zKey[0] = bByte; memcpy(&zKey[1], pToken, nToken); assert( iHash==fts5HashKey(pHash->nSlot, (u8*)zKey, nToken+1) ); p->nKey = nToken; @@ -326,11 +337,11 @@ pPtr = (u8*)p; /* If this is a new rowid, append the 4-byte size field for the previous ** entry, and the new rowid for this entry. */ if( iRowid!=p->iRowid ){ - fts5HashAddPoslistSize(pHash, p); + fts5HashAddPoslistSize(pHash, p, 0); p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid); p->iRowid = iRowid; bNew = 1; p->iSzPoslist = p->nData; if( pHash->eDetail!=FTS5_DETAIL_NONE ){ @@ -443,11 +454,13 @@ memset(ap, 0, sizeof(Fts5HashEntry*) * nMergeSlot); for(iSlot=0; iSlotnSlot; iSlot++){ Fts5HashEntry *pIter; for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){ - if( pTerm==0 || 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm) ){ + if( pTerm==0 + || (pIter->nKey+1>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm)) + ){ Fts5HashEntry *pEntry = pIter; pEntry->pScanNext = 0; for(i=0; ap[i]; i++){ pEntry = fts5HashEntryMerge(pEntry, ap[i]); ap[i] = 0; @@ -471,12 +484,13 @@ /* ** Query the hash table for a doclist associated with term pTerm/nTerm. */ int sqlite3Fts5HashQuery( Fts5Hash *pHash, /* Hash table to query */ + int nPre, const char *pTerm, int nTerm, /* Query term */ - const u8 **ppDoclist, /* OUT: Pointer to doclist for pTerm */ + void **ppOut, /* OUT: Pointer to new object */ int *pnDoclist /* OUT: Size of doclist in bytes */ ){ unsigned int iHash = fts5HashKey(pHash->nSlot, (const u8*)pTerm, nTerm); char *zKey = 0; Fts5HashEntry *p; @@ -486,15 +500,24 @@ assert( p->nKey+1==(int)strlen(zKey) ); if( nTerm==p->nKey+1 && memcmp(zKey, pTerm, nTerm)==0 ) break; } if( p ){ - fts5HashAddPoslistSize(pHash, p); - *ppDoclist = (const u8*)&zKey[nTerm+1]; - *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1); + int nHashPre = sizeof(Fts5HashEntry) + nTerm + 1; + int nList = p->nData - nHashPre; + u8 *pRet = (u8*)(*ppOut = sqlite3_malloc64(nPre + nList + 10)); + if( pRet ){ + Fts5HashEntry *pFaux = (Fts5HashEntry*)&pRet[nPre-nHashPre]; + memcpy(&pRet[nPre], &((u8*)p)[nHashPre], nList); + nList += fts5HashAddPoslistSize(pHash, p, pFaux); + *pnDoclist = nList; + }else{ + *pnDoclist = 0; + return SQLITE_NOMEM; + } }else{ - *ppDoclist = 0; + *ppOut = 0; *pnDoclist = 0; } return SQLITE_OK; } @@ -523,15 +546,15 @@ ){ Fts5HashEntry *p; if( (p = pHash->pScan) ){ char *zKey = fts5EntryKey(p); int nTerm = (int)strlen(zKey); - fts5HashAddPoslistSize(pHash, p); + fts5HashAddPoslistSize(pHash, p, 0); *pzTerm = zKey; *ppDoclist = (const u8*)&zKey[nTerm+1]; *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1); }else{ *pzTerm = 0; *ppDoclist = 0; *pnDoclist = 0; } } Index: ext/fts5/fts5_index.c ================================================================== --- ext/fts5/fts5_index.c +++ ext/fts5/fts5_index.c @@ -2455,35 +2455,44 @@ Fts5Index *p, /* FTS5 backend */ const u8 *pTerm, int nTerm, /* Term to seek to */ int flags, /* Mask of FTS5INDEX_XXX flags */ Fts5SegIter *pIter /* Object to populate */ ){ - const u8 *pList = 0; int nList = 0; const u8 *z = 0; int n = 0; + Fts5Data *pLeaf = 0; assert( p->pHash ); assert( p->rc==SQLITE_OK ); if( pTerm==0 || (flags & FTS5INDEX_QUERY_SCAN) ){ + const u8 *pList = 0; + p->rc = sqlite3Fts5HashScanInit(p->pHash, (const char*)pTerm, nTerm); sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &pList, &nList); n = (z ? (int)strlen((const char*)z) : 0); + if( pList ){ + pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data)); + if( pLeaf ){ + pLeaf->p = (u8*)pList; + } + } }else{ - pIter->flags |= FTS5_SEGITER_ONETERM; - sqlite3Fts5HashQuery(p->pHash, (const char*)pTerm, nTerm, &pList, &nList); + p->rc = sqlite3Fts5HashQuery(p->pHash, sizeof(Fts5Data), + (const char*)pTerm, nTerm, (void**)&pLeaf, &nList + ); + if( pLeaf ){ + pLeaf->p = (u8*)&pLeaf[1]; + } z = pTerm; n = nTerm; + pIter->flags |= FTS5_SEGITER_ONETERM; } - if( pList ){ - Fts5Data *pLeaf; + if( pLeaf ){ sqlite3Fts5BufferSet(&p->rc, &pIter->term, n, z); - pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data)); - if( pLeaf==0 ) return; - pLeaf->p = (u8*)pList; pLeaf->nn = pLeaf->szLeaf = nList; pIter->pLeaf = pLeaf; pIter->iLeafOffset = fts5GetVarint(pLeaf->p, (u64*)&pIter->iRowid); pIter->iEndofDoclist = pLeaf->nn; Index: ext/fts5/fts5_main.c ================================================================== --- ext/fts5/fts5_main.c +++ ext/fts5/fts5_main.c @@ -631,11 +631,11 @@ if( rc==SQLITE_OK ){ nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int); pCsr = (Fts5Cursor*)sqlite3_malloc64(nByte); if( pCsr ){ Fts5Global *pGlobal = pTab->pGlobal; - memset(pCsr, 0, nByte); + memset(pCsr, 0, (size_t)nByte); pCsr->aColumnSize = (int*)&pCsr[1]; pCsr->pNext = pGlobal->pCsr; pGlobal->pCsr = pCsr; pCsr->iCsrId = ++pGlobal->iNextId; }else{ @@ -912,11 +912,11 @@ nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1); pSorter = (Fts5Sorter*)sqlite3_malloc64(nByte); if( pSorter==0 ) return SQLITE_NOMEM; - memset(pSorter, 0, nByte); + memset(pSorter, 0, (size_t)nByte); pSorter->nIdx = nPhrase; /* TODO: It would be better to have some system for reusing statement ** handles here, rather than preparing a new one for each query. But that ** is not possible as SQLite reference counts the virtual table objects. Index: ext/fts5/fts5_storage.c ================================================================== --- ext/fts5/fts5_storage.c +++ ext/fts5/fts5_storage.c @@ -287,11 +287,11 @@ nByte = sizeof(Fts5Storage) /* Fts5Storage object */ + pConfig->nCol * sizeof(i64); /* Fts5Storage.aTotalSize[] */ *pp = p = (Fts5Storage*)sqlite3_malloc64(nByte); if( !p ) return SQLITE_NOMEM; - memset(p, 0, nByte); + memset(p, 0, (size_t)nByte); p->aTotalSize = (i64*)&p[1]; p->pConfig = pConfig; p->pIndex = pIndex; if( bCreate ){ Index: ext/fts5/fts5_unicode2.c ================================================================== --- ext/fts5/fts5_unicode2.c +++ ext/fts5/fts5_unicode2.c @@ -767,10 +767,10 @@ int iTbl = 0; while( i<128 ){ int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ]; int n = (aFts5UnicodeData[iTbl] >> 5) + i; for(; i<128 && i2 && res!=0 ){ Index: ext/misc/fuzzer.c ================================================================== --- ext/misc/fuzzer.c +++ ext/misc/fuzzer.c @@ -454,11 +454,11 @@ zOut = sqlite3_malloc64(nIn+1); if( zOut ){ char q = zIn[0]; /* Quote character (if any ) */ if( q!='[' && q!= '\'' && q!='"' && q!='`' ){ - memcpy(zOut, zIn, nIn+1); + memcpy(zOut, zIn, (size_t)(nIn+1)); }else{ int iOut = 0; /* Index of next byte to write to output */ int iIn; /* Index of next byte to read from input */ if( q=='[' ) q = ']'; @@ -522,11 +522,11 @@ }else{ char *zTab; /* Dequoted name of fuzzer data table */ memset(pNew, 0, sizeof(*pNew)); pNew->zClassName = (char*)&pNew[1]; - memcpy(pNew->zClassName, zModule, nModule+1); + memcpy(pNew->zClassName, zModule, (size_t)(nModule+1)); zTab = fuzzerDequote(argv[3]); if( zTab==0 ){ rc = SQLITE_NOMEM; }else{ Index: ext/misc/unionvtab.c ================================================================== --- ext/misc/unionvtab.c +++ ext/misc/unionvtab.c @@ -254,11 +254,11 @@ void *pRet; assert( nByte>0 ); if( *pRc==SQLITE_OK ){ pRet = sqlite3_malloc64(nByte); if( pRet ){ - memset(pRet, 0, nByte); + memset(pRet, 0, (size_t)nByte); }else{ *pRc = SQLITE_NOMEM; } }else{ pRet = 0; @@ -277,11 +277,11 @@ char *zRet = 0; if( zIn ){ sqlite3_int64 nByte = strlen(zIn) + 1; zRet = unionMalloc(pRc, nByte); if( zRet ){ - memcpy(zRet, zIn, nByte); + memcpy(zRet, zIn, (size_t)nByte); } } return zRet; } Index: ext/rtree/rtree.c ================================================================== --- ext/rtree/rtree.c +++ ext/rtree/rtree.c @@ -3753,53 +3753,49 @@ ** entry for each cell in the r-tree node. Each entry is itself a ** list, containing the 8-byte rowid/pageno followed by the ** *2 coordinates. */ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){ - char *zText = 0; RtreeNode node; Rtree tree; int ii; + int nData; + int errCode; + sqlite3_str *pOut; UNUSED_PARAMETER(nArg); memset(&node, 0, sizeof(RtreeNode)); memset(&tree, 0, sizeof(Rtree)); tree.nDim = (u8)sqlite3_value_int(apArg[0]); + if( tree.nDim<1 || tree.nDim>5 ) return; tree.nDim2 = tree.nDim*2; tree.nBytesPerCell = 8 + 8 * tree.nDim; node.zData = (u8 *)sqlite3_value_blob(apArg[1]); + nData = sqlite3_value_bytes(apArg[1]); + if( nData<4 ) return; + if( nData0 ) sqlite3_str_append(pOut, " ", 1); + sqlite3_str_appendf(pOut, "{%lld", cell.iRowid); for(jj=0; jj0 ){ - if( fread(pBuf, sz, 1, f)!=1 ){ - fprintf(stderr, "cannot read all %d bytes of \"%s\"\n", sz, zFilename); + if( fread(pBuf, (size_t)sz, 1, f)!=1 ){ + fprintf(stderr, "cannot read all %d bytes of \"%s\"\n", + (int)sz, zFilename); exit(1); } fclose(f); } - *pSz = sz; + *pSz = (int)sz; *ppBuf = pBuf; } /* Array for converting from half-bytes (nybbles) into ASCII hex ** digits. */ Index: src/alter.c ================================================================== --- src/alter.c +++ src/alter.c @@ -164,19 +164,19 @@ pVTab = 0; } } #endif - /* Begin a transaction for database iDb. - ** Then modify the schema cookie (since the ALTER TABLE modifies the - ** schema). Open a statement transaction if the table is a virtual - ** table. - */ + /* Begin a transaction for database iDb. Then modify the schema cookie + ** (since the ALTER TABLE modifies the schema). Call sqlite3MayAbort(), + ** as the scalar functions (e.g. sqlite_rename_table()) invoked by the + ** nested SQL may raise an exception. */ v = sqlite3GetVdbe(pParse); if( v==0 ){ goto exit_rename_table; } + sqlite3MayAbort(pParse); /* figure out how many UTF-8 characters are in zName */ zTabName = pTab->zName; nTabName = sqlite3Utf8CharLen(zTabName, -1); @@ -241,11 +241,10 @@ #ifndef SQLITE_OMIT_VIRTUALTABLE if( pVTab ){ int i = ++pParse->nMem; sqlite3VdbeLoadString(v, i, zName); sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB); - sqlite3MayAbort(pParse); } #endif renameReloadSchema(pParse, iDb); renameTestSchema(pParse, zDb, iDb==1); @@ -562,10 +561,11 @@ /* 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_master table. */ + sqlite3MayAbort(pParse); zNew = sqlite3NameFromToken(db, pNew); if( !zNew ) goto exit_rename_column; assert( pNew->n>0 ); bQuote = sqlite3Isquote(pNew->z[0]); sqlite3NestedParse(pParse, Index: src/attach.c ================================================================== --- src/attach.c +++ src/attach.c @@ -232,11 +232,13 @@ */ if( rc==SQLITE_OK ){ sqlite3BtreeEnterAll(db); db->init.iDb = 0; db->mDbFlags &= ~(DBFLAG_SchemaKnownOk); - rc = sqlite3Init(db, &zErrDyn); + if( !REOPEN_AS_MEMDB(db) ){ + rc = sqlite3Init(db, &zErrDyn); + } sqlite3BtreeLeaveAll(db); assert( zErrDyn==0 || rc!=SQLITE_OK ); } #ifdef SQLITE_USER_AUTHENTICATION if( rc==SQLITE_OK ){ Index: src/btree.c ================================================================== --- src/btree.c +++ src/btree.c @@ -1453,11 +1453,14 @@ if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PAGE(pPage); sz2 = get2byte(&data[iFree2+2]); if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage); memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz)); sz += sz2; + }else if( iFree+sz>usableSize ){ + return SQLITE_CORRUPT_PAGE(pPage); } + cbrk = top+sz; assert( cbrk+(iFree-top) <= usableSize ); memmove(&data[cbrk], &data[top], iFree-top); for(pAddr=&data[cellOffset]; pAddrnCell>0 - || get2byteNotZero(&data[5])==pBt->usableSize + || get2byteNotZero(&data[5])==(int)pBt->usableSize || CORRUPT_DB ); pPage->nFree = -1; /* Indicate that this value is yet uncomputed */ pPage->isInit = 1; if( pBt->db->flags & SQLITE_CellSizeCk ){ return btreeCellSizeCheck(pPage); @@ -6188,11 +6191,13 @@ assert( sqlite3_mutex_held(pBt->mutex) ); assert( CORRUPT_DB || iPage>1 ); assert( !pMemPage || pMemPage->pgno==iPage ); - if( iPage<2 ) return SQLITE_CORRUPT_BKPT; + if( iPage<2 || iPage>pBt->nPage ){ + return SQLITE_CORRUPT_BKPT; + } if( pMemPage ){ pPage = pMemPage; sqlite3PagerRef(pPage->pDbPage); }else{ pPage = btreePageLookup(pBt, iPage); @@ -7557,11 +7562,10 @@ if( rc ){ memset(apOld, 0, (i)*sizeof(MemPage*)); goto balance_cleanup; } } - nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow; if( (i--)==0 ) break; if( pParent->nOverflow && i+nxDiv==pParent->aiOvfl[0] ){ apDiv[i] = pParent->apOvfl[0]; pgno = get4byte(apDiv[i]); @@ -7601,10 +7605,11 @@ } } /* Make nMaxCells a multiple of 4 in order to preserve 8-byte ** alignment */ + nMaxCells = nOld*(MX_CELL(pBt) + ArraySize(pParent->apOvfl)); nMaxCells = (nMaxCells + 3)&~3; /* ** Allocate space for memory structures */ @@ -7611,11 +7616,11 @@ szScratch = nMaxCells*sizeof(u8*) /* b.apCell */ + nMaxCells*sizeof(u16) /* b.szCell */ + pBt->pageSize; /* aSpace1 */ - assert( szScratch<=6*(int)pBt->pageSize ); + assert( szScratch<=7*(int)pBt->pageSize ); b.apCell = sqlite3StackAllocRaw(0, szScratch ); if( b.apCell==0 ){ rc = SQLITE_NOMEM_BKPT; goto balance_cleanup; } @@ -8161,11 +8166,12 @@ */ assert( nNew==1 || CORRUPT_DB ); rc = defragmentPage(apNew[0], -1); testcase( rc!=SQLITE_OK ); assert( apNew[0]->nFree == - (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2) + (get2byteNotZero(&apNew[0]->aData[5]) - apNew[0]->cellOffset + - apNew[0]->nCell*2) || rc!=SQLITE_OK ); copyNodeContent(apNew[0], pParent, &rc); freePage(apNew[0], &rc); }else if( ISAUTOVACUUM && !leafCorrection ){ Index: src/build.c ================================================================== --- src/build.c +++ src/build.c @@ -1402,11 +1402,12 @@ && pCol && sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0 && sortOrder!=SQLITE_SO_DESC ){ if( IN_RENAME_OBJECT && pList ){ - sqlite3RenameTokenRemap(pParse, &pTab->iPKey, pList->a[0].pExpr); + Expr *pCExpr = sqlite3ExprSkipCollate(pList->a[0].pExpr); + sqlite3RenameTokenRemap(pParse, &pTab->iPKey, pCExpr); } pTab->iPKey = iCol; pTab->keyConf = (u8)onError; assert( autoInc==0 || autoInc==1 ); pTab->tabFlags |= autoInc*TF_Autoincrement; @@ -3151,17 +3152,17 @@ assert( pTab!=0 ); assert( pParse->nErr==0 ); if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 && db->init.busy==0 + && pTblName!=0 #if SQLITE_USER_AUTHENTICATION && sqlite3UserAuthTable(pTab->zName)==0 #endif #ifdef SQLITE_ALLOW_SQLITE_MASTER_INDEX && sqlite3StrICmp(&pTab->zName[7],"master")!=0 #endif - && sqlite3StrNICmp(&pTab->zName[7],"altertab_",9)!=0 ){ sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); goto exit_create_index; } #ifndef SQLITE_OMIT_VIEW Index: src/main.c ================================================================== --- src/main.c +++ src/main.c @@ -841,10 +841,12 @@ { SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, SQLITE_NoCkptOnClose }, { SQLITE_DBCONFIG_ENABLE_QPSG, SQLITE_EnableQPSG }, { SQLITE_DBCONFIG_TRIGGER_EQP, SQLITE_TriggerEQP }, { SQLITE_DBCONFIG_RESET_DATABASE, SQLITE_ResetDatabase }, { SQLITE_DBCONFIG_DEFENSIVE, SQLITE_Defensive }, + { SQLITE_DBCONFIG_WRITABLE_SCHEMA, SQLITE_WriteSchema| + SQLITE_NoSchemaError }, }; unsigned int i; rc = SQLITE_ERROR; /* IMP: R-42790-23372 */ for(i=0; idb, SQLITE_DBCONFIG_WRITABLE_SCHEMA, -1, &wrSchema); + sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, 1, 0); sqlite3_exec(p->db, - "CREATE TABLE IF NOT EXISTS temp.[" BIND_PARAM_TABLE "](\n" + "CREATE TABLE IF NOT EXISTS temp.sqlite_parameters(\n" " key TEXT PRIMARY KEY,\n" " value ANY\n" ") WITHOUT ROWID;", 0, 0, 0); + sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, wrSchema, 0); } /* ** Bind parameters on a prepared statement. ** ** Parameter bindings are taken from a TEMP table of the form: ** -** CREATE TEMP TABLE "$Parameters"(key TEXT PRIMARY KEY, value) +** CREATE TEMP TABLE sqlite_parameters(key TEXT PRIMARY KEY, value) ** WITHOUT ROWID; ** ** No bindings occur if this table does not exist. The special character '$' ** is included in the table name to help prevent collisions with actual tables. ** The table must be in the TEMP schema. @@ -2778,16 +2779,16 @@ int rc; sqlite3_stmt *pQ = 0; nVar = sqlite3_bind_parameter_count(pStmt); if( nVar==0 ) return; /* Nothing to do */ - if( sqlite3_table_column_metadata(pArg->db, "TEMP", BIND_PARAM_TABLE, + if( sqlite3_table_column_metadata(pArg->db, "TEMP", "sqlite_parameters", "key", 0, 0, 0, 0, 0)!=SQLITE_OK ){ return; /* Parameter table does not exist */ } rc = sqlite3_prepare_v2(pArg->db, - "SELECT value FROM temp.\"" BIND_PARAM_TABLE "\"" + "SELECT value FROM temp.sqlite_parameters" " WHERE key=?1", -1, &pQ, 0); if( rc || pQ==0 ) return; for(i=1; i<=nVar; i++){ char zNum[30]; const char *zVar = sqlite3_bind_parameter_name(pStmt, i); @@ -3450,11 +3451,12 @@ static const char *(azHelp[]) = { #if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) ".archive ... Manage SQL archives", " Each command must have exactly one of the following options:", " -c, --create Create a new archive", - " -u, --update Update or add files to an existing archive", + " -u, --update Add files or update files with changed mtime", + " -i, --insert Like -u but always add even if mtime unchanged", " -t, --list List contents of archive", " -x, --extract Extract files from archive", " Optional arguments:", " -v, --verbose Print each filename as it is processed", " -f FILE, --file FILE Operate on archive FILE (default is current db)", @@ -4771,20 +4773,31 @@ { "number of views:", "SELECT count(*) FROM %s WHERE type='view'" }, { "schema size:", "SELECT total(length(sql)) FROM %s" }, }; - int i; + int i, rc; unsigned iDataVersion; char *zSchemaTab; char *zDb = nArg>=2 ? azArg[1] : "main"; sqlite3_stmt *pStmt = 0; unsigned char aHdr[100]; open_db(p, 0); if( p->db==0 ) return 1; - sqlite3_prepare_v2(p->db,"SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1", - -1, &pStmt, 0); + rc = sqlite3_prepare_v2(p->db, + "SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1", + -1, &pStmt, 0); + if( rc ){ + if( !sqlite3_compileoption_used("ENABLE_DBPAGE_VTAB") ){ + utf8_printf(stderr, "the \".dbinfo\" command requires the " + "-DSQLITE_ENABLE_DBPAGE_VTAB compile-time options\n"); + }else{ + utf8_printf(stderr, "error: %s\n", sqlite3_errmsg(p->db)); + } + sqlite3_finalize(pStmt); + return 1; + } sqlite3_bind_text(pStmt, 1, zDb, -1, SQLITE_STATIC); if( sqlite3_step(pStmt)==SQLITE_ROW && sqlite3_column_bytes(pStmt,0)>100 ){ memcpy(aHdr, sqlite3_column_blob(pStmt,0), 100); @@ -5374,30 +5387,32 @@ /* ** Values for ArCommand.eCmd. */ #define AR_CMD_CREATE 1 -#define AR_CMD_EXTRACT 2 -#define AR_CMD_LIST 3 -#define AR_CMD_UPDATE 4 -#define AR_CMD_HELP 5 +#define AR_CMD_UPDATE 2 +#define AR_CMD_INSERT 3 +#define AR_CMD_EXTRACT 4 +#define AR_CMD_LIST 5 +#define AR_CMD_HELP 6 /* ** Other (non-command) switches. */ -#define AR_SWITCH_VERBOSE 6 -#define AR_SWITCH_FILE 7 -#define AR_SWITCH_DIRECTORY 8 -#define AR_SWITCH_APPEND 9 -#define AR_SWITCH_DRYRUN 10 +#define AR_SWITCH_VERBOSE 7 +#define AR_SWITCH_FILE 8 +#define AR_SWITCH_DIRECTORY 9 +#define AR_SWITCH_APPEND 10 +#define AR_SWITCH_DRYRUN 11 static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){ switch( eSwitch ){ case AR_CMD_CREATE: case AR_CMD_EXTRACT: case AR_CMD_LIST: case AR_CMD_UPDATE: + case AR_CMD_INSERT: case AR_CMD_HELP: if( pAr->eCmd ){ return arErrorMsg(pAr, "multiple command options"); } pAr->eCmd = eSwitch; @@ -5440,10 +5455,11 @@ u8 eSwitch; u8 bArg; } aSwitch[] = { { "create", 'c', AR_CMD_CREATE, 0 }, { "extract", 'x', AR_CMD_EXTRACT, 0 }, + { "insert", 'i', AR_CMD_INSERT, 0 }, { "list", 't', AR_CMD_LIST, 0 }, { "update", 'u', AR_CMD_UPDATE, 0 }, { "help", 'h', AR_CMD_HELP, 0 }, { "verbose", 'v', AR_SWITCH_VERBOSE, 0 }, { "file", 'f', AR_SWITCH_FILE, 1 }, @@ -5775,23 +5791,31 @@ return rc; } /* -** Implementation of .ar "create" and "update" commands. +** Implementation of .ar "create", "insert", and "update" commands. +** +** create -> Create a new SQL archive +** insert -> Insert or reinsert all files listed +** update -> Insert files that have changed or that were not +** previously in the archive ** ** Create the "sqlar" table in the database if it does not already exist. ** Then add each file in the azFile[] array to the archive. Directories ** are added recursively. If argument bVerbose is non-zero, a message is ** printed on stdout for each file archived. ** ** The create command is the same as update, except that it drops -** any existing "sqlar" table before beginning. +** any existing "sqlar" table before beginning. The "insert" command +** always overwrites every file named on the command-line, where as +** "update" only overwrites if the size or mtime or mode has changed. */ static int arCreateOrUpdateCommand( ArCommand *pAr, /* Command arguments and options */ - int bUpdate /* true for a --create. false for --update */ + int bUpdate, /* true for a --create. */ + int bOnlyIfChanged /* Only update if file has changed */ ){ const char *zCreate = "CREATE TABLE IF NOT EXISTS sqlar(\n" " name TEXT PRIMARY KEY, -- name of the file\n" " mode INT, -- access permissions\n" @@ -5809,26 +5833,28 @@ " CASE substr(lsmode(mode),1,1)\n" " WHEN '-' THEN length(data)\n" " WHEN 'd' THEN 0\n" " ELSE -1 END,\n" " sqlar_compress(data)\n" - " FROM fsdir(%Q,%Q)\n" - " WHERE lsmode(mode) NOT LIKE '?%%';", + " FROM fsdir(%Q,%Q) AS disk\n" + " WHERE lsmode(mode) NOT LIKE '?%%'%s;" + , "REPLACE INTO %s(name,mode,mtime,data)\n" " SELECT\n" " %s,\n" " mode,\n" " mtime,\n" " data\n" - " FROM fsdir(%Q,%Q)\n" - " WHERE lsmode(mode) NOT LIKE '?%%';" + " FROM fsdir(%Q,%Q) AS disk\n" + " WHERE lsmode(mode) NOT LIKE '?%%'%s;" }; int i; /* For iterating through azFile[] */ int rc; /* Return code */ const char *zTab = 0; /* SQL table into which to insert */ char *zSql; char zTemp[50]; + char *zExists = 0; arExecSql(pAr, "PRAGMA page_size=512"); rc = arExecSql(pAr, "SAVEPOINT ar;"); if( rc!=SQLITE_OK ) return rc; zTemp[0] = 0; @@ -5855,14 +5881,25 @@ rc = arExecSql(pAr, zDrop); if( rc!=SQLITE_OK ) goto end_ar_transaction; } rc = arExecSql(pAr, zCreate); } + if( bOnlyIfChanged ){ + zExists = sqlite3_mprintf( + " AND NOT EXISTS(" + "SELECT 1 FROM %s AS mem" + " WHERE mem.name=disk.name" + " AND mem.mtime=disk.mtime" + " AND mem.mode=disk.mode)", zTab); + }else{ + zExists = sqlite3_mprintf(""); + } + if( zExists==0 ) rc = SQLITE_NOMEM; for(i=0; inArg && rc==SQLITE_OK; i++){ char *zSql2 = sqlite3_mprintf(zInsertFmt[pAr->bZip], zTab, pAr->bVerbose ? "shell_putsnl(name)" : "name", - pAr->azArg[i], pAr->zDir); + pAr->azArg[i], pAr->zDir, zExists); rc = arExecSql(pAr, zSql2); sqlite3_free(zSql2); } end_ar_transaction: if( rc!=SQLITE_OK ){ @@ -5873,10 +5910,11 @@ zSql = sqlite3_mprintf("DROP TABLE %s", zTemp); arExecSql(pAr, zSql); sqlite3_free(zSql); } } + sqlite3_free(zExists); return rc; } /* ** Implementation of ".ar" dot command. @@ -5911,11 +5949,12 @@ } cmd.bZip = 1; }else if( cmd.zFile ){ int flags; if( cmd.bAppend ) eDbType = SHELL_OPEN_APPENDVFS; - if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_UPDATE ){ + if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_INSERT + || cmd.eCmd==AR_CMD_UPDATE ){ flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; }else{ flags = SQLITE_OPEN_READONLY; } cmd.db = 0; @@ -5948,11 +5987,11 @@ cmd.zSrcTable = sqlite3_mprintf("sqlar"); } switch( cmd.eCmd ){ case AR_CMD_CREATE: - rc = arCreateOrUpdateCommand(&cmd, 0); + rc = arCreateOrUpdateCommand(&cmd, 0, 0); break; case AR_CMD_EXTRACT: rc = arExtractCommand(&cmd); break; @@ -5963,13 +6002,17 @@ case AR_CMD_HELP: arUsage(pState->out); break; + case AR_CMD_INSERT: + rc = arCreateOrUpdateCommand(&cmd, 1, 0); + break; + default: assert( cmd.eCmd==AR_CMD_UPDATE ); - rc = arCreateOrUpdateCommand(&cmd, 1); + rc = arCreateOrUpdateCommand(&cmd, 1, 1); break; } } end_ar_command: if( cmd.db!=pState->db ){ @@ -7098,12 +7141,16 @@ /* .parameter clear ** Clear all bind parameters by dropping the TEMP table that holds them. */ if( nArg==2 && strcmp(azArg[1],"clear")==0 ){ - sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp.[" BIND_PARAM_TABLE "];", + int wrSchema = 0; + sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, -1, &wrSchema); + sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, 1, 0); + sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp.sqlite_parameters;", 0, 0, 0); + sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, wrSchema, 0); }else /* .parameter list ** List all bind parameters. */ @@ -7111,21 +7158,21 @@ sqlite3_stmt *pStmt = 0; int rx; int len = 0; rx = sqlite3_prepare_v2(p->db, "SELECT max(length(key)) " - "FROM temp.[" BIND_PARAM_TABLE "];", -1, &pStmt, 0); + "FROM temp.sqlite_parameters;", -1, &pStmt, 0); if( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ len = sqlite3_column_int(pStmt, 0); if( len>40 ) len = 40; } sqlite3_finalize(pStmt); pStmt = 0; if( len ){ rx = sqlite3_prepare_v2(p->db, "SELECT key, quote(value) " - "FROM temp.[" BIND_PARAM_TABLE "];", -1, &pStmt, 0); + "FROM temp.sqlite_parameters;", -1, &pStmt, 0); while( sqlite3_step(pStmt)==SQLITE_ROW ){ utf8_printf(p->out, "%-*s %s\n", len, sqlite3_column_text(pStmt,0), sqlite3_column_text(pStmt,1)); } sqlite3_finalize(pStmt); @@ -7152,21 +7199,21 @@ sqlite3_stmt *pStmt; const char *zKey = azArg[2]; const char *zValue = azArg[3]; bind_table_init(p); zSql = sqlite3_mprintf( - "REPLACE INTO temp.[" BIND_PARAM_TABLE "](key,value)" + "REPLACE INTO temp.sqlite_parameters(key,value)" "VALUES(%Q,%s);", zKey, zValue); if( zSql==0 ) shell_out_of_memory(); pStmt = 0; rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); if( rx!=SQLITE_OK ){ sqlite3_finalize(pStmt); pStmt = 0; zSql = sqlite3_mprintf( - "REPLACE INTO temp.[" BIND_PARAM_TABLE "](key,value)" + "REPLACE INTO temp.sqlite_parameters(key,value)" "VALUES(%Q,%Q);", zKey, zValue); if( zSql==0 ) shell_out_of_memory(); rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); if( rx!=SQLITE_OK ){ @@ -7184,11 +7231,11 @@ ** Remove the NAME binding from the parameter binding table, if it ** exists. */ if( nArg==3 && strcmp(azArg[1],"unset")==0 ){ char *zSql = sqlite3_mprintf( - "DELETE FROM temp.[" BIND_PARAM_TABLE "] WHERE key=%Q", azArg[2]); + "DELETE FROM temp.sqlite_parameters WHERE key=%Q", azArg[2]); if( zSql==0 ) shell_out_of_memory(); sqlite3_exec(p->db, zSql, 0, 0, 0); sqlite3_free(zSql); }else /* If no command name matches, show a syntax error */ Index: src/sqlite.h.in ================================================================== --- src/sqlite.h.in +++ src/sqlite.h.in @@ -2197,10 +2197,21 @@ **
  • The [PRAGMA writable_schema=ON] statement. **
  • Writes to the [sqlite_dbpage] virtual table. **
  • Direct writes to [shadow tables]. ** ** +** +** [[SQLITE_DBCONFIG_WRITABLE_SCHEMA]]
    SQLITE_DBCONFIG_WRITABLE_SCHEMA
    +**
    The SQLITE_DBCONFIG_WRITABLE_SCHEMA option activates or deactivates the +** "writable_schema" flag. This has the same effect and is logically equivalent +** to setting [PRAGMA writable_schema=ON] or [PRAGMA writable_schema=OFF]. +** The first argument to this setting is an integer which is 0 to disable +** the writable_schema, positive to enable writable_schema, or negative to +** leave the setting unchanged. The second parameter is a pointer to an +** integer into which is written 0 or 1 to indicate whether the writable_schema +** is enabled or disabled following this call. +**
    ** */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ #define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ #define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */ @@ -2210,11 +2221,12 @@ #define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */ #define SQLITE_DBCONFIG_TRIGGER_EQP 1008 /* int int* */ #define SQLITE_DBCONFIG_RESET_DATABASE 1009 /* int int* */ #define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */ -#define SQLITE_DBCONFIG_MAX 1010 /* Largest DBCONFIG */ +#define SQLITE_DBCONFIG_WRITABLE_SCHEMA 1011 /* int int* */ +#define SQLITE_DBCONFIG_MAX 1011 /* Largest DBCONFIG */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes ** METHOD: sqlite3 ** @@ -4043,11 +4055,13 @@ ** 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 bind API fails. +** 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 @@ -5801,11 +5815,11 @@ ** ** ^The sqlite3_db_filename(D,N) interface returns a pointer to a filename ** associated with database N of connection D. ^The main database file ** has the name "main". If there is no attached database N on the database ** connection D, or if database N is a temporary or in-memory database, then -** a NULL pointer is returned. +** this function will return either a NULL pointer or an empty string. ** ** ^The filename returned by this function is the output of the ** xFullPathname method of the [VFS]. ^In other words, the filename ** will be an absolute pathname, even if the filename used ** to open the database originally was a URI or relative pathname. Index: src/test_fs.c ================================================================== --- src/test_fs.c +++ src/test_fs.c @@ -235,18 +235,14 @@ static int fsdirNext(sqlite3_vtab_cursor *cur){ FsdirCsr *pCsr = (FsdirCsr*)cur; if( pCsr->pDir ){ struct DIRENT *pRes = 0; -#if defined(__MINGW_H) pRes = readdir(pCsr->pDir); if( pRes!=0 ){ memcpy(&pCsr->entry, pRes, sizeof(struct DIRENT)); } -#else - readdir_r(pCsr->pDir, &pCsr->entry, &pRes); -#endif if( pRes==0 ){ closedir(pCsr->pDir); pCsr->pDir = 0; } pCsr->iRowid++; Index: src/vacuum.c ================================================================== --- src/vacuum.c +++ src/vacuum.c @@ -141,19 +141,20 @@ */ int sqlite3RunVacuum( char **pzErrMsg, /* Write error message here */ sqlite3 *db, /* Database connection */ int iDb, /* Which attached DB to vacuum */ - sqlite3_value *pOut /* Write results here, if not NULL */ + sqlite3_value *pOut /* Write results here, if not NULL. VACUUM INTO */ ){ int rc = SQLITE_OK; /* Return code from service routines */ Btree *pMain; /* The database being vacuumed */ Btree *pTemp; /* The temporary database we vacuum into */ u32 saved_mDbFlags; /* Saved value of db->mDbFlags */ u64 saved_flags; /* Saved value of db->flags */ int saved_nChange; /* Saved value of db->nChange */ int saved_nTotalChange; /* Saved value of db->nTotalChange */ + u32 saved_openFlags; /* Saved value of db->openFlags */ u8 saved_mTrace; /* Saved trace settings */ Db *pDb = 0; /* Database to detach at end of vacuum */ int isMemDb; /* True if vacuuming a :memory: database */ int nRes; /* Bytes of reserved space at the end of each page */ int nDb; /* Number of attached databases */ @@ -166,16 +167,19 @@ } if( db->nVdbeActive>1 ){ sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress"); return SQLITE_ERROR; } + saved_openFlags = db->openFlags; if( pOut ){ if( sqlite3_value_type(pOut)!=SQLITE_TEXT ){ sqlite3SetString(pzErrMsg, db, "non-text filename"); return SQLITE_ERROR; } zOut = (const char*)sqlite3_value_text(pOut); + db->openFlags &= ~SQLITE_OPEN_READONLY; + db->openFlags |= SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE; }else{ zOut = ""; } /* Save the current value of the database flags so that it can be @@ -210,10 +214,11 @@ ** time to parse and run the PRAGMA to turn journalling off than it does ** to write the journal header file. */ nDb = db->nDb; rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut); + db->openFlags = saved_openFlags; if( rc!=SQLITE_OK ) goto end_of_vacuum; assert( (db->nDb-1)==nDb ); pDb = &db->aDb[nDb]; assert( strcmp(pDb->zDbSName,"vacuum_db")==0 ); pTemp = pDb->pBt; Index: src/vdbeaux.c ================================================================== --- src/vdbeaux.c +++ src/vdbeaux.c @@ -635,10 +635,11 @@ while( (pOp = opIterNext(&sIter))!=0 ){ int opcode = pOp->opcode; if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename || opcode==OP_VDestroy + || (opcode==OP_Function0 && pOp->p4.pFunc->funcFlags&SQLITE_FUNC_INTERNAL) || ((opcode==OP_Halt || opcode==OP_HaltIfNull) && ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort)) ){ hasAbort = 1; break; Index: src/wherecode.c ================================================================== --- src/wherecode.c +++ src/wherecode.c @@ -1158,11 +1158,11 @@ sqlite3WalkExprList(&w, pWInfo->pResultSet); } } /* -** The pTruth expression is always tree because it is the WHERE clause +** The pTruth expression is always true because it is the WHERE clause ** a partial index that is driving a query loop. Look through all of the ** WHERE clause terms on the query, and if any of those terms must be ** true because pTruth is true, then mark those WHERE clause terms as ** coded. */ Index: src/whereexpr.c ================================================================== --- src/whereexpr.c +++ src/whereexpr.c @@ -1518,10 +1518,16 @@ if( ExprHasProperty(p, EP_VarSelect) ) pMaskSet->bVarSelect = 1; mask |= exprSelectUsage(pMaskSet, p->x.pSelect); }else if( p->x.pList ){ mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList); } +#ifndef SQLITE_OMIT_WINDOWFUNC + if( p->op==TK_FUNCTION && p->y.pWin ){ + mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pPartition); + mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pOrderBy); + } +#endif return mask; } Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){ return p ? sqlite3WhereExprUsageNN(pMaskSet,p) : 0; } Index: test/altertab3.test ================================================================== --- test/altertab3.test +++ test/altertab3.test @@ -79,10 +79,67 @@ do_execsql_test 3.2 { SELECT sql FROM sqlite_master WHERE name = 'v1' } {{CREATE VIEW v1 AS SELECT * FROM t1 WHERE a=1 OR (bbb IN ())}} +#------------------------------------------------------------------------- +reset_db +do_execsql_test 4.0 { + CREATE TABLE t1(a, b); + CREATE TABLE t3(e, f); + CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN + INSERT INTO t2 VALUES(new.a, new.b); + END; +} + +do_catchsql_test 4.1.2 { + BEGIN; + ALTER TABLE t3 RENAME TO t4; +} {1 {error in trigger tr1: no such table: main.t2}} +do_execsql_test 4.1.2 { + COMMIT; +} +do_execsql_test 4.1.3 { + SELECT * FROM sqlite_master WHERE type='table' AND name!='t1'; +} {table t3 t3 3 {CREATE TABLE t3(e, f)}} + + +do_catchsql_test 4.2.1 { + BEGIN; + ALTER TABLE t3 RENAME e TO eee; +} {1 {error in trigger tr1: no such table: main.t2}} +do_execsql_test 4.2.2 { + COMMIT; +} +do_execsql_test 4.2.3 { + SELECT * FROM sqlite_master WHERE type='table' AND name!='t1'; +} {table t3 t3 3 {CREATE TABLE t3(e, f)}} + +#------------------------------------------------------------------------- +reset_db +do_execsql_test 5.0 { + CREATE TABLE t1 ( + c1 integer, c2, PRIMARY KEY(c1 collate rtrim), + UNIQUE(c2) + ) +} +do_execsql_test 5.1 { + ALTER TABLE t1 RENAME c1 TO c3; +} + +#------------------------------------------------------------------------- +reset_db +do_execsql_test 6.0 { + CREATE TEMPORARY TABLE Table0 ( + Col0 INTEGER, + PRIMARY KEY(Col0 COLLATE RTRIM), + FOREIGN KEY (Col0) REFERENCES Table0 + ); +} +do_execsql_test 6.1 { + ALTER TABLE Table0 RENAME Col0 TO Col0; +} finish_test Index: test/corruptL.test ================================================================== --- test/corruptL.test +++ test/corruptL.test @@ -121,19 +121,24 @@ }]} {} do_catchsql_test 1.1 { PRAGMA cell_size_check = off; DROP INDEX t1x1; -} {1 {no such index: t1x1}} +} {1 {database disk image is malformed}} do_catchsql_test 1.2 { SELECT sum(s+length(b)) FROM t1 WHERE a IN (110,10,150) AND q IS NULL; -} {1 {no such table: t1}} +} {1 {database disk image is malformed}} do_catchsql_test 1.3 { REINDEX t1; -} {1 {unable to identify the object to be reindexed}} +} {1 {database disk image is malformed}} + +do_catchsql_test 1.4 { + PRAGMA integrity_check +} {1 {database disk image is malformed}} + #------------------------------------------------------------------------- reset_db do_test 2.0 { sqlite3 db {} @@ -719,7 +724,118 @@ }]} {} do_catchsql_test 7.1 { SELECT * FROM sqlite_master; } {1 {malformed database schema (t1x1) - invalid rootpage}} + +#------------------------------------------------------------------------- +reset_db +do_test 8.0 { + sqlite3 db {} + db deserialize [decode_hexdb { +| size 2048 pagesize 512 filename a.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: 02 00 01 01 00 40 20 20 ff ff 00 0c 00 00 00 07 .....@ ........ +| 32: 0b 00 00 00 00 00 00 00 00 00 00 08 9c 00 00 04 ................ +| 48: 00 00 00 e0 09 00 00 01 00 00 00 01 00 00 00 00 ................ +| 64: 00 00 00 00 f2 ff 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 0c ................ +| 96: 00 2e 2c 50 0d 00 00 00 06 01 06 00 01 da 01 b0 ..,P............ +| 112: 05 56 01 86 01 2a 01 06 00 00 00 00 00 06 00 00 .V...*.......... +| 128: 00 ff 00 00 ff ff ff e1 00 00 00 00 00 00 00 00 ................ +| 144: 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 ................ +| 160: 00 00 00 00 00 00 00 00 f2 00 00 00 00 00 00 00 ................ +| 176: 00 00 f9 ff ff ff ff ff ff ff 00 00 00 5f 00 fb ............._.. +| 192: 00 00 00 00 00 00 00 00 00 e1 ff 00 00 00 00 00 ................ +| 208: 00 00 10 00 00 00 00 00 1e 00 00 00 fe 00 00 00 ................ +| 224: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ca 00 ................ +| 240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 35 ...............5 +| 256: 00 00 00 00 ef ff 22 07 06 17 11 11 01 30 39 38 .............098 +| 272: 62 6c 65 74 38 38 74 04 43 52 45 41 54 45 20 54 blet88t.CREATE T +| 288: 41 42 4c 45 20 74 34 28 87 29 2a 06 06 17 13 11 ABLE t4(.)*..... +| 304: 01 3f 69 4f 64 65 78 74 33 78 74 40 05 43 52 45 .?iOdext3xt@.CRE +| 320: 41 54 45 20 49 6e 44 45 58 20 74 33 78 20 4f 4e ATE InDEX t3x ON +| 336: 20 74 33 28 78 29 2e 04 06 17 15 11 01 45 69 6e t3(x).......Ein +| 352: 00 04 00 00 34 63 64 74 3d 05 43 52 45 41 54 45 ....4cdt=.CREATE +| 368: 20 49 4e 44 45 58 20 63 74 64 32 20 4f 4e 20 74 INDEX ctd2 ON t +| 384: 32 28 0a 0c 44 29 28 05 06 17 11 11 01 3d 74 6c 2(..D)(......=tl +| 400: 62 61 d4 65 33 74 33 04 43 52 45 41 54 45 20 54 ba.e3t3.CREATE T +| 416: 41 42 4c 45 20 74 33 28 63 2c 78 2c 65 2c 66 29 ABLE t3(c,x,e,f) +| 432: 28 02 06 17 11 11 01 3d 74 61 62 6c 65 74 32 74 (......=tablet2t +| 448: 32 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 2.CREATE TABLE t +| 464: 32 28 63 2c 64 2c 65 2c 66 29 24 01 06 17 11 11 2(c,d,e,f)$..... +| 480: 01 35 74 60 62 6c 65 74 31 74 31 02 43 52 45 41 .5t`blet1t1.CREA +| 496: 54 45 20 54 41 42 4c 45 20 74 30 28 61 2c 62 29 TE TABLE t0(a,b) +| page 2 offset 512 +| 0: 0d 00 ff 11 04 01 cf 80 01 fa 01 09 00 de 01 cf ................ +| 16: 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 ................ +| 32: 00 00 08 00 00 00 00 00 00 11 00 00 00 00 00 13 ................ +| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 e0 ff ff ................ +| 64: ff d2 ff ff ff 00 f8 ff ff ff 00 00 00 00 00 00 ................ +| 80: 00 ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +| 96: 00 00 00 00 ff de 00 00 00 00 00 00 00 00 00 00 ................ +| 112: 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 .............@.. +| 128: 2a 00 00 00 00 00 00 00 00 f7 00 00 00 00 00 00 *............... +| 144: 00 00 00 00 00 21 00 00 00 00 00 00 00 00 00 00 .....!.......... +| 160: 01 64 00 00 00 00 04 80 ff ff ff 00 00 00 00 00 .d.............. +| 176: 00 00 00 00 00 00 00 00 1f 00 00 00 00 00 00 00 ................ +| 192: 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 ..@............. +| 208: b5 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 .......@........ +| 224: 00 00 00 f6 00 ee ff ff ff 00 00 00 00 00 00 00 ................ +| 272: f2 00 00 00 00 00 00 00 00 00 f9 ff ff ff ff ff ................ +| 288: ff ff 00 00 00 5f 00 fb 00 00 00 00 00 00 00 00 ....._.......... +| 320: 1e 00 00 00 fe 00 00 00 00 00 00 00 00 00 00 00 ................ +| 336: 00 00 00 00 00 00 ca 00 00 00 00 00 00 00 ff ec ................ +| 352: 00 00 00 00 00 00 00 32 00 00 00 00 ef ff 22 07 .......2........ +| 368: 06 17 11 11 01 30 74 61 62 6c 65 74 38 38 74 04 .....0tablet88t. +| 384: 43 52 45 41 54 45 20 54 41 42 4c 45 20 8c cb d7 CREATE TABLE ... +| 400: 78 d6 d5 f9 f9 17 13 11 01 3f 69 4f 64 65 78 74 x........?iOdext +| 416: 33 78 74 33 05 43 52 45 41 54 45 26 49 6e 44 45 3xt3.CREATE&InDE +| 432: 58 20 74 33 78 00 00 00 00 00 00 00 00 00 00 00 X t3x........... +| 464: 00 00 00 00 00 13 76 65 6e 65 69 67 68 74 13 03 ......veneight.. +| 480: 03 40 07 07 15 00 54 45 20 49 4e 44 45 58 20 74 .@....TE INDEX t +| 496: 31 63 64 20 4f 4e 20 74 ce d7 f5 f0 44 09 01 02 1cd ON t....D... +| page 3 offset 1024 +| 0: 0d 00 00 00 48 01 54 00 01 f6 e2 ec 01 c5 01 aa ....H.T......... +| 16: 30 34 28 87 29 32 06 f5 16 13 11 01 8e 61 24 64 04(.)2.......a$d +| 32: 65 78 74 37 78 1f 33 6d 6d 6d 6d 6d 00 00 04 06 ext7x.3mmmmm.... +| 48: 6d 41 6d 6d 6e 6d 6d 00 00 02 00 6d 6d 6d 6d 6d mAmmnmm....mmmmm +| 64: 15 11 01 45 45 45 45 45 45 45 45 45 45 45 45 45 ...EEEEEEEEEEEEE +| 80: 45 45 45 45 45 45 45 45 45 45 45 00 45 63 74 64 EEEEEEEEEEE.Ectd +| 96: 34 20 4f 4e 20 61 62 6c 5d 74 38 38 74 04 43 52 4 ON abl]t88t.CR +| 112: 45 41 54 45 20 54 41 42 4c 45 20 74 34 28 87 29 EATE TABLE t4(.) +| 128: 2a 06 06 13 13 01 00 00 00 4f 64 6e 78 74 33 44 *........Odnxt3D +| 144: 74 13 05 43 52 45 41 54 45 20 49 6e 44 45 00 00 t..CREATE InDE.. +| 160: 00 00 00 00 00 00 00 f9 ff ff ff ff ff ff ff 00 ................ +| 176: 00 00 5f 00 fb 00 00 2d 00 00 00 00 00 00 00 00 .._....-........ +| 192: 00 00 00 00 00 00 00 00 00 00 00 00 00 1e 00 00 ................ +| 208: 00 fe 00 00 00 00 17 15 11 01 45 69 6e 64 65 2e ..........Einde. +| 224: 5b 38 63 64 74 3d 05 43 52 45 41 54 45 20 49 4e [8cdt=.CREATE IN +| 240: 44 45 58 20 63 20 64 32 20 4f 4e 20 74 32 28 0a DEX c d2 ON t2(. +| 256: 0c 44 32 05 00 10 00 00 11 11 3d 74 6c 62 61 d4 .D2.......=tlba. +| 272: 65 33 74 33 04 43 52 45 41 54 45 20 54 41 42 4c e3t3.CREATE TABL +| 288: 45 20 74 36 ff ff 7f ff 43 52 45 41 54 45 20 49 E t6....CREATE I +| 304: 73 71 6c 69 74 65 5f 73 65 71 75 65 6e 63 65 28 sqlite_sequence( +| 320: 0a 0c 44 29 28 05 06 17 11 11 01 3d 74 6c 62 61 ..D)(......=tlba +| 336: 20 00 00 00 33 04 43 52 45 41 54 45 20 54 41 42 ...3.CREATE TAB +| 352: 4c 45 20 74 33 28 63 2c 78 2c 65 2c 66 29 28 02 LE t3(c,x,e,f)(. +| 368: 06 00 00 7f ff 40 41 54 45 20 49 6e 44 45 58 20 .....@ATE InDEX +| 384: 74 33 78 20 4f 4e 20 74 31 28 78 29 2e 04 06 17 t3x ON t1(x).... +| 400: 15 11 01 45 69 6e 64 65 2e 74 34 63 64 74 3d 05 ...Einde.t4cdt=. +| 416: 00 00 00 00 00 00 00 00 00 00 00 4d 00 00 00 00 ...........M.... +| 432: 01 00 00 00 00 00 00 05 00 00 10 00 00 00 00 00 ................ +| 448: 00 01 00 00 00 00 01 00 00 00 00 07 40 14 00 00 ............@... +| 464: 00 00 21 00 40 18 00 00 00 00 00 00 40 1c 00 00 ..!.@.......@... +| 480: 00 00 ff ff ff 00 00 00 5f 00 fb 00 00 2d 00 00 ........_....-.. +| 496: 00 00 00 1e 00 00 00 fe 00 00 64 00 00 ff fb 02 ..........d..... +| page 4 offset 1536 +| 0: 0d 00 39 00 00 02 00 00 00 00 00 00 00 00 00 00 ..9............. +| end a.db +}]} {} + + +do_catchsql_test 8.1 { + INSERT INTO t3 SELECT * FROM t2; +} {1 {database disk image is malformed}} finish_test Index: test/dbfuzz2.c ================================================================== --- test/dbfuzz2.c +++ test/dbfuzz2.c @@ -72,10 +72,14 @@ static int bVdbeDebug = 0; /* Maximum size of the in-memory database file */ static sqlite3_int64 szMax = 104857600; +/* Progress handler callback data */ +static int nCb = 0; /* Number of callbacks seen so far */ +static int mxCb = 250000; /* Maximum allowed callbacks */ + /***** Copy/paste from ext/misc/memtrace.c ***************************/ /* The original memory allocation routines */ static sqlite3_mem_methods memtraceBase; static FILE *memtraceOut; @@ -154,10 +158,25 @@ } memtraceOut = 0; return rc; } /***** End copy/paste from ext/misc/memtrace.c ***************************/ + +/* +** Progress handler callback +** +** Count the number of callbacks and cause an abort once the limit is +** reached. +*/ +static int progress_handler(void *pNotUsed){ + nCb++; + if( nCb=1 ){ + printf("-- Progress limit of %d reached\n", mxCb); + } + return 1; +} /* libFuzzer invokes this routine with fuzzed database files (in aData). ** This routine run SQLite against the malformed database to see if it ** can provoke a failure or malfunction. */ @@ -187,16 +206,20 @@ sqlite3_file_control(db, "main", SQLITE_FCNTL_SIZE_LIMIT, &x); #endif if( bVdbeDebug ){ sqlite3_exec(db, "PRAGMA vdbe_debug=ON", 0, 0, 0); } + if( mxCb>0 ){ + sqlite3_progress_handler(db, 10, progress_handler, 0); + } for(i=0; i=1 ){ printf("%s\n", azSql[i]); fflush(stdout); } zErr = 0; + nCb = 0; rc = sqlite3_exec(db, azSql[i], 0, 0, &zErr); if( rc && eVerbosity>=1 ){ printf("-- rc=%d zErr=%s\n", rc, zErr); } sqlite3_free(zErr); @@ -246,10 +269,18 @@ continue; } if( strcmp(z,"vdbe-debug")==0 ){ bVdbeDebug = 1; continue; + } + if( strcmp(z,"limit")==0 ){ + if( i+1==argc ){ + fprintf(stderr, "missing argument to %s\n", argv[i]); + exit(1); + } + mxCb = strtol(argv[++i], 0, 0); + continue; } if( strcmp(z,"memtrace")==0 ){ sqlite3MemTraceActivate(stdout); continue; } Index: test/fuzzcheck.c ================================================================== --- test/fuzzcheck.c +++ test/fuzzcheck.c @@ -529,11 +529,11 @@ a = sqlite3_malloc64( nAlloc ); if( a==0 ){ fprintf(stderr, "Out of memory!\n"); exit(1); } - memset(a, 0, nAlloc); + memset(a, 0, (size_t)nAlloc); for(i=k=0; i nAlloc ); - memset(a+nAlloc, 0, newSize - nAlloc); + memset(a+nAlloc, 0, (size_t)(newSize - nAlloc)); nAlloc = newSize; } if( j>=(unsigned)mx ){ mx = (j + 4095)&~4095; if( mx>MX_FILE_SZ ) mx = MX_FILE_SZ; Index: test/fuzzdata7.db ================================================================== --- test/fuzzdata7.db +++ test/fuzzdata7.db cannot compute difference between binary files Index: test/fuzzdata8.db ================================================================== --- test/fuzzdata8.db +++ test/fuzzdata8.db cannot compute difference between binary files Index: test/memdb1.test ================================================================== --- test/memdb1.test +++ test/memdb1.test @@ -182,7 +182,23 @@ } {1 {unknown option: a}} do_test 620 { set rc [catch {db serialize a b} msg] lappend rc $msg } {1 {wrong # args: should be "db serialize ?DATABASE?"}} + +#------------------------------------------------------------------------- +reset_db +do_execsql_test 700 { + CREATE TABLE t1(a, b); + PRAGMA schema_version = 0; +} +do_test 710 { + set ser [db serialize main] + db close + sqlite3 db + db deserialize main $ser + catchsql { + CREATE VIRTUAL TABLE t1 USING rtree(id, a, b, c, d); + } +} {1 {table t1 already exists}} finish_test Index: test/sessionfuzz.c ================================================================== --- test/sessionfuzz.c +++ test/sessionfuzz.c @@ -828,11 +828,10 @@ int eConflict, sqlite3_changeset_iter *p ){ (void)NotUsed; (void)p; - printf("Conflict %d\n", eConflict); return SQLITE_CHANGESET_OMIT; } /* ** Reset the database file Index: test/vacuum-into.test ================================================================== --- test/vacuum-into.test +++ test/vacuum-into.test @@ -84,7 +84,20 @@ } 1 do_catchsql_test vacuum-into-420 { VACUUM INTO target2() } {1 {no such function: target2}} +# The ability to VACUUM INTO a read-only database +db close +sqlite3 db test.db -readonly 1 +forcedelete test.db2 +do_execsql_test vacuum-into-500 { + VACUUM INTO 'test.db2'; +} +sqlite3 db2 test.db2 +do_test vacuum-into-510 { + db2 eval {SELECT name FROM sqlite_master ORDER BY 1} +} {t1 t1b t2} +db2 close +db close finish_test Index: test/window1.test ================================================================== --- test/window1.test +++ test/window1.test @@ -717,8 +717,35 @@ do_execsql_test 17.3 { SELECT 10+sum(a) OVER (ORDER BY a) FROM t8 ORDER BY 10+sum(a) OVER (ORDER BY a) DESC; } {16 13 11} + +#------------------------------------------------------------------------- +# +reset_db +do_execsql_test 18.0 { + CREATE TABLE t1 ( t1_id INTEGER PRIMARY KEY ); + CREATE TABLE t2 ( t2_id INTEGER PRIMARY KEY ); + CREATE TABLE t3 ( t3_id INTEGER PRIMARY KEY ); + + INSERT INTO t1 VALUES(1), (3), (5); + INSERT INTO t2 VALUES (3), (5); + INSERT INTO t3 VALUES(10), (11), (12); +} + +do_execsql_test 18.1 { + SELECT t1.* FROM t1, t2 WHERE + t1_id=t2_id AND t1_id IN ( + SELECT t1_id + row_number() OVER ( ORDER BY t1_id ) FROM t3 + ) +} + +do_execsql_test 18.2 { + SELECT t1.* FROM t1, t2 WHERE + t1_id=t2_id AND t1_id IN ( + SELECT row_number() OVER ( ORDER BY t1_id ) FROM t3 + ) +} {3} finish_test Index: tool/cg_anno.tcl ================================================================== --- tool/cg_anno.tcl +++ tool/cg_anno.tcl @@ -1,6 +1,8 @@ -#!/usr/bin/tclsh +#!/bin/sh +# \ +exec tclsh "$0" ${1+"$@"} # # A wrapper around cg_annotate that sets appropriate command-line options # and rearranges the output so that annotated files occur in a consistent # sorted order. Used by the speed-check.tcl script. #