diff --git a/configure b/configure index 84422d3343..8805614438 100755 --- a/configure +++ b/configure @@ -11252,7 +11252,7 @@ else fi if test "${use_debug}" = "yes" ; then - TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE" + TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0" else TARGET_DEBUG="-DNDEBUG" fi @@ -11356,7 +11356,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support MEMSYS5" >&5 $as_echo_n "checking whether to support MEMSYS5... " >&6; } if test "${enable_memsys5}" = "yes"; then - OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_MEMSYS5" + OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MEMSYS5" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else @@ -11373,7 +11373,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support MEMSYS3" >&5 $as_echo_n "checking whether to support MEMSYS3... " >&6; } if test "${enable_memsys3}" = "yes" -a "${enable_memsys5}" = "no"; then - OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_MEMSYS3" + OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MEMSYS3" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else @@ -11391,7 +11391,7 @@ else fi if test "${enable_fts3}" = "yes" ; then - OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS3" + OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3" fi # Check whether --enable-fts4 was given. if test "${enable_fts4+set}" = set; then : @@ -11401,7 +11401,7 @@ else fi if test "${enable_fts4}" = "yes" ; then - OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS4" + OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS4" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5 $as_echo_n "checking for library containing log... " >&6; } if ${ac_cv_search_log+:} false; then : @@ -11467,7 +11467,7 @@ else fi if test "${enable_fts5}" = "yes" ; then - OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS5" + OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS5" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5 $as_echo_n "checking for library containing log... " >&6; } if ${ac_cv_search_log+:} false; then : @@ -11536,7 +11536,7 @@ else fi if test "${enable_json1}" = "yes" ; then - OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_JSON1" + OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_JSON1" fi ######### @@ -11549,7 +11549,7 @@ else fi if test "${enable_rtree}" = "yes" ; then - OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_RTREE" + OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE" fi ######### @@ -11562,8 +11562,8 @@ else fi if test "${enable_session}" = "yes" ; then - OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_SESSION" - OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_PREUPDATE_HOOK" + OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION" + OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK" fi ######### diff --git a/configure.ac b/configure.ac index 095db6bf81..a0aeb94f72 100644 --- a/configure.ac +++ b/configure.ac @@ -560,7 +560,7 @@ AC_SEARCH_LIBS(fdatasync, [rt]) AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],[enable debugging & verbose explain]), [use_debug=$enableval],[use_debug=no]) if test "${use_debug}" = "yes" ; then - TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE" + TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0" else TARGET_DEBUG="-DNDEBUG" fi @@ -596,7 +596,7 @@ AC_ARG_ENABLE(memsys5, [enable_memsys5=yes],[enable_memsys5=no]) AC_MSG_CHECKING([whether to support MEMSYS5]) if test "${enable_memsys5}" = "yes"; then - OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_MEMSYS5" + OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MEMSYS5" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) @@ -606,7 +606,7 @@ AC_ARG_ENABLE(memsys3, [enable_memsys3=yes],[enable_memsys3=no]) AC_MSG_CHECKING([whether to support MEMSYS3]) if test "${enable_memsys3}" = "yes" -a "${enable_memsys5}" = "no"; then - OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_MEMSYS3" + OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MEMSYS3" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) @@ -618,20 +618,20 @@ AC_ARG_ENABLE(fts3, AC_HELP_STRING([--enable-fts3], [Enable the FTS3 extension]), [enable_fts3=yes],[enable_fts3=no]) if test "${enable_fts3}" = "yes" ; then - OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS3" + OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3" fi AC_ARG_ENABLE(fts4, AC_HELP_STRING([--enable-fts4], [Enable the FTS4 extension]), [enable_fts4=yes],[enable_fts4=no]) if test "${enable_fts4}" = "yes" ; then - OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS4" + OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS4" AC_SEARCH_LIBS([log],[m]) fi AC_ARG_ENABLE(fts5, AC_HELP_STRING([--enable-fts5], [Enable the FTS5 extension]), [enable_fts5=yes],[enable_fts5=no]) if test "${enable_fts5}" = "yes" ; then - OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_FTS5" + OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS5" AC_SEARCH_LIBS([log],[m]) fi @@ -641,7 +641,7 @@ AC_ARG_ENABLE(json1, AC_HELP_STRING([--enable-json1], [Enable the JSON1 extension]), [enable_json1=yes],[enable_json1=no]) if test "${enable_json1}" = "yes" ; then - OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_JSON1" + OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_JSON1" fi ######### @@ -650,7 +650,7 @@ AC_ARG_ENABLE(rtree, AC_HELP_STRING([--enable-rtree], [Enable the RTREE extension]), [enable_rtree=yes],[enable_rtree=no]) if test "${enable_rtree}" = "yes" ; then - OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_RTREE" + OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE" fi ######### @@ -659,8 +659,8 @@ AC_ARG_ENABLE(session, AC_HELP_STRING([--enable-session], [Enable the SESSION extension]), [enable_session=yes],[enable_session=no]) if test "${enable_session}" = "yes" ; then - OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_SESSION" - OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_PREUPDATE_HOOK" + OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION" + OPT_FEATURE_FLAGS="$(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK" fi ######### diff --git a/ext/fts5/fts5Int.h b/ext/fts5/fts5Int.h index d350856573..83e5238b48 100644 --- a/ext/fts5/fts5Int.h +++ b/ext/fts5/fts5Int.h @@ -446,9 +446,9 @@ int sqlite3Fts5IndexBeginWrite( /* ** Flush any data stored in the in-memory hash tables to the database. -** If the bCommit flag is true, also close any open blob handles. +** Also close any open blob handles. */ -int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit); +int sqlite3Fts5IndexSync(Fts5Index *p); /* ** Discard any data stored in the in-memory hash tables. Do not write it @@ -618,7 +618,7 @@ int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol); int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnAvg); int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow); -int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit); +int sqlite3Fts5StorageSync(Fts5Storage *p); int sqlite3Fts5StorageRollback(Fts5Storage *p); int sqlite3Fts5StorageConfigValue( diff --git a/ext/fts5/fts5_index.c b/ext/fts5/fts5_index.c index 750e0ca82d..27e28a84ab 100644 --- a/ext/fts5/fts5_index.c +++ b/ext/fts5/fts5_index.c @@ -628,7 +628,6 @@ static void fts5CloseReader(Fts5Index *p){ } } - /* ** Retrieve a record from the %_data table. ** @@ -5131,10 +5130,10 @@ int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){ /* ** Commit data to disk. */ -int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit){ +int sqlite3Fts5IndexSync(Fts5Index *p){ assert( p->rc==SQLITE_OK ); fts5IndexFlush(p); - if( bCommit ) fts5CloseReader(p); + fts5CloseReader(p); return fts5IndexReturn(p); } diff --git a/ext/fts5/fts5_main.c b/ext/fts5/fts5_main.c index 384d3dd8f7..d20cb7ea39 100644 --- a/ext/fts5/fts5_main.c +++ b/ext/fts5/fts5_main.c @@ -1579,7 +1579,7 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){ fts5CheckTransactionState(pTab, FTS5_SYNC, 0); pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg; fts5TripCursors(pTab); - rc = sqlite3Fts5StorageSync(pTab->pStorage, 1); + rc = sqlite3Fts5StorageSync(pTab->pStorage); pTab->pConfig->pzErrmsg = 0; return rc; } @@ -2390,7 +2390,7 @@ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint); fts5TripCursors(pTab); - return sqlite3Fts5StorageSync(pTab->pStorage, 0); + return sqlite3Fts5StorageSync(pTab->pStorage); } /* @@ -2403,7 +2403,7 @@ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint); fts5TripCursors(pTab); - return sqlite3Fts5StorageSync(pTab->pStorage, 0); + return sqlite3Fts5StorageSync(pTab->pStorage); } /* diff --git a/ext/fts5/fts5_storage.c b/ext/fts5/fts5_storage.c index c8c26bd1b6..ee099154cb 100644 --- a/ext/fts5/fts5_storage.c +++ b/ext/fts5/fts5_storage.c @@ -218,7 +218,7 @@ static void fts5StorageRenameOne( int sqlite3Fts5StorageRename(Fts5Storage *pStorage, const char *zName){ Fts5Config *pConfig = pStorage->pConfig; - int rc = sqlite3Fts5StorageSync(pStorage, 1); + int rc = sqlite3Fts5StorageSync(pStorage); fts5StorageRenameOne(pConfig, &rc, "data", zName); fts5StorageRenameOne(pConfig, &rc, "idx", zName); @@ -1081,15 +1081,15 @@ int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){ /* ** Flush any data currently held in-memory to disk. */ -int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit){ +int sqlite3Fts5StorageSync(Fts5Storage *p){ int rc = SQLITE_OK; i64 iLastRowid = sqlite3_last_insert_rowid(p->pConfig->db); if( p->bTotalsValid ){ rc = fts5StorageSaveTotals(p); - if( bCommit ) p->bTotalsValid = 0; + p->bTotalsValid = 0; } if( rc==SQLITE_OK ){ - rc = sqlite3Fts5IndexSync(p->pIndex, bCommit); + rc = sqlite3Fts5IndexSync(p->pIndex); } sqlite3_set_last_insert_rowid(p->pConfig->db, iLastRowid); return rc; diff --git a/ext/fts5/test/fts5aa.test b/ext/fts5/test/fts5aa.test index 428ca6c1ea..9a95d81cfb 100644 --- a/ext/fts5/test/fts5aa.test +++ b/ext/fts5/test/fts5aa.test @@ -561,6 +561,22 @@ do_test 20.1 { execsql { SELECT rowid FROM tmp WHERE tmp MATCH 'y' } } $::ids +#-------------------------------------------------------------------- +# Test that a DROP TABLE may be executed within a transaction that +# writes to an FTS5 table. +# +do_execsql_test 21.0 { + CREATE TEMP TABLE t8(a, b); + CREATE VIRTUAL TABLE ft USING fts5(x, detail=%DETAIL%); +} + +do_execsql_test 21.1 { + BEGIN; + INSERT INTO ft VALUES('a b c'); + DROP TABLE t8; + COMMIT; +} + } diff --git a/ext/misc/json1.c b/ext/misc/json1.c index bad5cd9b53..b12964ba4d 100644 --- a/ext/misc/json1.c +++ b/ext/misc/json1.c @@ -727,13 +727,14 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ int iThis; int x; JsonNode *pNode; - while( safe_isspace(pParse->zJson[i]) ){ i++; } - if( (c = pParse->zJson[i])=='{' ){ + const char *z = pParse->zJson; + while( safe_isspace(z[i]) ){ i++; } + if( (c = z[i])=='{' ){ /* Parse object */ iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); if( iThis<0 ) return -1; for(j=i+1;;j++){ - while( safe_isspace(pParse->zJson[j]) ){ j++; } + while( safe_isspace(z[j]) ){ j++; } x = jsonParseValue(pParse, j); if( x<0 ){ if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1; @@ -744,14 +745,14 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ if( pNode->eType!=JSON_STRING ) return -1; pNode->jnFlags |= JNODE_LABEL; j = x; - while( safe_isspace(pParse->zJson[j]) ){ j++; } - if( pParse->zJson[j]!=':' ) return -1; + while( safe_isspace(z[j]) ){ j++; } + if( z[j]!=':' ) return -1; j++; x = jsonParseValue(pParse, j); if( x<0 ) return -1; j = x; - while( safe_isspace(pParse->zJson[j]) ){ j++; } - c = pParse->zJson[j]; + while( safe_isspace(z[j]) ){ j++; } + c = z[j]; if( c==',' ) continue; if( c!='}' ) return -1; break; @@ -763,15 +764,15 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); if( iThis<0 ) return -1; for(j=i+1;;j++){ - while( safe_isspace(pParse->zJson[j]) ){ j++; } + while( safe_isspace(z[j]) ){ j++; } x = jsonParseValue(pParse, j); if( x<0 ){ if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1; return -1; } j = x; - while( safe_isspace(pParse->zJson[j]) ){ j++; } - c = pParse->zJson[j]; + while( safe_isspace(z[j]) ){ j++; } + c = z[j]; if( c==',' ) continue; if( c!=']' ) return -1; break; @@ -783,13 +784,13 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ u8 jnFlags = 0; j = i+1; for(;;){ - c = pParse->zJson[j]; + c = z[j]; if( c==0 ) return -1; if( c=='\\' ){ - c = pParse->zJson[++j]; + c = z[++j]; if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f' || c=='n' || c=='r' || c=='t' - || (c=='u' && jsonIs4Hex(pParse->zJson+j+1)) ){ + || (c=='u' && jsonIs4Hex(z+j+1)) ){ jnFlags = JNODE_ESCAPE; }else{ return -1; @@ -799,55 +800,60 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ } j++; } - jsonParseAddNode(pParse, JSON_STRING, j+1-i, &pParse->zJson[i]); + jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]); if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags; return j+1; }else if( c=='n' - && strncmp(pParse->zJson+i,"null",4)==0 - && !safe_isalnum(pParse->zJson[i+4]) ){ + && strncmp(z+i,"null",4)==0 + && !safe_isalnum(z[i+4]) ){ jsonParseAddNode(pParse, JSON_NULL, 0, 0); return i+4; }else if( c=='t' - && strncmp(pParse->zJson+i,"true",4)==0 - && !safe_isalnum(pParse->zJson[i+4]) ){ + && strncmp(z+i,"true",4)==0 + && !safe_isalnum(z[i+4]) ){ jsonParseAddNode(pParse, JSON_TRUE, 0, 0); return i+4; }else if( c=='f' - && strncmp(pParse->zJson+i,"false",5)==0 - && !safe_isalnum(pParse->zJson[i+5]) ){ + && strncmp(z+i,"false",5)==0 + && !safe_isalnum(z[i+5]) ){ jsonParseAddNode(pParse, JSON_FALSE, 0, 0); return i+5; }else if( c=='-' || (c>='0' && c<='9') ){ /* Parse number */ u8 seenDP = 0; u8 seenE = 0; + assert( '-' < '0' ); + if( c<='0' ){ + j = c=='-' ? i+1 : i; + if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1; + } j = i+1; for(;; j++){ - c = pParse->zJson[j]; + c = z[j]; if( c>='0' && c<='9' ) continue; if( c=='.' ){ - if( pParse->zJson[j-1]=='-' ) return -1; + if( z[j-1]=='-' ) return -1; if( seenDP ) return -1; seenDP = 1; continue; } if( c=='e' || c=='E' ){ - if( pParse->zJson[j-1]<'0' ) return -1; + if( z[j-1]<'0' ) return -1; if( seenE ) return -1; seenDP = seenE = 1; - c = pParse->zJson[j+1]; + c = z[j+1]; if( c=='+' || c=='-' ){ j++; - c = pParse->zJson[j+1]; + c = z[j+1]; } if( c<'0' || c>'9' ) return -1; continue; } break; } - if( pParse->zJson[j-1]<'0' ) return -1; + if( z[j-1]<'0' ) return -1; jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT, - j - i, &pParse->zJson[i]); + j - i, &z[i]); return j; }else if( c=='}' ){ return -2; /* End of {...} */ diff --git a/ext/rtree/rtree.c b/ext/rtree/rtree.c index 42f08a9628..8196e351bc 100644 --- a/ext/rtree/rtree.c +++ b/ext/rtree/rtree.c @@ -3198,12 +3198,35 @@ static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){ , pRtree->zDb, pRtree->zName, zNewName ); if( zSql ){ + nodeBlobReset(pRtree); rc = sqlite3_exec(pRtree->db, zSql, 0, 0, 0); sqlite3_free(zSql); } return rc; } +/* +** The xSavepoint method. +** +** This module does not need to do anything to support savepoints. However, +** it uses this hook to close any open blob handle. This is done because a +** DROP TABLE command - which fortunately always opens a savepoint - cannot +** succeed if there are any open blob handles. i.e. if the blob handle were +** not closed here, the following would fail: +** +** BEGIN; +** INSERT INTO rtree... +** DROP TABLE ; -- Would fail with SQLITE_LOCKED +** COMMIT; +*/ +static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){ + Rtree *pRtree = (Rtree *)pVtab; + int iwt = pRtree->inWrTrans; + pRtree->inWrTrans = 0; + nodeBlobReset(pRtree); + pRtree->inWrTrans = iwt; + return SQLITE_OK; +} /* ** This function populates the pRtree->nRowEst variable with an estimate @@ -3250,7 +3273,7 @@ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){ } static sqlite3_module rtreeModule = { - 0, /* iVersion */ + 2, /* iVersion */ rtreeCreate, /* xCreate - create a table */ rtreeConnect, /* xConnect - connect to an existing table */ rtreeBestIndex, /* xBestIndex - Determine search strategy */ @@ -3270,7 +3293,7 @@ static sqlite3_module rtreeModule = { rtreeEndTransaction, /* xRollback - rollback transaction */ 0, /* xFindFunction - function overloading */ rtreeRename, /* xRename - rename the table */ - 0, /* xSavepoint */ + rtreeSavepoint, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ }; diff --git a/ext/rtree/rtree1.test b/ext/rtree/rtree1.test index 9dc101a7b2..a29cfb945d 100644 --- a/ext/rtree/rtree1.test +++ b/ext/rtree/rtree1.test @@ -39,6 +39,8 @@ set testprefix rtree1 # inserted. Also that if a non-numeric is inserted into one # of the min/max dimension columns, it is converted to the # required type before being inserted. +# rtree-15.*: Check that DROP TABLE works within a transaction that +# writes to an r-tree table. # ifcapable !rtree { @@ -592,4 +594,20 @@ do_execsql_test 14.5 { 3 42 49 } +#------------------------------------------------------------------------- +# +do_execsql_test 15.0 { + CREATE VIRTUAL TABLE rt USING rtree(id, x1,x2, y1,y2); + CREATE TEMP TABLE t13(a, b, c); +} +do_execsql_test 15.1 { + BEGIN; + INSERT INTO rt VALUES(1,2,3,4,5); +} +breakpoint +do_execsql_test 15.2 { + DROP TABLE t13; + COMMIT; +} + finish_test diff --git a/manifest b/manifest index 5deeb9c637..bcb6036c74 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Rename\sshell6.test\sto\sexpert1.test.\sHave\sit\sinvoke\sthe\ssqlite3_expert\sbinary\nif\sit\sis\spresent. -D 2017-04-08T18:56:32.081 +C Merge\slatest\strunk\swith\sthis\sbranch. +D 2017-04-08T19:00:37.586 F Makefile.in 1cc758ce3374a32425e4d130c2fe7b026b20de5b8843243de75f087c0a2661fb F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc a4c0613a18663bda56d8cf76079ab6590a7c3602e54befb4bbdef76bcaa38b6a @@ -30,8 +30,8 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63 F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977 F config.h.in 6376abec766e9a0785178b1823b5a587e9f1ccbc F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55 -F configure cea63449647267beb335e899fd8a79778912ffa55d6b179730267b8ef84aa1aa x -F configure.ac 605173e829ab64514ed89f9b53d0da1739d7b0a0 +F configure bddf7d1d945894b724e2b16a1266359a40abec2c798c95b4409a7ebf771c38ef x +F configure.ac 901e8db2c211e8b655e51ee24f2b8faa33407acde87effc47f70380f3b04e452 F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad F doc/lemon.html b5a3c07d33ecb8e019ce8f7660fe2dbbad9d7977 F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710 @@ -102,15 +102,15 @@ F ext/fts3/unicode/mkunicode.tcl ab0543a3b2399092ea2dd75df1bef333405b0d7f6b8c495 F ext/fts3/unicode/parseunicode.tcl da577d1384810fb4e2b209bf3313074353193e95 F ext/fts5/extract_api_docs.tcl a36e54ec777172ddd3f9a88daf593b00848368e0 F ext/fts5/fts5.h 62f3e33ceeb9a428db139f9c012186b371da1cc7 -F ext/fts5/fts5Int.h c629b24d2b92b99596f3b8e82289fddca06df6e1 +F ext/fts5/fts5Int.h 88c1a9a01cd5cd7b9a3c95699d1f61cdb277b2fa087a07d3fc989b49970437d9 F ext/fts5/fts5_aux.c 67acf8d51723cf28ffc3828210ba662df4b8d267 F ext/fts5/fts5_buffer.c 4c1502d4c956cd092c89ce4480867f9d8bf325cd F ext/fts5/fts5_config.c 5af9c360e99669d29f06492c370892394aba0857 F ext/fts5/fts5_expr.c c6ecc2280162a3714d15dce2a8f2299f748b627c F ext/fts5/fts5_hash.c 880998e596b60f078348d48732ca4ad9a90caad2 -F ext/fts5/fts5_index.c f67032a9a529ba52a545e6e3ab970764199c05d4 -F ext/fts5/fts5_main.c f85281445dcf8be32d18841c93a6f90fe27dbfe2 -F ext/fts5/fts5_storage.c 8f0e65cb33bde8f449e1c9b4be4600d18b4da6e9 +F ext/fts5/fts5_index.c a3a9ae1c6f8a3652eb45dd732a71cdc92b48df047af134da38cd0c425649e042 +F ext/fts5/fts5_main.c 24cafdc44c06b9665d73c34b75966f6223e9299cc9fd10184c6bf888e3ff563f +F ext/fts5/fts5_storage.c 7750986004f3f0c94619a85ecb5dd6cbef53e5e3853488e8a906c269d4d11db6 F ext/fts5/fts5_tcl.c 4a901f00c8553740dba63511603f5527d741c26a F ext/fts5/fts5_test_mi.c 783b86697ebf773c18fc109992426c0173a055bc F ext/fts5/fts5_test_tok.c db08af63673c3a7d39f053b36fd6e065017706be @@ -121,7 +121,7 @@ F ext/fts5/fts5_vocab.c e44fefa7f0c1db252998af071daf06a7147e17e7 F ext/fts5/fts5parse.y e51b375403421b8b37428a89b095d00597129aae F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba F ext/fts5/test/fts5_common.tcl b01c584144b5064f30e6c648145a2dd6bc440841 -F ext/fts5/test/fts5aa.test bd2d88182b9f7f30d300044048ad14683306b745 +F ext/fts5/test/fts5aa.test b3cb080db4851580705c5e261c9d4308edf030d5cbbc24b5d6668403b73f023b F ext/fts5/test/fts5ab.test 30325a89453280160106be411bba3acf138e6d1b F ext/fts5/test/fts5ac.test 55cad4275a1f5acabfe14d8442a8046b47e49e5f F ext/fts5/test/fts5ad.test 36995f0586f30f5602074e012b9224c71ec5171c @@ -221,7 +221,7 @@ F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2 F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25 F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c -F ext/misc/json1.c 92b9e404bd79cc76d3ef2b3a9e37bf775700f7d645466fd41d2e8742e3fa16fb +F ext/misc/json1.c 312b4ddf4c7399dcbd2189f492e8ca92a872c2df7347473bfb38854f9d60c06a F ext/misc/memvfs.c e5225bc22e79dde6b28380f3a068ddf600683a33 F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342 F ext/misc/percentile.c 92699c8cd7d517ff610e6037e56506f8904dae2e @@ -274,9 +274,9 @@ F ext/rbu/sqlite3rbu.c 2a89efba9eeba8e6c89a498dc195e8efbdde2694 F ext/rbu/sqlite3rbu.h 6fb6294c34a9ca93b5894a33bca530c6f08decba F ext/rbu/test_rbu.c 5aa22616afac6f71ebd3d9bc9bf1006cfabcca88 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 -F ext/rtree/rtree.c 0acd285bfacc347579a5df9fe947212fb99e2775a40c43f027c3a16936c58e7e +F ext/rtree/rtree.c 37c603c6b8aed1a760661ceb5a025bd36bac14cf56d59949bd8de14b2a17e9ed F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e -F ext/rtree/rtree1.test 42dadfc7b44a436cd74a1bebc0b9b689e4eaf7ec +F ext/rtree/rtree1.test d5f0ba215b3bd1d05269ada86e74073b8445852aa0d33a63e10ec63a09c39473 F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba F ext/rtree/rtree3.test 2cafe8265d1ff28f206fce88d114f208349df482 F ext/rtree/rtree4.test c8fe384f60ebd49540a5fecc990041bf452eb6e0 @@ -347,17 +347,17 @@ F src/auth.c 930b376a9c56998557367e6f7f8aaeac82a2a792 F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca -F src/btree.c 64ff65a01851a34c8145e5bc767df9e57d2f3c1acdc6aba334794b7c40c684e6 +F src/btree.c 24ae5472bd0b53b4130ecdda389deb621af721d1fcb50890b878102b00bd10fa F src/btree.h bf64dfeeddeebdb775a5eba0098bbc00d073290d -F src/btreeInt.h cd55d39d9916270837a88c12e701047cba0729b0 -F src/build.c 43f903c9082040ced2b421543cb0300c2973647d +F src/btreeInt.h a392d353104b4add58b4a59cb185f5d5693dde832c565b77d8d4c343ed98f610 +F src/build.c 4026a9c554b233e50c5e9ad46963e676cf54dd2306d952aa1eaa07a1bc9ce14f F src/callback.c 2e76147783386374bf01b227f752c81ec872d730 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 47d91a25ad8f199a71a5b1b7b169d6dd0d6e98c5719eca801568798743d1161c F src/date.c ee676e7694dfadbdd2fde1a258a71be8360ba5ae F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d F src/delete.c 0d9d5549d42e79ce4d82ff1db1e6c81e36d2f67c -F src/expr.c f12a581f342a6fd85d14c31e4fb84f16b3dd107f54d7728dddb62cebc79d7ce1 +F src/expr.c 6bce2cbdd822963cf28e782938a96274cc37f18ac28dec7a4e35ccac09f66ce8 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 2e9aabe1aee76273aff8a84ee92c464e095400ae F src/func.c 9d52522cc8ae7f5cdadfe14594262f1618bc1f86083c4cd6da861b4cf5af6174 @@ -370,7 +370,7 @@ F src/insert.c d4bb3a135948553d18cf992f76f7ed7b18aa0327f250607b5a6671e55d9947d5 F src/legacy.c e88ed13c2d531decde75d42c2e35623fb9ce3cb0 F src/loadext.c a72909474dadce771d3669bf84bf689424f6f87d471fee898589c3ef9b2acfd9 F src/main.c 4b93bda0f1f916f4cb618a6fce358f7e01ab060971c586c4cea90ad0c83a83f5 -F src/malloc.c 89c98e3619d362dcffa5c1c639b364b65b474751 +F src/malloc.c e20bb2b48abec52d3faf01cce12e8b4f95973755fafec98d45162dfdab111978 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3 @@ -397,19 +397,19 @@ F src/parse.y 48b03113704ee8bd78ee6996d81de7fbee22e105 F src/pcache.c 62835bed959e2914edd26afadfecce29ece0e870 F src/pcache.h 2cedcd8407eb23017d92790b112186886e179490 F src/pcache1.c 1195a21fe28e223e024f900b2011e80df53793f0356a24caace4188b098540dc -F src/pragma.c 157c323aef421d55905b42162ba16bc874c0dce3102c543b4092c202f881f2c6 -F src/pragma.h c9c763958fec92b04125571472c9500b351c5f7f +F src/pragma.c 150821702fc90694b46c3432c1402fc970a4c5b8595cb13c21aeb568f9a78fc3 +F src/pragma.h 37a1311d0388db480388d7ec09054f7103045eff20d4971f8a433b77f40b9921 F src/prepare.c b1140c3d0cf59bc85ace00ce363153041b424b7a F src/printf.c 8757834f1b54dae512fb25eb1acc8e94a0d15dd2290b58f2563f65973265adb2 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c 3e518b962d932a997fae373366880fc028c75706 F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac -F src/select.c 2496d0cc6368dabe7ad2e4c7f5ed3ad9aa3b4d11cd90f33fa1d1ef72493f43aa -F src/shell.c ceb2b2f1f958ea2c47a7f37972d0f715fbf9dcf6a34a5e98c886b85e3ce6a238 -F src/sqlite.h.in ae5c9cbf2e77492c319fca08769575d9695e64718a16d32324944d24e291bcf7 +F src/select.c afcf31d8ed7c890328a31d3f350467ccd273af345b24562382b398d6d9cd0664 +F src/shell.c 70f4957b988572315e97c56941fdc81fd35907fee36b7b2e7be5ec4c7e9d065d +F src/sqlite.h.in 8ed51474c7a9edacbf328e2a6ce63de5cde8f50793c6063cb508f9de128e5a4c F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 58fd0676d3111d02e62e5a35992a7d3da5d3f88753acc174f2d37b774fbbdd28 -F src/sqliteInt.h 9af1569ac748f72169b4ad0004d03ea14c75b59eb955a2c0ecca75a16ea2015f +F src/sqliteInt.h 36eec0868d25b50e64a05bc7355557a0aa9bd14330c16b7d7568520b2bf2bb4e F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1 F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -464,28 +464,28 @@ F src/test_windirent.c 17f91f5f2aa1bb7328abb49414c363b5d2a9d3ff F src/test_windirent.h 5d67483a55442e31e1bde0f4a230e6e932ad5906 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c -F src/tokenize.c de2ec4fed5aa9770791be7528a08597a77a36b2ffbbeb0c2cb6951e80357730b +F src/tokenize.c 1003d6d90c6783206c711f0a9397656fa5b055209f4d092caa43bb3bf5215db5 F src/treeview.c 84d0ac737e1231702679f0289180021e19c5cc186ec413e8dcb704a887c76ec8 F src/trigger.c c9f0810043b265724fdb1bdd466894f984dfc182 F src/update.c 456d4a4656f8a03c2abc88a51b19172197400e58 F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c F src/util.c ca8440ede81e155d15cff7c101654f60b55a9ae6 F src/vacuum.c 1fe4555cd8c9b263afb85b5b4ee3a4a4181ad569 -F src/vdbe.c f1acf5744cef62cbfd0b503d84289f840b6cdc980ac47b0d9632dfdb89cc79eb +F src/vdbe.c 808fda3d50f544120d27c731449b524b4ec8f8b0f734b228831078f0ba53ecb9 F src/vdbe.h caa5346d52bae2a3c8c1dcfa60a7a4dc878a9e3865cb8239da55808b316c8158 F src/vdbeInt.h 5db089ce18c4feff8820ec6e4cac2d2c82e03d4b1d96f10a6e43832147b8dffe F src/vdbeapi.c 5b08d82592bcff4470601fe78aaabebd50837860 -F src/vdbeaux.c ecd0468611925d218e1eb4b3f538907904b136f0e15e333291a232b521bfcef1 +F src/vdbeaux.c 0ecacf8c7ca93e430b30819b8fc9b2c1ffe88202d1437e88c08a1f0b6159c58c F src/vdbeblob.c 359891617358deefc85bef7bcf787fa6b77facb9 -F src/vdbemem.c 3b5a9a5b375458d3e12a50ae1aaa41eeec2175fd -F src/vdbesort.c eda25cb2d1727efca6f7862fea32b8aa33c0face +F src/vdbemem.c 8bb4dd22837da969bfda25ef3f92d41aaad192328f89a0951290d5e26ad7dbc4 +F src/vdbesort.c e72fe02a2121386ba767ede8942e9450878b8fc873abf3d1b6824485f092570c F src/vdbetrace.c 41963d5376f0349842b5fc4aaaaacd7d9cdc0834 F src/vtab.c 007513c2ef52472fcdea6a741683d50662e82790 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c 40c543f0a2195d1b0dc88ef12142bea690009344 F src/wal.h 06b2a0b599cc0f53ea97f497cf8c6b758c999f71 F src/walker.c b71a992b413b3a022572eccf29ef4b4890223791 -F src/where.c be352441558b55e21964ff53f0483776594789d0ede12dd9c58b022873c858f8 +F src/where.c 613b1cac781b2725bb0a841d5c264ae9475380ee3063c3ce9c81814b03a83c20 F src/whereInt.h 2d50c2b74a33be44cb68fdecee30b4d93552f1f4 F src/wherecode.c 677e95413c472c0b413023b6b69a47f40fce1b04 F src/whereexpr.c 130cdd1a43af71b19755270fb1224874cf55158c @@ -887,7 +887,7 @@ F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7 F test/insert.test 38742b5e9601c8f8d76e9b7555f7270288c2d371 F test/insert2.test 4d14b8f1b810a41995f6286b64a6943215d52208 F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30 -F test/insert4.test a20432f1c0fbbcff8f11d0e6ab4acb8c9db58023 +F test/insert4.test 46bead5f39e181850ee56adcf49d3a3157c460c52249211714612ac89fe34835 F test/insert5.test 394f96728d1258f406fe5f5aeb0aaf29487c39a6 F test/instr.test 9a8802f28437d8ade53fedfc47b2ca599b4e48ba F test/instrfault.test 0f870b218ea17cd477bb19ed330eecdb460dd53a @@ -915,7 +915,7 @@ F test/jrnlmode.test 7864d59cf7f6e552b9b99ba0f38acd167edc10fa F test/jrnlmode2.test 81610545a4e6ed239ea8fa661891893385e23a1d F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa F test/json101.test c0897616f32d95431f37fd291cb78742181980ac -F test/json102.test bf3fe7a706d30936a76a0f7a0375e1e8e73aff5a +F test/json102.test de1728e8ffde4a57cbc77b6815a60ccb82a6c759967be44e71952757e7d7947b F test/json103.test c5f6b85e69de05f6b3195f9f9d5ce9cd179099a0 F test/json104.test 877d5845f6303899b7889ea5dd1bea99076e3100574d5c536082245c5805dcaa F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff @@ -1036,6 +1036,7 @@ F test/pragma.test 1e94755164a3a3264cd39836de4bebcb7809e5f8 F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f F test/pragma3.test 14c12bc5352b1e100e0b6b44f371053a81ccf8ed F test/pragma4.test 6e85b6eab8e61ffc9c7db59d842276674e8e3264 +F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8 F test/printf.test b3ff34e73d59124140eaf89f7672e21bc2ca5fcc F test/printf2.test 9e6db85f81c63f2367c34a9d7db384088bd374ad F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb @@ -1123,6 +1124,7 @@ F test/shell2.test e242a9912f44f4c23c3d1d802a83e934e84c853b F test/shell3.test 9b95ba643eaa228376f06a898fb410ee9b6e57c1 F test/shell4.test 89ad573879a745974ff2df20ff97c5d6ffffbd5d F test/shell5.test 50a732c1c2158b1cd62cf53975ce1ea7ce6b9dc9 +F test/shell6.test ab1592ebe881371f651f18ee6a0df21cbfb5310f88cb832ab642d4038f679772 F test/shell7.test 07751911b294698e0c5df67bcbd29e7d2f0f2907 F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3 F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5 @@ -1170,7 +1172,7 @@ F test/subtype1.test 7fe09496352f97053af1437150751be2d0a0cae8 F test/superlock.test ec94f0556b6488d97f71c79f9061ae08d9ab8f12 F test/symlink.test c9ebe7330d228249e447038276bfc8a7b22f4849 F test/sync.test 2f84bdbc2b2df1fcb0220575b4b9f8cea94b7529 -F test/sync2.test 29af00fe9e468a1e20315d1edced8f8a32ac156df983ae9b53802e7d472675d5 +F test/sync2.test 6be8ed007fa063b147773c1982b5bdba97a32badc536bdc6077eff5cf8710ece F test/syscall.test f59ba4e25f7ba4a4c031026cc2ef8b6e4b4c639c F test/sysfault.test c9f2b0d8d677558f74de750c75e12a5454719d04 F test/tabfunc01.test 699251cb99651415218a891384510a685c7ab012 @@ -1510,7 +1512,7 @@ F tool/mkmsvcmin.tcl 95b37e202cbed873aa8ffdbb493b9db45927be2b F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c F tool/mkopcodeh.tcl a01d2c1d8a6205b03fc635adf3735b4c523befd3 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e -F tool/mkpragmatab.tcl 2ffe6d5fdc2d3381621d6c77978ba054466e757f +F tool/mkpragmatab.tcl 32bb40741df11bddc8451de9ea4d130e7b4476d8064794b1cf402ac110840fba F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 F tool/mksqlite3c-noext.tcl fef88397668ae83166735c41af99d79f56afaabb F tool/mksqlite3c.tcl 06b2e6a0f21cc0a5d70fbbd136b3e0a96470645e @@ -1573,7 +1575,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 bf10e68d9e4d5eae7ae6148a7ad64c9596f2ed8ccd36065adb09a1f9e7dae50b -R e14200231c0812aa1e853be6a898ba2f +P be0deff940bea4f653d644113f42529a32ff7039d1d168119233aaf000a22f40 204e72f0080e8f08f99978870bd3cb9d59b068ecffee82192d707c650548b43b +R 6e0d9b80ca81b8d3b8a7b8f8dc2a80a0 U dan -Z b04d01a3056a5795f1f1bb4407f0bf9d +Z 4063bdd74acb02b7df335075f419d3f7 diff --git a/manifest.uuid b/manifest.uuid index 6f644ebe90..581e5de589 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -be0deff940bea4f653d644113f42529a32ff7039d1d168119233aaf000a22f40 \ No newline at end of file +e051e8f21b909c5e89a7203eef6501fecd64f82a634c4e10398b5ef7d716eb37 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index aecf06e63f..48cfae5c72 100644 --- a/src/btree.c +++ b/src/btree.c @@ -4317,7 +4317,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){ CellInfo info; int iPage = pCur->iPage; memset(&info, 0, sizeof(info)); - btreeParseCell(pCur->apPage[iPage], pCur->aiIdx[iPage], &info); + btreeParseCell(pCur->apPage[iPage], pCur->ix, &info); assert( CORRUPT_DB || memcmp(&info, &pCur->info, sizeof(info))==0 ); } #else @@ -4327,7 +4327,7 @@ static SQLITE_NOINLINE void getCellInfo(BtCursor *pCur){ if( pCur->info.nSize==0 ){ int iPage = pCur->iPage; pCur->curFlags |= BTCF_ValidNKey; - btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); + btreeParseCell(pCur->apPage[iPage],pCur->ix,&pCur->info); }else{ assertCellInfo(pCur); } @@ -4534,7 +4534,7 @@ static int accessPayload( assert( pPage ); assert( eOp==0 || eOp==1 ); assert( pCur->eState==CURSOR_VALID ); - assert( pCur->aiIdx[pCur->iPage]nCell ); + assert( pCur->ixnCell ); assert( cursorHoldsMutex(pCur) ); getCellInfo(pCur); @@ -4721,7 +4721,7 @@ int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] ); - assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); + assert( pCur->ixapPage[pCur->iPage]->nCell ); return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0); } @@ -4783,7 +4783,7 @@ static const void *fetchPayload( assert( pCur->eState==CURSOR_VALID ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( cursorOwnsBtShared(pCur) ); - assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); + assert( pCur->ixapPage[pCur->iPage]->nCell ); assert( pCur->info.nSize>0 ); assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB ); assert( pCur->info.pPayloadapPage[pCur->iPage]->aDataEnd ||CORRUPT_DB); @@ -4834,8 +4834,8 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){ } pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); - pCur->iPage++; - pCur->aiIdx[pCur->iPage] = 0; + pCur->aiIdx[pCur->iPage++] = pCur->ix; + pCur->ix = 0; return getAndInitPage(pBt, newPgno, &pCur->apPage[pCur->iPage], pCur, pCur->curPagerFlags); } @@ -4883,6 +4883,7 @@ static void moveToParent(BtCursor *pCur){ testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell ); pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); + pCur->ix = pCur->aiIdx[pCur->iPage-1]; releasePageNotNull(pCur->apPage[pCur->iPage--]); } @@ -4964,7 +4965,7 @@ static int moveToRoot(BtCursor *pCur){ } skip_init: - pCur->aiIdx[0] = 0; + pCur->ix = 0; pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl); @@ -4998,8 +4999,8 @@ static int moveToLeftmost(BtCursor *pCur){ assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){ - assert( pCur->aiIdx[pCur->iPage]nCell ); - pgno = get4byte(findCell(pPage, pCur->aiIdx[pCur->iPage])); + assert( pCur->ixnCell ); + pgno = get4byte(findCell(pPage, pCur->ix)); rc = moveToChild(pCur, pgno); } return rc; @@ -5024,11 +5025,11 @@ static int moveToRightmost(BtCursor *pCur){ assert( pCur->eState==CURSOR_VALID ); while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){ pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); - pCur->aiIdx[pCur->iPage] = pPage->nCell; + pCur->ix = pPage->nCell; rc = moveToChild(pCur, pgno); if( rc ) return rc; } - pCur->aiIdx[pCur->iPage] = pPage->nCell-1; + pCur->ix = pPage->nCell-1; assert( pCur->info.nSize==0 ); assert( (pCur->curFlags & BTCF_ValidNKey)==0 ); return SQLITE_OK; @@ -5076,7 +5077,7 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ for(ii=0; iiiPage; ii++){ assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell ); } - assert( pCur->aiIdx[pCur->iPage]==pCur->apPage[pCur->iPage]->nCell-1 ); + assert( pCur->ix==pCur->apPage[pCur->iPage]->nCell-1 ); assert( pCur->apPage[pCur->iPage]->leaf ); #endif return SQLITE_OK; @@ -5223,7 +5224,7 @@ int sqlite3BtreeMovetoUnpacked( upr = pPage->nCell-1; assert( biasRight==0 || biasRight==1 ); idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */ - pCur->aiIdx[pCur->iPage] = (u16)idx; + pCur->ix = (u16)idx; if( xRecordCompare==0 ){ for(;;){ i64 nCellKey; @@ -5242,7 +5243,7 @@ int sqlite3BtreeMovetoUnpacked( if( lwr>upr ){ c = +1; break; } }else{ assert( nCellKey==intKey ); - pCur->aiIdx[pCur->iPage] = (u16)idx; + pCur->ix = (u16)idx; if( !pPage->leaf ){ lwr = idx; goto moveto_next_layer; @@ -5311,7 +5312,7 @@ int sqlite3BtreeMovetoUnpacked( rc = SQLITE_NOMEM_BKPT; goto moveto_finish; } - pCur->aiIdx[pCur->iPage] = (u16)idx; + pCur->ix = (u16)idx; rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0); pCur->curFlags &= ~BTCF_ValidOvfl; if( rc ){ @@ -5333,7 +5334,7 @@ int sqlite3BtreeMovetoUnpacked( assert( c==0 ); *pRes = 0; rc = SQLITE_OK; - pCur->aiIdx[pCur->iPage] = (u16)idx; + pCur->ix = (u16)idx; if( pIdxKey->errCode ) rc = SQLITE_CORRUPT; goto moveto_finish; } @@ -5345,8 +5346,8 @@ int sqlite3BtreeMovetoUnpacked( assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) ); assert( pPage->isInit ); if( pPage->leaf ){ - assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); - pCur->aiIdx[pCur->iPage] = (u16)idx; + assert( pCur->ixapPage[pCur->iPage]->nCell ); + pCur->ix = (u16)idx; *pRes = c; rc = SQLITE_OK; goto moveto_finish; @@ -5357,7 +5358,7 @@ moveto_next_layer: }else{ chldPg = get4byte(findCell(pPage, lwr)); } - pCur->aiIdx[pCur->iPage] = (u16)lwr; + pCur->ix = (u16)lwr; rc = moveToChild(pCur, chldPg); if( rc ) break; } @@ -5458,7 +5459,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ } pPage = pCur->apPage[pCur->iPage]; - idx = ++pCur->aiIdx[pCur->iPage]; + idx = ++pCur->ix; assert( pPage->isInit ); /* If the database file is corrupt, it is possible for the value of idx @@ -5482,7 +5483,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ } moveToParent(pCur); pPage = pCur->apPage[pCur->iPage]; - }while( pCur->aiIdx[pCur->iPage]>=pPage->nCell ); + }while( pCur->ix>=pPage->nCell ); if( pPage->intKey ){ return sqlite3BtreeNext(pCur, pRes); }else{ @@ -5506,8 +5507,8 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ *pRes = 0; if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, pRes); pPage = pCur->apPage[pCur->iPage]; - if( (++pCur->aiIdx[pCur->iPage])>=pPage->nCell ){ - pCur->aiIdx[pCur->iPage]--; + if( (++pCur->ix)>=pPage->nCell ){ + pCur->ix--; return btreeNext(pCur, pRes); } if( pPage->leaf ){ @@ -5571,12 +5572,12 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){ pPage = pCur->apPage[pCur->iPage]; assert( pPage->isInit ); if( !pPage->leaf ){ - int idx = pCur->aiIdx[pCur->iPage]; + int idx = pCur->ix; rc = moveToChild(pCur, get4byte(findCell(pPage, idx))); if( rc ) return rc; rc = moveToRightmost(pCur); }else{ - while( pCur->aiIdx[pCur->iPage]==0 ){ + while( pCur->ix==0 ){ if( pCur->iPage==0 ){ pCur->eState = CURSOR_INVALID; *pRes = 1; @@ -5587,7 +5588,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){ assert( pCur->info.nSize==0 ); assert( (pCur->curFlags & (BTCF_ValidOvfl))==0 ); - pCur->aiIdx[pCur->iPage]--; + pCur->ix--; pPage = pCur->apPage[pCur->iPage]; if( pPage->intKey && !pPage->leaf ){ rc = sqlite3BtreePrevious(pCur, pRes); @@ -5606,12 +5607,12 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey); pCur->info.nSize = 0; if( pCur->eState!=CURSOR_VALID - || pCur->aiIdx[pCur->iPage]==0 + || pCur->ix==0 || pCur->apPage[pCur->iPage]->leaf==0 ){ return btreePrevious(pCur, pRes); } - pCur->aiIdx[pCur->iPage]--; + pCur->ix--; return SQLITE_OK; } @@ -7933,8 +7934,8 @@ static int balance(BtCursor *pCur){ rc = balance_deeper(pPage, &pCur->apPage[1]); if( rc==SQLITE_OK ){ pCur->iPage = 1; + pCur->ix = 0; pCur->aiIdx[0] = 0; - pCur->aiIdx[1] = 0; assert( pCur->apPage[1]->nOverflow ); } }else{ @@ -8163,7 +8164,7 @@ int sqlite3BtreeInsert( if( rc ) goto end_insert; assert( szNew==pPage->xCellSize(pPage, newCell) ); assert( szNew <= MX_CELL_SIZE(pBt) ); - idx = pCur->aiIdx[pCur->iPage]; + idx = pCur->ix; if( loc==0 ){ CellInfo info; assert( idxnCell ); @@ -8191,7 +8192,7 @@ int sqlite3BtreeInsert( if( rc ) goto end_insert; }else if( loc<0 && pPage->nCell>0 ){ assert( pPage->leaf ); - idx = ++pCur->aiIdx[pCur->iPage]; + idx = ++pCur->ix; }else{ assert( pPage->leaf ); } @@ -8287,12 +8288,12 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ assert( pCur->curFlags & BTCF_WriteFlag ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); assert( !hasReadConflicts(p, pCur->pgnoRoot) ); - assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); + assert( pCur->ixapPage[pCur->iPage]->nCell ); assert( pCur->eState==CURSOR_VALID ); assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 ); iCellDepth = pCur->iPage; - iCellIdx = pCur->aiIdx[iCellDepth]; + iCellIdx = pCur->ix; pPage = pCur->apPage[iCellDepth]; pCell = findCell(pPage, iCellIdx); @@ -8409,7 +8410,7 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ pCur->eState = CURSOR_SKIPNEXT; if( iCellIdx>=pPage->nCell ){ pCur->skipNext = -1; - pCur->aiIdx[iCellDepth] = pPage->nCell-1; + pCur->ix = pPage->nCell-1; }else{ pCur->skipNext = 1; } @@ -8922,16 +8923,16 @@ int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){ return moveToRoot(pCur); } moveToParent(pCur); - }while ( pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell ); + }while ( pCur->ix>=pCur->apPage[pCur->iPage]->nCell ); - pCur->aiIdx[pCur->iPage]++; + pCur->ix++; pPage = pCur->apPage[pCur->iPage]; } /* Descend to the child node of the cell that the cursor currently ** points at. This is the right-child if (iIdx==pPage->nCell). */ - iIdx = pCur->aiIdx[pCur->iPage]; + iIdx = pCur->ix; if( iIdx==pPage->nCell ){ rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8])); }else{ diff --git a/src/btreeInt.h b/src/btreeInt.h index b01163c33f..47de58f509 100644 --- a/src/btreeInt.h +++ b/src/btreeInt.h @@ -517,10 +517,10 @@ struct BtCursor { ** initialized. */ i8 iPage; /* Index of current page in apPage */ u8 curIntKey; /* Value of apPage[0]->intKey */ - struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */ - void *padding1; /* Make object size a multiple of 16 */ - u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */ - MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */ + u16 ix; /* Current index for apPage[iPage] */ + u16 aiIdx[BTCURSOR_MAX_DEPTH-1]; /* Current index in apPage[i] */ + struct KeyInfo *pKeyInfo; /* Arg passed to comparison function */ + MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */ }; /* diff --git a/src/build.c b/src/build.c index 2ce7c90747..e04406d857 100644 --- a/src/build.c +++ b/src/build.c @@ -3623,7 +3623,7 @@ void sqlite3IdListDelete(sqlite3 *db, IdList *pList){ sqlite3DbFree(db, pList->a[i].zName); } sqlite3DbFree(db, pList->a); - sqlite3DbFree(db, pList); + sqlite3DbFreeNN(db, pList); } /* @@ -3813,7 +3813,7 @@ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){ sqlite3ExprDelete(db, pItem->pOn); sqlite3IdListDelete(db, pItem->pUsing); } - sqlite3DbFree(db, pList); + sqlite3DbFreeNN(db, pList); } /* diff --git a/src/expr.c b/src/expr.c index ce948be69e..e3db59732e 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1038,7 +1038,7 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){ } if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken); if( !ExprHasProperty(p, EP_Static) ){ - sqlite3DbFree(db, p); + sqlite3DbFreeNN(db, p); } } void sqlite3ExprDelete(sqlite3 *db, Expr *p){ @@ -1305,15 +1305,11 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){ Expr *pPriorSelectCol = 0; assert( db!=0 ); if( p==0 ) return 0; - pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) ); + pNew = sqlite3DbMallocRawNN(db, + sizeof(*pNew)+sizeof(pNew->a[0])*(p->nExpr-1) ); if( pNew==0 ) return 0; - pNew->nExpr = i = p->nExpr; - if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; inExpr; i+=i){} - pNew->a = pItem = sqlite3DbMallocRawNN(db, i*sizeof(p->a[0]) ); - if( pItem==0 ){ - sqlite3DbFree(db, pNew); - return 0; - } + pNew->nAlloc = pNew->nExpr = p->nExpr; + pItem = pNew->a; pOldItem = p->a; for(i=0; inExpr; i++, pItem++, pOldItem++){ Expr *pOldExpr = pOldItem->pExpr; @@ -1404,7 +1400,7 @@ IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){ pNew->nId = p->nId; pNew->a = sqlite3DbMallocRawNN(db, p->nId*sizeof(p->a[0]) ); if( pNew->a==0 ){ - sqlite3DbFree(db, pNew); + sqlite3DbFreeNN(db, pNew); return 0; } /* Note that because the size of the allocation for p->a[] is not @@ -1475,6 +1471,7 @@ ExprList *sqlite3ExprListAppend( 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 ){ @@ -1483,23 +1480,20 @@ ExprList *sqlite3ExprListAppend( goto no_mem; } pList->nExpr = 0; - pList->a = sqlite3DbMallocRawNN(db, sizeof(pList->a[0])); - if( pList->a==0 ) goto no_mem; - }else if( (pList->nExpr & (pList->nExpr-1))==0 ){ - struct ExprList_item *a; - assert( pList->nExpr>0 ); - a = sqlite3DbRealloc(db, pList->a, pList->nExpr*2*sizeof(pList->a[0])); - if( a==0 ){ + pList->nAlloc = 1; + }else if( pList->nExpr==pList->nAlloc ){ + ExprList *pNew; + pNew = sqlite3DbRealloc(db, pList, + sizeof(*pList)+(2*pList->nAlloc - 1)*sizeof(pList->a[0])); + if( pNew==0 ){ goto no_mem; } - pList->a = a; - } - assert( pList->a!=0 ); - if( 1 ){ - struct ExprList_item *pItem = &pList->a[pList->nExpr++]; - memset(pItem, 0, sizeof(*pItem)); - pItem->pExpr = pExpr; + pList = pNew; + pList->nAlloc *= 2; } + pItem = &pList->a[pList->nExpr++]; + memset(pItem, 0, sizeof(*pItem)); + pItem->pExpr = pExpr; return pList; no_mem: @@ -1556,20 +1550,19 @@ ExprList *sqlite3ExprListAppendVector( } } - if( pExpr->op==TK_SELECT ){ - if( pList && pList->a[iFirst].pExpr ){ - Expr *pFirst = pList->a[iFirst].pExpr; - assert( pFirst->op==TK_SELECT_COLUMN ); + if( pExpr->op==TK_SELECT && pList ){ + Expr *pFirst = pList->a[iFirst].pExpr; + assert( pFirst!=0 ); + assert( pFirst->op==TK_SELECT_COLUMN ); - /* Store the SELECT statement in pRight so it will be deleted when - ** sqlite3ExprListDelete() is called */ - pFirst->pRight = pExpr; - pExpr = 0; + /* Store the SELECT statement in pRight so it will be deleted when + ** sqlite3ExprListDelete() is called */ + pFirst->pRight = pExpr; + pExpr = 0; - /* Remember the size of the LHS in iTable so that we can check that - ** the RHS and LHS sizes match during code generation. */ - pFirst->iTable = pColumns->nId; - } + /* Remember the size of the LHS in iTable so that we can check that + ** the RHS and LHS sizes match during code generation. */ + pFirst->iTable = pColumns->nId; } vector_append_error: @@ -1663,16 +1656,16 @@ void sqlite3ExprListCheckLength( ** Delete an entire expression list. */ static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){ - int i; - struct ExprList_item *pItem; - assert( pList->a!=0 || pList->nExpr==0 ); - for(pItem=pList->a, i=0; inExpr; i++, pItem++){ + int i = pList->nExpr; + struct ExprList_item *pItem = pList->a; + assert( pList->nExpr>0 ); + do{ sqlite3ExprDelete(db, pItem->pExpr); sqlite3DbFree(db, pItem->zName); sqlite3DbFree(db, pItem->zSpan); - } - sqlite3DbFree(db, pList->a); - sqlite3DbFree(db, pList); + pItem++; + }while( --i>0 ); + sqlite3DbFreeNN(db, pList); } void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){ if( pList ) exprListDeleteNN(db, pList); diff --git a/src/malloc.c b/src/malloc.c index 6d49107790..5eb65bf623 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -474,11 +474,12 @@ static SQLITE_NOINLINE void measureAllocationSize(sqlite3 *db, void *p){ /* ** Free memory that might be associated with a particular database -** connection. +** connection. Calling sqlite3DbFree(D,X) for X==0 is a harmless no-op. +** The sqlite3DbFreeNN(D,X) version requires that X be non-NULL. */ -void sqlite3DbFree(sqlite3 *db, void *p){ +void sqlite3DbFreeNN(sqlite3 *db, void *p){ assert( db==0 || sqlite3_mutex_held(db->mutex) ); - if( p==0 ) return; + assert( p!=0 ); if( db ){ if( db->pnBytesFreed ){ measureAllocationSize(db, p); @@ -502,6 +503,10 @@ void sqlite3DbFree(sqlite3 *db, void *p){ sqlite3MemdebugSetType(p, MEMTYPE_HEAP); sqlite3_free(p); } +void sqlite3DbFree(sqlite3 *db, void *p){ + assert( db==0 || sqlite3_mutex_held(db->mutex) ); + if( p ) sqlite3DbFreeNN(db, p); +} /* ** Change the size of an existing memory allocation diff --git a/src/pragma.c b/src/pragma.c index f83e1eb461..28538f43d2 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1542,25 +1542,28 @@ void sqlite3Pragma( } /* Verify CHECK constraints */ if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){ - int addrCkFault = sqlite3VdbeMakeLabel(v); - int addrCkOk = sqlite3VdbeMakeLabel(v); - ExprList *pCheck = pTab->pCheck; - char *zErr; - int k; - pParse->iSelfTab = iDataCur; - sqlite3ExprCachePush(pParse); - for(k=pCheck->nExpr-1; k>0; k--){ - sqlite3ExprIfFalse(pParse, pCheck->a[k].pExpr, addrCkFault, 0); + ExprList *pCheck = sqlite3ExprListDup(db, pTab->pCheck, 0); + if( db->mallocFailed==0 ){ + int addrCkFault = sqlite3VdbeMakeLabel(v); + int addrCkOk = sqlite3VdbeMakeLabel(v); + char *zErr; + int k; + pParse->iSelfTab = iDataCur; + sqlite3ExprCachePush(pParse); + for(k=pCheck->nExpr-1; k>0; k--){ + sqlite3ExprIfFalse(pParse, pCheck->a[k].pExpr, addrCkFault, 0); + } + sqlite3ExprIfTrue(pParse, pCheck->a[0].pExpr, addrCkOk, + SQLITE_JUMPIFNULL); + sqlite3VdbeResolveLabel(v, addrCkFault); + zErr = sqlite3MPrintf(db, "CHECK constraint failed in %s", + pTab->zName); + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); + integrityCheckResultRow(v, 3); + sqlite3VdbeResolveLabel(v, addrCkOk); + sqlite3ExprCachePop(pParse); } - sqlite3ExprIfTrue(pParse, pCheck->a[0].pExpr, addrCkOk, - SQLITE_JUMPIFNULL); - sqlite3VdbeResolveLabel(v, addrCkFault); - zErr = sqlite3MPrintf(db, "CHECK constraint failed in %s", - pTab->zName); - sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); - integrityCheckResultRow(v, 3); - sqlite3VdbeResolveLabel(v, addrCkOk); - sqlite3ExprCachePop(pParse); + sqlite3ExprListDelete(db, pCheck); } /* Validate index entries for the current row */ for(j=0, pIdx=pTab->pIndex; pIdx && !isQuick; pIdx=pIdx->pNext, j++){ diff --git a/src/pragma.h b/src/pragma.h index 9b1c723b3e..d05657c799 100644 --- a/src/pragma.h +++ b/src/pragma.h @@ -417,7 +417,7 @@ static const PragmaName aPragmaName[] = { #endif {/* zName: */ "optimize", /* ePragTyp: */ PragTyp_OPTIMIZE, - /* ePragFlg: */ PragFlg_Result1, + /* ePragFlg: */ PragFlg_Result1|PragFlg_NeedSchema, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) diff --git a/src/select.c b/src/select.c index bb055c7894..334307cce7 100644 --- a/src/select.c +++ b/src/select.c @@ -76,7 +76,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){ sqlite3ExprDelete(db, p->pLimit); sqlite3ExprDelete(db, p->pOffset); if( p->pWith ) sqlite3WithDelete(db, p->pWith); - if( bFree ) sqlite3DbFree(db, p); + if( bFree ) sqlite3DbFreeNN(db, p); p = pPrior; bFree = 1; } @@ -1055,7 +1055,7 @@ void sqlite3KeyInfoUnref(KeyInfo *p){ if( p ){ assert( p->nRef>0 ); p->nRef--; - if( p->nRef==0 ) sqlite3DbFree(p->db, p); + if( p->nRef==0 ) sqlite3DbFreeNN(p->db, p); } } @@ -2900,7 +2900,7 @@ static int multiSelectOrderBy( if( pNew==0 ) return SQLITE_NOMEM_BKPT; pNew->flags |= EP_IntValue; pNew->u.iValue = i; - pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew); + p->pOrderBy = pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew); if( pOrderBy ) pOrderBy->a[nOrderBy++].u.x.iOrderByCol = (u16)i; } } diff --git a/src/shell.c b/src/shell.c index 1236b12a0e..8341d828c1 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1488,13 +1488,72 @@ static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){ raw_printf(out,"'"); } +/* +** Find a string that is not found anywhere in z[]. Return a pointer +** to that string. +** +** Try to use zA and zB first. If both of those are already found in z[] +** then make up some string and store it in the buffer zBuf. +*/ +static const char *unused_string( + const char *z, /* Result must not appear anywhere in z */ + const char *zA, const char *zB, /* Try these first */ + char *zBuf /* Space to store a generated string */ +){ + unsigned i = 0; + if( strstr(z, zA)==0 ) return zA; + if( strstr(z, zB)==0 ) return zB; + do{ + sqlite3_snprintf(20,zBuf,"(%s%u)", zA, i++); + }while( strstr(z,zBuf)!=0 ); + return zBuf; +} + /* ** Output the given string as a quoted string using SQL quoting conventions. ** -** The "\n" and "\r" characters are converted to char(10) and char(13) -** to prevent them from being transformed by end-of-line translators. +** See also: output_quoted_escaped_string() */ static void output_quoted_string(FILE *out, const char *z){ + int i; + char c; + setBinaryMode(out, 1); + for(i=0; (c = z[i])!=0 && c!='\''; i++){} + if( c==0 ){ + utf8_printf(out,"'%s'",z); + }else{ + raw_printf(out, "'"); + while( *z ){ + for(i=0; (c = z[i])!=0 && c!='\''; i++){} + if( c=='\'' ) i++; + if( i ){ + utf8_printf(out, "%.*s", i, z); + z += i; + } + if( c=='\'' ){ + raw_printf(out, "'"); + continue; + } + if( c==0 ){ + break; + } + z++; + } + raw_printf(out, "'"); + } + setTextMode(out, 1); +} + +/* +** Output the given string as a quoted string using SQL quoting conventions. +** Additionallly , escape the "\n" and "\r" characters so that they do not +** get corrupted by end-of-line translation facilities in some operating +** systems. +** +** This is like output_quoted_string() but with the addition of the \r\n +** escape mechanism. +*/ +static void output_quoted_escaped_string(FILE *out, const char *z){ int i; char c; setBinaryMode(out, 1); @@ -1502,40 +1561,52 @@ static void output_quoted_string(FILE *out, const char *z){ if( c==0 ){ utf8_printf(out,"'%s'",z); }else{ - int inQuote = 0; - int bStarted = 0; + const char *zNL = 0; + const char *zCR = 0; + int nNL = 0; + int nCR = 0; + char zBuf1[20], zBuf2[20]; + for(i=0; z[i]; i++){ + if( z[i]=='\n' ) nNL++; + if( z[i]=='\r' ) nCR++; + } + if( nNL ){ + raw_printf(out, "replace("); + zNL = unused_string(z, "\\n", "\\012", zBuf1); + } + if( nCR ){ + raw_printf(out, "replace("); + zCR = unused_string(z, "\\r", "\\015", zBuf2); + } + raw_printf(out, "'"); while( *z ){ for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){} if( c=='\'' ) i++; if( i ){ - if( !inQuote ){ - if( bStarted ) raw_printf(out, "||"); - raw_printf(out, "'"); - inQuote = 1; - } utf8_printf(out, "%.*s", i, z); z += i; - bStarted = 1; } if( c=='\'' ){ raw_printf(out, "'"); continue; } - if( inQuote ){ - raw_printf(out, "'"); - inQuote = 0; - } if( c==0 ){ break; } - for(i=0; (c = z[i])=='\r' || c=='\n'; i++){ - if( bStarted ) raw_printf(out, "||"); - raw_printf(out, "char(%d)", c); - bStarted = 1; + z++; + if( c=='\n' ){ + raw_printf(out, "%s", zNL); + continue; } - z += i; + raw_printf(out, "%s", zCR); + } + raw_printf(out, "'"); + if( nCR ){ + raw_printf(out, ",'%s',char(13))", zCR); + } + if( nNL ){ + raw_printf(out, ",'%s',char(10))", zNL); } - if( inQuote ) raw_printf(out, "'"); } setTextMode(out, 1); } @@ -1998,21 +2069,53 @@ static int shell_callback( setTextMode(p->out, 1); break; } - case MODE_Quote: case MODE_Insert: { if( azArg==0 ) break; - if( p->cMode==MODE_Insert ){ - utf8_printf(p->out,"INSERT INTO %s",p->zDestTable); - if( p->showHeader ){ - raw_printf(p->out,"("); - for(i=0; i0 ? ",": ""; - utf8_printf(p->out, "%s%s", zSep, azCol[i]); + utf8_printf(p->out,"INSERT INTO %s",p->zDestTable); + if( p->showHeader ){ + raw_printf(p->out,"("); + for(i=0; i0 ) raw_printf(p->out, ","); + if( quoteChar(azCol[i]) ){ + char *z = sqlite3_mprintf("\"%w\"", azCol[i]); + utf8_printf(p->out, "%s", z); + sqlite3_free(z); + }else{ + raw_printf(p->out, "%s", azCol[i]); } - raw_printf(p->out,")"); } - raw_printf(p->out," VALUES("); - }else if( p->cnt==0 && p->showHeader ){ + raw_printf(p->out,")"); + } + p->cnt++; + for(i=0; iout, i>0 ? "," : " VALUES("); + if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){ + utf8_printf(p->out,"NULL"); + }else if( aiType && aiType[i]==SQLITE_TEXT ){ + output_quoted_escaped_string(p->out, azArg[i]); + }else if( aiType && aiType[i]==SQLITE_INTEGER ){ + utf8_printf(p->out,"%s", azArg[i]); + }else if( aiType && aiType[i]==SQLITE_FLOAT ){ + char z[50]; + double r = sqlite3_column_double(p->pStmt, i); + sqlite3_snprintf(50,z,"%!.20g", r); + raw_printf(p->out, "%s", z); + }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){ + const void *pBlob = sqlite3_column_blob(p->pStmt, i); + int nBlob = sqlite3_column_bytes(p->pStmt, i); + output_hex_blob(p->out, pBlob, nBlob); + }else if( isNumber(azArg[i], 0) ){ + utf8_printf(p->out,"%s", azArg[i]); + }else{ + output_quoted_escaped_string(p->out, azArg[i]); + } + } + raw_printf(p->out,");\n"); + break; + } + case MODE_Quote: { + if( azArg==0 ) break; + if( p->cnt==0 && p->showHeader ){ for(i=0; i0 ) raw_printf(p->out, ","); output_quoted_string(p->out, azCol[i]); @@ -2021,32 +2124,29 @@ static int shell_callback( } p->cnt++; for(i=0; i0 ? ",": ""; + if( i>0 ) raw_printf(p->out, ","); if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){ - utf8_printf(p->out,"%sNULL",zSep); + utf8_printf(p->out,"NULL"); }else if( aiType && aiType[i]==SQLITE_TEXT ){ - if( zSep[0] ) utf8_printf(p->out,"%s",zSep); output_quoted_string(p->out, azArg[i]); }else if( aiType && aiType[i]==SQLITE_INTEGER ){ - utf8_printf(p->out,"%s%s",zSep, azArg[i]); + utf8_printf(p->out,"%s", azArg[i]); }else if( aiType && aiType[i]==SQLITE_FLOAT ){ char z[50]; double r = sqlite3_column_double(p->pStmt, i); sqlite3_snprintf(50,z,"%!.20g", r); - raw_printf(p->out, "%s%s", zSep, z); + raw_printf(p->out, "%s", z); }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){ const void *pBlob = sqlite3_column_blob(p->pStmt, i); int nBlob = sqlite3_column_bytes(p->pStmt, i); - if( zSep[0] ) utf8_printf(p->out,"%s",zSep); output_hex_blob(p->out, pBlob, nBlob); }else if( isNumber(azArg[i], 0) ){ - utf8_printf(p->out,"%s%s",zSep, azArg[i]); + utf8_printf(p->out,"%s", azArg[i]); }else{ - if( zSep[0] ) utf8_printf(p->out,"%s",zSep); output_quoted_string(p->out, azArg[i]); } } - raw_printf(p->out,p->cMode==MODE_Quote?"\n":");\n"); + raw_printf(p->out,"\n"); break; } case MODE_Ascii: { @@ -4331,29 +4431,30 @@ static int lintFkeyIndexes( "SELECT " " 'EXPLAIN QUERY PLAN SELECT rowid FROM ' || quote(s.name) || ' WHERE '" " || group_concat(quote(s.name) || '.' || quote(f.[from]) || '=?' " - " || fkey_collate_clause(f.[table], f.[to], s.name, f.[from]),' AND ')" + " || fkey_collate_clause(" + " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]),' AND ')" ", " " 'SEARCH TABLE ' || s.name || ' USING COVERING INDEX*('" " || group_concat('*=?', ' AND ') || ')'" ", " " s.name || '(' || group_concat(f.[from], ', ') || ')'" ", " - " f.[table] || '(' || group_concat(COALESCE(f.[to], " - " (SELECT name FROM pragma_table_info(f.[table]) WHERE pk=seq+1)" - " )) || ')'" + " f.[table] || '(' || group_concat(COALESCE(f.[to], p.[name])) || ')'" ", " " 'CREATE INDEX ' || quote(s.name ||'_'|| group_concat(f.[from], '_'))" " || ' ON ' || quote(s.name) || '('" " || group_concat(quote(f.[from]) ||" - " fkey_collate_clause(f.[table], f.[to], s.name, f.[from]), ', ')" + " fkey_collate_clause(" + " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]), ', ')" " || ');'" ", " " f.[table] " - "FROM sqlite_master AS s, pragma_foreign_key_list(s.name) AS f " + "LEFT JOIN pragma_table_info AS p ON (pk-1=seq AND p.arg=f.[table]) " "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=?)"; for(i=2; ishowHeader; ShellClearFlag(p, SHFLG_PreserveRowid); for(i=1; iout, "PRAGMA foreign_keys=OFF;\n"); raw_printf(p->out, "BEGIN TRANSACTION;\n"); p->writableSchema = 0; + p->showHeader = 0; /* Set writable_schema=ON since doing so forces SQLite to initialize ** as much of the schema as it can even if the sqlite_master table is ** corrupt. */ @@ -4756,6 +4862,7 @@ static int do_meta_command(char *zLine, ShellState *p){ sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0); raw_printf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n"); + p->showHeader = savedShowHeader; }else if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){ diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 3f9fb2fccb..b561d8244d 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -2210,9 +2210,6 @@ int sqlite3_total_changes(sqlite3*); ** ^A call to sqlite3_interrupt(D) that occurs when there are no running ** SQL statements is a no-op and has no effect on SQL statements ** that are started after the sqlite3_interrupt() call returns. -** -** If the database connection closes while [sqlite3_interrupt()] -** is running then bad things will likely happen. */ void sqlite3_interrupt(sqlite3*); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index c5f5ccf0da..6cffd59ee7 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2447,6 +2447,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 *zName; /* Token associated with this expression */ @@ -2462,7 +2463,7 @@ struct ExprList { } x; int iConstExprReg; /* Register in which Expr value is cached */ } u; - } *a; /* Alloc a power of two greater or equal to nExpr */ + } a[1]; /* One slot for each expression in the list */ }; /* @@ -3480,6 +3481,7 @@ void *sqlite3Realloc(void*, u64); void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64); void *sqlite3DbRealloc(sqlite3 *, void *, u64); void sqlite3DbFree(sqlite3*, void*); +void sqlite3DbFreeNN(sqlite3*, void*); int sqlite3MallocSize(void*); int sqlite3DbMallocSize(sqlite3*, void*); void *sqlite3ScratchMalloc(int); diff --git a/src/tokenize.c b/src/tokenize.c index 7f5f298987..2aab334ae9 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -604,7 +604,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ while( pParse->pAinc ){ AutoincInfo *p = pParse->pAinc; pParse->pAinc = p->pNext; - sqlite3DbFree(db, p); + sqlite3DbFreeNN(db, p); } while( pParse->pZombieTab ){ Table *p = pParse->pZombieTab; diff --git a/src/vdbe.c b/src/vdbe.c index 406394c5be..a990afb11d 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2440,7 +2440,7 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ ** ** The value extracted is stored in register P3. ** -** If the column contains fewer than P2 fields, then extract a NULL. Or, +** If the record contains fewer than P2 fields, then extract a NULL. Or, ** if the P4 argument is a P4_MEM use the value of the P4 argument as ** the result. ** @@ -2449,7 +2449,7 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ ** The first OP_Column against a pseudo-table after the value of the content ** register has changed should have this bit set. ** -** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 when +** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 then ** the result is guaranteed to only be used as the argument of a length() ** or typeof() function, respectively. The loading of large blobs can be ** skipped for length() and all content loading can be skipped for typeof(). @@ -2710,18 +2710,18 @@ op_column_out: */ case OP_Affinity: { const char *zAffinity; /* The affinity to be applied */ - char cAff; /* A single character of affinity */ zAffinity = pOp->p4.z; assert( zAffinity!=0 ); + assert( pOp->p2>0 ); assert( zAffinity[pOp->p2]==0 ); pIn1 = &aMem[pOp->p1]; - while( (cAff = *(zAffinity++))!=0 ){ + do{ assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] ); assert( memIsValid(pIn1) ); - applyAffinity(pIn1, cAff, encoding); + applyAffinity(pIn1, *(zAffinity++), encoding); pIn1++; - } + }while( zAffinity[0] ); break; } @@ -2892,7 +2892,6 @@ case OP_MakeRecord: { pOut->u.nZero = nZero; pOut->flags |= MEM_Zero; } - pOut->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */ REGISTER_TRACE(pOp->p3, pOut); UPDATE_MAX_BLOBSIZE(pOut); break; @@ -4077,7 +4076,7 @@ case OP_Found: { /* jump, in3 */ } } rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, pIdxKey, 0, 0, &res); - if( pFree ) sqlite3DbFree(db, pFree); + if( pFree ) sqlite3DbFreeNN(db, pFree); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } @@ -5387,10 +5386,17 @@ case OP_IdxGE: { /* jump */ ** might be moved into the newly deleted root page in order to keep all ** root pages contiguous at the beginning of the database. The former ** value of the root page that moved - its value before the move occurred - -** is stored in register P2. If no page -** movement was required (because the table being dropped was already -** the last one in the database) then a zero is stored in register P2. -** If AUTOVACUUM is disabled then a zero is stored in register P2. +** is stored in register P2. If no page movement was required (because the +** table being dropped was already the last one in the database) then a +** zero is stored in register P2. If AUTOVACUUM is disabled then a zero +** is stored in register P2. +** +** This opcode throws an error if there are any active reader VMs when +** it is invoked. This is done to avoid the difficulty associated with +** updating existing cursors when a root page is moved in an AUTOVACUUM +** database. This error is thrown even if the database is not an AUTOVACUUM +** db in order to avoid introducing an incompatibility between autovacuum +** and non-autovacuum modes. ** ** See also: Clear */ @@ -5595,7 +5601,7 @@ case OP_ParseSchema: { assert( !db->mallocFailed ); rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); if( rc==SQLITE_OK ) rc = initData.rc; - sqlite3DbFree(db, zSql); + sqlite3DbFreeNN(db, zSql); db->init.busy = 0; } } diff --git a/src/vdbeaux.c b/src/vdbeaux.c index a8f215420a..3fcfb681d1 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -811,7 +811,7 @@ void sqlite3VdbeJumpHere(Vdbe *p, int addr){ */ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){ if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){ - sqlite3DbFree(db, pDef); + sqlite3DbFreeNN(db, pDef); } } @@ -822,11 +822,11 @@ static void vdbeFreeOpArray(sqlite3 *, Op *, int); */ static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){ if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc); - sqlite3DbFree(db, p); + sqlite3DbFreeNN(db, p); } static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){ freeEphemeralFunction(db, p->pFunc); - sqlite3DbFree(db, p); + sqlite3DbFreeNN(db, p); } static void freeP4(sqlite3 *db, int p4type, void *p4){ assert( db ); @@ -885,8 +885,8 @@ static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){ sqlite3DbFree(db, pOp->zComment); #endif } + sqlite3DbFreeNN(db, aOp); } - sqlite3DbFree(db, aOp); } /* @@ -1559,7 +1559,7 @@ static void releaseMemArray(Mem *p, int N){ if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){ sqlite3VdbeMemRelease(p); }else if( p->szMalloc ){ - sqlite3DbFree(db, p->zMalloc); + sqlite3DbFreeNN(db, p->zMalloc); p->szMalloc = 0; } @@ -2930,7 +2930,6 @@ int sqlite3VdbeReset(Vdbe *p){ } } #endif - p->iCurrentTime = 0; p->magic = VDBE_MAGIC_RESET; return p->rc & db->errMask; } @@ -3040,7 +3039,7 @@ void sqlite3VdbeDelete(Vdbe *p){ } p->magic = VDBE_MAGIC_DEAD; p->db = 0; - sqlite3DbFree(db, p); + sqlite3DbFreeNN(db, p); } /* @@ -4599,7 +4598,7 @@ static void vdbeFreeUnpacked(sqlite3 *db, int nField, UnpackedRecord *p){ Mem *pMem = &p->aMem[i]; if( pMem->zMalloc ) sqlite3VdbeMemRelease(pMem); } - sqlite3DbFree(db, p); + sqlite3DbFreeNN(db, p); } } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ @@ -4666,7 +4665,7 @@ void sqlite3VdbePreUpdateHook( for(i=0; inField; i++){ sqlite3VdbeMemRelease(&preupdate.aNew[i]); } - sqlite3DbFree(db, preupdate.aNew); + sqlite3DbFreeNN(db, preupdate.aNew); } } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ diff --git a/src/vdbemem.c b/src/vdbemem.c index 656e19bfa8..d7963cb7e7 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -131,7 +131,7 @@ SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n); bPreserve = 0; }else{ - if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc); + if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc); pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n); } if( pMem->zMalloc==0 ){ @@ -341,7 +341,7 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){ ctx.pFunc = pFunc; pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */ assert( (pMem->flags & MEM_Dyn)==0 ); - if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc); + if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc); memcpy(pMem, &t, sizeof(t)); rc = ctx.isError; } @@ -392,7 +392,7 @@ static SQLITE_NOINLINE void vdbeMemClear(Mem *p){ vdbeMemClearExternAndSetNull(p); } if( p->szMalloc ){ - sqlite3DbFree(p->db, p->zMalloc); + sqlite3DbFreeNN(p->db, p->zMalloc); p->szMalloc = 0; } p->z = 0; @@ -420,7 +420,7 @@ void sqlite3VdbeMemRelease(Mem *p){ ** If the double is out of range of a 64-bit signed integer then ** return the closest available 64-bit signed integer. */ -static i64 doubleToInt64(double r){ +static SQLITE_NOINLINE i64 doubleToInt64(double r){ #ifdef SQLITE_OMIT_FLOATING_POINT /* When floating-point is omitted, double and int64 are the same thing */ return r; @@ -456,6 +456,11 @@ static i64 doubleToInt64(double r){ ** ** If pMem represents a string value, its encoding might be changed. */ +static SQLITE_NOINLINE i64 memIntValue(Mem *pMem){ + i64 value = 0; + sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc); + return value; +} i64 sqlite3VdbeIntValue(Mem *pMem){ int flags; assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); @@ -466,10 +471,8 @@ i64 sqlite3VdbeIntValue(Mem *pMem){ }else if( flags & MEM_Real ){ return doubleToInt64(pMem->u.r); }else if( flags & (MEM_Str|MEM_Blob) ){ - i64 value = 0; assert( pMem->z || pMem->n==0 ); - sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc); - return value; + return memIntValue(pMem); }else{ return 0; } @@ -481,6 +484,12 @@ i64 sqlite3VdbeIntValue(Mem *pMem){ ** value. If it is a string or blob, try to convert it to a double. ** If it is a NULL, return 0.0. */ +static SQLITE_NOINLINE double memRealValue(Mem *pMem){ + /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ + double val = (double)0; + sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc); + return val; +} double sqlite3VdbeRealValue(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); @@ -489,10 +498,7 @@ double sqlite3VdbeRealValue(Mem *pMem){ }else if( pMem->flags & MEM_Int ){ return (double)pMem->u.i; }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ - /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ - double val = (double)0; - sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc); - return val; + return memRealValue(pMem); }else{ /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ return (double)0; @@ -1117,7 +1123,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ pRec->aMem[i].db = db; } }else{ - sqlite3DbFree(db, pRec); + sqlite3DbFreeNN(db, pRec); pRec = 0; } } @@ -1229,7 +1235,7 @@ static int valueFromFunction( for(i=0; ipKeyInfo); - sqlite3DbFree(db, pRec); + sqlite3DbFreeNN(db, pRec); } } #endif /* ifdef SQLITE_ENABLE_STAT4 */ @@ -1679,7 +1685,7 @@ void sqlite3ValueSetStr( void sqlite3ValueFree(sqlite3_value *v){ if( !v ) return; sqlite3VdbeMemRelease((Mem *)v); - sqlite3DbFree(((Mem*)v)->db, v); + sqlite3DbFreeNN(((Mem*)v)->db, v); } /* diff --git a/src/vdbesort.c b/src/vdbesort.c index 631fb19616..7dbb1b063f 100644 --- a/src/vdbesort.c +++ b/src/vdbesort.c @@ -858,37 +858,36 @@ static int vdbeSorterCompareInt( assert( (s1>0 && s1<7) || s1==8 || s1==9 ); assert( (s2>0 && s2<7) || s2==8 || s2==9 ); - if( s1>7 && s2>7 ){ + if( s1==s2 ){ + /* The two values have the same sign. Compare using memcmp(). */ + static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8, 0, 0, 0 }; + const u8 n = aLen[s1]; + int i; + res = 0; + for(i=0; i7 && s2>7 ){ res = s1 - s2; }else{ - if( s1==s2 ){ - if( (*v1 ^ *v2) & 0x80 ){ - /* The two values have different signs */ - res = (*v1 & 0x80) ? -1 : +1; - }else{ - /* The two values have the same sign. Compare using memcmp(). */ - static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8 }; - int i; - res = 0; - for(i=0; i7 ){ + res = +1; + }else if( s1>7 ){ + res = -1; }else{ - if( s2>7 ){ - res = +1; - }else if( s1>7 ){ - res = -1; - }else{ - res = s1 - s2; - } - assert( res!=0 ); + res = s1 - s2; + } + assert( res!=0 ); - if( res>0 ){ - if( *v1 & 0x80 ) res = -1; - }else{ - if( *v2 & 0x80 ) res = +1; - } + if( res>0 ){ + if( *v1 & 0x80 ) res = -1; + }else{ + if( *v2 & 0x80 ) res = +1; } } diff --git a/src/where.c b/src/where.c index a423fa1839..44a8df8d94 100644 --- a/src/where.c +++ b/src/where.c @@ -1786,7 +1786,7 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){ p->u.vtab.idxStr = 0; }else if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && p->u.btree.pIndex!=0 ){ sqlite3DbFree(db, p->u.btree.pIndex->zColAff); - sqlite3DbFree(db, p->u.btree.pIndex); + sqlite3DbFreeNN(db, p->u.btree.pIndex); p->u.btree.pIndex = 0; } } @@ -1796,7 +1796,7 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){ ** Deallocate internal memory used by a WhereLoop object */ static void whereLoopClear(sqlite3 *db, WhereLoop *p){ - if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm); + if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm); whereLoopClearUnion(db, p); whereLoopInit(p); } @@ -1811,7 +1811,7 @@ static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){ paNew = sqlite3DbMallocRawNN(db, sizeof(p->aLTerm[0])*n); if( paNew==0 ) return SQLITE_NOMEM_BKPT; memcpy(paNew, p->aLTerm, sizeof(p->aLTerm[0])*p->nLSlot); - if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm); + if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm); p->aLTerm = paNew; p->nLSlot = n; return SQLITE_OK; @@ -1841,7 +1841,7 @@ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){ */ static void whereLoopDelete(sqlite3 *db, WhereLoop *p){ whereLoopClear(db, p); - sqlite3DbFree(db, p); + sqlite3DbFreeNN(db, p); } /* @@ -1862,7 +1862,7 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ pWInfo->pLoops = p->pNextLoop; whereLoopDelete(db, p); } - sqlite3DbFree(db, pWInfo); + sqlite3DbFreeNN(db, pWInfo); } } @@ -3253,7 +3253,7 @@ static int whereLoopAddVirtual( } if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr); - sqlite3DbFree(pParse->db, p); + sqlite3DbFreeNN(pParse->db, p); return rc; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -4108,7 +4108,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ if( nFrom==0 ){ sqlite3ErrorMsg(pParse, "no query solution"); - sqlite3DbFree(db, pSpace); + sqlite3DbFreeNN(db, pSpace); return SQLITE_ERROR; } @@ -4184,7 +4184,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ pWInfo->nRowOut = pFrom->nRow; /* Free temporary memory and return success */ - sqlite3DbFree(db, pSpace); + sqlite3DbFreeNN(db, pSpace); return SQLITE_OK; } @@ -4262,7 +4262,8 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ if( pLoop->wsFlags ){ pLoop->nOut = (LogEst)1; pWInfo->a[0].pWLoop = pLoop; - pLoop->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); + assert( pWInfo->sMaskSet.n==1 && iCur==pWInfo->sMaskSet.ix[0] ); + pLoop->maskSelf = 1; /* sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); */ pWInfo->a[0].iTabCur = iCur; pWInfo->nRowOut = 1; if( pWInfo->pOrderBy ) pWInfo->nOBSat = pWInfo->pOrderBy->nExpr; diff --git a/test/insert4.test b/test/insert4.test index 3eece87e5f..85cbf82a56 100644 --- a/test/insert4.test +++ b/test/insert4.test @@ -15,6 +15,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix insert4 ifcapable !view||!subquery { finish_test @@ -566,4 +567,36 @@ do_catchsql_test insert4-9.1 { INSERT INTO t1(x) VALUES(5 COLLATE xyzzy) UNION SELECT 0; } {1 {no such collation sequence: xyzzy}} +#------------------------------------------------------------------------- +# Check that running an integrity-check does not disable the xfer +# optimization for tables with CHECK constraints. +# +do_execsql_test 10.1 { + CREATE TABLE t8( + rid INTEGER, + pid INTEGER, + mid INTEGER, + px INTEGER DEFAULT(0) CHECK(px IN(0, 1)) + ); + CREATE TEMP TABLE x( + rid INTEGER, + pid INTEGER, + mid INTEGER, + px INTEGER DEFAULT(0) CHECK(px IN(0, 1)) + ); +} +do_test 10.2 { + set sqlite3_xferopt_count 0 + execsql { INSERT INTO x SELECT * FROM t8 } + set sqlite3_xferopt_count +} {1} + +do_test 10.3 { + execsql { PRAGMA integrity_check } + set sqlite3_xferopt_count 0 + execsql { INSERT INTO x SELECT * FROM t8 } + set sqlite3_xferopt_count +} {1} + + finish_test diff --git a/test/json102.test b/test/json102.test index a4d88dbeaa..d1f2a4d36d 100644 --- a/test/json102.test +++ b/test/json102.test @@ -298,4 +298,25 @@ for {set i 0} {$i<100} {incr i} { } {1} } +#------------------------------------------------------------------------- +# 2017-04-08 ticket b93be8729a895a528e2849fca99f7 +# JSON extension accepts invalid numeric values +# +# JSON does not allow leading zeros. But the JSON extension was +# allowing them. The following tests verify that the problem is now +# fixed. +# +do_execsql_test json102-1401 { SELECT json_valid('{"x":01}') } 0 +do_execsql_test json102-1402 { SELECT json_valid('{"x":-01}') } 0 +do_execsql_test json102-1403 { SELECT json_valid('{"x":0}') } 1 +do_execsql_test json102-1404 { SELECT json_valid('{"x":-0}') } 1 +do_execsql_test json102-1405 { SELECT json_valid('{"x":0.1}') } 1 +do_execsql_test json102-1406 { SELECT json_valid('{"x":-0.1}') } 1 +do_execsql_test json102-1407 { SELECT json_valid('{"x":0.0000}') } 1 +do_execsql_test json102-1408 { SELECT json_valid('{"x":-0.0000}') } 1 +do_execsql_test json102-1409 { SELECT json_valid('{"x":01.5}') } 0 +do_execsql_test json102-1410 { SELECT json_valid('{"x":-01.5}') } 0 +do_execsql_test json102-1411 { SELECT json_valid('{"x":00}') } 0 +do_execsql_test json102-1412 { SELECT json_valid('{"x":-00}') } 0 + finish_test diff --git a/test/pragmafault.test b/test/pragmafault.test new file mode 100644 index 0000000000..34718aeca1 --- /dev/null +++ b/test/pragmafault.test @@ -0,0 +1,39 @@ +# 2010 June 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. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/lock_common.tcl +source $testdir/malloc_common.tcl +set testprefix pragmafault + +db close +sqlite3 db test.db +sqlite3_db_config_lookaside db 0 0 0 +do_execsql_test 1.0 { + CREATE TABLE t1(a, b, CHECK(a!=b)); + INSERT INTO t1 VALUES(1, 2); + INSERT INTO t1 VALUES(3, 4); +} +faultsim_save_and_close + +do_faultsim_test 1 -prep { + faultsim_restore_and_reopen +} -body { + catchsql { PRAGMA integrity_check } + set {} 0 +} -test { + faultsim_test_result {0 0} +} + + +finish_test diff --git a/test/shell6.test b/test/shell6.test new file mode 100644 index 0000000000..25bfa32338 --- /dev/null +++ b/test/shell6.test @@ -0,0 +1,121 @@ +# 2016 December 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. +# +#*********************************************************************** +# +# Test the shell tool ".lint fkey-indexes" command. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +ifcapable !vtab {finish_test; return} +set testprefix shell6 +set CLI [test_find_cli] +db close +forcedelete test.db test.db-journal test.db-wal + +foreach {tn schema output} { + 1 { + CREATE TABLE p1(a PRIMARY KEY, b); + CREATE TABLE c1(x, y REFERENCES p1); + } { + CREATE INDEX 'c1_y' ON 'c1'('y'); --> p1(a) + } + + 2 { + CREATE TABLE p1(a PRIMARY KEY, b); + CREATE TABLE c2(x REFERENCES p1, y REFERENCES p1); + } { + CREATE INDEX 'c2_y' ON 'c2'('y'); --> p1(a) + CREATE INDEX 'c2_x' ON 'c2'('x'); --> p1(a) + } + + 3 { + CREATE TABLE 'p 1'(a, b, c, PRIMARY KEY(c, b)); + CREATE TABLE 'c 1'(x, y, z, FOREIGN KEY (z, y) REFERENCES 'p 1'); + } { + CREATE INDEX 'c 1_z_y' ON 'c 1'('z', 'y'); --> p 1(c,b) + } + + 4 { + CREATE TABLE p1(a, 'b b b' PRIMARY KEY); + CREATE TABLE c1('x y z' REFERENCES p1); + CREATE INDEX i1 ON c1('x y z') WHERE "x y z" IS NOT NULL; + } { + } + + 5 { + CREATE TABLE p1(a, 'b b b' PRIMARY KEY); + CREATE TABLE c1('x y z' REFERENCES p1); + CREATE INDEX i1 ON c1('x y z') WHERE "x y z" IS NOT 12; + } { + CREATE INDEX 'c1_x y z' ON 'c1'('x y z'); --> p1(b b b) + } + + 6 { + CREATE TABLE x1(a, b, c, UNIQUE(a, b)); + CREATE TABLE y1(a, b, c, FOREIGN KEY(b, a) REFERENCES x1(a, b)); + CREATE INDEX y1i ON y1(a, c, b); + } { + CREATE INDEX 'y1_b_a' ON 'y1'('b', 'a'); --> x1(a,b) + } + + 6 { + CREATE TABLE x1(a COLLATE nocase, b, UNIQUE(a)); + CREATE TABLE y1(a COLLATE rtrim REFERENCES x1(a)); + } { + CREATE INDEX 'y1_a' ON 'y1'('a' COLLATE nocase); --> x1(a) + } + + 7 { + CREATE TABLE x1(a PRIMARY KEY COLLATE nocase, b); + CREATE TABLE y1(a REFERENCES x1); + } { + CREATE INDEX 'y1_a' ON 'y1'('a' COLLATE nocase); --> x1(a) + } + + 8 { + CREATE TABLE x1(a, b COLLATE nocase, c COLLATE rtrim, PRIMARY KEY(c, b, a)); + CREATE TABLE y1(d, e, f, FOREIGN KEY(d, e, f) REFERENCES x1); + } { + CREATE INDEX 'y1_d_e_f' ON 'y1'('d' COLLATE rtrim, 'e' COLLATE nocase, 'f'); --> x1(c,b,a) + } + + 9 { + CREATE TABLE p1(a, b UNIQUE); + CREATE TABLE c1(x INTEGER PRIMARY KEY REFERENCES p1(b)); + } { + } + +} { + forcedelete test.db + sqlite3 db test.db + execsql $schema + + set expected "" + foreach line [split $output "\n"] { + set line [string trim $line] + if {$line!=""} { + append expected "$line\n" + } + } + + do_test 1.$tn.1 { + set RES [catchcmd test.db [list .lint fkey-indexes]] + } [list 0 [string trim $expected]] + + do_test 1.$tn.2 { + execsql [lindex $RES 1] + catchcmd test.db [list .lint fkey-indexes] + } {0 {}} + + db close +} + +finish_test diff --git a/test/sync2.test b/test/sync2.test index 4f6ed7754c..46e8bc72fb 100644 --- a/test/sync2.test +++ b/test/sync2.test @@ -22,7 +22,7 @@ set testprefix sync2 # enabled. Also, since every test uses an ATTACHed database, they # are only run when ATTACH is enabled. # -ifcapable !pager_pragmas||!attach { +ifcapable !pager_pragmas||!attach||!dirsync { finish_test return } diff --git a/tool/mkpragmatab.tcl b/tool/mkpragmatab.tcl index 59b245cc76..080e3da003 100644 --- a/tool/mkpragmatab.tcl +++ b/tool/mkpragmatab.tcl @@ -363,7 +363,7 @@ set pragma_def { FLAG: Result0 NAME: optimize - FLAG: Result1 + FLAG: Result1 NeedSchema } # Open the output file