Index: Makefile.in ================================================================== --- Makefile.in +++ Makefile.in @@ -392,11 +392,10 @@ # Statically linked extensions # TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/closure.c \ - $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/nextchar.c \ $(TOP)/ext/misc/percentile.c \ Index: Makefile.msc ================================================================== --- Makefile.msc +++ Makefile.msc @@ -861,11 +861,10 @@ # Statically linked extensions # TESTEXT = \ $(TOP)\ext\misc\amatch.c \ $(TOP)\ext\misc\closure.c \ - $(TOP)\ext\misc\eval.c \ $(TOP)\ext\misc\fileio.c \ $(TOP)\ext\misc\fuzzer.c \ $(TOP)\ext\misc\ieee754.c \ $(TOP)\ext\misc\nextchar.c \ $(TOP)\ext\misc\percentile.c \ Index: VERSION ================================================================== --- VERSION +++ VERSION @@ -1,1 +1,1 @@ -3.8.8 +3.8.7.1 Index: configure ================================================================== --- configure +++ configure @@ -1,8 +1,8 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.62 for sqlite 3.8.8. +# Generated by GNU Autoconf 2.62 for sqlite 3.8.7.1. # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. @@ -741,12 +741,12 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' -PACKAGE_VERSION='3.8.8' -PACKAGE_STRING='sqlite 3.8.8' +PACKAGE_VERSION='3.8.7.1' +PACKAGE_STRING='sqlite 3.8.7.1' PACKAGE_BUGREPORT='' # Factoring default headers for most tests. ac_includes_default="\ #include @@ -1481,11 +1481,11 @@ # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures sqlite 3.8.8 to adapt to many kinds of systems. +\`configure' configures sqlite 3.8.7.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. @@ -1546,11 +1546,11 @@ _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of sqlite 3.8.8:";; + short | recursive ) echo "Configuration of sqlite 3.8.7.1:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options @@ -1662,11 +1662,11 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -sqlite configure 3.8.8 +sqlite configure 3.8.7.1 generated by GNU Autoconf 2.62 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation @@ -1676,11 +1676,11 @@ fi cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by sqlite $as_me 3.8.8, which was +It was created by sqlite $as_me 3.8.7.1, which was generated by GNU Autoconf 2.62. Invocation command line was $ $0 $@ _ACEOF @@ -14019,11 +14019,11 @@ # Save the log message, to keep $[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by sqlite $as_me 3.8.8, which was +This file was extended by sqlite $as_me 3.8.7.1, which was generated by GNU Autoconf 2.62. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS @@ -14072,11 +14072,11 @@ Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_version="\\ -sqlite config.status 3.8.8 +sqlite config.status 3.8.7.1 configured by $0, generated by GNU Autoconf 2.62, with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" Copyright (C) 2008 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation DELETED ext/misc/eval.c Index: ext/misc/eval.c ================================================================== --- ext/misc/eval.c +++ /dev/null @@ -1,119 +0,0 @@ -/* -** 2014-11-10 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This SQLite extension implements SQL function eval() which runs -** SQL statements recursively. -*/ -#include "sqlite3ext.h" -SQLITE_EXTENSION_INIT1 -#include - -/* -** Structure used to accumulate the output -*/ -struct EvalResult { - char *z; /* Accumulated output */ - const char *zSep; /* Separator */ - int szSep; /* Size of the separator string */ - int nAlloc; /* Number of bytes allocated for z[] */ - int nUsed; /* Number of bytes of z[] actually used */ -}; - -/* -** Callback from sqlite_exec() for the eval() function. -*/ -static int callback(void *pCtx, int argc, char **argv, char **colnames){ - struct EvalResult *p = (struct EvalResult*)pCtx; - int i; - for(i=0; inUsed+p->szSep+1 > p->nAlloc ){ - char *zNew; - p->nAlloc = p->nAlloc*2 + sz + p->szSep + 1; - zNew = sqlite3_realloc(p->z, p->nAlloc); - if( zNew==0 ){ - sqlite3_free(p->z); - memset(p, 0, sizeof(*p)); - return 1; - } - p->z = zNew; - } - if( p->nUsed>0 ){ - memcpy(&p->z[p->nUsed], p->zSep, p->szSep); - p->nUsed += p->szSep; - } - memcpy(&p->z[p->nUsed], z, sz); - p->nUsed += sz; - } - return 0; -} - -/* -** Implementation of the eval(X) and eval(X,Y) SQL functions. -** -** Evaluate the SQL text in X. Return the results, using string -** Y as the separator. If Y is omitted, use a single space character. -*/ -static void sqlEvalFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - const char *zSql; - sqlite3 *db; - char *zErr = 0; - int rc; - struct EvalResult x; - - memset(&x, 0, sizeof(x)); - x.zSep = " "; - zSql = (const char*)sqlite3_value_text(argv[0]); - if( zSql==0 ) return; - if( argc>1 ){ - x.zSep = (const char*)sqlite3_value_text(argv[1]); - if( x.zSep==0 ) return; - } - x.szSep = (int)strlen(x.zSep); - db = sqlite3_context_db_handle(context); - rc = sqlite3_exec(db, zSql, callback, &x, &zErr); - if( rc!=SQLITE_OK ){ - sqlite3_result_error(context, zErr, -1); - sqlite3_free(zErr); - }else if( x.zSep==0 ){ - sqlite3_result_error_nomem(context); - sqlite3_free(x.z); - }else{ - sqlite3_result_text(context, x.z, x.nUsed, sqlite3_free); - } -} - - -#ifdef _WIN32 -__declspec(dllexport) -#endif -int sqlite3_eval_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi -){ - int rc = SQLITE_OK; - SQLITE_EXTENSION_INIT2(pApi); - (void)pzErrMsg; /* Unused parameter */ - rc = sqlite3_create_function(db, "eval", 1, SQLITE_UTF8, 0, - sqlEvalFunc, 0, 0); - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0, - sqlEvalFunc, 0, 0); - } - return rc; -} Index: ext/rtree/rtree6.test ================================================================== --- ext/rtree/rtree6.test +++ ext/rtree/rtree6.test @@ -100,11 +100,11 @@ } do_eqp_test rtree6.2.4.2 { SELECT * FROM t1,t2 WHERE v=10 and x1<10 and x2>10 } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0E1} - 0 1 1 {SEARCH TABLE t2 USING AUTOMATIC PARTIAL COVERING INDEX (v=?)} + 0 1 1 {SEARCH TABLE t2 USING AUTOMATIC COVERING INDEX (v=?)} } do_eqp_test rtree6.2.5 { SELECT * FROM t1,t2 WHERE k=ii AND x1 .B create table memos(text, priority INTEGER); @@ -105,70 +105,63 @@ the '.help' command. For example: .sp sqlite> .B .help .nf -.tr %. -%backup ?DB? FILE Backup DB (default "main") to FILE -%bail on|off Stop after hitting an error. Default OFF -%clone NEWDB Clone data into NEWDB from the existing database -%databases List names and files of attached databases -%dump ?TABLE? ... Dump the database in an SQL text format +.cc | +.backup ?DB? FILE Backup DB (default "main") to FILE +.bail ON|OFF Stop after hitting an error. Default OFF +.databases List names and files of attached databases +.dump ?TABLE? ... Dump the database in an SQL text format If TABLE specified, only dump tables matching LIKE pattern TABLE. -%echo on|off Turn command echo on or off -%eqp on|off Enable or disable automatic EXPLAIN QUERY PLAN -%exit Exit this program -%explain ?on|off? Turn output mode suitable for EXPLAIN on or off. +.echo ON|OFF Turn command echo on or off +.exit Exit this program +.explain ?ON|OFF? Turn output mode suitable for EXPLAIN on or off. With no args, it turns EXPLAIN on. -%fullschema Show schema and the content of sqlite_stat tables -%headers on|off Turn display of headers on or off -%help Show this message -%import FILE TABLE Import data from FILE into TABLE -%indices ?TABLE? Show names of all indices +.header(s) ON|OFF Turn display of headers on or off +.help Show this message +.import FILE TABLE Import data from FILE into TABLE +.indices ?TABLE? Show names of all indices If TABLE specified, only show indices for tables matching LIKE pattern TABLE. -%load FILE ?ENTRY? Load an extension library -%log FILE|off Turn logging on or off. FILE can be stderr/stdout -%mode MODE ?TABLE? Set output mode where MODE is one of: +.load FILE ?ENTRY? Load an extension library +.log FILE|off Turn logging on or off. FILE can be stderr/stdout +.mode MODE ?TABLE? Set output mode where MODE is one of: csv Comma-separated values column Left-aligned columns. (See .width) html HTML code insert SQL insert statements for TABLE line One value per line list Values delimited by .separator string tabs Tab-separated values tcl TCL list elements -%nullvalue STRING Use STRING in place of NULL values -%once FILENAME Output for the next SQL command only to FILENAME -%open ?FILENAME? Close existing database and reopen FILENAME -%output ?FILENAME? Send output to FILENAME or stdout -%print STRING... Print literal STRING -%prompt MAIN CONTINUE Replace the standard prompts -%quit Exit this program -%read FILENAME Execute SQL in FILENAME -%restore ?DB? FILE Restore content of DB (default "main") from FILE -%save FILE Write in-memory database into FILE -%schema ?TABLE? Show the CREATE statements +.nullvalue STRING Use STRING in place of NULL values +.open ?FILENAME? Close existing database and reopen FILENAME +.output FILENAME Send output to FILENAME +.output stdout Send output to the screen +.print STRING... Print literal STRING +.prompt MAIN CONTINUE Replace the standard prompts +.quit Exit this program +.read FILENAME Execute SQL in FILENAME +.restore ?DB? FILE Restore content of DB (default "main") from FILE +.schema ?TABLE? Show the CREATE statements If TABLE specified, only show tables matching LIKE pattern TABLE. -%separator STRING ?NL? Change separator used by output mode and .import - NL is the end-of-line mark for CSV -%shell CMD ARGS... Run CMD ARGS... in a system shell -%show Show the current values for various settings -%stats on|off Turn stats on or off -%system CMD ARGS... Run CMD ARGS... in a system shell -%tables ?TABLE? List names of tables +.separator STRING Change separator used by output mode and .import +.show Show the current values for various settings +.stats ON|OFF Turn stats on or off +.tables ?TABLE? List names of tables If TABLE specified, only list tables matching LIKE pattern TABLE. -%timeout MS Try opening locked tables for MS milliseconds -%timer on|off Turn SQL timer on or off -%trace FILE|off Output each SQL statement as it is run -%vfsname ?AUX? Print the name of the VFS stack -%width NUM1 NUM2 ... Set column widths for "column" mode - Negative values right-justify +.timeout MS Try opening locked tables for MS milliseconds +.trace FILE|off Output each SQL statement as it is run +.vfsname ?AUX? Print the name of the VFS stack +.width NUM1 NUM2 ... Set column widths for "column" mode +.timer ON|OFF Turn the CPU timer measurement on or off sqlite> +|cc . .sp .fi .SH OPTIONS .B sqlite3 has the following options: @@ -274,13 +267,13 @@ o If the -init option is present, the specified file is processed. o All other command line options are processed. .SH SEE ALSO -http://www.sqlite.org/cli.html +http://www.sqlite.org/ .br The sqlite3-doc package. .SH AUTHOR This manual page was originally written by Andreas Rottmann , for the Debian GNU/Linux system (but may be used by others). It was subsequently revised by Bill Bumgarner and further updated by Laszlo Boszormenyi . Index: src/analyze.c ================================================================== --- src/analyze.c +++ src/analyze.c @@ -1597,11 +1597,10 @@ nSample--; }else{ nRow = pIdx->aiRowEst[0]; nDist100 = ((i64)100 * pIdx->aiRowEst[0]) / pIdx->aiRowEst[iCol+1]; } - pIdx->nRowEst0 = nRow; /* Set nSum to the number of distinct (iCol+1) field prefixes that ** occur in the stat4 table for this index. Set sumEq to the sum of ** the nEq values for column iCol for the same set (adding the value ** only once where there exist duplicate prefixes). */ @@ -1859,11 +1858,11 @@ } /* Load the statistics from the sqlite_stat4 table. */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - if( rc==SQLITE_OK && OptimizationEnabled(db, SQLITE_Stat34) ){ + if( rc==SQLITE_OK ){ int lookasideEnabled = db->lookaside.bEnabled; db->lookaside.bEnabled = 0; rc = loadStat4(db, sInfo.zDatabase); db->lookaside.bEnabled = lookasideEnabled; } Index: src/auth.c ================================================================== --- src/auth.c +++ src/auth.c @@ -70,13 +70,10 @@ int sqlite3_set_authorizer( sqlite3 *db, int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), void *pArg ){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif sqlite3_mutex_enter(db->mutex); db->xAuth = (sqlite3_xauth)xAuth; db->pAuthArg = pArg; sqlite3ExpirePreparedStatements(db); sqlite3_mutex_leave(db->mutex); Index: src/backup.c ================================================================== --- src/backup.c +++ src/backup.c @@ -136,17 +136,10 @@ sqlite3* pSrcDb, /* Database connection to read from */ const char *zSrcDb /* Name of database within pSrcDb */ ){ sqlite3_backup *p; /* Value to return */ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(pSrcDb)||!sqlite3SafetyCheckOk(pDestDb) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif - /* Lock the source database handle. The destination database ** handle is not locked in this routine, but it is locked in ** sqlite3_backup_step(). The user is required to ensure that no ** other thread accesses the destination handle for the duration ** of the backup operation. Any attempt to use the destination @@ -339,13 +332,10 @@ int rc; int destMode; /* Destination journal mode */ int pgszSrc = 0; /* Source page size */ int pgszDest = 0; /* Destination page size */ -#ifdef SQLITE_ENABLE_API_ARMOR - if( p==0 ) return SQLITE_MISUSE_BKPT; -#endif sqlite3_mutex_enter(p->pSrcDb->mutex); sqlite3BtreeEnter(p->pSrc); if( p->pDestDb ){ sqlite3_mutex_enter(p->pDestDb->mutex); } @@ -631,30 +621,18 @@ /* ** Return the number of pages still to be backed up as of the most recent ** call to sqlite3_backup_step(). */ int sqlite3_backup_remaining(sqlite3_backup *p){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( p==0 ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif return p->nRemaining; } /* ** Return the total number of pages in the source database as of the most ** recent call to sqlite3_backup_step(). */ int sqlite3_backup_pagecount(sqlite3_backup *p){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( p==0 ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif return p->nPagecount; } /* ** This function is called after the contents of page iPage of the Index: src/btree.c ================================================================== --- src/btree.c +++ src/btree.c @@ -1149,27 +1149,28 @@ int cellOffset; /* Offset to the cell pointer array */ int cbrk; /* Offset to the cell content area */ int nCell; /* Number of cells on the page */ unsigned char *data; /* The page data */ unsigned char *temp; /* Temp area for cell content */ - unsigned char *src; /* Source of content */ int iCellFirst; /* First allowable cell index */ int iCellLast; /* Last possible cell index */ assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( pPage->pBt!=0 ); assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE ); assert( pPage->nOverflow==0 ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); - temp = 0; - src = data = pPage->aData; + temp = sqlite3PagerTempSpace(pPage->pBt->pPager); + data = pPage->aData; hdr = pPage->hdrOffset; cellOffset = pPage->cellOffset; nCell = pPage->nCell; assert( nCell==get2byte(&data[hdr+3]) ); usableSize = pPage->pBt->usableSize; + cbrk = get2byte(&data[hdr+5]); + memcpy(&temp[cbrk], &data[cbrk], usableSize - cbrk); cbrk = usableSize; iCellFirst = cellOffset + 2*nCell; iCellLast = usableSize - 4; for(i=0; iiCellLast ){ return SQLITE_CORRUPT_BKPT; } #endif assert( pc>=iCellFirst && pc<=iCellLast ); - size = cellSizePtr(pPage, &src[pc]); + size = cellSizePtr(pPage, &temp[pc]); cbrk -= size; #if defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK) if( cbrk=iCellFirst ); testcase( cbrk+size==usableSize ); testcase( pc+size==usableSize ); + memcpy(&data[cbrk], &temp[pc], size); put2byte(pAddr, cbrk); - if( temp==0 ){ - int x; - if( cbrk==pc ) continue; - temp = sqlite3PagerTempSpace(pPage->pBt->pPager); - x = get2byte(&data[hdr+5]); - memcpy(&temp[x], &data[x], (cbrk+size) - x); - src = temp; - } - memcpy(&data[cbrk], &src[pc], size); } assert( cbrk>=iCellFirst ); put2byte(&data[hdr+5], cbrk); data[hdr+1] = 0; data[hdr+2] = 0; @@ -1222,66 +1215,10 @@ return SQLITE_CORRUPT_BKPT; } return SQLITE_OK; } -/* -** Search the free-list on page pPg for space to store a cell nByte bytes in -** size. If one can be found, return a pointer to the space and remove it -** from the free-list. -** -** If no suitable space can be found on the free-list, return NULL. -** -** This function may detect corruption within pPg. If corruption is -** detected then *pRc is set to SQLITE_CORRUPT and NULL is returned. -** -** If a slot of at least nByte bytes is found but cannot be used because -** there are already at least 60 fragmented bytes on the page, return NULL. -** In this case, if pbDefrag parameter is not NULL, set *pbDefrag to true. -*/ -static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc, int *pbDefrag){ - const int hdr = pPg->hdrOffset; - u8 * const aData = pPg->aData; - int iAddr; - int pc; - int usableSize = pPg->pBt->usableSize; - - for(iAddr=hdr+1; (pc = get2byte(&aData[iAddr]))>0; iAddr=pc){ - int size; /* Size of the free slot */ - if( pc>usableSize-4 || pc=nByte ){ - int x = size - nByte; - testcase( x==4 ); - testcase( x==3 ); - if( x<4 ){ - if( aData[hdr+7]>=60 ){ - if( pbDefrag ) *pbDefrag = 1; - return 0; - } - /* Remove the slot from the free-list. Update the number of - ** fragmented bytes within the page. */ - memcpy(&aData[iAddr], &aData[pc], 2); - aData[hdr+7] += (u8)x; - }else if( size+pc > usableSize ){ - *pRc = SQLITE_CORRUPT_BKPT; - return 0; - }else{ - /* The slot remains on the free-list. Reduce its size to account - ** for the portion used by the new allocation. */ - put2byte(&aData[pc+2], x); - } - return &aData[pc + x]; - } - } - - return 0; -} - /* ** Allocate nByte bytes of space from within the B-Tree page passed ** as the first argument. Write into *pIdx the index into pPage->aData[] ** of the first byte of allocated space. Return either SQLITE_OK or ** an error code (usually SQLITE_CORRUPT). @@ -1295,20 +1232,22 @@ */ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ const int hdr = pPage->hdrOffset; /* Local cache of pPage->hdrOffset */ u8 * const data = pPage->aData; /* Local cache of pPage->aData */ int top; /* First byte of cell content area */ - int rc = SQLITE_OK; /* Integer return code */ int gap; /* First byte of gap between cell pointers and cell content */ + int rc; /* Integer return code */ + int usableSize; /* Usable size of the page */ assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( pPage->pBt ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( nByte>=0 ); /* Minimum cell size is 4 */ assert( pPage->nFree>=nByte ); assert( pPage->nOverflow==0 ); - assert( nByte < (int)(pPage->pBt->usableSize-8) ); + usableSize = pPage->pBt->usableSize; + assert( nByte < usableSize-8 ); assert( pPage->cellOffset == hdr + 12 - 4*pPage->leaf ); gap = pPage->cellOffset + 2*pPage->nCell; assert( gap<=65536 ); top = get2byte(&data[hdr+5]); @@ -1326,27 +1265,46 @@ */ testcase( gap+2==top ); testcase( gap+1==top ); testcase( gap==top ); if( gap+2<=top && (data[hdr+1] || data[hdr+2]) ){ - int bDefrag = 0; - u8 *pSpace = pageFindSlot(pPage, nByte, &rc, &bDefrag); - if( rc ) return rc; - if( bDefrag ) goto defragment_page; - if( pSpace ){ - assert( pSpace>=data && (pSpace - data)<65536 ); - *pIdx = (int)(pSpace - data); - return SQLITE_OK; + int pc, addr; + for(addr=hdr+1; (pc = get2byte(&data[addr]))>0; addr=pc){ + int size; /* Size of the free slot */ + if( pc>usableSize-4 || pc=nByte ){ + int x = size - nByte; + testcase( x==4 ); + testcase( x==3 ); + if( x<4 ){ + if( data[hdr+7]>=60 ) goto defragment_page; + /* Remove the slot from the free-list. Update the number of + ** fragmented bytes within the page. */ + memcpy(&data[addr], &data[pc], 2); + data[hdr+7] += (u8)x; + }else if( size+pc > usableSize ){ + return SQLITE_CORRUPT_BKPT; + }else{ + /* The slot remains on the free-list. Reduce its size to account + ** for the portion used by the new allocation. */ + put2byte(&data[pc+2], x); + } + *pIdx = pc + x; + return SQLITE_OK; + } } } /* The request could not be fulfilled using a freelist slot. Check ** to see if defragmentation is necessary. */ testcase( gap+2+nByte==top ); if( gap+2+nByte>top ){ - defragment_page: +defragment_page: testcase( pPage->nCell==0 ); rc = defragmentPage(pPage); if( rc ) return rc; top = get2byteNotZero(&data[hdr+5]); assert( gap+nByte<=top ); @@ -1390,11 +1348,11 @@ unsigned char *data = pPage->aData; /* Page content */ assert( pPage->pBt!=0 ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( iStart>=pPage->hdrOffset+6+pPage->childPtrSize ); - assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize ); + assert( iEnd <= pPage->pBt->usableSize ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( iSize>=4 ); /* Minimum cell size is 4 */ assert( iStart<=iLast ); /* Overwrite deleted information with zeros when the secure_delete @@ -6009,266 +5967,49 @@ #endif } } /* -** Array apCell[] contains pointers to nCell b-tree page cells. The -** szCell[] array contains the size in bytes of each cell. This function -** replaces the current contents of page pPg with the contents of the cell -** array. -** -** Some of the cells in apCell[] may currently be stored in pPg. This -** function works around problems caused by this by making a copy of any -** such cells before overwriting the page data. -** -** The MemPage.nFree field is invalidated by this function. It is the -** responsibility of the caller to set it correctly. -*/ -static void rebuildPage( - MemPage *pPg, /* Edit this page */ - int nCell, /* Final number of cells on page */ - u8 **apCell, /* Array of cells */ - u16 *szCell /* Array of cell sizes */ -){ - const int hdr = pPg->hdrOffset; /* Offset of header on pPg */ - u8 * const aData = pPg->aData; /* Pointer to data for pPg */ - const int usableSize = pPg->pBt->usableSize; - u8 * const pEnd = &aData[usableSize]; - int i; - u8 *pCellptr = pPg->aCellIdx; - u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager); - u8 *pData; - - i = get2byte(&aData[hdr+5]); - memcpy(&pTmp[i], &aData[i], usableSize - i); - - pData = pEnd; - for(i=0; iaData && pCellnFree field is now set incorrectly. The caller will fix it. */ - pPg->nCell = nCell; - pPg->nOverflow = 0; - - put2byte(&aData[hdr+1], 0); - put2byte(&aData[hdr+3], pPg->nCell); - put2byte(&aData[hdr+5], pData - aData); - aData[hdr+7] = 0x00; -} - -/* -** Array apCell[] contains nCell pointers to b-tree cells. Array szCell -** contains the size in bytes of each such cell. This function attempts to -** add the cells stored in the array to page pPg. If it cannot (because -** the page needs to be defragmented before the cells will fit), non-zero -** is returned. Otherwise, if the cells are added successfully, zero is -** returned. -** -** Argument pCellptr points to the first entry in the cell-pointer array -** (part of page pPg) to populate. After cell apCell[0] is written to the -** page body, a 16-bit offset is written to pCellptr. And so on, for each -** cell in the array. It is the responsibility of the caller to ensure -** that it is safe to overwrite this part of the cell-pointer array. -** -** When this function is called, *ppData points to the start of the -** content area on page pPg. If the size of the content area is extended, -** *ppData is updated to point to the new start of the content area -** before returning. -** -** Finally, argument pBegin points to the byte immediately following the -** end of the space required by this page for the cell-pointer area (for -** all cells - not just those inserted by the current call). If the content -** area must be extended to before this point in order to accomodate all -** cells in apCell[], then the cells do not fit and non-zero is returned. -*/ -static int pageInsertArray( - MemPage *pPg, /* Page to add cells to */ - u8 *pBegin, /* End of cell-pointer array */ - u8 **ppData, /* IN/OUT: Page content -area pointer */ - u8 *pCellptr, /* Pointer to cell-pointer area */ - int nCell, /* Number of cells to add to pPg */ - u8 **apCell, /* Array of cells */ - u16 *szCell /* Array of cell sizes */ -){ - int i; - u8 *aData = pPg->aData; - u8 *pData = *ppData; - const int bFreelist = aData[1] || aData[2]; - assert( CORRUPT_DB || pPg->hdrOffset==0 ); /* Never called on page 1 */ - for(i=0; iaData; - u8 * const pEnd = &aData[pPg->pBt->usableSize]; - u8 * const pStart = &aData[pPg->hdrOffset + 8 + pPg->childPtrSize]; - int nRet = 0; - int i; - u8 *pFree = 0; - int szFree = 0; - - for(i=0; i=pStart && pCellaData && (pFree - aData)<65536 ); - freeSpace(pPg, (u16)(pFree - aData), szFree); - } - pFree = pCell; - szFree = sz; - if( pFree+sz>pEnd ) return 0; - }else{ - pFree = pCell; - szFree += sz; - } - nRet++; - } - } - if( pFree ){ - assert( pFree>aData && (pFree - aData)<65536 ); - freeSpace(pPg, (u16)(pFree - aData), szFree); - } - return nRet; -} - -/* -** The pPg->nFree field is invalid when this function returns. It is the -** responsibility of the caller to set it correctly. -*/ -static void editPage( - MemPage *pPg, /* Edit this page */ - int iOld, /* Index of first cell currently on page */ - int iNew, /* Index of new first cell on page */ - int nNew, /* Final number of cells on page */ - u8 **apCell, /* Array of cells */ - u16 *szCell /* Array of cell sizes */ -){ - u8 * const aData = pPg->aData; - const int hdr = pPg->hdrOffset; - u8 *pBegin = &pPg->aCellIdx[nNew * 2]; - int nCell = pPg->nCell; /* Cells stored on pPg */ - u8 *pData; - u8 *pCellptr; - int i; - int iOldEnd = iOld + pPg->nCell + pPg->nOverflow; - int iNewEnd = iNew + nNew; - -#ifdef SQLITE_DEBUG - u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager); - memcpy(pTmp, aData, pPg->pBt->usableSize); -#endif - - /* Remove cells from the start and end of the page */ - if( iOldaCellIdx, &pPg->aCellIdx[nShift*2], nCell*2); - nCell -= nShift; - } - if( iNewEnd < iOldEnd ){ - nCell -= pageFreeArray( - pPg, iOldEnd-iNewEnd, &apCell[iNewEnd], &szCell[iNewEnd] - ); - } - - pData = &aData[get2byte(&aData[hdr+5])]; - if( pDataaCellIdx; - memmove(&pCellptr[nAdd*2], pCellptr, nCell*2); - if( pageInsertArray( - pPg, pBegin, &pData, pCellptr, - nAdd, &apCell[iNew], &szCell[iNew] - ) ) goto editpage_fail; - nCell += nAdd; - } - - /* Add any overflow cells */ - for(i=0; inOverflow; i++){ - int iCell = (iOld + pPg->aiOvfl[i]) - iNew; - if( iCell>=0 && iCellaCellIdx[iCell * 2]; - memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2); - nCell++; - if( pageInsertArray( - pPg, pBegin, &pData, pCellptr, - 1, &apCell[iCell + iNew], &szCell[iCell + iNew] - ) ) goto editpage_fail; - } - } - - /* Append cells to the end of the page */ - pCellptr = &pPg->aCellIdx[nCell*2]; - if( pageInsertArray( - pPg, pBegin, &pData, pCellptr, - nNew-nCell, &apCell[iNew+nCell], &szCell[iNew+nCell] - ) ) goto editpage_fail; - - pPg->nCell = nNew; - pPg->nOverflow = 0; - - put2byte(&aData[hdr+3], pPg->nCell); - put2byte(&aData[hdr+5], pData - aData); - -#ifdef SQLITE_DEBUG - for(i=0; iaCellIdx[i*2]); - if( pCell>=aData && pCell<&aData[pPg->pBt->usableSize] ){ - pCell = &pTmp[pCell - aData]; - } - assert( 0==memcmp(pCell, &aData[iOff], szCell[i+iNew]) ); - } -#endif - - return; - editpage_fail: - /* Unable to edit this page. Rebuild it from scratch instead. */ - rebuildPage(pPg, nNew, &apCell[iNew], &szCell[iNew]); +** Add a list of cells to a page. The page should be initially empty. +** The cells are guaranteed to fit on the page. +*/ +static void assemblePage( + MemPage *pPage, /* The page to be assembled */ + int nCell, /* The number of cells to add to this page */ + u8 **apCell, /* Pointers to cell bodies */ + u16 *aSize /* Sizes of the cells */ +){ + int i; /* Loop counter */ + u8 *pCellptr; /* Address of next cell pointer */ + int cellbody; /* Address of next cell body */ + u8 * const data = pPage->aData; /* Pointer to data for pPage */ + const int hdr = pPage->hdrOffset; /* Offset of header on pPage */ + const int nUsable = pPage->pBt->usableSize; /* Usable size of page */ + + assert( pPage->nOverflow==0 ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( nCell>=0 && nCell<=(int)MX_CELL(pPage->pBt) + && (int)MX_CELL(pPage->pBt)<=10921); + assert( sqlite3PagerIswriteable(pPage->pDbPage) ); + + /* Check that the page has just been zeroed by zeroPage() */ + assert( pPage->nCell==0 ); + assert( get2byteNotZero(&data[hdr+5])==nUsable ); + + pCellptr = &pPage->aCellIdx[nCell*2]; + cellbody = nUsable; + for(i=nCell-1; i>=0; i--){ + u16 sz = aSize[i]; + pCellptr -= 2; + cellbody -= sz; + put2byte(pCellptr, cellbody); + memcpy(&data[cellbody], apCell[i], sz); + } + put2byte(&data[hdr+3], nCell); + put2byte(&data[hdr+5], cellbody); + pPage->nFree -= (nCell*2 + nUsable - cellbody); + pPage->nCell = (u16)nCell; } /* ** The following parameters determine how many adjacent pages get involved ** in a balancing operation. NN is the number of neighbors on either side @@ -6336,12 +6077,11 @@ u8 *pStop; assert( sqlite3PagerIswriteable(pNew->pDbPage) ); assert( pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) ); zeroPage(pNew, PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF); - rebuildPage(pNew, 1, &pCell, &szCell); - pNew->nFree = pBt->usableSize - pNew->cellOffset - 2 - szCell; + assemblePage(pNew, 1, &pCell, &szCell); /* If this is an auto-vacuum database, update the pointer map ** with entries for the new page, and any pointer from the ** cell on the page to an overflow page. If either of these ** operations fails, the return code is set, but the contents @@ -6556,26 +6296,21 @@ int subtotal; /* Subtotal of bytes in cells on one page */ int iSpace1 = 0; /* First unused byte of aSpace1[] */ int iOvflSpace = 0; /* First unused byte of aOvflSpace[] */ int szScratch; /* Size of scratch memory requested */ MemPage *apOld[NB]; /* pPage and up to two siblings */ + MemPage *apCopy[NB]; /* Private copies of apOld[] pages */ MemPage *apNew[NB+2]; /* pPage and up to NB siblings after balancing */ u8 *pRight; /* Location in parent of right-sibling pointer */ u8 *apDiv[NB-1]; /* Divider cells in pParent */ int cntNew[NB+2]; /* Index in aCell[] of cell after i-th page */ - int cntOld[NB+2]; /* Old index in aCell[] after i-th page */ - int szNew[NB+2]; /* Combined size of cells placed on i-th page */ + int szNew[NB+2]; /* Combined size of cells place on i-th page */ u8 **apCell = 0; /* All cells begin balanced */ u16 *szCell; /* Local size of all cells in apCell[] */ u8 *aSpace1; /* Space for copies of dividers cells */ Pgno pgno; /* Temp var to store a page number in */ - u8 abDone[NB+2]; /* True after i'th new page is populated */ - Pgno aPgno[NB+2]; /* Page numbers of new pages before shuffling */ - Pgno aPgOrder[NB+2]; /* Copy of aPgno[] used for sorting pages */ - u16 aPgFlags[NB+2]; /* flags field of new pages before shuffling */ - memset(abDone, 0, sizeof(abDone)); pBt = pParent->pBt; assert( sqlite3_mutex_held(pBt->mutex) ); assert( sqlite3PagerIswriteable(pParent->pDbPage) ); #if 0 @@ -6680,18 +6415,16 @@ nMaxCells = (nMaxCells + 3)&~3; /* ** Allocate space for memory structures */ + k = pBt->pageSize + ROUND8(sizeof(MemPage)); szScratch = nMaxCells*sizeof(u8*) /* apCell */ + nMaxCells*sizeof(u16) /* szCell */ - + pBt->pageSize; /* aSpace1 */ - - /* EVIDENCE-OF: R-28375-38319 SQLite will never request a scratch buffer - ** that is more than 6 times the database page size. */ - assert( szScratch<=6*pBt->pageSize ); + + pBt->pageSize /* aSpace1 */ + + k*nOld; /* Page copies (apCopy) */ apCell = sqlite3ScratchMalloc( szScratch ); if( apCell==0 ){ rc = SQLITE_NOMEM; goto balance_cleanup; } @@ -6700,12 +6433,12 @@ assert( EIGHT_BYTE_ALIGNMENT(aSpace1) ); /* ** Load pointers to all cells on sibling pages and the divider cells ** into the local apCell[] array. Make copies of the divider cells - ** into space obtained from aSpace1[]. The divider cells have already - ** been removed from pParent. + ** into space obtained from aSpace1[] and remove the divider cells + ** from pParent. ** ** If the siblings are on leaf pages, then the child pointers of the ** divider cells are stripped from the cells before they are copied ** into aSpace1[]. In this way, all cells in apCell[] are without ** child pointers. If siblings are not leaves, then all cell in @@ -6717,11 +6450,19 @@ */ leafCorrection = apOld[0]->leaf*4; leafData = apOld[0]->intKeyLeaf; for(i=0; ipageSize + k*i]; + memcpy(pOld, apOld[i], sizeof(MemPage)); + pOld->aData = (void*)&pOld[1]; + memcpy(pOld->aData, apOld[i]->aData, pBt->pageSize); limit = pOld->nCell+pOld->nOverflow; if( pOld->nOverflow>0 ){ for(j=0; jusableSize - 12 + leafCorrection; for(subtotal=k=i=0; i usableSpace ){ - szNew[k] = subtotal - szCell[i] - 2; + szNew[k] = subtotal - szCell[i]; cntNew[k] = i; if( leafData ){ i--; } subtotal = 0; k++; if( k>NB+1 ){ rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; } @@ -6804,14 +6544,13 @@ cntNew[k] = nCell; k++; /* ** The packing computed by the previous block is biased toward the siblings - ** on the left side (siblings with smaller keys). The left siblings are - ** always nearly full, while the right-most sibling might be nearly empty. - ** The next block of code attempts to adjust the packing of siblings to - ** get a better balance. + ** on the left side. The left siblings are always nearly full, while the + ** right-most sibling might be nearly empty. This block of code attempts + ** to adjust the packing of siblings to get a better balance. ** ** This adjustment is more than an optimization. The packing above might ** be so out of balance as to be illegal. For example, the right-most ** sibling might be completely empty. This adjustment is not optional. */ @@ -6836,22 +6575,26 @@ } szNew[i] = szRight; szNew[i-1] = szLeft; } - /* Sanity check: For a non-corrupt database file one of the follwing - ** must be true: - ** (1) We found one or more cells (cntNew[0])>0), or - ** (2) pPage is a virtual root page. A virtual root page is when - ** the real root page is page 1 and we are the only child of - ** that page. + /* Either we found one or more cells (cntnew[0])>0) or pPage is + ** a virtual root page. A virtual root page is when the real root + ** page is page 1 and we are the only child of that page. + ** + ** UPDATE: The assert() below is not necessarily true if the database + ** file is corrupt. The corruption will be detected and reported later + ** in this procedure so there is no need to act upon it now. */ - assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) || CORRUPT_DB); - TRACE(("BALANCE: old: %d(nc=%d) %d(nc=%d) %d(nc=%d)\n", - apOld[0]->pgno, apOld[0]->nCell, - nOld>=2 ? apOld[1]->pgno : 0, nOld>=2 ? apOld[1]->nCell : 0, - nOld>=3 ? apOld[2]->pgno : 0, nOld>=3 ? apOld[2]->nCell : 0 +#if 0 + assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) ); +#endif + + TRACE(("BALANCE: old: %d %d %d ", + apOld[0]->pgno, + nOld>=2 ? apOld[1]->pgno : 0, + nOld>=3 ? apOld[2]->pgno : 0 )); /* ** Allocate k new pages. Reuse old pages where possible. */ @@ -6870,14 +6613,12 @@ if( rc ) goto balance_cleanup; }else{ assert( i>0 ); rc = allocateBtreePage(pBt, &pNew, &pgno, (bBulk ? 1 : pgno), 0); if( rc ) goto balance_cleanup; - zeroPage(pNew, pageFlags); apNew[i] = pNew; nNew++; - cntOld[i] = nCell; /* Set the pointer-map entry for the new sibling page. */ if( ISAUTOVACUUM ){ ptrmapPut(pBt, pNew->pgno, PTRMAP_BTREE, pParent->pgno, &rc); if( rc!=SQLITE_OK ){ @@ -6884,248 +6625,140 @@ goto balance_cleanup; } } } } + + /* Free any old pages that were not reused as new pages. + */ + while( ipgno; - aPgFlags[i] = apNew[i]->pDbPage->flags; - for(j=0; ji ){ - sqlite3PagerRekey(apNew[iBest]->pDbPage, pBt->nPage+iBest+1, 0); - } - sqlite3PagerRekey(apNew[i]->pDbPage, pgno, aPgFlags[iBest]); - apNew[i]->pgno = pgno; - } - } - - TRACE(("BALANCE: new: %d(%d nc=%d) %d(%d nc=%d) %d(%d nc=%d) " - "%d(%d nc=%d) %d(%d nc=%d)\n", - apNew[0]->pgno, szNew[0], cntNew[0], + ** Put the new pages in ascending order. This helps to + ** keep entries in the disk file in order so that a scan + ** of the table is a linear scan through the file. That + ** in turn helps the operating system to deliver pages + ** from the disk more rapidly. + ** + ** An O(n^2) insertion sort algorithm is used, but since + ** n is never more than NB (a small constant), that should + ** not be a problem. + ** + ** When NB==3, this one optimization makes the database + ** about 25% faster for large insertions and deletions. + */ + for(i=0; ipgno; + int minI = i; + for(j=i+1; jpgno<(unsigned)minV ){ + minI = j; + minV = apNew[j]->pgno; + } + } + if( minI>i ){ + MemPage *pT; + pT = apNew[i]; + apNew[i] = apNew[minI]; + apNew[minI] = pT; + } + } + TRACE(("new: %d(%d) %d(%d) %d(%d) %d(%d) %d(%d)\n", + apNew[0]->pgno, szNew[0], nNew>=2 ? apNew[1]->pgno : 0, nNew>=2 ? szNew[1] : 0, - nNew>=2 ? cntNew[1] - cntNew[0] - !leafData : 0, nNew>=3 ? apNew[2]->pgno : 0, nNew>=3 ? szNew[2] : 0, - nNew>=3 ? cntNew[2] - cntNew[1] - !leafData : 0, nNew>=4 ? apNew[3]->pgno : 0, nNew>=4 ? szNew[3] : 0, - nNew>=4 ? cntNew[3] - cntNew[2] - !leafData : 0, - nNew>=5 ? apNew[4]->pgno : 0, nNew>=5 ? szNew[4] : 0, - nNew>=5 ? cntNew[4] - cntNew[3] - !leafData : 0 - )); + nNew>=5 ? apNew[4]->pgno : 0, nNew>=5 ? szNew[4] : 0)); assert( sqlite3PagerIswriteable(pParent->pDbPage) ); put4byte(pRight, apNew[nNew-1]->pgno); - /* If the sibling pages are not leaves, ensure that the right-child pointer - ** of the right-most new sibling page is set to the value that was - ** originally in the same field of the right-most old sibling page. */ - if( (pageFlags & PTF_LEAF)==0 && nOld!=nNew ){ - MemPage *pOld = (nNew>nOld ? apNew : apOld)[nOld-1]; - memcpy(&apNew[nNew-1]->aData[8], &pOld->aData[8], 4); - } - - /* Make any required updates to pointer map entries associated with - ** cells stored on sibling pages following the balance operation. Pointer - ** map entries associated with divider cells are set by the insertCell() - ** routine. The associated pointer map entries are: - ** - ** a) if the cell contains a reference to an overflow chain, the - ** entry associated with the first page in the overflow chain, and - ** - ** b) if the sibling pages are not leaves, the child page associated - ** with the cell. - ** - ** If the sibling pages are not leaves, then the pointer map entry - ** associated with the right-child of each sibling may also need to be - ** updated. This happens below, after the sibling pages have been - ** populated, not here. + /* + ** Evenly distribute the data in apCell[] across the new pages. + ** Insert divider cells into pParent as necessary. */ - if( ISAUTOVACUUM ){ - MemPage *pNew = apNew[0]; - u8 *aOld = pNew->aData; - int cntOldNext = pNew->nCell + pNew->nOverflow; - int usableSize = pBt->usableSize; - int iNew = 0; - int iOld = 0; - - for(i=0; inCell + pOld->nOverflow + !leafData; - aOld = pOld->aData; - } - if( i==cntNew[iNew] ){ - pNew = apNew[++iNew]; - if( !leafData ) continue; - } - - /* Cell pCell is destined for new sibling page pNew. Originally, it - ** was either part of sibling page iOld (possibly an overflow cell), - ** or else the divider cell to the left of sibling page iOld. So, - ** if sibling page iOld had the same page number as pNew, and if - ** pCell really was a part of sibling page iOld (not a divider or - ** overflow cell), we can skip updating the pointer map entries. */ - if( pNew->pgno!=aPgno[iOld] || pCell=&aOld[usableSize] ){ - if( !leafCorrection ){ - ptrmapPut(pBt, get4byte(pCell), PTRMAP_BTREE, pNew->pgno, &rc); - } - if( szCell[i]>pNew->minLocal ){ - ptrmapPutOvflPtr(pNew, pCell, &rc); - } - } - } - } - - /* Insert new divider cells into pParent. */ - for(i=0; inCell>0 || (nNew==1 && cntNew[0]==0) ); + assert( pNew->nOverflow==0 ); + j = cntNew[i]; - assert( jleaf ){ - memcpy(&pNew->aData[8], pCell, 4); - }else if( leafData ){ - /* If the tree is a leaf-data tree, and the siblings are leaves, - ** then there is no divider cell in apCell[]. Instead, the divider - ** cell consists of the integer key for the right-most cell of - ** the sibling-page assembled above only. - */ - CellInfo info; - j--; - btreeParseCellPtr(pNew, apCell[j], &info); - pCell = pTemp; - sz = 4 + putVarint(&pCell[4], info.nKey); - pTemp = 0; - }else{ - pCell -= 4; - /* Obscure case for non-leaf-data trees: If the cell at pCell was - ** previously stored on a leaf node, and its reported size was 4 - ** bytes, then it may actually be smaller than this - ** (see btreeParseCellPtr(), 4 bytes is the minimum size of - ** any cell). But it is important to pass the correct size to - ** insertCell(), so reparse the cell now. - ** - ** Note that this can never happen in an SQLite data file, as all - ** cells are at least 4 bytes. It only happens in b-trees used - ** to evaluate "IN (SELECT ...)" and similar clauses. - */ - if( szCell[j]==4 ){ - assert(leafCorrection==4); - sz = cellSizePtr(pParent, pCell); - } - } - iOvflSpace += sz; - assert( sz<=pBt->maxLocal+23 ); - assert( iOvflSpace <= (int)pBt->pageSize ); - insertCell(pParent, nxDiv+i, pCell, sz, pTemp, pNew->pgno, &rc); - if( rc!=SQLITE_OK ) goto balance_cleanup; - assert( sqlite3PagerIswriteable(pParent->pDbPage) ); - } - - /* Now update the actual sibling pages. The order in which they are updated - ** is important, as this code needs to avoid disrupting any page from which - ** cells may still to be read. In practice, this means: - ** - ** (1) If cells are moving left (from apNew[iPg] to apNew[iPg-1]) - ** then it is not safe to update page apNew[iPg] until after - ** the left-hand sibling apNew[iPg-1] has been updated. - ** - ** (2) If cells are moving right (from apNew[iPg] to apNew[iPg+1]) - ** then it is not safe to update page apNew[iPg] until after - ** the right-hand sibling apNew[iPg+1] has been updated. - ** - ** If neither of the above apply, the page is safe to update. - ** - ** The iPg value in the following loop starts at nNew-1 goes down - ** to 0, then back up to nNew-1 again, thus making two passes over - ** the pages. On the initial downward pass, only condition (1) above - ** needs to be tested because (2) will always be true from the previous - ** step. On the upward pass, both conditions are always true, so the - ** upwards pass simply processes pages that were missed on the downward - ** pass. - */ - for(i=1-nNew; i=0 && iPg=0 /* On the upwards pass, or... */ - || cntOld[iPg-1]>=cntNew[iPg-1] /* Condition (1) is true */ - ){ - int iNew; - int iOld; - int nNewCell; - - /* Verify condition (1): If cells are moving left, update iPg - ** only after iPg-1 has already been updated. */ - assert( iPg==0 || cntOld[iPg-1]>=cntNew[iPg-1] || abDone[iPg-1] ); - - /* Verify condition (2): If cells are moving right, update iPg - ** only after iPg+1 has already been updated. */ - assert( cntNew[iPg]>=cntOld[iPg] || abDone[iPg+1] ); - - if( iPg==0 ){ - iNew = iOld = 0; - nNewCell = cntNew[0]; - }else{ - iOld = iPgnFree = usableSpace-szNew[iPg]; - assert( apNew[iPg]->nOverflow==0 ); - assert( apNew[iPg]->nCell==nNewCell ); - } - } - - /* All pages have been processed exactly once */ - assert( memcmp(abDone, "\01\01\01\01\01", nNew)==0 ); - + /* If the sibling page assembled above was not the right-most sibling, + ** insert a divider cell into the parent page. + */ + assert( ileaf ){ + memcpy(&pNew->aData[8], pCell, 4); + }else if( leafData ){ + /* If the tree is a leaf-data tree, and the siblings are leaves, + ** then there is no divider cell in apCell[]. Instead, the divider + ** cell consists of the integer key for the right-most cell of + ** the sibling-page assembled above only. + */ + CellInfo info; + j--; + btreeParseCellPtr(pNew, apCell[j], &info); + pCell = pTemp; + sz = 4 + putVarint(&pCell[4], info.nKey); + pTemp = 0; + }else{ + pCell -= 4; + /* Obscure case for non-leaf-data trees: If the cell at pCell was + ** previously stored on a leaf node, and its reported size was 4 + ** bytes, then it may actually be smaller than this + ** (see btreeParseCellPtr(), 4 bytes is the minimum size of + ** any cell). But it is important to pass the correct size to + ** insertCell(), so reparse the cell now. + ** + ** Note that this can never happen in an SQLite data file, as all + ** cells are at least 4 bytes. It only happens in b-trees used + ** to evaluate "IN (SELECT ...)" and similar clauses. + */ + if( szCell[j]==4 ){ + assert(leafCorrection==4); + sz = cellSizePtr(pParent, pCell); + } + } + iOvflSpace += sz; + assert( sz<=pBt->maxLocal+23 ); + assert( iOvflSpace <= (int)pBt->pageSize ); + insertCell(pParent, nxDiv, pCell, sz, pTemp, pNew->pgno, &rc); + if( rc!=SQLITE_OK ) goto balance_cleanup; + assert( sqlite3PagerIswriteable(pParent->pDbPage) ); + + j++; + nxDiv++; + } + } + assert( j==nCell ); assert( nOld>0 ); assert( nNew>0 ); + if( (pageFlags & PTF_LEAF)==0 ){ + u8 *zChild = &apCopy[nOld-1]->aData[8]; + memcpy(&apNew[nNew-1]->aData[8], zChild, 4); + } if( isRoot && pParent->nCell==0 && pParent->hdrOffset<=apNew[0]->nFree ){ /* The root page of the b-tree now contains no cells. The only sibling ** page is the right-child of the parent. Copy the contents of the ** child page into the parent, decreasing the overall height of the @@ -7134,54 +6767,130 @@ ** ** If this is an auto-vacuum database, the call to copyNodeContent() ** sets all pointer-map entries corresponding to database image pages ** for which the pointer is stored within the content being copied. ** - ** It is critical that the child page be defragmented before being - ** copied into the parent, because if the parent is page 1 then it will - ** by smaller than the child due to the database header, and so all the - ** free space needs to be up front. - */ + ** The second assert below verifies that the child page is defragmented + ** (it must be, as it was just reconstructed using assemblePage()). This + ** is important if the parent page happens to be page 1 of the database + ** image. */ assert( nNew==1 ); - rc = defragmentPage(apNew[0]); - testcase( rc!=SQLITE_OK ); assert( apNew[0]->nFree == - (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2) - || rc!=SQLITE_OK + (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2) ); copyNodeContent(apNew[0], pParent, &rc); freePage(apNew[0], &rc); - }else if( ISAUTOVACUUM && !leafCorrection ){ - /* Fix the pointer map entries associated with the right-child of each - ** sibling page. All other pointer map entries have already been taken - ** care of. */ - for(i=0; iaData[8]); - ptrmapPut(pBt, key, PTRMAP_BTREE, apNew[i]->pgno, &rc); - } - } - - assert( pParent->isInit ); - TRACE(("BALANCE: finished: old=%d new=%d cells=%d\n", - nOld, nNew, nCell)); - - /* Free any old pages that were not reused as new pages. - */ - for(i=nNew; iisInit ){ + }else if( ISAUTOVACUUM ){ + /* Fix the pointer-map entries for all the cells that were shifted around. + ** There are several different types of pointer-map entries that need to + ** be dealt with by this routine. Some of these have been set already, but + ** many have not. The following is a summary: + ** + ** 1) The entries associated with new sibling pages that were not + ** siblings when this function was called. These have already + ** been set. We don't need to worry about old siblings that were + ** moved to the free-list - the freePage() code has taken care + ** of those. + ** + ** 2) The pointer-map entries associated with the first overflow + ** page in any overflow chains used by new divider cells. These + ** have also already been taken care of by the insertCell() code. + ** + ** 3) If the sibling pages are not leaves, then the child pages of + ** cells stored on the sibling pages may need to be updated. + ** + ** 4) If the sibling pages are not internal intkey nodes, then any + ** overflow pages used by these cells may need to be updated + ** (internal intkey nodes never contain pointers to overflow pages). + ** + ** 5) If the sibling pages are not leaves, then the pointer-map + ** entries for the right-child pages of each sibling may need + ** to be updated. + ** + ** Cases 1 and 2 are dealt with above by other code. The next + ** block deals with cases 3 and 4 and the one after that, case 5. Since + ** setting a pointer map entry is a relatively expensive operation, this + ** code only sets pointer map entries for child or overflow pages that have + ** actually moved between pages. */ + MemPage *pNew = apNew[0]; + MemPage *pOld = apCopy[0]; + int nOverflow = pOld->nOverflow; + int iNextOld = pOld->nCell + nOverflow; + int iOverflow = (nOverflow ? pOld->aiOvfl[0] : -1); + j = 0; /* Current 'old' sibling page */ + k = 0; /* Current 'new' sibling page */ + for(i=0; inCell + pOld->nOverflow; + if( pOld->nOverflow ){ + nOverflow = pOld->nOverflow; + iOverflow = i + !leafData + pOld->aiOvfl[0]; + } + isDivider = !leafData; + } + + assert(nOverflow>0 || iOverflowaiOvfl[0]==pOld->aiOvfl[1]-1); + assert(nOverflow<3 || pOld->aiOvfl[1]==pOld->aiOvfl[2]-1); + if( i==iOverflow ){ + isDivider = 1; + if( (--nOverflow)>0 ){ + iOverflow++; + } + } + + if( i==cntNew[k] ){ + /* Cell i is the cell immediately following the last cell on new + ** sibling page k. If the siblings are not leaf pages of an + ** intkey b-tree, then cell i is a divider cell. */ + pNew = apNew[++k]; + if( !leafData ) continue; + } + assert( jpgno!=pNew->pgno ){ + if( !leafCorrection ){ + ptrmapPut(pBt, get4byte(apCell[i]), PTRMAP_BTREE, pNew->pgno, &rc); + } + if( szCell[i]>pNew->minLocal ){ + ptrmapPutOvflPtr(pNew, apCell[i], &rc); + } + } + } + + if( !leafCorrection ){ + for(i=0; iaData[8]); + ptrmapPut(pBt, key, PTRMAP_BTREE, apNew[i]->pgno, &rc); + } + } + +#if 0 /* The ptrmapCheckPages() contains assert() statements that verify that ** all pointer map pages are set correctly. This is helpful while ** debugging. This is usually disabled because a corrupt database may ** cause an assert() statement to fail. */ ptrmapCheckPages(apNew, nNew); ptrmapCheckPages(&pParent, 1); - } #endif + } + + assert( pParent->isInit ); + TRACE(("BALANCE: finished: old=%d new=%d cells=%d\n", + nOld, nNew, nCell)); /* ** Cleanup before returning. */ balance_cleanup: @@ -9002,10 +8711,5 @@ ** Return true if the given Btree is read-only. */ int sqlite3BtreeIsReadonly(Btree *p){ return (p->pBt->btsFlags & BTS_READ_ONLY)!=0; } - -/* -** Return the size of the header added to each page by this module. -*/ -int sqlite3HeaderSizeBtree(void){ return sizeof(MemPage); } Index: src/btree.h ================================================================== --- src/btree.h +++ src/btree.h @@ -194,11 +194,10 @@ void sqlite3BtreeIncrblobCursor(BtCursor *); void sqlite3BtreeClearCursor(BtCursor *); int sqlite3BtreeSetVersion(Btree *pBt, int iVersion); void sqlite3BtreeCursorHints(BtCursor *, unsigned int mask); int sqlite3BtreeIsReadonly(Btree *pBt); -int sqlite3HeaderSizeBtree(void); #ifndef NDEBUG int sqlite3BtreeCursorIsValid(BtCursor*); #endif Index: src/build.c ================================================================== --- src/build.c +++ src/build.c @@ -305,15 +305,11 @@ ** See also sqlite3LocateTable(). */ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){ Table *p = 0; int i; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) || zName==0 ) return 0; -#endif - + assert( zName!=0 ); /* All mutexes are required for schema access. Make sure we hold them. */ assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) ); #if SQLITE_USER_AUTHENTICATION /* Only the admin user is allowed to know that the sqlite_user table ** exists */ Index: src/complete.c ================================================================== --- src/complete.c +++ src/complete.c @@ -103,17 +103,10 @@ */ int sqlite3_complete(const char *zSql){ u8 state = 0; /* Current state, using numbers defined in header comment */ u8 token; /* Value of the next token */ -#ifdef SQLITE_ENABLE_API_ARMOR - if( zSql==0 ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif - #ifndef SQLITE_OMIT_TRIGGER /* A complex statement machine used to detect the end of a CREATE TRIGGER ** statement. This is the normal case. */ static const u8 trans[8][8] = { Index: src/ctime.c ================================================================== --- src/ctime.c +++ src/ctime.c @@ -61,13 +61,10 @@ "DISABLE_DIRSYNC", #endif #ifdef SQLITE_DISABLE_LFS "DISABLE_LFS", #endif -#ifdef SQLITE_ENABLE_API_ARMOR - "ENABLE_API_ARMOR", -#endif #ifdef SQLITE_ENABLE_ATOMIC_WRITE "ENABLE_ATOMIC_WRITE", #endif #ifdef SQLITE_ENABLE_CEROD "ENABLE_CEROD", @@ -389,17 +386,10 @@ ** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix ** is not required for a match. */ int sqlite3_compileoption_used(const char *zOptName){ int i, n; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( zOptName==0 ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7; n = sqlite3Strlen30(zOptName); /* Since ArraySize(azCompileOpt) is normally in single digits, a ** linear search is adequate. No need for a binary search. */ Index: src/date.c ================================================================== --- src/date.c +++ src/date.c @@ -14,11 +14,11 @@ ** ** There is only one exported symbol in this file - the function ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file. ** All other code has file scope. ** -** SQLite processes all times and dates as julian day numbers. The +** SQLite processes all times and dates as Julian Day numbers. The ** dates and times are stored as the number of days since noon ** in Greenwich on November 24, 4714 B.C. according to the Gregorian ** calendar system. ** ** 1970-01-01 00:00:00 is JD 2440587.5 @@ -29,11 +29,11 @@ ** be represented, even though julian day numbers allow a much wider ** range of dates. ** ** The Gregorian calendar system is used for all dates and times, ** even those that predate the Gregorian calendar. Historians usually -** use the julian calendar for dates prior to 1582-10-15 and for some +** use the Julian calendar for dates prior to 1582-10-15 and for some ** dates afterwards, depending on locale. Beware of this difference. ** ** The conversion algorithms are implemented based on descriptions ** in the following text: ** @@ -302,11 +302,11 @@ return 1; } } /* -** Attempt to parse the given string into a julian day number. Return +** Attempt to parse the given string into a Julian Day Number. Return ** the number of errors. ** ** The following are acceptable forms for the input string: ** ** YYYY-MM-DD HH:MM:SS.FFF +/-HH:MM @@ -873,11 +873,11 @@ ** ** %d day of month ** %f ** fractional seconds SS.SSS ** %H hour 00-24 ** %j day of year 000-366 -** %J ** julian day number +** %J ** Julian day number ** %m month 01-12 ** %M minute 00-59 ** %s seconds since 1970-01-01 ** %S seconds 00-59 ** %w day of week 0-6 sunday==0 Index: src/expr.c ================================================================== --- src/expr.c +++ src/expr.c @@ -1208,79 +1208,69 @@ sqlite3DbFree(db, pList->a); sqlite3DbFree(db, pList); } /* -** These routines are Walker callbacks used to check expressions to -** see if they are "constant" for some definition of constant. The -** Walker.eCode value determines the type of "constant" we are looking -** for. +** These routines are Walker callbacks. Walker.u.pi is a pointer +** to an integer. These routines are checking an expression to see +** if it is a constant. Set *Walker.u.i to 0 if the expression is +** not constant. ** ** These callback routines are used to implement the following: ** -** sqlite3ExprIsConstant() pWalker->eCode==1 -** sqlite3ExprIsConstantNotJoin() pWalker->eCode==2 -** sqlite3ExprRefOneTableOnly() pWalker->eCode==3 -** sqlite3ExprIsConstantOrFunction() pWalker->eCode==4 or 5 -** -** In all cases, the callbacks set Walker.eCode=0 and abort if the expression -** is found to not be a constant. +** sqlite3ExprIsConstant() pWalker->u.i==1 +** sqlite3ExprIsConstantNotJoin() pWalker->u.i==2 +** sqlite3ExprIsConstantOrFunction() pWalker->u.i==3 or 4 ** ** The sqlite3ExprIsConstantOrFunction() is used for evaluating expressions -** in a CREATE TABLE statement. The Walker.eCode value is 5 when parsing -** an existing schema and 4 when processing a new statement. A bound +** in a CREATE TABLE statement. The Walker.u.i value is 4 when parsing +** an existing schema and 3 when processing a new statement. A bound ** parameter raises an error for new statements, but is silently converted ** to NULL for existing schemas. This allows sqlite_master tables that ** contain a bound parameter because they were generated by older versions ** of SQLite to be parsed by newer versions of SQLite without raising a ** malformed schema error. */ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ - /* If pWalker->eCode is 2 then any term of the expression that comes from - ** the ON or USING clauses of a left join disqualifies the expression + /* If pWalker->u.i is 2 then any term of the expression that comes from + ** the ON or USING clauses of a join disqualifies the expression ** from being considered constant. */ - if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_FromJoin) ){ - pWalker->eCode = 0; + if( pWalker->u.i==2 && ExprHasProperty(pExpr, EP_FromJoin) ){ + pWalker->u.i = 0; return WRC_Abort; } switch( pExpr->op ){ /* Consider functions to be constant if all their arguments are constant - ** and either pWalker->eCode==4 or 5 or the function has the - ** SQLITE_FUNC_CONST flag. */ + ** and either pWalker->u.i==3 or 4 or the function as the SQLITE_FUNC_CONST + ** flag. */ case TK_FUNCTION: - if( pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_Constant) ){ + if( pWalker->u.i>=3 || ExprHasProperty(pExpr,EP_Constant) ){ return WRC_Continue; - }else{ - pWalker->eCode = 0; - return WRC_Abort; } + /* Fall through */ case TK_ID: case TK_COLUMN: case TK_AGG_FUNCTION: case TK_AGG_COLUMN: testcase( pExpr->op==TK_ID ); testcase( pExpr->op==TK_COLUMN ); testcase( pExpr->op==TK_AGG_FUNCTION ); testcase( pExpr->op==TK_AGG_COLUMN ); - if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){ - return WRC_Continue; - }else{ - pWalker->eCode = 0; - return WRC_Abort; - } + pWalker->u.i = 0; + return WRC_Abort; case TK_VARIABLE: - if( pWalker->eCode==5 ){ + if( pWalker->u.i==4 ){ /* Silently convert bound parameters that appear inside of CREATE ** statements into a NULL when parsing the CREATE statement text out ** of the sqlite_master table */ pExpr->op = TK_NULL; - }else if( pWalker->eCode==4 ){ + }else if( pWalker->u.i==3 ){ /* A bound parameter in a CREATE statement that originates from ** sqlite3_prepare() causes an error */ - pWalker->eCode = 0; + pWalker->u.i = 0; return WRC_Abort; } /* Fall through */ default: testcase( pExpr->op==TK_SELECT ); /* selectNodeIsConstant will disallow */ @@ -1288,68 +1278,57 @@ return WRC_Continue; } } static int selectNodeIsConstant(Walker *pWalker, Select *NotUsed){ UNUSED_PARAMETER(NotUsed); - pWalker->eCode = 0; + pWalker->u.i = 0; return WRC_Abort; } -static int exprIsConst(Expr *p, int initFlag, int iCur){ +static int exprIsConst(Expr *p, int initFlag){ Walker w; memset(&w, 0, sizeof(w)); - w.eCode = initFlag; + w.u.i = initFlag; w.xExprCallback = exprNodeIsConstant; w.xSelectCallback = selectNodeIsConstant; - w.u.iCur = iCur; sqlite3WalkExpr(&w, p); - return w.eCode; + return w.u.i; } /* -** Walk an expression tree. Return non-zero if the expression is constant +** Walk an expression tree. Return 1 if the expression is constant ** and 0 if it involves variables or function calls. ** ** For the purposes of this function, a double-quoted string (ex: "abc") ** is considered a variable but a single-quoted string (ex: 'abc') is ** a constant. */ int sqlite3ExprIsConstant(Expr *p){ - return exprIsConst(p, 1, 0); + return exprIsConst(p, 1); } /* -** Walk an expression tree. Return non-zero if the expression is constant +** Walk an expression tree. Return 1 if the expression is constant ** that does no originate from the ON or USING clauses of a join. ** Return 0 if it involves variables or function calls or terms from ** an ON or USING clause. */ int sqlite3ExprIsConstantNotJoin(Expr *p){ - return exprIsConst(p, 2, 0); + return exprIsConst(p, 2); } /* -** Walk an expression tree. Return non-zero if the expression constant -** for any single row of the table with cursor iCur. In other words, the -** expression must not refer to any non-deterministic function nor any -** table other than iCur. -*/ -int sqlite3ExprIsTableConstant(Expr *p, int iCur){ - return exprIsConst(p, 3, iCur); -} - -/* -** Walk an expression tree. Return non-zero if the expression is constant +** Walk an expression tree. Return 1 if the expression is constant ** or a function call with constant arguments. Return and 0 if there ** are any variables. ** ** For the purposes of this function, a double-quoted string (ex: "abc") ** is considered a variable but a single-quoted string (ex: 'abc') is ** a constant. */ int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){ assert( isInit==0 || isInit==1 ); - return exprIsConst(p, 4+isInit, 0); + return exprIsConst(p, 3+isInit); } /* ** If the expression p codes a constant integer that is small enough ** to fit in a 32-bit integer, return 1 and put the value of the integer @@ -1855,11 +1834,10 @@ sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable); dest.affSdst = (u8)affinity; assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); pSelect->iLimit = 0; testcase( pSelect->selFlags & SF_Distinct ); - pSelect->selFlags &= ~SF_Distinct; testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */ if( sqlite3Select(pParse, pSelect, &dest) ){ sqlite3KeyInfoUnref(pKeyInfo); return 0; } Index: src/global.c ================================================================== --- src/global.c +++ src/global.c @@ -133,23 +133,15 @@ ** compatibility for legacy applications, the URI filename capability is ** disabled by default. ** ** EVIDENCE-OF: R-38799-08373 URI filenames can be enabled or disabled ** using the SQLITE_USE_URI=1 or SQLITE_USE_URI=0 compile-time options. -** -** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally -** disabled. The default value may be changed by compiling with the -** SQLITE_USE_URI symbol defined. */ #ifndef SQLITE_USE_URI # define SQLITE_USE_URI 0 #endif -/* EVIDENCE-OF: R-38720-18127 The default setting is determined by the -** SQLITE_ALLOW_COVERING_INDEX_SCAN compile-time option, or is "on" if -** that compile-time option is omitted. -*/ #ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN # define SQLITE_ALLOW_COVERING_INDEX_SCAN 1 #endif /* @@ -235,12 +227,12 @@ ** than 1 GiB. The sqlite3_test_control() interface can be used to ** move the pending byte. ** ** IMPORTANT: Changing the pending byte to any value other than ** 0x40000000 results in an incompatible database file format! -** Changing the pending byte during operation will result in undefined -** and incorrect behavior. +** Changing the pending byte during operating results in undefined +** and dileterious behavior. */ #ifndef SQLITE_OMIT_WSD int sqlite3PendingByte = 0x40000000; #endif Index: src/main.c ================================================================== --- src/main.c +++ src/main.c @@ -327,107 +327,75 @@ va_start(ap, op); switch( op ){ /* Mutex configuration options are only available in a threadsafe - ** compile. + ** compile. */ -#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-54466-46756 */ +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 case SQLITE_CONFIG_SINGLETHREAD: { /* Disable all mutexing */ sqlite3GlobalConfig.bCoreMutex = 0; sqlite3GlobalConfig.bFullMutex = 0; break; } -#endif -#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-20520-54086 */ case SQLITE_CONFIG_MULTITHREAD: { /* Disable mutexing of database connections */ /* Enable mutexing of core data structures */ sqlite3GlobalConfig.bCoreMutex = 1; sqlite3GlobalConfig.bFullMutex = 0; break; } -#endif -#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-59593-21810 */ case SQLITE_CONFIG_SERIALIZED: { /* Enable all mutexing */ sqlite3GlobalConfig.bCoreMutex = 1; sqlite3GlobalConfig.bFullMutex = 1; break; } -#endif -#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-63666-48755 */ case SQLITE_CONFIG_MUTEX: { /* Specify an alternative mutex implementation */ sqlite3GlobalConfig.mutex = *va_arg(ap, sqlite3_mutex_methods*); break; } -#endif -#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-14450-37597 */ case SQLITE_CONFIG_GETMUTEX: { /* Retrieve the current mutex implementation */ *va_arg(ap, sqlite3_mutex_methods*) = sqlite3GlobalConfig.mutex; break; } #endif + case SQLITE_CONFIG_MALLOC: { - /* EVIDENCE-OF: R-55594-21030 The SQLITE_CONFIG_MALLOC option takes a - ** single argument which is a pointer to an instance of the - ** sqlite3_mem_methods structure. The argument specifies alternative - ** low-level memory allocation routines to be used in place of the memory - ** allocation routines built into SQLite. */ + /* Specify an alternative malloc implementation */ sqlite3GlobalConfig.m = *va_arg(ap, sqlite3_mem_methods*); break; } case SQLITE_CONFIG_GETMALLOC: { - /* EVIDENCE-OF: R-51213-46414 The SQLITE_CONFIG_GETMALLOC option takes a - ** single argument which is a pointer to an instance of the - ** sqlite3_mem_methods structure. The sqlite3_mem_methods structure is - ** filled with the currently defined memory allocation routines. */ + /* Retrieve the current malloc() implementation */ if( sqlite3GlobalConfig.m.xMalloc==0 ) sqlite3MemSetDefault(); *va_arg(ap, sqlite3_mem_methods*) = sqlite3GlobalConfig.m; break; } case SQLITE_CONFIG_MEMSTATUS: { - /* EVIDENCE-OF: R-61275-35157 The SQLITE_CONFIG_MEMSTATUS option takes - ** single argument of type int, interpreted as a boolean, which enables - ** or disables the collection of memory allocation statistics. */ + /* Enable or disable the malloc status collection */ sqlite3GlobalConfig.bMemstat = va_arg(ap, int); break; } case SQLITE_CONFIG_SCRATCH: { - /* EVIDENCE-OF: R-08404-60887 There are three arguments to - ** SQLITE_CONFIG_SCRATCH: A pointer an 8-byte aligned memory buffer from - ** which the scratch allocations will be drawn, the size of each scratch - ** allocation (sz), and the maximum number of scratch allocations (N). */ + /* Designate a buffer for scratch memory space */ sqlite3GlobalConfig.pScratch = va_arg(ap, void*); sqlite3GlobalConfig.szScratch = va_arg(ap, int); sqlite3GlobalConfig.nScratch = va_arg(ap, int); break; } case SQLITE_CONFIG_PAGECACHE: { - /* EVIDENCE-OF: R-31408-40510 There are three arguments to - ** SQLITE_CONFIG_PAGECACHE: A pointer to 8-byte aligned memory, the size - ** of each page buffer (sz), and the number of pages (N). */ + /* Designate a buffer for page cache memory space */ sqlite3GlobalConfig.pPage = va_arg(ap, void*); sqlite3GlobalConfig.szPage = va_arg(ap, int); sqlite3GlobalConfig.nPage = va_arg(ap, int); break; } - case SQLITE_CONFIG_PCACHE_HDRSZ: { - /* EVIDENCE-OF: R-39100-27317 The SQLITE_CONFIG_PCACHE_HDRSZ option takes - ** a single parameter which is a pointer to an integer and writes into - ** that integer the number of extra bytes per page required for each page - ** in SQLITE_CONFIG_PAGECACHE. */ - *va_arg(ap, int*) = - sqlite3HeaderSizeBtree() + - sqlite3HeaderSizePcache() + - sqlite3HeaderSizePcache1(); - break; - } case SQLITE_CONFIG_PCACHE: { /* no-op */ break; } @@ -436,37 +404,25 @@ rc = SQLITE_ERROR; break; } case SQLITE_CONFIG_PCACHE2: { - /* EVIDENCE-OF: R-63325-48378 The SQLITE_CONFIG_PCACHE2 option takes a - ** single argument which is a pointer to an sqlite3_pcache_methods2 - ** object. This object specifies the interface to a custom page cache - ** implementation. */ + /* Specify an alternative page cache implementation */ sqlite3GlobalConfig.pcache2 = *va_arg(ap, sqlite3_pcache_methods2*); break; } case SQLITE_CONFIG_GETPCACHE2: { - /* EVIDENCE-OF: R-22035-46182 The SQLITE_CONFIG_GETPCACHE2 option takes a - ** single argument which is a pointer to an sqlite3_pcache_methods2 - ** object. SQLite copies of the current page cache implementation into - ** that object. */ if( sqlite3GlobalConfig.pcache2.xInit==0 ){ sqlite3PCacheSetDefault(); } *va_arg(ap, sqlite3_pcache_methods2*) = sqlite3GlobalConfig.pcache2; break; } -/* EVIDENCE-OF: R-06626-12911 The SQLITE_CONFIG_HEAP option is only -** available if SQLite is compiled with either SQLITE_ENABLE_MEMSYS3 or -** SQLITE_ENABLE_MEMSYS5 and returns SQLITE_ERROR if invoked otherwise. */ #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) case SQLITE_CONFIG_HEAP: { - /* EVIDENCE-OF: R-19854-42126 There are three arguments to - ** SQLITE_CONFIG_HEAP: An 8-byte aligned pointer to the memory, the - ** number of bytes in the memory buffer, and the minimum allocation size. */ + /* Designate a buffer for heap memory space */ sqlite3GlobalConfig.pHeap = va_arg(ap, void*); sqlite3GlobalConfig.nHeap = va_arg(ap, int); sqlite3GlobalConfig.mnReq = va_arg(ap, int); if( sqlite3GlobalConfig.mnReq<1 ){ @@ -475,23 +431,21 @@ /* cap min request size at 2^12 */ sqlite3GlobalConfig.mnReq = (1<<12); } if( sqlite3GlobalConfig.pHeap==0 ){ - /* EVIDENCE-OF: R-49920-60189 If the first pointer (the memory pointer) - ** is NULL, then SQLite reverts to using its default memory allocator - ** (the system malloc() implementation), undoing any prior invocation of - ** SQLITE_CONFIG_MALLOC. - ** - ** Setting sqlite3GlobalConfig.m to all zeros will cause malloc to - ** revert to its default implementation when sqlite3_initialize() is run + /* If the heap pointer is NULL, then restore the malloc implementation + ** back to NULL pointers too. This will cause the malloc to go + ** back to its default implementation when sqlite3_initialize() is + ** run. */ memset(&sqlite3GlobalConfig.m, 0, sizeof(sqlite3GlobalConfig.m)); }else{ - /* EVIDENCE-OF: R-61006-08918 If the memory pointer is not NULL then the - ** alternative memory allocator is engaged to handle all of SQLites - ** memory allocation needs. */ + /* The heap pointer is not NULL, then install one of the + ** mem5.c/mem3.c methods. The enclosing #if guarantees at + ** least one of these methods is currently enabled. + */ #ifdef SQLITE_ENABLE_MEMSYS3 sqlite3GlobalConfig.m = *sqlite3MemGetMemsys3(); #endif #ifdef SQLITE_ENABLE_MEMSYS5 sqlite3GlobalConfig.m = *sqlite3MemGetMemsys5(); @@ -526,23 +480,15 @@ ** can be changed at start-time using the ** sqlite3_config(SQLITE_CONFIG_URI,1) or ** sqlite3_config(SQLITE_CONFIG_URI,0) configuration calls. */ case SQLITE_CONFIG_URI: { - /* EVIDENCE-OF: R-25451-61125 The SQLITE_CONFIG_URI option takes a single - ** argument of type int. If non-zero, then URI handling is globally - ** enabled. If the parameter is zero, then URI handling is globally - ** disabled. */ sqlite3GlobalConfig.bOpenUri = va_arg(ap, int); break; } case SQLITE_CONFIG_COVERING_INDEX_SCAN: { - /* EVIDENCE-OF: R-36592-02772 The SQLITE_CONFIG_COVERING_INDEX_SCAN - ** option takes a single integer argument which is interpreted as a - ** boolean in order to enable or disable the use of covering indices for - ** full table scans in the query optimizer. */ sqlite3GlobalConfig.bUseCis = va_arg(ap, int); break; } #ifdef SQLITE_ENABLE_SQLLOG @@ -553,37 +499,24 @@ break; } #endif case SQLITE_CONFIG_MMAP_SIZE: { - /* EVIDENCE-OF: R-58063-38258 SQLITE_CONFIG_MMAP_SIZE takes two 64-bit - ** integer (sqlite3_int64) values that are the default mmap size limit - ** (the default setting for PRAGMA mmap_size) and the maximum allowed - ** mmap size limit. */ sqlite3_int64 szMmap = va_arg(ap, sqlite3_int64); sqlite3_int64 mxMmap = va_arg(ap, sqlite3_int64); - /* EVIDENCE-OF: R-53367-43190 If either argument to this option is - ** negative, then that argument is changed to its compile-time default. - ** - ** EVIDENCE-OF: R-34993-45031 The maximum allowed mmap size will be - ** silently truncated if necessary so that it does not exceed the - ** compile-time maximum mmap size set by the SQLITE_MAX_MMAP_SIZE - ** compile-time option. - */ - if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ) mxMmap = SQLITE_MAX_MMAP_SIZE; + if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ){ + mxMmap = SQLITE_MAX_MMAP_SIZE; + } + sqlite3GlobalConfig.mxMmap = mxMmap; if( szMmap<0 ) szMmap = SQLITE_DEFAULT_MMAP_SIZE; if( szMmap>mxMmap) szMmap = mxMmap; - sqlite3GlobalConfig.mxMmap = mxMmap; sqlite3GlobalConfig.szMmap = szMmap; break; } -#if SQLITE_OS_WIN && defined(SQLITE_WIN32_MALLOC) /* IMP: R-04780-55815 */ +#if SQLITE_OS_WIN && defined(SQLITE_WIN32_MALLOC) case SQLITE_CONFIG_WIN32_HEAPSIZE: { - /* EVIDENCE-OF: R-34926-03360 SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit - ** unsigned integer value that specifies the maximum size of the created - ** heap. */ sqlite3GlobalConfig.nHeap = va_arg(ap, int); break; } #endif @@ -663,29 +596,19 @@ /* ** Return the mutex associated with a database connection. */ sqlite3_mutex *sqlite3_db_mutex(sqlite3 *db){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif return db->mutex; } /* ** Free up as much memory as we can from the given database ** connection. */ int sqlite3_db_release_memory(sqlite3 *db){ int i; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif sqlite3_mutex_enter(db->mutex); sqlite3BtreeEnterAll(db); for(i=0; inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ @@ -812,42 +735,24 @@ /* ** Return the ROWID of the most recent insert */ sqlite_int64 sqlite3_last_insert_rowid(sqlite3 *db){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif return db->lastRowid; } /* ** Return the number of changes in the most recent call to sqlite3_exec(). */ int sqlite3_changes(sqlite3 *db){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif return db->nChange; } /* ** Return the number of changes since the database handle was opened. */ int sqlite3_total_changes(sqlite3 *db){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif return db->nTotalChange; } /* ** Close all open savepoints. This function only manipulates fields of the @@ -1392,13 +1297,10 @@ int sqlite3_busy_handler( sqlite3 *db, int (*xBusy)(void*,int), void *pArg ){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE; -#endif sqlite3_mutex_enter(db->mutex); db->busyHandler.xFunc = xBusy; db->busyHandler.pArg = pArg; db->busyHandler.nBusy = 0; db->busyTimeout = 0; @@ -1416,16 +1318,10 @@ sqlite3 *db, int nOps, int (*xProgress)(void*), void *pArg ){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return; - } -#endif sqlite3_mutex_enter(db->mutex); if( nOps>0 ){ db->xProgress = xProgress; db->nProgressOps = (unsigned)nOps; db->pProgressArg = pArg; @@ -1442,13 +1338,10 @@ /* ** This routine installs a default busy handler that waits for the ** specified number of milliseconds before returning 0. */ int sqlite3_busy_timeout(sqlite3 *db, int ms){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif if( ms>0 ){ sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db); db->busyTimeout = ms; }else{ sqlite3_busy_handler(db, 0, 0); @@ -1458,16 +1351,10 @@ /* ** Cause any pending operation to stop at its earliest opportunity. */ void sqlite3_interrupt(sqlite3 *db){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return; - } -#endif db->u1.isInterrupted = 1; } /* @@ -1601,16 +1488,10 @@ void (*xFinal)(sqlite3_context*), void (*xDestroy)(void *) ){ int rc = SQLITE_ERROR; FuncDestructor *pArg = 0; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - return SQLITE_MISUSE_BKPT; - } -#endif sqlite3_mutex_enter(db->mutex); if( xDestroy ){ pArg = (FuncDestructor *)sqlite3DbMallocZero(db, sizeof(FuncDestructor)); if( !pArg ){ xDestroy(p); @@ -1643,14 +1524,10 @@ void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*) ){ int rc; char *zFunc8; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) || zFunctionName==0 ) return SQLITE_MISUSE_BKPT; -#endif sqlite3_mutex_enter(db->mutex); assert( !db->mallocFailed ); zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE); rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal,0); sqlite3DbFree(db, zFunc8); @@ -1678,16 +1555,10 @@ const char *zName, int nArg ){ int nName = sqlite3Strlen30(zName); int rc = SQLITE_OK; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) || zName==0 || nArg<-2 ){ - return SQLITE_MISUSE_BKPT; - } -#endif sqlite3_mutex_enter(db->mutex); if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){ rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8, 0, sqlite3InvalidFunction, 0, 0, 0); } @@ -1705,17 +1576,10 @@ ** trace is a pointer to a function that is invoked at the start of each ** SQL statement. */ void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){ void *pOld; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif sqlite3_mutex_enter(db->mutex); pOld = db->pTraceArg; db->xTrace = xTrace; db->pTraceArg = pArg; sqlite3_mutex_leave(db->mutex); @@ -1733,17 +1597,10 @@ sqlite3 *db, void (*xProfile)(void*,const char*,sqlite_uint64), void *pArg ){ void *pOld; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif sqlite3_mutex_enter(db->mutex); pOld = db->pProfileArg; db->xProfile = xProfile; db->pProfileArg = pArg; sqlite3_mutex_leave(db->mutex); @@ -1760,17 +1617,10 @@ sqlite3 *db, /* Attach the hook to this database */ int (*xCallback)(void*), /* Function to invoke on each commit */ void *pArg /* Argument to the function */ ){ void *pOld; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif sqlite3_mutex_enter(db->mutex); pOld = db->pCommitArg; db->xCommitCallback = xCallback; db->pCommitArg = pArg; sqlite3_mutex_leave(db->mutex); @@ -1785,17 +1635,10 @@ sqlite3 *db, /* Attach the hook to this database */ void (*xCallback)(void*,int,char const *,char const *,sqlite_int64), void *pArg /* Argument to the function */ ){ void *pRet; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif sqlite3_mutex_enter(db->mutex); pRet = db->pUpdateArg; db->xUpdateCallback = xCallback; db->pUpdateArg = pArg; sqlite3_mutex_leave(db->mutex); @@ -1810,17 +1653,10 @@ sqlite3 *db, /* Attach the hook to this database */ void (*xCallback)(void*), /* Callback function */ void *pArg /* Argument to the function */ ){ void *pRet; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif sqlite3_mutex_enter(db->mutex); pRet = db->pRollbackArg; db->xRollbackCallback = xCallback; db->pRollbackArg = pArg; sqlite3_mutex_leave(db->mutex); @@ -1863,13 +1699,10 @@ int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){ #ifdef SQLITE_OMIT_WAL UNUSED_PARAMETER(db); UNUSED_PARAMETER(nFrame); #else -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif if( nFrame>0 ){ sqlite3_wal_hook(db, sqlite3WalDefaultHook, SQLITE_INT_TO_PTR(nFrame)); }else{ sqlite3_wal_hook(db, 0, 0); } @@ -1886,16 +1719,10 @@ int(*xCallback)(void *, sqlite3*, const char*, int), void *pArg /* First argument passed to xCallback() */ ){ #ifndef SQLITE_OMIT_WAL void *pRet; -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif sqlite3_mutex_enter(db->mutex); pRet = db->pWalArg; db->xWalCallback = xCallback; db->pWalArg = pArg; sqlite3_mutex_leave(db->mutex); @@ -1919,14 +1746,10 @@ return SQLITE_OK; #else int rc; /* Return code */ int iDb = SQLITE_MAX_ATTACHED; /* sqlite3.aDb[] index of db to checkpoint */ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif - /* Initialize the output variables to -1 in case an error occurs. */ if( pnLog ) *pnLog = -1; if( pnCkpt ) *pnCkpt = -1; assert( SQLITE_CHECKPOINT_FULL>SQLITE_CHECKPOINT_PASSIVE ); @@ -2319,16 +2142,10 @@ ** from forming. */ int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ int oldLimit; -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return -1; - } -#endif /* EVIDENCE-OF: R-30189-54097 For each limit category SQLITE_LIMIT_NAME ** there is a hard upper bound set at compile-time by a C preprocessor ** macro called SQLITE_MAX_NAME. (The "_LIMIT_" in the name is changed to ** "_MAX_".) @@ -2401,12 +2218,11 @@ char c; int nUri = sqlite3Strlen30(zUri); assert( *pzErrMsg==0 ); - if( ((flags & SQLITE_OPEN_URI) /* IMP: R-48725-32206 */ - || sqlite3GlobalConfig.bOpenUri) /* IMP: R-51689-46548 */ + if( ((flags & SQLITE_OPEN_URI) || sqlite3GlobalConfig.bOpenUri) && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */ ){ char *zOpt; int eState; /* Parser state when parsing URI */ int iIn; /* Input character index */ @@ -2611,13 +2427,10 @@ int rc; /* Return code */ int isThreadsafe; /* True for threadsafe connections */ char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */ char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */ -#ifdef SQLITE_ENABLE_API_ARMOR - if( ppDb==0 ) return SQLITE_MISUSE_BKPT; -#endif *ppDb = 0; #ifndef SQLITE_OMIT_AUTOINIT rc = sqlite3_initialize(); if( rc ) return rc; #endif @@ -2903,19 +2716,17 @@ ){ char const *zFilename8; /* zFilename encoded in UTF-8 instead of UTF-16 */ sqlite3_value *pVal; int rc; -#ifdef SQLITE_ENABLE_API_ARMOR - if( ppDb==0 ) return SQLITE_MISUSE_BKPT; -#endif + assert( zFilename ); + assert( ppDb ); *ppDb = 0; #ifndef SQLITE_OMIT_AUTOINIT rc = sqlite3_initialize(); if( rc ) return rc; #endif - if( zFilename==0 ) zFilename = "\000\000"; pVal = sqlite3ValueNew(0); sqlite3ValueSetStr(pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC); zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8); if( zFilename8 ){ rc = openDatabase(zFilename8, ppDb, @@ -2941,11 +2752,17 @@ const char *zName, int enc, void* pCtx, int(*xCompare)(void*,int,const void*,int,const void*) ){ - return sqlite3_create_collation_v2(db, zName, enc, pCtx, xCompare, 0); + int rc; + sqlite3_mutex_enter(db->mutex); + assert( !db->mallocFailed ); + rc = createCollation(db, zName, (u8)enc, pCtx, xCompare, 0); + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; } /* ** Register a new collation sequence with the database handle db. */ @@ -2956,14 +2773,10 @@ void* pCtx, int(*xCompare)(void*,int,const void*,int,const void*), void(*xDel)(void*) ){ int rc; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; -#endif sqlite3_mutex_enter(db->mutex); assert( !db->mallocFailed ); rc = createCollation(db, zName, (u8)enc, pCtx, xCompare, xDel); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); @@ -2981,14 +2794,10 @@ void* pCtx, int(*xCompare)(void*,int,const void*,int,const void*) ){ int rc = SQLITE_OK; char *zName8; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; -#endif sqlite3_mutex_enter(db->mutex); assert( !db->mallocFailed ); zName8 = sqlite3Utf16to8(db, zName, -1, SQLITE_UTF16NATIVE); if( zName8 ){ rc = createCollation(db, zName8, (u8)enc, pCtx, xCompare, 0); @@ -3007,13 +2816,10 @@ int sqlite3_collation_needed( sqlite3 *db, void *pCollNeededArg, void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*) ){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif sqlite3_mutex_enter(db->mutex); db->xCollNeeded = xCollNeeded; db->xCollNeeded16 = 0; db->pCollNeededArg = pCollNeededArg; sqlite3_mutex_leave(db->mutex); @@ -3028,13 +2834,10 @@ int sqlite3_collation_needed16( sqlite3 *db, void *pCollNeededArg, void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*) ){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif sqlite3_mutex_enter(db->mutex); db->xCollNeeded = 0; db->xCollNeeded16 = xCollNeeded16; db->pCollNeededArg = pCollNeededArg; sqlite3_mutex_leave(db->mutex); @@ -3057,16 +2860,10 @@ ** mode. Return TRUE if it is and FALSE if not. Autocommit mode is on ** by default. Autocommit is disabled by a BEGIN statement and reenabled ** by the next COMMIT or ROLLBACK. */ int sqlite3_get_autocommit(sqlite3 *db){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif return db->autoCommit; } /* ** The following routines are substitutes for constants SQLITE_CORRUPT, @@ -3245,13 +3042,10 @@ /* ** Enable or disable the extended result codes. */ int sqlite3_extended_result_codes(sqlite3 *db, int onoff){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif sqlite3_mutex_enter(db->mutex); db->errMask = onoff ? 0xffffffff : 0xff; sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } @@ -3261,13 +3055,10 @@ */ int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){ int rc = SQLITE_ERROR; Btree *pBtree; -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif sqlite3_mutex_enter(db->mutex); pBtree = sqlite3DbNameToBtree(db, zDbName); if( pBtree ){ Pager *pPager; sqlite3_file *fd; @@ -3606,11 +3397,11 @@ ** query parameter we seek. This routine returns the value of the zParam ** parameter if it exists. If the parameter does not exist, this routine ** returns a NULL pointer. */ const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){ - if( zFilename==0 || zParam==0 ) return 0; + if( zFilename==0 ) return 0; zFilename += sqlite3Strlen30(zFilename) + 1; while( zFilename[0] ){ int x = strcmp(zFilename, zParam); zFilename += sqlite3Strlen30(zFilename) + 1; if( x==0 ) return zFilename; @@ -3662,29 +3453,17 @@ /* ** Return the filename of the database associated with a database ** connection. */ const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif Btree *pBt = sqlite3DbNameToBtree(db, zDbName); return pBt ? sqlite3BtreeGetFilename(pBt) : 0; } /* ** Return 1 if database is read-only or 0 if read/write. Return -1 if ** no such database exists. */ int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return -1; - } -#endif Btree *pBt = sqlite3DbNameToBtree(db, zDbName); return pBt ? sqlite3BtreeIsReadonly(pBt) : -1; } Index: src/malloc.c ================================================================== --- src/malloc.c +++ src/malloc.c @@ -375,16 +375,15 @@ } assert( sqlite3_mutex_notheld(mem0.mutex) ); #if SQLITE_THREADSAFE==0 && !defined(NDEBUG) - /* EVIDENCE-OF: R-12970-05880 SQLite will not use more than one scratch - ** buffers per thread. - ** - ** This can only be checked in single-threaded mode. - */ - assert( scratchAllocOut==0 ); + /* Verify that no more than two scratch allocations per thread + ** are outstanding at one time. (This is only checked in the + ** single-threaded case since checking in the multi-threaded case + ** would be much more complicated.) */ + assert( scratchAllocOut<=1 ); if( p ) scratchAllocOut++; #endif return p; } Index: src/mutex.c ================================================================== --- src/mutex.c +++ src/mutex.c @@ -80,11 +80,10 @@ ** Retrieve a pointer to a static mutex or allocate a new dynamic one. */ sqlite3_mutex *sqlite3_mutex_alloc(int id){ #ifndef SQLITE_OMIT_AUTOINIT if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0; - if( id>SQLITE_MUTEX_RECURSIVE && sqlite3MutexInit() ) return 0; #endif return sqlite3GlobalConfig.mutex.xMutexAlloc(id); } sqlite3_mutex *sqlite3MutexAlloc(int id){ Index: src/mutex_unix.c ================================================================== --- src/mutex_unix.c +++ src/mutex_unix.c @@ -173,16 +173,12 @@ pthread_mutex_init(&p->mutex, 0); } break; } default: { -#ifdef SQLITE_ENABLE_API_ARMOR - if( iType-2<0 || iType-2>=ArraySize(staticMutexes) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif + assert( iType-2 >= 0 ); + assert( iType-2 < ArraySize(staticMutexes) ); p = &staticMutexes[iType-2]; #if SQLITE_MUTEX_NREF p->id = iType; #endif break; Index: src/os.c ================================================================== --- src/os.c +++ src/os.c @@ -359,14 +359,10 @@ MUTEX_LOGIC(sqlite3_mutex *mutex;) #ifndef SQLITE_OMIT_AUTOINIT int rc = sqlite3_initialize(); if( rc ) return rc; #endif -#ifdef SQLITE_ENABLE_API_ARMOR - if( pVfs==0 ) return SQLITE_MISUSE_BKPT; -#endif - MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) sqlite3_mutex_enter(mutex); vfsUnlink(pVfs); if( makeDflt || vfsList==0 ){ pVfs->pNext = vfsList; Index: src/os_win.c ================================================================== --- src/os_win.c +++ src/os_win.c @@ -32,15 +32,10 @@ #if !SQLITE_OS_WINNT && !defined(SQLITE_OMIT_WAL) # error "WAL mode requires support from the Windows NT kernel, compile\ with SQLITE_OMIT_WAL." #endif -#if !SQLITE_OS_WINNT && SQLITE_MAX_MMAP_SIZE>0 -# error "Memory mapped files require support from the Windows NT kernel,\ - compile with SQLITE_MAX_MMAP_SIZE=0." -#endif - /* ** Are most of the Win32 ANSI APIs available (i.e. with certain exceptions ** based on the sub-platform)? */ #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(SQLITE_WIN32_NO_ANSI) @@ -166,15 +161,14 @@ # define winGetDirSep() '\\' #endif /* ** Do we need to manually define the Win32 file mapping APIs for use with WAL -** mode or memory mapped files (e.g. these APIs are available in the Windows -** CE SDK; however, they are not present in the header file)? +** mode (e.g. these APIs are available in the Windows CE SDK; however, they +** are not present in the header file)? */ -#if SQLITE_WIN32_FILEMAPPING_API && \ - (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) +#if SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL) /* ** Two of the file mapping APIs are different under WinRT. Figure out which ** set we need. */ #if SQLITE_OS_WINRT @@ -198,11 +192,11 @@ /* ** This file mapping API is common to both Win32 and WinRT. */ WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID); -#endif /* SQLITE_WIN32_FILEMAPPING_API */ +#endif /* SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL) */ /* ** Some Microsoft compilers lack this definition. */ #ifndef INVALID_FILE_ATTRIBUTES @@ -491,21 +485,21 @@ #define osCreateFileW ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD, \ LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent) #if (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \ - (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)) + !defined(SQLITE_OMIT_WAL)) { "CreateFileMappingA", (SYSCALL)CreateFileMappingA, 0 }, #else { "CreateFileMappingA", (SYSCALL)0, 0 }, #endif #define osCreateFileMappingA ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \ DWORD,DWORD,DWORD,LPCSTR))aSyscall[6].pCurrent) #if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ - (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)) + !defined(SQLITE_OMIT_WAL)) { "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 }, #else { "CreateFileMappingW", (SYSCALL)0, 0 }, #endif @@ -841,12 +835,11 @@ #ifndef osLockFileEx #define osLockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD,DWORD, \ LPOVERLAPPED))aSyscall[48].pCurrent) #endif -#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && \ - (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)) +#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL)) { "MapViewOfFile", (SYSCALL)MapViewOfFile, 0 }, #else { "MapViewOfFile", (SYSCALL)0, 0 }, #endif @@ -912,11 +905,11 @@ #endif #define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ LPOVERLAPPED))aSyscall[58].pCurrent) -#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 +#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL) { "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 }, #else { "UnmapViewOfFile", (SYSCALL)0, 0 }, #endif @@ -975,11 +968,11 @@ #endif #define osGetFileInformationByHandleEx ((BOOL(WINAPI*)(HANDLE, \ FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[66].pCurrent) -#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) +#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL) { "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 }, #else { "MapViewOfFileFromApp", (SYSCALL)0, 0 }, #endif @@ -1039,11 +1032,11 @@ { "GetProcessHeap", (SYSCALL)GetProcessHeap, 0 }, #define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[74].pCurrent) -#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) +#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL) { "CreateFileMappingFromApp", (SYSCALL)CreateFileMappingFromApp, 0 }, #else { "CreateFileMappingFromApp", (SYSCALL)0, 0 }, #endif Index: src/pager.c ================================================================== --- src/pager.c +++ src/pager.c @@ -6845,22 +6845,10 @@ return SQLITE_OK; } #endif -/* -** The page handle passed as the first argument refers to a dirty page -** with a page number other than iNew. This function changes the page's -** page number to iNew and sets the value of the PgHdr.flags field to -** the value passed as the third parameter. -*/ -void sqlite3PagerRekey(DbPage *pPg, Pgno iNew, u16 flags){ - assert( pPg->pgno!=iNew ); - pPg->flags = flags; - sqlite3PcacheMove(pPg, iNew); -} - /* ** Return a pointer to the data for the specified page. */ void *sqlite3PagerGetData(DbPage *pPg){ assert( pPg->nRef>0 || pPg->pPager->memDb ); @@ -7254,8 +7242,7 @@ int sqlite3PagerWalFramesize(Pager *pPager){ assert( pPager->eState>=PAGER_READER ); return sqlite3WalFramesize(pPager->pWal); } #endif - #endif /* SQLITE_OMIT_DISKIO */ Index: src/pager.h ================================================================== --- src/pager.h +++ src/pager.h @@ -186,12 +186,10 @@ int sqlite3SectorSize(sqlite3_file *); /* Functions used to truncate the database file. */ void sqlite3PagerTruncateImage(Pager*,Pgno); -void sqlite3PagerRekey(DbPage*, Pgno, u16); - #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) void *sqlite3PagerCodec(DbPage *); #endif /* Functions to support testing and debugging. */ Index: src/pcache.c ================================================================== --- src/pcache.c +++ src/pcache.c @@ -648,17 +648,10 @@ */ void sqlite3PcacheShrink(PCache *pCache){ assert( pCache->pCache!=0 ); sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache); } - -/* -** Return the size of the header added by this middleware layer -** in the page-cache hierarchy. -*/ -int sqlite3HeaderSizePcache(void){ return sizeof(PgHdr); } - #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) /* ** For all dirty pages currently in the cache, invoke the specified ** callback. This is only used if the SQLITE_CHECK_PAGES macro is Index: src/pcache.h ================================================================== --- src/pcache.h +++ src/pcache.h @@ -158,10 +158,6 @@ void sqlite3PcacheStats(int*,int*,int*,int*); #endif void sqlite3PCacheSetDefault(void); -/* Return the header size */ -int sqlite3HeaderSizePcache(void); -int sqlite3HeaderSizePcache1(void); - #endif /* _PCACHE_H_ */ Index: src/pcache1.c ================================================================== --- src/pcache1.c +++ src/pcache1.c @@ -979,15 +979,10 @@ pcache1Shrink /* xShrink */ }; sqlite3_config(SQLITE_CONFIG_PCACHE2, &defaultMethods); } -/* -** Return the size of the header on each page of this PCACHE implementation. -*/ -int sqlite3HeaderSizePcache1(void){ return sizeof(PgHdr1); } - #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT /* ** This function is called to free superfluous dynamically allocated memory ** held by the pager system. Memory in use by any SQLite pager allocated ** by the current thread may be sqlite3_free()ed. Index: src/prepare.c ================================================================== --- src/prepare.c +++ src/prepare.c @@ -707,16 +707,13 @@ Vdbe *pOld, /* VM being reprepared */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ){ int rc; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( ppStmt==0 ) return SQLITE_MISUSE_BKPT; -#endif + assert( ppStmt!=0 ); *ppStmt = 0; - if( !sqlite3SafetyCheckOk(db)||zSql==0 ){ + if( !sqlite3SafetyCheckOk(db) ){ return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(db->mutex); sqlite3BtreeEnterAll(db); rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail); @@ -819,15 +816,13 @@ */ char *zSql8; const char *zTail8 = 0; int rc = SQLITE_OK; -#ifdef SQLITE_ENABLE_API_ARMOR - if( ppStmt==0 ) return SQLITE_MISUSE_BKPT; -#endif + assert( ppStmt ); *ppStmt = 0; - if( !sqlite3SafetyCheckOk(db)||zSql==0 ){ + if( !sqlite3SafetyCheckOk(db) ){ return SQLITE_MISUSE_BKPT; } if( nBytes>=0 ){ int sz; const char *z = (const char*)zSql; Index: src/printf.c ================================================================== --- src/printf.c +++ src/printf.c @@ -221,17 +221,10 @@ etByte flag_rtz; /* True if trailing zeros should be removed */ #endif PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */ char buf[etBUFSIZE]; /* Conversion buffer */ -#ifdef SQLITE_ENABLE_API_ARMOR - if( ap==0 ){ - (void)SQLITE_MISUSE_BKPT; - sqlite3StrAccumReset(pAccum); - return; - } -#endif bufpt = 0; if( bFlags ){ if( (bArgList = (bFlags & SQLITE_PRINTF_SQLFUNC))!=0 ){ pArgList = va_arg(ap, PrintfArguments*); } @@ -768,15 +761,10 @@ return N; }else{ char *zOld = (p->zText==p->zBase ? 0 : p->zText); i64 szNew = p->nChar; szNew += N + 1; - if( szNew+p->nChar<=p->mxAlloc ){ - /* Force exponential buffer size growth as long as it does not overflow, - ** to avoid having to call this routine too often */ - szNew += p->nChar; - } if( szNew > p->mxAlloc ){ sqlite3StrAccumReset(p); setStrAccumError(p, STRACCUM_TOOBIG); return 0; }else{ @@ -789,11 +777,10 @@ } if( zNew ){ assert( p->zText!=0 || p->nChar==0 ); if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar); p->zText = zNew; - p->nAlloc = sqlite3DbMallocSize(p->db, zNew); }else{ sqlite3StrAccumReset(p); setStrAccumError(p, STRACCUM_NOMEM); return 0; } @@ -959,17 +946,10 @@ */ char *sqlite3_vmprintf(const char *zFormat, va_list ap){ char *z; char zBase[SQLITE_PRINT_BUF_SIZE]; StrAccum acc; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( zFormat==0 ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif sqlite3StrAccumInit(&acc, zBase, sizeof(zBase), SQLITE_MAX_LENGTH); acc.useMalloc = 2; @@ -1008,17 +988,10 @@ ** sqlite3_vsnprintf() is the varargs version. */ char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){ StrAccum acc; if( n<=0 ) return zBuf; -#ifdef SQLITE_ENABLE_API_ARMOR - if( zBuf==0 || zFormat==0 ) { - (void)SQLITE_MISUSE_BKPT; - if( zBuf && n>0 ) zBuf[0] = 0; - return zBuf; - } -#endif sqlite3StrAccumInit(&acc, zBuf, n, 0); acc.useMalloc = 0; sqlite3VXPrintf(&acc, 0, zFormat, ap); return sqlite3StrAccumFinish(&acc); } Index: src/random.c ================================================================== --- src/random.c +++ src/random.c @@ -46,23 +46,15 @@ #else # define wsdPrng sqlite3Prng #endif #if SQLITE_THREADSAFE - sqlite3_mutex *mutex; -#endif - -#ifndef SQLITE_OMIT_AUTOINIT - if( sqlite3_initialize() ) return; + sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG); + sqlite3_mutex_enter(mutex); #endif -#if SQLITE_THREADSAFE - mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG); -#endif - - sqlite3_mutex_enter(mutex); - if( N<=0 || pBuf==0 ){ + if( N<=0 ){ wsdPrng.isInit = 0; sqlite3_mutex_leave(mutex); return; } Index: src/resolve.c ================================================================== --- src/resolve.c +++ src/resolve.c @@ -26,19 +26,19 @@ ** ** incrAggFunctionDepth(pExpr,n) is the main routine. incrAggDepth(..) ** is a helper function - a callback for the tree walker. */ static int incrAggDepth(Walker *pWalker, Expr *pExpr){ - if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.n; + if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.i; return WRC_Continue; } static void incrAggFunctionDepth(Expr *pExpr, int N){ if( N>0 ){ Walker w; memset(&w, 0, sizeof(w)); w.xExprCallback = incrAggDepth; - w.u.n = N; + w.u.i = N; sqlite3WalkExpr(&w, pExpr); } } /* @@ -582,11 +582,11 @@ double r = -1.0; if( p->op!=TK_FLOAT ) return -1; sqlite3AtoF(p->u.zToken, &r, sqlite3Strlen30(p->u.zToken), SQLITE_UTF8); assert( r>=0.0 ); if( r>1.0 ) return -1; - return (int)(r*134217728.0); + return (int)(r*1000.0); } /* ** This routine is callback for sqlite3WalkExpr(). ** @@ -714,11 +714,11 @@ ** EVIDENCE-OF: R-36850-34127 The likely(X) function is short-hand for ** likelihood(X,0.9375). ** EVIDENCE-OF: R-53436-40973 The likely(X) function is equivalent to ** likelihood(X,0.9375). */ /* TUNING: unlikely() probability is 0.0625. likely() is 0.9375 */ - pExpr->iTable = pDef->zName[0]=='u' ? 8388608 : 125829120; + pExpr->iTable = pDef->zName[0]=='u' ? 62 : 938; } } #ifndef SQLITE_OMIT_AUTHORIZATION auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0, pDef->zName, 0); if( auth!=SQLITE_OK ){ Index: src/shell.c ================================================================== --- src/shell.c +++ src/shell.c @@ -170,12 +170,11 @@ /* Saved resource information for the beginning of an operation */ static HANDLE hProcess; static FILETIME ftKernelBegin; static FILETIME ftUserBegin; static sqlite3_int64 ftWallBegin; -typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, - LPFILETIME, LPFILETIME); +typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME); static GETPROCTIMES getProcessTimesAddr = NULL; /* ** Check to see if we have timer support. Return 1 if necessary ** support found (or found previously). @@ -182,20 +181,19 @@ */ static int hasTimer(void){ if( getProcessTimesAddr ){ return 1; } else { - /* GetProcessTimes() isn't supported in WIN95 and some other Windows - ** versions. See if the version we are running on has it, and if it - ** does, save off a pointer to it and the current process handle. + /* GetProcessTimes() isn't supported in WIN95 and some other Windows versions. + ** See if the version we are running on has it, and if it does, save off + ** a pointer to it and the current process handle. */ hProcess = GetCurrentProcess(); if( hProcess ){ HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll")); if( NULL != hinstLib ){ - getProcessTimesAddr = - (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes"); + getProcessTimesAddr = (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes"); if( NULL != getProcessTimesAddr ){ return 1; } FreeLibrary(hinstLib); } @@ -208,12 +206,11 @@ ** Begin timing an operation */ static void beginTimer(void){ if( enableTimer && getProcessTimesAddr ){ FILETIME ftCreation, ftExit; - getProcessTimesAddr(hProcess,&ftCreation,&ftExit, - &ftKernelBegin,&ftUserBegin); + getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelBegin, &ftUserBegin); ftWallBegin = timeOfDay(); } } /* Return the difference of two FILETIME structs in seconds */ @@ -228,11 +225,11 @@ */ static void endTimer(void){ if( enableTimer && getProcessTimesAddr){ FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd; sqlite3_int64 ftWallEnd = timeOfDay(); - getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd); + getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd); printf("Run Time: real %.3f user %f sys %f\n", (ftWallEnd - ftWallBegin)*0.001, timeDiff(&ftUserBegin, &ftUserEnd), timeDiff(&ftKernelBegin, &ftKernelEnd)); } @@ -458,11 +455,10 @@ struct ShellState { sqlite3 *db; /* The database */ int echoOn; /* True to echo input commands */ int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */ int statsOn; /* True to display memory stats before each finalize */ - int scanstatsOn; /* True to display scan stats before each finalize */ int outCount; /* Revert to stdout when reaching zero */ int cnt; /* Number of records displayed so far */ FILE *out; /* Write results here */ FILE *traceOut; /* Output for sqlite3_trace() */ int nErr; /* Number of errors seen */ @@ -727,17 +723,11 @@ /* ** This is the callback routine that the shell ** invokes for each row of a query result. */ -static int shell_callback( - void *pArg, - int nArg, /* Number of result columns */ - char **azArg, /* Text of each result column */ - char **azCol, /* Column names */ - int *aiType /* Column types */ -){ +static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int *aiType){ int i; ShellState *p = (ShellState*)pArg; switch( p->mode ){ case MODE_Line: { @@ -890,11 +880,11 @@ for(i=0; iout,"%s",p->newline); } - if( nArg>0 ){ + if( azArg>0 ){ for(i=0; iout,"%s",p->newline); } @@ -1112,81 +1102,61 @@ if( pArg && pArg->out ){ iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, - "Memory Used: %d (max %d) bytes\n", - iCur, iHiwtr); + fprintf(pArg->out, "Memory Used: %d (max %d) bytes\n", iCur, iHiwtr); iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Number of Outstanding Allocations: %d (max %d)\n", - iCur, iHiwtr); + fprintf(pArg->out, "Number of Outstanding Allocations: %d (max %d)\n", iCur, iHiwtr); if( pArg->shellFlgs & SHFLG_Pagecache ){ iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, - "Number of Pcache Pages Used: %d (max %d) pages\n", - iCur, iHiwtr); + fprintf(pArg->out, "Number of Pcache Pages Used: %d (max %d) pages\n", iCur, iHiwtr); } iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, - "Number of Pcache Overflow Bytes: %d (max %d) bytes\n", - iCur, iHiwtr); + fprintf(pArg->out, "Number of Pcache Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr); if( pArg->shellFlgs & SHFLG_Scratch ){ iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Number of Scratch Allocations Used: %d (max %d)\n", - iCur, iHiwtr); + fprintf(pArg->out, "Number of Scratch Allocations Used: %d (max %d)\n", iCur, iHiwtr); } iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, - "Number of Scratch Overflow Bytes: %d (max %d) bytes\n", - iCur, iHiwtr); + fprintf(pArg->out, "Number of Scratch Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr); iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Largest Allocation: %d bytes\n", - iHiwtr); + fprintf(pArg->out, "Largest Allocation: %d bytes\n", iHiwtr); iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Largest Pcache Allocation: %d bytes\n", - iHiwtr); + fprintf(pArg->out, "Largest Pcache Allocation: %d bytes\n", iHiwtr); iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Largest Scratch Allocation: %d bytes\n", - iHiwtr); + fprintf(pArg->out, "Largest Scratch Allocation: %d bytes\n", iHiwtr); #ifdef YYTRACKMAXSTACKDEPTH iHiwtr = iCur = -1; sqlite3_status(SQLITE_STATUS_PARSER_STACK, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Deepest Parser Stack: %d (max %d)\n", - iCur, iHiwtr); + fprintf(pArg->out, "Deepest Parser Stack: %d (max %d)\n", iCur, iHiwtr); #endif } if( pArg && pArg->out && db ){ if( pArg->shellFlgs & SHFLG_Lookaside ){ iHiwtr = iCur = -1; - sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, - &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Lookaside Slots Used: %d (max %d)\n", - iCur, iHiwtr); - sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, - &iCur, &iHiwtr, bReset); + sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHiwtr, bReset); + fprintf(pArg->out, "Lookaside Slots Used: %d (max %d)\n", iCur, iHiwtr); + sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHiwtr, bReset); fprintf(pArg->out, "Successful lookaside attempts: %d\n", iHiwtr); - sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, - &iCur, &iHiwtr, bReset); + sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur, &iHiwtr, bReset); fprintf(pArg->out, "Lookaside failures due to size: %d\n", iHiwtr); - sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, - &iCur, &iHiwtr, bReset); + sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur, &iHiwtr, bReset); fprintf(pArg->out, "Lookaside failures due to OOM: %d\n", iHiwtr); } iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Pager Heap Usage: %d bytes\n",iCur); - iHiwtr = iCur = -1; + fprintf(pArg->out, "Pager Heap Usage: %d bytes\n", iCur); iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1); fprintf(pArg->out, "Page cache hits: %d\n", iCur); iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1); fprintf(pArg->out, "Page cache misses: %d\n", iCur); @@ -1193,76 +1163,30 @@ iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1); fprintf(pArg->out, "Page cache writes: %d\n", iCur); iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Schema Heap Usage: %d bytes\n",iCur); + fprintf(pArg->out, "Schema Heap Usage: %d bytes\n", iCur); iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset); - fprintf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n",iCur); + fprintf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n", iCur); } if( pArg && pArg->out && db && pArg->pStmt ){ - iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, - bReset); + iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset); fprintf(pArg->out, "Fullscan Steps: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset); fprintf(pArg->out, "Sort Operations: %d\n", iCur); - iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset); + iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX, bReset); fprintf(pArg->out, "Autoindex Inserts: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset); fprintf(pArg->out, "Virtual Machine Steps: %d\n", iCur); } return 0; } -/* -** Display scan stats. -*/ -static void display_scanstats( - sqlite3 *db, /* Database to query */ - ShellState *pArg /* Pointer to ShellState */ -){ -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS - int i, k, n, mx; - fprintf(pArg->out, "-------- scanstats --------\n"); - mx = 0; - for(k=0; k<=mx; k++){ - double rEstLoop = 1.0; - for(i=n=0; 1; i++){ - sqlite3_stmt *p = pArg->pStmt; - sqlite3_int64 nLoop, nVisit; - double rEst; - int iSid; - const char *zExplain; - if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){ - break; - } - sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_SELECTID, (void*)&iSid); - if( iSid>mx ) mx = iSid; - if( iSid!=k ) continue; - if( n==0 ){ - rEstLoop = (double)nLoop; - if( k>0 ) fprintf(pArg->out, "-------- subquery %d -------\n", k); - } - n++; - sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit); - sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst); - sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain); - fprintf(pArg->out, "Loop %2d: %s\n", n, zExplain); - rEstLoop *= rEst; - fprintf(pArg->out, - " nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n", - nLoop, nVisit, (sqlite3_int64)(rEstLoop+0.5), rEst - ); - } - } - fprintf(pArg->out, "---------------------------\n"); -#endif -} - /* ** Parameter azArray points to a zero-terminated array of strings. zStr ** points to a single nul-terminated string. Return non-zero if zStr ** is equal, according to strcmp(), to any of the strings in the array. ** Otherwise, return zero. @@ -1300,12 +1224,11 @@ int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */ int iOp; /* Index of operation in p->aiIndent[] */ const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", "NextIfOpen", "PrevIfOpen", 0 }; - const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead", - "Rewind", 0 }; + const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead", "Rewind", 0 }; const char *azGoto[] = { "Goto", 0 }; /* Try to figure out if this is really an EXPLAIN statement. If this ** cannot be verified, return early. */ zSql = sqlite3_sql(pSql); @@ -1414,12 +1337,11 @@ } /* Show the EXPLAIN QUERY PLAN if .eqp is on */ if( pArg && pArg->autoEQP ){ sqlite3_stmt *pExplain; - char *zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", - sqlite3_sql(pStmt)); + char *zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", sqlite3_sql(pStmt)); rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0); if( rc==SQLITE_OK ){ while( sqlite3_step(pExplain)==SQLITE_ROW ){ fprintf(pArg->out,"--EQP-- %d,", sqlite3_column_int(pExplain, 0)); fprintf(pArg->out,"%d,", sqlite3_column_int(pExplain, 1)); @@ -1499,15 +1421,10 @@ /* print usage stats if stats on */ if( pArg && pArg->statsOn ){ display_stats(db, pArg, 0); } - /* print loop-counters if required */ - if( pArg && pArg->scanstatsOn ){ - display_scanstats(db, pArg); - } - /* Finalize the statement just executed. If this fails, save a ** copy of the error message. Otherwise, set zSql to point to the ** next statement to execute. */ rc2 = sqlite3_finalize(pStmt); if( rc!=SQLITE_NOMEM ) rc = rc2; @@ -1714,11 +1631,10 @@ ".prompt MAIN CONTINUE Replace the standard prompts\n" ".quit Exit this program\n" ".read FILENAME Execute SQL in FILENAME\n" ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n" ".save FILE Write in-memory database into FILE\n" - ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off\n" ".schema ?TABLE? Show the CREATE statements\n" " If TABLE specified, only show tables matching\n" " LIKE pattern TABLE.\n" ".separator STRING ?NL? Change separator used by output mode and .import\n" " NL is the end-of-line mark for CSV\n" @@ -3096,23 +3012,10 @@ rc = 1; } sqlite3_close(pSrc); }else - - if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){ - if( nArg==2 ){ - p->scanstatsOn = booleanValue(azArg[1]); -#ifndef SQLITE_ENABLE_STMT_SCANSTATUS - fprintf(stderr, "Warning: .scanstats not available in this build.\n"); -#endif - }else{ - fprintf(stderr, "Usage: .scanstats on|off\n"); - rc = 1; - } - }else - if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){ ShellState data; char *zErrMsg = 0; open_db(p, 0); memcpy(&data, p, sizeof(data)); @@ -3366,11 +3269,11 @@ if( nPrintCol<1 ) nPrintCol = 1; nPrintRow = (nRow + nPrintCol - 1)/nPrintCol; for(i=0; iout, "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j]:""); + fprintf(p->out, "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : ""); } fprintf(p->out, "\n"); } } for(ii=0; iipw_dir; @@ -4236,12 +4138,10 @@ data.echoOn = 1; }else if( strcmp(z,"-eqp")==0 ){ data.autoEQP = 1; }else if( strcmp(z,"-stats")==0 ){ data.statsOn = 1; - }else if( strcmp(z,"-scanstats")==0 ){ - data.scanstatsOn = 1; }else if( strcmp(z,"-bail")==0 ){ bail_on_error = 1; }else if( strcmp(z,"-version")==0 ){ printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid()); return 0; Index: src/sqlite.h.in ================================================================== --- src/sqlite.h.in +++ src/sqlite.h.in @@ -50,11 +50,11 @@ #endif /* ** These no-op macros are used in front of interfaces to mark those ** interfaces as either deprecated or experimental. New applications -** should not use deprecated interfaces - they are supported for backwards +** should not use deprecated interfaces - they are support for backwards ** compatibility only. Application writers should be aware that ** experimental interfaces are subject to change in point releases. ** ** These macros used to resolve to various kinds of compiler magic that ** would generate warning messages when they were used. But that @@ -1497,31 +1497,29 @@ ** it is not possible to set the Serialized [threading mode] and ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the ** SQLITE_CONFIG_SERIALIZED configuration option. ** ** [[SQLITE_CONFIG_MALLOC]]
SQLITE_CONFIG_MALLOC
-**
^(The SQLITE_CONFIG_MALLOC option takes a single argument which is -** a pointer to an instance of the [sqlite3_mem_methods] structure. -** The argument specifies +**
^(This option takes a single argument which is a pointer to an +** instance of the [sqlite3_mem_methods] structure. The argument specifies ** alternative low-level memory allocation routines to be used in place of ** the memory allocation routines built into SQLite.)^ ^SQLite makes ** its own private copy of the content of the [sqlite3_mem_methods] structure ** before the [sqlite3_config()] call returns.
** ** [[SQLITE_CONFIG_GETMALLOC]]
SQLITE_CONFIG_GETMALLOC
-**
^(The SQLITE_CONFIG_GETMALLOC option takes a single argument which -** is a pointer to an instance of the [sqlite3_mem_methods] structure. -** The [sqlite3_mem_methods] +**
^(This option takes a single argument which is a pointer to an +** instance of the [sqlite3_mem_methods] structure. The [sqlite3_mem_methods] ** structure is filled with the currently defined memory allocation routines.)^ ** This option can be used to overload the default memory allocation ** routines with a wrapper that simulations memory allocation failure or ** tracks memory usage, for example.
** ** [[SQLITE_CONFIG_MEMSTATUS]]
SQLITE_CONFIG_MEMSTATUS
-**
^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int, -** interpreted as a boolean, which enables or disables the collection of -** memory allocation statistics. ^(When memory allocation statistics are disabled, the +**
^This option takes single argument of type int, interpreted as a +** boolean, which enables or disables the collection of memory allocation +** statistics. ^(When memory allocation statistics are disabled, the ** following SQLite interfaces become non-operational: **
    **
  • [sqlite3_memory_used()] **
  • [sqlite3_memory_highwater()] **
  • [sqlite3_soft_heap_limit64()] @@ -1531,90 +1529,78 @@ ** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory ** allocation statistics are disabled by default. **
** ** [[SQLITE_CONFIG_SCRATCH]]
SQLITE_CONFIG_SCRATCH
-**
^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer -** that SQLite can use for scratch memory. ^(There are three arguments -** to SQLITE_CONFIG_SCRATCH: A pointer an 8-byte +**
^This option specifies a static memory buffer that SQLite can use for +** scratch memory. There are three arguments: A pointer an 8-byte ** aligned memory buffer from which the scratch allocations will be ** drawn, the size of each scratch allocation (sz), -** and the maximum number of scratch allocations (N).)^ +** and the maximum number of scratch allocations (N). The sz +** argument must be a multiple of 16. ** The first argument must be a pointer to an 8-byte aligned buffer ** of at least sz*N bytes of memory. -** ^SQLite will not use more than one scratch buffers per thread. -** ^SQLite will never request a scratch buffer that is more than 6 -** times the database page size. -** ^If SQLite needs needs additional +** ^SQLite will use no more than two scratch buffers per thread. So +** N should be set to twice the expected maximum number of threads. +** ^SQLite will never require a scratch buffer that is more than 6 +** times the database page size. ^If SQLite needs needs additional ** scratch memory beyond what is provided by this configuration option, then -** [sqlite3_malloc()] will be used to obtain the memory needed.

-** ^When the application provides any amount of scratch memory using -** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large -** [sqlite3_malloc|heap allocations]. -** This can help [Robson proof|prevent memory allocation failures] due to heap -** fragmentation in low-memory embedded systems. -**

+** [sqlite3_malloc()] will be used to obtain the memory needed. ** ** [[SQLITE_CONFIG_PAGECACHE]]
SQLITE_CONFIG_PAGECACHE
-**
^The SQLITE_CONFIG_PAGECACHE option specifies a static memory buffer -** that SQLite can use for the database page cache with the default page -** cache implementation. +**
^This option specifies a static memory buffer that SQLite can use for +** the database page cache with the default page cache implementation. ** This configuration should not be used if an application-define page -** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2] -** configuration option. -** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to 8-byte aligned +** cache implementation is loaded using the SQLITE_CONFIG_PCACHE2 option. +** There are three arguments to this option: A pointer to 8-byte aligned ** memory, the size of each page buffer (sz), and the number of pages (N). ** The sz argument should be the size of the largest database page -** (a power of two between 512 and 32768) plus some extra bytes for each -** page header. ^The number of extra bytes needed by the page header -** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option -** to [sqlite3_config()]. -** ^It is harmless, apart from the wasted memory, -** for the sz parameter to be larger than necessary. The first -** argument should pointer to an 8-byte aligned block of memory that -** is at least sz*N bytes of memory, otherwise subsequent behavior is -** undefined. +** (a power of two between 512 and 32768) plus a little extra for each +** page header. ^The page header size is 20 to 40 bytes depending on +** the host architecture. ^It is harmless, apart from the wasted memory, +** to make sz a little too large. The first +** argument should point to an allocation of at least sz*N bytes of memory. ** ^SQLite will use the memory provided by the first argument to satisfy its ** memory needs for the first N pages that it adds to cache. ^If additional ** page cache memory is needed beyond what is provided by this option, then -** SQLite goes to [sqlite3_malloc()] for the additional storage space.
+** SQLite goes to [sqlite3_malloc()] for the additional storage space. +** The pointer in the first argument must +** be aligned to an 8-byte boundary or subsequent behavior of SQLite +** will be undefined. ** ** [[SQLITE_CONFIG_HEAP]]
SQLITE_CONFIG_HEAP
-**
^The SQLITE_CONFIG_HEAP option specifies a static memory buffer -** that SQLite will use for all of its dynamic memory allocation needs -** beyond those provided for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE]. -** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled -** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns -** [SQLITE_ERROR] if invoked otherwise. -** ^There are three arguments to SQLITE_CONFIG_HEAP: -** An 8-byte aligned pointer to the memory, +**
^This option specifies a static memory buffer that SQLite will use +** for all of its dynamic memory allocation needs beyond those provided +** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE]. +** There are three arguments: An 8-byte aligned pointer to the memory, ** the number of bytes in the memory buffer, and the minimum allocation size. ** ^If the first pointer (the memory pointer) is NULL, then SQLite reverts ** to using its default memory allocator (the system malloc() implementation), ** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the -** memory pointer is not NULL then the alternative memory +** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or +** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory ** allocator is engaged to handle all of SQLites memory allocation needs. ** The first pointer (the memory pointer) must be aligned to an 8-byte ** boundary or subsequent behavior of SQLite will be undefined. ** The minimum allocation size is capped at 2**12. Reasonable values ** for the minimum allocation size are 2**5 through 2**8.
** ** [[SQLITE_CONFIG_MUTEX]]
SQLITE_CONFIG_MUTEX
-**
^(The SQLITE_CONFIG_MUTEX option takes a single argument which is a -** pointer to an instance of the [sqlite3_mutex_methods] structure. -** The argument specifies alternative low-level mutex routines to be used in place +**
^(This option takes a single argument which is a pointer to an +** instance of the [sqlite3_mutex_methods] structure. The argument specifies +** alternative low-level mutex routines to be used in place ** the mutex routines built into SQLite.)^ ^SQLite makes a copy of the ** content of the [sqlite3_mutex_methods] structure before the call to ** [sqlite3_config()] returns. ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then ** the entire mutexing subsystem is omitted from the build and hence calls to ** [sqlite3_config()] with the SQLITE_CONFIG_MUTEX configuration option will ** return [SQLITE_ERROR].
** ** [[SQLITE_CONFIG_GETMUTEX]]
SQLITE_CONFIG_GETMUTEX
-**
^(The SQLITE_CONFIG_GETMUTEX option takes a single argument which -** is a pointer to an instance of the [sqlite3_mutex_methods] structure. The +**
^(This option takes a single argument which is a pointer to an +** instance of the [sqlite3_mutex_methods] structure. The ** [sqlite3_mutex_methods] ** structure is filled with the currently defined mutex routines.)^ ** This option can be used to overload the default mutex allocation ** routines with a wrapper used to track mutex usage for performance ** profiling or testing, for example. ^If SQLite is compiled with @@ -1622,28 +1608,28 @@ ** the entire mutexing subsystem is omitted from the build and hence calls to ** [sqlite3_config()] with the SQLITE_CONFIG_GETMUTEX configuration option will ** return [SQLITE_ERROR].
** ** [[SQLITE_CONFIG_LOOKASIDE]]
SQLITE_CONFIG_LOOKASIDE
-**
^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine -** the default size of lookaside memory on each [database connection]. -** The first argument is the +**
^(This option takes two arguments that determine the default +** memory allocation for the lookaside memory allocator on each +** [database connection]. The first argument is the ** size of each lookaside buffer slot and the second is the number of -** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE -** sets the default lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] -** option to [sqlite3_db_config()] can be used to change the lookaside +** slots allocated to each database connection.)^ ^(This option sets the +** default lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] +** verb to [sqlite3_db_config()] can be used to change the lookaside ** configuration on individual connections.)^
** ** [[SQLITE_CONFIG_PCACHE2]]
SQLITE_CONFIG_PCACHE2
-**
^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is -** a pointer to an [sqlite3_pcache_methods2] object. This object specifies -** the interface to a custom page cache implementation.)^ -** ^SQLite makes a copy of the [sqlite3_pcache_methods2] object.
+**
^(This option takes a single argument which is a pointer to +** an [sqlite3_pcache_methods2] object. This object specifies the interface +** to a custom page cache implementation.)^ ^SQLite makes a copy of the +** object and uses it for page cache memory allocations.
** ** [[SQLITE_CONFIG_GETPCACHE2]]
SQLITE_CONFIG_GETPCACHE2
-**
^(The SQLITE_CONFIG_GETPCACHE2 option takes a single argument which -** is a pointer to an [sqlite3_pcache_methods2] object. SQLite copies of the current +**
^(This option takes a single argument which is a pointer to an +** [sqlite3_pcache_methods2] object. SQLite copies of the current ** page cache implementation into that object.)^
** ** [[SQLITE_CONFIG_LOG]]
SQLITE_CONFIG_LOG
**
The SQLITE_CONFIG_LOG option is used to configure the SQLite ** global [error log]. @@ -1663,27 +1649,26 @@ ** supplied by the application must not invoke any SQLite interface. ** In a multi-threaded application, the application-defined logger ** function must be threadsafe.
** ** [[SQLITE_CONFIG_URI]]
SQLITE_CONFIG_URI -**
^(The SQLITE_CONFIG_URI option takes a single argument of type int. -** If non-zero, then URI handling is globally enabled. If the parameter is zero, -** then URI handling is globally disabled.)^ ^If URI handling is globally enabled, -** all filenames passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or +**
^(This option takes a single argument of type int. If non-zero, then +** URI handling is globally enabled. If the parameter is zero, then URI handling +** is globally disabled.)^ ^If URI handling is globally enabled, all filenames +** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or ** specified as part of [ATTACH] commands are interpreted as URIs, regardless ** of whether or not the [SQLITE_OPEN_URI] flag is set when the database ** connection is opened. ^If it is globally disabled, filenames are ** only interpreted as URIs if the SQLITE_OPEN_URI flag is set when the ** database connection is opened. ^(By default, URI handling is globally ** disabled. The default value may be changed by compiling with the ** [SQLITE_USE_URI] symbol defined.)^ ** ** [[SQLITE_CONFIG_COVERING_INDEX_SCAN]]
SQLITE_CONFIG_COVERING_INDEX_SCAN -**
^The SQLITE_CONFIG_COVERING_INDEX_SCAN option takes a single integer -** argument which is interpreted as a boolean in order to enable or disable -** the use of covering indices for full table scans in the query optimizer. -** ^The default setting is determined +**
^This option takes a single integer argument which is interpreted as +** a boolean in order to enable or disable the use of covering indices for +** full table scans in the query optimizer. ^The default setting is determined ** by the [SQLITE_ALLOW_COVERING_INDEX_SCAN] compile-time option, or is "on" ** if that compile-time option is omitted. ** The ability to disable the use of covering indices for full table scans ** is because some incorrectly coded legacy applications might malfunction ** when the optimization is enabled. Providing the ability to @@ -1719,32 +1704,23 @@ ** that are the default mmap size limit (the default setting for ** [PRAGMA mmap_size]) and the maximum allowed mmap size limit. ** ^The default setting can be overridden by each database connection using ** either the [PRAGMA mmap_size] command, or by using the ** [SQLITE_FCNTL_MMAP_SIZE] file control. ^(The maximum allowed mmap size -** will be silently truncated if necessary so that it does not exceed the -** compile-time maximum mmap size set by the +** cannot be changed at run-time. Nor may the maximum allowed mmap size +** exceed the compile-time maximum mmap size set by the ** [SQLITE_MAX_MMAP_SIZE] compile-time option.)^ ** ^If either argument to this option is negative, then that argument is ** changed to its compile-time default. ** ** [[SQLITE_CONFIG_WIN32_HEAPSIZE]] **
SQLITE_CONFIG_WIN32_HEAPSIZE -**
^The SQLITE_CONFIG_WIN32_HEAPSIZE option is only available if SQLite is -** compiled for Windows with the [SQLITE_WIN32_MALLOC] pre-processor macro defined. -** ^SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value +**
^This option is only available if SQLite is compiled for Windows +** with the [SQLITE_WIN32_MALLOC] pre-processor macro defined. +** SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value ** that specifies the maximum size of the created heap. ** -** -** [[SQLITE_CONFIG_PCACHE_HDRSZ]] -**
SQLITE_CONFIG_PCACHE_HDRSZ -**
^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which -** is a pointer to an integer and writes into that integer the number of extra -** bytes per page required for each page in [SQLITE_CONFIG_PAGECACHE]. The amount of -** extra space required can change depending on the compiler, -** target platform, and SQLite version. -** */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ #define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ @@ -1765,11 +1741,10 @@ #define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ #define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ #define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */ #define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */ -#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */ /* ** CAPI3REF: Database Connection Configuration Options ** ** These constants are the available integer configuration options that @@ -1893,49 +1868,51 @@ sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); /* ** CAPI3REF: Count The Number Of Rows Modified ** -** ^This function returns the number of rows modified, inserted or -** deleted by the most recently completed INSERT, UPDATE or DELETE -** statement on the database connection specified by the only parameter. -** ^Executing any other type of SQL statement does not modify the value -** returned by this function. -** -** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are -** considered - auxiliary changes caused by [CREATE TRIGGER | triggers], -** [foreign key actions] or [REPLACE] constraint resolution are not counted. -** -** Changes to a view that are intercepted by -** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value -** returned by sqlite3_changes() immediately after an INSERT, UPDATE or -** DELETE statement run on a view is always zero. Only changes made to real -** tables are counted. -** -** Things are more complicated if the sqlite3_changes() function is -** executed while a trigger program is running. This may happen if the -** program uses the [changes() SQL function], or if some other callback -** function invokes sqlite3_changes() directly. Essentially: -** -**
    -**
  • ^(Before entering a trigger program the value returned by -** sqlite3_changes() function is saved. After the trigger program -** has finished, the original value is restored.)^ -** -**
  • ^(Within a trigger program each INSERT, UPDATE and DELETE -** statement sets the value returned by sqlite3_changes() -** upon completion as normal. Of course, this value will not include -** any changes performed by sub-triggers, as the sqlite3_changes() -** value will be saved and restored after each sub-trigger has run.)^ -**
-** -** ^This means that if the changes() SQL function (or similar) is used -** by the first INSERT, UPDATE or DELETE statement within a trigger, it -** returns the value as set when the calling statement began executing. -** ^If it is used by the second or subsequent such statement within a trigger -** program, the value returned reflects the number of rows modified by the -** previous INSERT, UPDATE or DELETE statement within the same trigger. +** ^This function returns the number of database rows that were changed +** or inserted or deleted by the most recently completed SQL statement +** on the [database connection] specified by the first parameter. +** ^(Only changes that are directly specified by the [INSERT], [UPDATE], +** or [DELETE] statement are counted. Auxiliary changes caused by +** triggers or [foreign key actions] are not counted.)^ Use the +** [sqlite3_total_changes()] function to find the total number of changes +** including changes caused by triggers and foreign key actions. +** +** ^Changes to a view that are simulated by an [INSTEAD OF trigger] +** are not counted. Only real table changes are counted. +** +** ^(A "row change" is a change to a single row of a single table +** caused by an INSERT, DELETE, or UPDATE statement. Rows that +** are changed as side effects of [REPLACE] constraint resolution, +** rollback, ABORT processing, [DROP TABLE], or by any other +** mechanisms do not count as direct row changes.)^ +** +** A "trigger context" is a scope of execution that begins and +** ends with the script of a [CREATE TRIGGER | trigger]. +** Most SQL statements are +** evaluated outside of any trigger. This is the "top level" +** trigger context. If a trigger fires from the top level, a +** new trigger context is entered for the duration of that one +** trigger. Subtriggers create subcontexts for their duration. +** +** ^Calling [sqlite3_exec()] or [sqlite3_step()] recursively does +** not create a new trigger context. +** +** ^This function returns the number of direct row changes in the +** most recent INSERT, UPDATE, or DELETE statement within the same +** trigger context. +** +** ^Thus, when called from the top level, this function returns the +** number of changes in the most recent INSERT, UPDATE, or DELETE +** that also occurred at the top level. ^(Within the body of a trigger, +** the sqlite3_changes() interface can be called to find the number of +** changes in the most recently completed INSERT, UPDATE, or DELETE +** statement within the body of the same trigger. +** However, the number returned does not include changes +** caused by subtriggers since those have their own context.)^ ** ** See also the [sqlite3_total_changes()] interface, the ** [count_changes pragma], and the [changes() SQL function]. ** ** If a separate thread makes changes on the same database connection @@ -1945,21 +1922,24 @@ int sqlite3_changes(sqlite3*); /* ** CAPI3REF: Total Number Of Rows Modified ** -** ^This function returns the total number of rows inserted, modified or -** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed -** since the database connection was opened, including those executed as -** part of trigger programs. ^Executing any other type of SQL statement -** does not affect the value returned by sqlite3_total_changes(). -** -** ^Changes made as part of [foreign key actions] are included in the -** count, but those made as part of REPLACE constraint resolution are -** not. ^Changes to a view that are intercepted by INSTEAD OF triggers -** are not counted. -** +** ^This function returns the number of row changes caused by [INSERT], +** [UPDATE] or [DELETE] statements since the [database connection] was opened. +** ^(The count returned by sqlite3_total_changes() includes all changes +** from all [CREATE TRIGGER | trigger] contexts and changes made by +** [foreign key actions]. However, +** the count does not include changes used to implement [REPLACE] constraints, +** do rollbacks or ABORT processing, or [DROP TABLE] processing. The +** count does not include rows of views that fire an [INSTEAD OF trigger], +** though if the INSTEAD OF trigger makes changes of its own, those changes +** are counted.)^ +** ^The sqlite3_total_changes() function counts the changes as soon as +** the statement that makes them is completed (when the statement handle +** is passed to [sqlite3_reset()] or [sqlite3_finalize()]). +** ** See also the [sqlite3_changes()] interface, the ** [count_changes pragma], and the [total_changes() SQL function]. ** ** If a separate thread makes changes on the same database connection ** while [sqlite3_total_changes()] is running then the value @@ -2433,18 +2413,17 @@ ** already uses the largest possible [ROWID]. The PRNG is also used for ** the build-in random() and randomblob() SQL functions. This interface allows ** applications to access the same PRNG for other purposes. ** ** ^A call to this routine stores N bytes of randomness into buffer P. -** ^The P parameter can be a NULL pointer. +** ^If N is less than one, then P can be a NULL pointer. ** ** ^If this routine has not been previously called or if the previous -** call had N less than one or a NULL pointer for P, then the PRNG is -** seeded using randomness obtained from the xRandomness method of -** the default [sqlite3_vfs] object. -** ^If the previous call to this routine had an N of 1 or more and a -** non-NULL P then the pseudo-randomness is generated +** call had N less than one, then the PRNG is seeded using randomness +** obtained from the xRandomness method of the default [sqlite3_vfs] object. +** ^If the previous call to this routine had an N of 1 or more then +** the pseudo-randomness is generated ** internally and without recourse to the [sqlite3_vfs] xRandomness ** method. */ void sqlite3_randomness(int N, void *P); @@ -5655,46 +5634,30 @@ ** **
 **     SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow;
 ** 
)^ ** -** ^(Parameter zDb is not the filename that contains the database, but -** rather the symbolic name of the database. For attached databases, this is -** the name that appears after the AS keyword in the [ATTACH] statement. -** For the main database file, the database name is "main". For TEMP -** tables, the database name is "temp".)^ -** ** ^If the flags parameter is non-zero, then the BLOB is opened for read -** and write access. ^If the flags parameter is zero, the BLOB is opened for -** read-only access. -** -** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored -** in *ppBlob. Otherwise an [error code] is returned and, unless the error -** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided -** the API is not misused, it is always safe to call [sqlite3_blob_close()] -** on *ppBlob after this function it returns. -** -** This function fails with SQLITE_ERROR if any of the following are true: -**
    -**
  • ^(Database zDb does not exist)^, -**
  • ^(Table zTable does not exist within database zDb)^, -**
  • ^(Table zTable is a WITHOUT ROWID table)^, -**
  • ^(Column zColumn does not exist)^, -**
  • ^(Row iRow is not present in the table)^, -**
  • ^(The specified column of row iRow contains a value that is not -** a TEXT or BLOB value)^, -**
  • ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE -** constraint and the blob is being opened for read/write access)^, -**
  • ^([foreign key constraints | Foreign key constraints] are enabled, -** column zColumn is part of a [child key] definition and the blob is -** being opened for read/write access)^. -**
-** -** ^Unless it returns SQLITE_MISUSE, this function sets the -** [database connection] error code and message accessible via -** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. -** +** and write access. ^If it is zero, the BLOB is opened for read access. +** ^It is not possible to open a column that is part of an index or primary +** key for writing. ^If [foreign key constraints] are enabled, it is +** not possible to open a column that is part of a [child key] for writing. +** +** ^Note that the database name is not the filename that contains +** the database but rather the symbolic name of the database that +** appears after the AS keyword when the database is connected using [ATTACH]. +** ^For the main database file, the database name is "main". +** ^For TEMP tables, the database name is "temp". +** +** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is written +** to *ppBlob. Otherwise an [error code] is returned and *ppBlob is set +** to be a null pointer.)^ +** ^This function sets the [database connection] error code and message +** accessible via [sqlite3_errcode()] and [sqlite3_errmsg()] and related +** functions. ^Note that the *ppBlob variable is always initialized in a +** way that makes it safe to invoke [sqlite3_blob_close()] on *ppBlob +** regardless of the success or failure of this routine. ** ** ^(If the row that a BLOB handle points to is modified by an ** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects ** then the BLOB handle is marked as "expired". ** This is true if any column of the row is changed, even a column @@ -5708,13 +5671,17 @@ ** ^Use the [sqlite3_blob_bytes()] interface to determine the size of ** the opened blob. ^The size of a blob may not be changed by this ** interface. Use the [UPDATE] SQL command to change the size of a ** blob. ** +** ^The [sqlite3_blob_open()] interface will fail for a [WITHOUT ROWID] +** table. Incremental BLOB I/O is not possible on [WITHOUT ROWID] tables. +** ** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces -** and the built-in [zeroblob] SQL function may be used to create a -** zero-filled blob to read or write using the incremental-blob interface. +** and the built-in [zeroblob] SQL function can be used, if desired, +** to create an empty, zero-filled blob in which to read or write using +** this interface. ** ** To avoid a resource leak, every open [BLOB handle] should eventually ** be released by a call to [sqlite3_blob_close()]. */ int sqlite3_blob_open( @@ -5752,26 +5719,28 @@ SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64); /* ** CAPI3REF: Close A BLOB Handle ** -** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed -** unconditionally. Even if this routine returns an error code, the -** handle is still closed.)^ -** -** ^If the blob handle being closed was opened for read-write access, and if -** the database is in auto-commit mode and there are no other open read-write -** blob handles or active write statements, the current transaction is -** committed. ^If an error occurs while committing the transaction, an error -** code is returned and the transaction rolled back. -** -** Calling this function with an argument that is not a NULL pointer or an -** open blob handle results in undefined behaviour. ^Calling this routine -** with a null pointer (such as would be returned by a failed call to -** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function -** is passed a valid open blob handle, the values returned by the -** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning. +** ^Closes an open [BLOB handle]. +** +** ^Closing a BLOB shall cause the current transaction to commit +** if there are no other BLOBs, no pending prepared statements, and the +** database connection is in [autocommit mode]. +** ^If any writes were made to the BLOB, they might be held in cache +** until the close operation if they will fit. +** +** ^(Closing the BLOB often forces the changes +** out to disk and so if any I/O errors occur, they will likely occur +** at the time when the BLOB is closed. Any errors that occur during +** closing are reported as a non-zero return value.)^ +** +** ^(The BLOB is closed unconditionally. Even if this routine returns +** an error code, the BLOB is still closed.)^ +** +** ^Calling this routine with a null pointer (such as would be returned +** by a failed call to [sqlite3_blob_open()]) is a harmless no-op. */ int sqlite3_blob_close(sqlite3_blob *); /* ** CAPI3REF: Return The Size Of An Open BLOB @@ -5817,39 +5786,36 @@ int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset); /* ** CAPI3REF: Write Data Into A BLOB Incrementally ** -** ^(This function is used to write data into an open [BLOB handle] from a -** caller-supplied buffer. N bytes of data are copied from the buffer Z -** into the open BLOB, starting at offset iOffset.)^ -** -** ^(On success, sqlite3_blob_write() returns SQLITE_OK. -** Otherwise, an [error code] or an [extended error code] is returned.)^ -** ^Unless SQLITE_MISUSE is returned, this function sets the -** [database connection] error code and message accessible via -** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. +** ^This function is used to write data into an open [BLOB handle] from a +** caller-supplied buffer. ^N bytes of data are copied from the buffer Z +** into the open BLOB, starting at offset iOffset. ** ** ^If the [BLOB handle] passed as the first argument was not opened for ** writing (the flags parameter to [sqlite3_blob_open()] was zero), ** this function returns [SQLITE_READONLY]. ** -** This function may only modify the contents of the BLOB; it is +** ^This function may only modify the contents of the BLOB; it is ** not possible to increase the size of a BLOB using this API. ** ^If offset iOffset is less than N bytes from the end of the BLOB, -** [SQLITE_ERROR] is returned and no data is written. The size of the -** BLOB (and hence the maximum value of N+iOffset) can be determined -** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less -** than zero [SQLITE_ERROR] is returned and no data is written. +** [SQLITE_ERROR] is returned and no data is written. ^If N is +** less than zero [SQLITE_ERROR] is returned and no data is written. +** The size of the BLOB (and hence the maximum value of N+iOffset) +** can be determined using the [sqlite3_blob_bytes()] interface. ** ** ^An attempt to write to an expired [BLOB handle] fails with an ** error code of [SQLITE_ABORT]. ^Writes to the BLOB that occurred ** before the [BLOB handle] expired are not rolled back by the ** expiration of the handle, though of course those changes might ** have been overwritten by the statement that expired the BLOB handle ** or by other independent statements. ** +** ^(On success, sqlite3_blob_write() returns SQLITE_OK. +** Otherwise, an [error code] or an [extended error code] is returned.)^ +** ** This routine only works on a [BLOB handle] which has been created ** by a prior successful call to [sqlite3_blob_open()] and which has not ** been closed by [sqlite3_blob_close()]. Passing any other pointer in ** to this routine results in undefined and probably undesirable behavior. ** @@ -7438,102 +7404,10 @@ /* #define SQLITE_IGNORE 2 // Also used by sqlite3_authorizer() callback */ #define SQLITE_FAIL 3 /* #define SQLITE_ABORT 4 // Also an error code */ #define SQLITE_REPLACE 5 -/* -** CAPI3REF: Prepared Statement Scan Status Opcodes -** KEYWORDS: {scanstatus options} -** -** The following constants can be used for the T parameter to the -** [sqlite3_stmt_scanstatus(S,X,T,V)] interface. Each constant designates a -** different metric for sqlite3_stmt_scanstatus() to return. -** -**
-** [[SQLITE_SCANSTAT_NLOOP]]
SQLITE_SCANSTAT_NLOOP
-**
^The [sqlite3_int64] variable pointed to by the T parameter will be set to the -** total number of times that the X-th loop has run.
-** -** [[SQLITE_SCANSTAT_NVISIT]]
SQLITE_SCANSTAT_NVISIT
-**
^The [sqlite3_int64] variable pointed to by the T parameter will be set to the -** total number of rows examined by all iterations of the X-th loop.
-** -** [[SQLITE_SCANSTAT_EST]]
SQLITE_SCANSTAT_EST
-**
^The "double" variable pointed to by the T parameter will be set to the -** query planner's estimate for the average number of rows output from each -** iteration of the X-th loop. If the query planner's estimates was accurate, -** then this value will approximate the quotient NVISIT/NLOOP and the -** product of this value for all prior loops with the same SELECTID will -** be the NLOOP value for the current loop. -** -** [[SQLITE_SCANSTAT_NAME]]
SQLITE_SCANSTAT_NAME
-**
^The "const char *" variable pointed to by the T parameter will be set to -** a zero-terminated UTF-8 string containing the name of the index or table used -** for the X-th loop. -** -** [[SQLITE_SCANSTAT_EXPLAIN]]
SQLITE_SCANSTAT_EXPLAIN
-**
^The "const char *" variable pointed to by the T parameter will be set to -** a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN] description -** for the X-th loop. -** -** [[SQLITE_SCANSTAT_SELECTID]]
SQLITE_SCANSTAT_SELECT
-**
^The "int" variable pointed to by the T parameter will be set to the -** "select-id" for the X-th loop. The select-id identifies which query or -** subquery the loop is part of. The main query has a select-id of zero. -** The select-id is the same value as is output in the first column -** of an [EXPLAIN QUERY PLAN] query. -**
-*/ -#define SQLITE_SCANSTAT_NLOOP 0 -#define SQLITE_SCANSTAT_NVISIT 1 -#define SQLITE_SCANSTAT_EST 2 -#define SQLITE_SCANSTAT_NAME 3 -#define SQLITE_SCANSTAT_EXPLAIN 4 -#define SQLITE_SCANSTAT_SELECTID 5 - -/* -** CAPI3REF: Prepared Statement Scan Status -** -** Return status data for a single loop within query pStmt. -** -** The "iScanStatusOp" parameter determines which status information to return. -** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior of -** this interface is undefined. -** ^The requested measurement is written into a variable pointed to by -** the "pOut" parameter. -** Parameter "idx" identifies the specific loop to retrieve statistics for. -** Loops are numbered starting from zero. ^If idx is out of range - less than -** zero or greater than or equal to the total number of loops used to implement -** the statement - a non-zero value is returned and the variable that pOut -** points to is unchanged. -** -** ^Statistics might not be available for all loops in all statements. ^In cases -** where there exist loops with no available statistics, this function behaves -** as if the loop did not exist - it returns non-zero and leave the variable -** that pOut points to unchanged. -** -** This API is only available if the library is built with pre-processor -** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined. -** -** See also: [sqlite3_stmt_scanstatus_reset()] -*/ -SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus( - sqlite3_stmt *pStmt, /* Prepared statement for which info desired */ - int idx, /* Index of loop to report on */ - int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */ - void *pOut /* Result written here */ -); - -/* -** CAPI3REF: Zero Scan-Status Counters -** -** ^Zero all [sqlite3_stmt_scanstatus()] related event counters. -** -** This API is only available if the library is built with pre-processor -** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined. -*/ -SQLITE_EXPERIMENTAL void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -191,13 +191,14 @@ #ifndef SQLITE_POWERSAFE_OVERWRITE # define SQLITE_POWERSAFE_OVERWRITE 1 #endif /* -** EVIDENCE-OF: R-25715-37072 Memory allocation statistics are enabled by -** default unless SQLite is compiled with SQLITE_DEFAULT_MEMSTATUS=0 in -** which case memory allocation statistics are disabled by default. +** The SQLITE_DEFAULT_MEMSTATUS macro must be defined as either 0 or 1. +** It determines whether or not the features related to +** SQLITE_CONFIG_MEMSTATUS are available by default or not. This value can +** be overridden at runtime using the sqlite3_config() API. */ #if !defined(SQLITE_DEFAULT_MEMSTATUS) # define SQLITE_DEFAULT_MEMSTATUS 1 #endif @@ -560,11 +561,11 @@ ** Estimated quantities used for query planning are stored as 16-bit ** logarithms. For quantity X, the value stored is 10*log2(X). This ** gives a possible range of values of approximately 1.0e986 to 1e-986. ** But the allowed values are "grainy". Not every value is representable. ** For example, quantities 16 and 17 are both represented by a LogEst -** of 40. However, since LogEst quantities are suppose to be estimates, +** of 40. However, since LogEst quantaties are suppose to be estimates, ** not exact values, this imprecision is not a problem. ** ** "LogEst" is short for "Logarithmic Estimate". ** ** Examples: @@ -1211,11 +1212,11 @@ #define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */ #define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */ #define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */ #define SQLITE_Transitive 0x0200 /* Transitive constraints */ #define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */ -#define SQLITE_Stat34 0x0800 /* Use STAT3 or STAT4 data */ +#define SQLITE_Stat3 0x0800 /* Use the SQLITE_STAT3 table */ #define SQLITE_AllOpts 0xffff /* All optimizations */ /* ** Macros for testing whether or not optimizations are enabled or disabled. */ @@ -1798,12 +1799,11 @@ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 int nSample; /* Number of elements in aSample[] */ int nSampleCol; /* Size of IndexSample.anEq[] and so on */ tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */ IndexSample *aSample; /* Samples of the left-most key */ - tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this index */ - tRowcnt nRowEst0; /* Non-logarithmic number of rows in the index */ + tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this table */ #endif }; /* ** Allowed values for Index.idxType @@ -1997,11 +1997,11 @@ int nHeight; /* Height of the tree headed by this node */ #endif int iTable; /* TK_COLUMN: cursor number of table holding column ** TK_REGISTER: register number ** TK_TRIGGER: 1 -> new, 0 -> old - ** EP_Unlikely: 134217728 times likelihood */ + ** EP_Unlikely: 1000 times likelihood */ ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid. ** TK_VARIABLE: variable number (always >= 1). */ i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */ u8 op2; /* TK_REGISTER: original value of Expr.op @@ -2889,15 +2889,13 @@ int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */ int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */ void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */ Parse *pParse; /* Parser context. */ int walkerDepth; /* Number of subqueries */ - u8 eCode; /* A small processing code */ union { /* Extra data for callback */ NameContext *pNC; /* Naming context */ - int n; /* A counter */ - int iCur; /* A cursor number */ + int i; /* Integer value */ SrcList *pSrcList; /* FROM clause */ struct SrcCount *pSrcCount; /* Counting column references */ } u; }; @@ -3294,11 +3292,10 @@ void sqlite3CloseSavepoints(sqlite3 *); void sqlite3LeaveMutexAndCloseZombie(sqlite3*); int sqlite3ExprIsConstant(Expr*); int sqlite3ExprIsConstantNotJoin(Expr*); int sqlite3ExprIsConstantOrFunction(Expr*, u8); -int sqlite3ExprIsTableConstant(Expr*,int); int sqlite3ExprIsInteger(Expr*, int*); int sqlite3ExprCanBeNull(const Expr*); int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); int sqlite3IsRowid(const char*); void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8); Index: src/status.c ================================================================== --- src/status.c +++ src/status.c @@ -84,13 +84,10 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){ wsdStatInit; if( op<0 || op>=ArraySize(wsdStat.nowValue) ){ return SQLITE_MISUSE_BKPT; } -#ifdef SQLITE_ENABLE_API_ARMOR - if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT; -#endif *pCurrent = wsdStat.nowValue[op]; *pHighwater = wsdStat.mxValue[op]; if( resetFlag ){ wsdStat.mxValue[op] = wsdStat.nowValue[op]; } @@ -106,15 +103,10 @@ int *pCurrent, /* Write current value here */ int *pHighwater, /* Write high-water mark here */ int resetFlag /* Reset high-water mark if true */ ){ int rc = SQLITE_OK; /* Return code */ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) || pCurrent==0|| pHighwater==0 ){ - return SQLITE_MISUSE_BKPT; - } -#endif sqlite3_mutex_enter(db->mutex); switch( op ){ case SQLITE_DBSTATUS_LOOKASIDE_USED: { *pCurrent = db->lookaside.nOut; *pHighwater = db->lookaside.mxOut; Index: src/table.c ================================================================== --- src/table.c +++ src/table.c @@ -124,13 +124,10 @@ char **pzErrMsg /* Write error messages here */ ){ int rc; TabResult res; -#ifdef SQLITE_ENABLE_API_ARMOR - if( pazResult==0 ) return SQLITE_MISUSE_BKPT; -#endif *pazResult = 0; if( pnColumn ) *pnColumn = 0; if( pnRow ) *pnRow = 0; if( pzErrMsg ) *pzErrMsg = 0; res.zErrMsg = 0; Index: src/tclsqlite.c ================================================================== --- src/tclsqlite.c +++ src/tclsqlite.c @@ -3639,49 +3639,10 @@ pDb->bLegacyPrepare = bPrepare; Tcl_ResetResult(interp); return TCL_OK; } - -/* -** Tclcmd: db_last_stmt_ptr DB -** -** If the statement cache associated with database DB is not empty, -** return the text representation of the most recently used statement -** handle. -*/ -static int db_last_stmt_ptr( - ClientData cd, - Tcl_Interp *interp, - int objc, - Tcl_Obj *CONST objv[] -){ - extern int sqlite3TestMakePointerStr(Tcl_Interp*, char*, void*); - Tcl_CmdInfo cmdInfo; - SqliteDb *pDb; - sqlite3_stmt *pStmt = 0; - char zBuf[100]; - - if( objc!=2 ){ - Tcl_WrongNumArgs(interp, 1, objv, "DB"); - return TCL_ERROR; - } - - if( !Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){ - Tcl_AppendResult(interp, "no such db: ", Tcl_GetString(objv[1]), (char*)0); - return TCL_ERROR; - } - pDb = (SqliteDb*)cmdInfo.objClientData; - - if( pDb->stmtList ) pStmt = pDb->stmtList->pStmt; - if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ){ - return TCL_ERROR; - } - Tcl_SetResult(interp, zBuf, TCL_VOLATILE); - - return TCL_OK; -} #endif /* ** Configure the interpreter passed as the first argument to have access ** to the commands and linked variables that make up: @@ -3723,11 +3684,10 @@ extern int Sqlitetest7_Init(Tcl_Interp*); extern int Sqlitetest8_Init(Tcl_Interp*); extern int Sqlitetest9_Init(Tcl_Interp*); extern int Sqlitetestasync_Init(Tcl_Interp*); extern int Sqlitetest_autoext_Init(Tcl_Interp*); - extern int Sqlitetest_blob_Init(Tcl_Interp*); extern int Sqlitetest_demovfs_Init(Tcl_Interp *); extern int Sqlitetest_func_Init(Tcl_Interp*); extern int Sqlitetest_hexio_Init(Tcl_Interp*); extern int Sqlitetest_init_Init(Tcl_Interp*); extern int Sqlitetest_malloc_Init(Tcl_Interp*); @@ -3767,11 +3727,10 @@ Sqlitetest7_Init(interp); Sqlitetest8_Init(interp); Sqlitetest9_Init(interp); Sqlitetestasync_Init(interp); Sqlitetest_autoext_Init(interp); - Sqlitetest_blob_Init(interp); Sqlitetest_demovfs_Init(interp); Sqlitetest_func_Init(interp); Sqlitetest_hexio_Init(interp); Sqlitetest_init_Init(interp); Sqlitetest_malloc_Init(interp); @@ -3799,13 +3758,10 @@ interp, "load_testfixture_extensions", init_all_cmd, 0, 0 ); Tcl_CreateObjCommand( interp, "db_use_legacy_prepare", db_use_legacy_prepare_cmd, 0, 0 ); - Tcl_CreateObjCommand( - interp, "db_last_stmt_ptr", db_last_stmt_ptr, 0, 0 - ); #ifdef SQLITE_SSE Sqlitetestsse_Init(interp); #endif } Index: src/test1.c ================================================================== --- src/test1.c +++ src/test1.c @@ -1648,10 +1648,158 @@ *ppBlob = *((sqlite3_blob **)instanceData); } return TCL_OK; } + +/* +** sqlite3_blob_bytes CHANNEL +*/ +static int test_blob_bytes( + ClientData clientData, /* Not used */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3_blob *pBlob; + int nByte; + + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL"); + return TCL_ERROR; + } + + if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; + nByte = sqlite3_blob_bytes(pBlob); + Tcl_SetObjResult(interp, Tcl_NewIntObj(nByte)); + + return TCL_OK; +} + +/* +** sqlite3_blob_close CHANNEL +*/ +static int test_blob_close( + ClientData clientData, /* Not used */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3_blob *pBlob; + + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL"); + return TCL_ERROR; + } + + if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; + sqlite3_blob_close(pBlob); + + return TCL_OK; +} + +/* +** sqlite3_blob_read CHANNEL OFFSET N +** +** This command is used to test the sqlite3_blob_read() in ways that +** the Tcl channel interface does not. The first argument should +** be the name of a valid channel created by the [incrblob] method +** of a database handle. This function calls sqlite3_blob_read() +** to read N bytes from offset OFFSET from the underlying SQLite +** blob handle. +** +** On success, a byte-array object containing the read data is +** returned. On failure, the interpreter result is set to the +** text representation of the returned error code (i.e. "SQLITE_NOMEM") +** and a Tcl exception is thrown. +*/ +static int test_blob_read( + ClientData clientData, /* Not used */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3_blob *pBlob; + int nByte; + int iOffset; + unsigned char *zBuf = 0; + int rc; + + if( objc!=4 ){ + Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET N"); + return TCL_ERROR; + } + + if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; + if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset) + || TCL_OK!=Tcl_GetIntFromObj(interp, objv[3], &nByte) + ){ + return TCL_ERROR; + } + + if( nByte>0 ){ + zBuf = (unsigned char *)Tcl_Alloc(nByte); + } + rc = sqlite3_blob_read(pBlob, zBuf, nByte, iOffset); + if( rc==SQLITE_OK ){ + Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zBuf, nByte)); + }else{ + Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); + } + Tcl_Free((char *)zBuf); + + return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); +} + +/* +** sqlite3_blob_write CHANNEL OFFSET DATA ?NDATA? +** +** This command is used to test the sqlite3_blob_write() in ways that +** the Tcl channel interface does not. The first argument should +** be the name of a valid channel created by the [incrblob] method +** of a database handle. This function calls sqlite3_blob_write() +** to write the DATA byte-array to the underlying SQLite blob handle. +** at offset OFFSET. +** +** On success, an empty string is returned. On failure, the interpreter +** result is set to the text representation of the returned error code +** (i.e. "SQLITE_NOMEM") and a Tcl exception is thrown. +*/ +static int test_blob_write( + ClientData clientData, /* Not used */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3_blob *pBlob; + int iOffset; + int rc; + + unsigned char *zBuf; + int nBuf; + + if( objc!=4 && objc!=5 ){ + Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET DATA ?NDATA?"); + return TCL_ERROR; + } + + if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; + if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset) ){ + return TCL_ERROR; + } + + zBuf = Tcl_GetByteArrayFromObj(objv[3], &nBuf); + if( objc==5 && Tcl_GetIntFromObj(interp, objv[4], &nBuf) ){ + return TCL_ERROR; + } + rc = sqlite3_blob_write(pBlob, zBuf, nBuf, iOffset); + if( rc!=SQLITE_OK ){ + Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); + } + + return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); +} static int test_blob_reopen( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ @@ -2151,81 +2299,10 @@ iValue = sqlite3_stmt_status(pStmt, op, resetFlag); Tcl_SetObjResult(interp, Tcl_NewIntObj(iValue)); return TCL_OK; } -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS -/* -** Usage: sqlite3_stmt_scanstatus STMT IDX -*/ -static int test_stmt_scanstatus( - void * clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *CONST objv[] -){ - sqlite3_stmt *pStmt; /* First argument */ - int idx; /* Second argument */ - - const char *zName; - const char *zExplain; - sqlite3_int64 nLoop; - sqlite3_int64 nVisit; - double rEst; - int res; - - if( objc!=3 ){ - Tcl_WrongNumArgs(interp, 1, objv, "STMT IDX"); - return TCL_ERROR; - } - if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; - if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; - - res = sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop); - if( res==0 ){ - Tcl_Obj *pRet = Tcl_NewObj(); - Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nLoop", -1)); - Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nLoop)); - sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit); - Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nVisit", -1)); - Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nVisit)); - sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_EST, (void*)&rEst); - Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nEst", -1)); - Tcl_ListObjAppendElement(0, pRet, Tcl_NewDoubleObj(rEst)); - sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NAME, (void*)&zName); - Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("zName", -1)); - Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zName, -1)); - sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain); - Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("zExplain", -1)); - Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zExplain, -1)); - Tcl_SetObjResult(interp, pRet); - }else{ - Tcl_ResetResult(interp); - } - return TCL_OK; -} - -/* -** Usage: sqlite3_stmt_scanstatus_reset STMT -*/ -static int test_stmt_scanstatus_reset( - void * clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *CONST objv[] -){ - sqlite3_stmt *pStmt; /* First argument */ - if( objc!=2 ){ - Tcl_WrongNumArgs(interp, 1, objv, "STMT"); - return TCL_ERROR; - } - if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; - sqlite3_stmt_scanstatus_reset(pStmt); - return TCL_OK; -} -#endif - /* ** Usage: sqlite3_next_stmt DB STMT ** ** Return the next statment in sequence after STMT. */ @@ -6214,12 +6291,11 @@ { "cover-idx-scan", SQLITE_CoverIdxScan }, { "order-by-idx-join", SQLITE_OrderByIdxJoin }, { "transitive", SQLITE_Transitive }, { "subquery-coroutine", SQLITE_SubqCoroutine }, { "omit-noop-join", SQLITE_OmitNoopJoin }, - { "stat3", SQLITE_Stat34 }, - { "stat4", SQLITE_Stat34 }, + { "stat3", SQLITE_Stat3 }, }; if( objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB OPT BOOLEAN"); return TCL_ERROR; @@ -6258,11 +6334,10 @@ int objc, Tcl_Obj *CONST objv[] ){ extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*); - extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_percentile_init(sqlite3*,char**,const sqlite3_api_routines*); @@ -6274,11 +6349,10 @@ const char *zExtName; int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*); } aExtension[] = { { "amatch", sqlite3_amatch_init }, { "closure", sqlite3_closure_init }, - { "eval", sqlite3_eval_init }, { "fileio", sqlite3_fileio_init }, { "fuzzer", sqlite3_fuzzer_init }, { "ieee754", sqlite3_ieee_init }, { "nextchar", sqlite3_nextchar_init }, { "percentile", sqlite3_percentile_init }, @@ -6762,11 +6836,15 @@ { "sqlite3_libversion_number", test_libversion_number, 0 }, #ifdef SQLITE_ENABLE_COLUMN_METADATA { "sqlite3_table_column_metadata", test_table_column_metadata, 0 }, #endif #ifndef SQLITE_OMIT_INCRBLOB + { "sqlite3_blob_read", test_blob_read, 0 }, + { "sqlite3_blob_write", test_blob_write, 0 }, { "sqlite3_blob_reopen", test_blob_reopen, 0 }, + { "sqlite3_blob_bytes", test_blob_bytes, 0 }, + { "sqlite3_blob_close", test_blob_close, 0 }, #endif { "pcache_stats", test_pcache_stats, 0 }, #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY { "sqlite3_unlock_notify", test_unlock_notify, 0 }, #endif @@ -6787,14 +6865,10 @@ { "sqlite3_user_authenticate", test_user_authenticate, 0 }, { "sqlite3_user_add", test_user_add, 0 }, { "sqlite3_user_change", test_user_change, 0 }, { "sqlite3_user_delete", test_user_delete, 0 }, #endif -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS - { "sqlite3_stmt_scanstatus", test_stmt_scanstatus, 0 }, - { "sqlite3_stmt_scanstatus_reset", test_stmt_scanstatus_reset, 0 }, -#endif }; static int bitmask_size = sizeof(Bitmask)*8; int i; extern int sqlite3_sync_count, sqlite3_fullsync_count; DELETED src/test_blob.c Index: src/test_blob.c ================================================================== --- src/test_blob.c +++ /dev/null @@ -1,319 +0,0 @@ -/* -** 2014 October 30 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** -*/ -#include "sqliteInt.h" -#include "tcl.h" -#include -#include -#include - -/* These functions are implemented in main.c. */ -extern const char *sqlite3ErrName(int); - -/* From test1.c: */ -extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); -extern void *sqlite3TestTextToPtr(const char *z); - -/* -** Return a pointer to a buffer containing a text representation of the -** pointer passed as the only argument. The original pointer may be extracted -** from the text using sqlite3TestTextToPtr(). -*/ -static char *ptrToText(void *p){ - static char buf[100]; - sqlite3_snprintf(sizeof(buf)-1, buf, "%p", p); - return buf; -} - -/* -** Attempt to extract a blob handle (type sqlite3_blob*) from the Tcl -** object passed as the second argument. If successful, set *ppBlob to -** point to the blob handle and return TCL_OK. Otherwise, store an error -** message in the tcl interpreter and return TCL_ERROR. The final value -** of *ppBlob is undefined in this case. -** -** If the object contains a string that begins with "incrblob_", then it -** is assumed to be the name of a Tcl channel opened using the [db incrblob] -** command (see tclsqlite.c). Otherwise, it is assumed to be a pointer -** encoded using the ptrToText() routine or similar. -*/ -static int blobHandleFromObj( - Tcl_Interp *interp, - Tcl_Obj *pObj, - sqlite3_blob **ppBlob -){ - char *z; - int n; - - z = Tcl_GetStringFromObj(pObj, &n); - if( n==0 ){ - *ppBlob = 0; - }else if( n>9 && 0==memcmp("incrblob_", z, 9) ){ - int notUsed; - Tcl_Channel channel; - ClientData instanceData; - - channel = Tcl_GetChannel(interp, z, ¬Used); - if( !channel ) return TCL_ERROR; - - Tcl_Flush(channel); - Tcl_Seek(channel, 0, SEEK_SET); - - instanceData = Tcl_GetChannelInstanceData(channel); - *ppBlob = *((sqlite3_blob **)instanceData); - }else{ - *ppBlob = (sqlite3_blob*)sqlite3TestTextToPtr(z); - } - - return TCL_OK; -} - -/* -** Like Tcl_GetString(), except that if the string is 0 bytes in size, a -** NULL Pointer is returned. -*/ -static char *blobStringFromObj(Tcl_Obj *pObj){ - int n; - char *z; - z = Tcl_GetStringFromObj(pObj, &n); - return (n ? z : 0); -} - -/* -** sqlite3_blob_open DB DATABASE TABLE COLUMN ROWID FLAGS VARNAME -** -** Tcl test harness for the sqlite3_blob_open() function. -*/ -static int test_blob_open( - ClientData clientData, /* Not used */ - Tcl_Interp *interp, /* Calling TCL interpreter */ - int objc, /* Number of arguments */ - Tcl_Obj *CONST objv[] /* Command arguments */ -){ - sqlite3 *db; - const char *zDb; - const char *zTable; - const char *zColumn; - sqlite_int64 iRowid; - int flags; - const char *zVarname; - int nVarname; - - sqlite3_blob *pBlob = (sqlite3_blob*)0xFFFFFFFF; - int rc; - - if( objc!=8 ){ - const char *zUsage = "DB DATABASE TABLE COLUMN ROWID FLAGS VARNAME"; - Tcl_WrongNumArgs(interp, 1, objv, zUsage); - return TCL_ERROR; - } - if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; - zDb = Tcl_GetString(objv[2]); - zTable = blobStringFromObj(objv[3]); - zColumn = Tcl_GetString(objv[4]); - if( Tcl_GetWideIntFromObj(interp, objv[5], &iRowid) ) return TCL_ERROR; - if( Tcl_GetIntFromObj(interp, objv[6], &flags) ) return TCL_ERROR; - zVarname = Tcl_GetStringFromObj(objv[7], &nVarname); - - if( nVarname>0 ){ - rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRowid, flags, &pBlob); - Tcl_SetVar(interp, zVarname, ptrToText(pBlob), 0); - }else{ - rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRowid, flags, 0); - } - - if( rc==SQLITE_OK ){ - Tcl_ResetResult(interp); - }else{ - Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE); - return TCL_ERROR; - } - return TCL_OK; -} - - -/* -** sqlite3_blob_close HANDLE -*/ -static int test_blob_close( - ClientData clientData, /* Not used */ - Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ - int objc, /* Number of arguments */ - Tcl_Obj *CONST objv[] /* Command arguments */ -){ - sqlite3_blob *pBlob; - int rc; - - if( objc!=2 ){ - Tcl_WrongNumArgs(interp, 1, objv, "HANDLE"); - return TCL_ERROR; - } - - if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; - rc = sqlite3_blob_close(pBlob); - - if( rc ){ - Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE); - }else{ - Tcl_ResetResult(interp); - } - return TCL_OK; -} - -/* -** sqlite3_blob_bytes HANDLE -*/ -static int test_blob_bytes( - ClientData clientData, /* Not used */ - Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ - int objc, /* Number of arguments */ - Tcl_Obj *CONST objv[] /* Command arguments */ -){ - sqlite3_blob *pBlob; - int nByte; - - if( objc!=2 ){ - Tcl_WrongNumArgs(interp, 1, objv, "HANDLE"); - return TCL_ERROR; - } - - if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; - nByte = sqlite3_blob_bytes(pBlob); - Tcl_SetObjResult(interp, Tcl_NewIntObj(nByte)); - - return TCL_OK; -} - -/* -** sqlite3_blob_read CHANNEL OFFSET N -** -** This command is used to test the sqlite3_blob_read() in ways that -** the Tcl channel interface does not. The first argument should -** be the name of a valid channel created by the [incrblob] method -** of a database handle. This function calls sqlite3_blob_read() -** to read N bytes from offset OFFSET from the underlying SQLite -** blob handle. -** -** On success, a byte-array object containing the read data is -** returned. On failure, the interpreter result is set to the -** text representation of the returned error code (i.e. "SQLITE_NOMEM") -** and a Tcl exception is thrown. -*/ -static int test_blob_read( - ClientData clientData, /* Not used */ - Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ - int objc, /* Number of arguments */ - Tcl_Obj *CONST objv[] /* Command arguments */ -){ - sqlite3_blob *pBlob; - int nByte; - int iOffset; - unsigned char *zBuf = 0; - int rc; - - if( objc!=4 ){ - Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET N"); - return TCL_ERROR; - } - - if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; - if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset) - || TCL_OK!=Tcl_GetIntFromObj(interp, objv[3], &nByte) - ){ - return TCL_ERROR; - } - - if( nByte>0 ){ - zBuf = (unsigned char *)Tcl_Alloc(nByte); - } - rc = sqlite3_blob_read(pBlob, zBuf, nByte, iOffset); - if( rc==SQLITE_OK ){ - Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zBuf, nByte)); - }else{ - Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); - } - Tcl_Free((char *)zBuf); - - return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); -} - -/* -** sqlite3_blob_write HANDLE OFFSET DATA ?NDATA? -** -** This command is used to test the sqlite3_blob_write() in ways that -** the Tcl channel interface does not. The first argument should -** be the name of a valid channel created by the [incrblob] method -** of a database handle. This function calls sqlite3_blob_write() -** to write the DATA byte-array to the underlying SQLite blob handle. -** at offset OFFSET. -** -** On success, an empty string is returned. On failure, the interpreter -** result is set to the text representation of the returned error code -** (i.e. "SQLITE_NOMEM") and a Tcl exception is thrown. -*/ -static int test_blob_write( - ClientData clientData, /* Not used */ - Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ - int objc, /* Number of arguments */ - Tcl_Obj *CONST objv[] /* Command arguments */ -){ - sqlite3_blob *pBlob; - int iOffset; - int rc; - - unsigned char *zBuf; - int nBuf; - - if( objc!=4 && objc!=5 ){ - Tcl_WrongNumArgs(interp, 1, objv, "HANDLE OFFSET DATA ?NDATA?"); - return TCL_ERROR; - } - - if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; - if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset) ){ - return TCL_ERROR; - } - - zBuf = Tcl_GetByteArrayFromObj(objv[3], &nBuf); - if( objc==5 && Tcl_GetIntFromObj(interp, objv[4], &nBuf) ){ - return TCL_ERROR; - } - rc = sqlite3_blob_write(pBlob, zBuf, nBuf, iOffset); - if( rc!=SQLITE_OK ){ - Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); - } - - return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); -} - - -/* -** Register commands with the TCL interpreter. -*/ -int Sqlitetest_blob_Init(Tcl_Interp *interp){ - static struct { - char *zName; - Tcl_ObjCmdProc *xProc; - } aObjCmd[] = { - { "sqlite3_blob_open", test_blob_open }, - { "sqlite3_blob_close", test_blob_close }, - { "sqlite3_blob_bytes", test_blob_bytes }, - { "sqlite3_blob_read", test_blob_read }, - { "sqlite3_blob_write", test_blob_write }, - }; - int i; - for(i=0; i 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; } return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b]; } Index: src/vacuum.c ================================================================== --- src/vacuum.c +++ src/vacuum.c @@ -92,11 +92,11 @@ ** Two writes per page are required in step (3) because the original ** database content must be written into the rollback journal prior to ** overwriting the database with the vacuumed content. ** ** Only 1x temporary space and only 1x writes would be required if -** the copy of step (3) were replaced by deleting the original database +** the copy of step (3) were replace by deleting the original database ** and renaming the transient database as the original. But that will ** not work if other processes are attached to the original database. ** And a power loss in between deleting the original and renaming the ** transient would cause the database file to appear to be deleted ** following reboot. Index: src/vdbe.c ================================================================== --- src/vdbe.c +++ src/vdbe.c @@ -606,13 +606,10 @@ #ifdef VDBE_PROFILE start = sqlite3Hwtime(); #endif nVmStep++; pOp = &aOp[pc]; -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS - if( p->anExec ) p->anExec[pc]++; -#endif /* Only allow tracing if SQLITE_DEBUG is defined. */ #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeTrace ){ @@ -3802,15 +3799,14 @@ } pIdxKey = &r; }else{ pIdxKey = sqlite3VdbeAllocUnpackedRecord( pC->pKeyInfo, aTempRec, sizeof(aTempRec), &pFree - ); + ); if( pIdxKey==0 ) goto no_mem; assert( pIn3->flags & MEM_Blob ); - /* assert( (pIn3->flags & MEM_Zero)==0 ); // zeroblobs already expanded */ - ExpandBlob(pIn3); + assert( (pIn3->flags & MEM_Zero)==0 ); /* zeroblobs already expanded */ sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey); } pIdxKey->default_rc = 0; if( pOp->opcode==OP_NoConflict ){ /* For the OP_NoConflict opcode, take the jump if any of the @@ -4496,13 +4492,13 @@ } /* Opcode: Rewind P1 P2 * * * ** ** The next use of the Rowid or Column or Next instruction for P1 ** will refer to the first entry in the database table or index. -** If the table or index is empty, jump immediately to P2. -** If the table or index is not empty, fall through to the following -** instruction. +** If the table or index is empty and P2>0, then jump immediately to P2. +** If P2 is 0 or if the table or index is not empty, fall through +** to the following instruction. ** ** This opcode leaves the cursor configured to move in forward order, ** from the beginning toward the end. In other words, the cursor is ** configured to use Next, not Prev. */ @@ -5414,13 +5410,10 @@ pFrame->aOp = p->aOp; pFrame->nOp = p->nOp; pFrame->token = pProgram->token; pFrame->aOnceFlag = p->aOnceFlag; pFrame->nOnceFlag = p->nOnceFlag; -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS - pFrame->anExec = p->anExec; -#endif pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem]; for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){ pMem->flags = MEM_Undefined; pMem->db = db; @@ -5434,11 +5427,10 @@ p->nFrame++; pFrame->pParent = p->pFrame; pFrame->lastRowid = lastRowid; pFrame->nChange = p->nChange; - pFrame->nDbChange = p->db->nChange; p->nChange = 0; p->pFrame = pFrame; p->aMem = aMem = &VdbeFrameMem(pFrame)[-1]; p->nMem = pFrame->nChildMem; p->nCursor = (u16)pFrame->nChildCsr; @@ -5445,13 +5437,10 @@ p->apCsr = (VdbeCursor **)&aMem[p->nMem+1]; p->aOp = aOp = pProgram->aOp; p->nOp = pProgram->nOp; p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor]; p->nOnceFlag = pProgram->nOnce; -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS - p->anExec = 0; -#endif pc = -1; memset(p->aOnceFlag, 0, p->nOnceFlag); break; } Index: src/vdbe.h ================================================================== --- src/vdbe.h +++ src/vdbe.h @@ -280,12 +280,6 @@ # define VdbeCoverageAlwaysTaken(v) # define VdbeCoverageNeverTaken(v) # define VDBE_OFFSET_LINENO(x) 0 #endif -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS -void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const char*); -#else -# define sqlite3VdbeScanStatus(a,b,c,d,e) -#endif - #endif Index: src/vdbeInt.h ================================================================== --- src/vdbeInt.h +++ src/vdbeInt.h @@ -130,11 +130,10 @@ typedef struct VdbeFrame VdbeFrame; struct VdbeFrame { Vdbe *v; /* VM this frame belongs to */ VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */ Op *aOp; /* Program instructions for parent frame */ - i64 *anExec; /* Event counters from parent frame */ Mem *aMem; /* Array of memory cells for parent frame */ u8 *aOnceFlag; /* Array of OP_Once flags for parent frame */ VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */ void *token; /* Copy of SubProgram.token */ i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */ @@ -143,12 +142,11 @@ int nOp; /* Size of aOp array */ int nMem; /* Number of entries in aMem */ int nOnceFlag; /* Number of entries in aOnceFlag */ int nChildMem; /* Number of memory cells for child frame */ int nChildCsr; /* Number of cursors for child frame */ - int nChange; /* Statement changes (Vdbe.nChange) */ - int nDbChange; /* Value of db->nChange */ + int nChange; /* Statement changes (Vdbe.nChanges) */ }; #define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))]) /* @@ -295,20 +293,10 @@ /* A bitfield type for use inside of structures. Always follow with :N where ** N is the number of bits. */ typedef unsigned bft; /* Bit Field Type */ -typedef struct ScanStatus ScanStatus; -struct ScanStatus { - int addrExplain; /* OP_Explain for loop */ - int addrLoop; /* Address of "loops" counter */ - int addrVisit; /* Address of "rows visited" counter */ - int iSelectID; /* The "Select-ID" for this loop */ - LogEst nEst; /* Estimated output rows per loop */ - char *zName; /* Name of table or index */ -}; - /* ** An instance of the virtual machine. This structure contains the complete ** state of the virtual machine. ** ** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare() @@ -377,15 +365,10 @@ u32 expmask; /* Binding to these vars invalidates VM */ SubProgram *pProgram; /* Linked list of all sub-programs used by VM */ int nOnceFlag; /* Size of array aOnceFlag[] */ u8 *aOnceFlag; /* Flags for OP_Once */ AuxData *pAuxData; /* Linked list of auxdata allocations */ -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS - i64 *anExec; /* Number of times each op has been executed */ - int nScan; /* Entries in aScan[] */ - ScanStatus *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */ -#endif }; /* ** The following are allowed values for Vdbe.magic */ Index: src/vdbeapi.c ================================================================== --- src/vdbeapi.c +++ src/vdbeapi.c @@ -964,23 +964,15 @@ sqlite3_stmt *pStmt, int N, const void *(*xFunc)(Mem*), int useType ){ - const void *ret; - Vdbe *p; + const void *ret = 0; + Vdbe *p = (Vdbe *)pStmt; int n; - sqlite3 *db; -#ifdef SQLITE_ENABLE_API_ARMOR - if( pStmt==0 ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif - ret = 0; - p = (Vdbe *)pStmt; - db = p->db; + sqlite3 *db = p->db; + assert( db!=0 ); n = sqlite3_column_count(pStmt); if( N=0 ){ N += useType*n; sqlite3_mutex_enter(db->mutex); @@ -1441,16 +1433,10 @@ ** prepared statement for the database connection. Return NULL if there ** are no more. */ sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){ sqlite3_stmt *pNext; -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(pDb) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif sqlite3_mutex_enter(pDb->mutex); if( pStmt==0 ){ pNext = (sqlite3_stmt*)pDb->pVdbe; }else{ pNext = (sqlite3_stmt*)((Vdbe*)pStmt)->pNext; @@ -1462,85 +1448,9 @@ /* ** Return the value of a status counter for a prepared statement */ int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){ Vdbe *pVdbe = (Vdbe*)pStmt; - u32 v; -#ifdef SQLITE_ENABLE_API_ARMOR - if( !pStmt ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif - v = pVdbe->aCounter[op]; + u32 v = pVdbe->aCounter[op]; if( resetFlag ) pVdbe->aCounter[op] = 0; return (int)v; } - -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS -/* -** Return status data for a single loop within query pStmt. -*/ -int sqlite3_stmt_scanstatus( - sqlite3_stmt *pStmt, /* Prepared statement being queried */ - int idx, /* Index of loop to report on */ - int iScanStatusOp, /* Which metric to return */ - void *pOut /* OUT: Write the answer here */ -){ - Vdbe *p = (Vdbe*)pStmt; - ScanStatus *pScan; - if( idx<0 || idx>=p->nScan ) return 1; - pScan = &p->aScan[idx]; - switch( iScanStatusOp ){ - case SQLITE_SCANSTAT_NLOOP: { - *(sqlite3_int64*)pOut = p->anExec[pScan->addrLoop]; - break; - } - case SQLITE_SCANSTAT_NVISIT: { - *(sqlite3_int64*)pOut = p->anExec[pScan->addrVisit]; - break; - } - case SQLITE_SCANSTAT_EST: { - double r = 1.0; - LogEst x = pScan->nEst; - while( x<100 ){ - x += 10; - r *= 0.5; - } - *(double*)pOut = r*sqlite3LogEstToInt(x); - break; - } - case SQLITE_SCANSTAT_NAME: { - *(const char**)pOut = pScan->zName; - break; - } - case SQLITE_SCANSTAT_EXPLAIN: { - if( pScan->addrExplain ){ - *(const char**)pOut = p->aOp[ pScan->addrExplain ].p4.z; - }else{ - *(const char**)pOut = 0; - } - break; - } - case SQLITE_SCANSTAT_SELECTID: { - if( pScan->addrExplain ){ - *(int*)pOut = p->aOp[ pScan->addrExplain ].p1; - }else{ - *(int*)pOut = -1; - } - break; - } - default: { - return 1; - } - } - return 0; -} - -/* -** Zero all counters associated with the sqlite3_stmt_scanstatus() data. -*/ -void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){ - Vdbe *p = (Vdbe*)pStmt; - memset(p->anExec, 0, p->nOp * sizeof(i64)); -} -#endif /* SQLITE_ENABLE_STMT_SCANSTATUS */ Index: src/vdbeaux.c ================================================================== --- src/vdbeaux.c +++ src/vdbeaux.c @@ -594,38 +594,10 @@ } p->nOp += nOp; } return addr; } - -#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) -/* -** Add an entry to the array of counters managed by sqlite3_stmt_scanstatus(). -*/ -void sqlite3VdbeScanStatus( - Vdbe *p, /* VM to add scanstatus() to */ - int addrExplain, /* Address of OP_Explain (or 0) */ - int addrLoop, /* Address of loop counter */ - int addrVisit, /* Address of rows visited counter */ - LogEst nEst, /* Estimated number of output rows */ - const char *zName /* Name of table or index being scanned */ -){ - int nByte = (p->nScan+1) * sizeof(ScanStatus); - ScanStatus *aNew; - aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte); - if( aNew ){ - ScanStatus *pNew = &aNew[p->nScan++]; - pNew->addrExplain = addrExplain; - pNew->addrLoop = addrLoop; - pNew->addrVisit = addrVisit; - pNew->nEst = nEst; - pNew->zName = sqlite3DbStrDup(p->db, zName); - p->aScan = aNew; - } -} -#endif - /* ** Change the value of the P1 operand for a specific instruction. ** This routine is useful when a large program is loaded from a ** static array using sqlite3VdbeAddOpList but we want to make a @@ -1721,13 +1693,10 @@ p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte); p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte); p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*), &zCsr, zEnd, &nByte); p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, &zCsr, zEnd, &nByte); -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS - p->anExec = allocSpace(p->anExec, p->nOp*sizeof(i64), &zCsr, zEnd, &nByte); -#endif if( nByte ){ p->pFree = sqlite3DbMallocZero(db, nByte); } zCsr = p->pFree; zEnd = &zCsr[nByte]; @@ -1791,13 +1760,10 @@ ** is used, for example, when a trigger sub-program is halted to restore ** control to the main program. */ int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){ Vdbe *v = pFrame->v; -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS - v->anExec = pFrame->anExec; -#endif v->aOnceFlag = pFrame->aOnceFlag; v->nOnceFlag = pFrame->nOnceFlag; v->aOp = pFrame->aOp; v->nOp = pFrame->nOp; v->aMem = pFrame->aMem; @@ -1804,11 +1770,10 @@ v->nMem = pFrame->nMem; v->apCsr = pFrame->apCsr; v->nCursor = pFrame->nCursor; v->db->lastRowid = pFrame->lastRowid; v->nChange = pFrame->nChange; - v->db->nChange = pFrame->nDbChange; return pFrame->pc; } /* ** Close all cursors. @@ -2372,11 +2337,10 @@ ** so, abort any other statements this handle currently has active. */ sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); sqlite3CloseSavepoints(db); db->autoCommit = 1; - p->nChange = 0; } } } /* Check for immediate foreign key violations. */ @@ -2413,20 +2377,18 @@ sqlite3VdbeLeave(p); return SQLITE_BUSY; }else if( rc!=SQLITE_OK ){ p->rc = rc; sqlite3RollbackAll(db, SQLITE_OK); - p->nChange = 0; }else{ db->nDeferredCons = 0; db->nDeferredImmCons = 0; db->flags &= ~SQLITE_DeferFKs; sqlite3CommitInternalChanges(db); } }else{ sqlite3RollbackAll(db, SQLITE_OK); - p->nChange = 0; } db->nStatement = 0; }else if( eStatementOp==0 ){ if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){ eStatementOp = SAVEPOINT_RELEASE; @@ -2434,11 +2396,10 @@ eStatementOp = SAVEPOINT_ROLLBACK; }else{ sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); sqlite3CloseSavepoints(db); db->autoCommit = 1; - p->nChange = 0; } } /* If eStatementOp is non-zero, then a statement transaction needs to ** be committed or rolled back. Call sqlite3VdbeCloseStatement() to @@ -2455,11 +2416,10 @@ p->zErrMsg = 0; } sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); sqlite3CloseSavepoints(db); db->autoCommit = 1; - p->nChange = 0; } } /* If this was an INSERT, UPDATE or DELETE and no statement transaction ** has been rolled back, update the database connection change-counter. @@ -2717,16 +2677,10 @@ for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]); vdbeFreeOpArray(db, p->aOp, p->nOp); sqlite3DbFree(db, p->aColName); sqlite3DbFree(db, p->zSql); sqlite3DbFree(db, p->pFree); -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS - for(i=0; inScan; i++){ - sqlite3DbFree(db, p->aScan[i].zName); - } - sqlite3DbFree(db, p->aScan); -#endif } /* ** Delete an entire VDBE. */ Index: src/vdbeblob.c ================================================================== --- src/vdbeblob.c +++ src/vdbeblob.c @@ -151,15 +151,10 @@ char *zErr = 0; Table *pTab; Parse *pParse = 0; Incrblob *pBlob = 0; -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) || ppBlob==0 || zTable==0 ){ - return SQLITE_MISUSE_BKPT; - } -#endif flags = !!flags; /* flags = (flags ? 1 : 0); */ *ppBlob = 0; sqlite3_mutex_enter(db->mutex); @@ -374,10 +369,11 @@ v = (Vdbe*)p->pStmt; if( n<0 || iOffset<0 || (iOffset+n)>p->nByte ){ /* Request is out of range. Return a transient error. */ rc = SQLITE_ERROR; + sqlite3Error(db, SQLITE_ERROR); }else if( v==0 ){ /* If there is no statement handle, then the blob-handle has ** already been invalidated. Return SQLITE_ABORT in this case. */ rc = SQLITE_ABORT; @@ -391,14 +387,14 @@ sqlite3BtreeLeaveCursor(p->pCsr); if( rc==SQLITE_ABORT ){ sqlite3VdbeFinalize(v); p->pStmt = 0; }else{ + db->errCode = rc; v->rc = rc; } } - sqlite3Error(db, rc); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } Index: src/vdbesort.c ================================================================== --- src/vdbesort.c +++ src/vdbesort.c @@ -98,11 +98,11 @@ ** itself. ** ** The sorter is running in multi-threaded mode if (a) the library was built ** with pre-processor symbol SQLITE_MAX_WORKER_THREADS set to a value greater ** than zero, and (b) worker threads have been enabled at runtime by calling -** "PRAGMA threads=N" with some value of N greater than 0. +** sqlite3_config(SQLITE_CONFIG_WORKER_THREADS, ...). ** ** When Rewind() is called, any data remaining in memory is flushed to a ** final PMA. So at this point the data is stored in some number of sorted ** PMAs within temporary files on disk. ** @@ -845,13 +845,15 @@ pSorter->mnPmaSize = SORTER_MIN_WORKING * pgsz; mxCache = db->aDb[0].pSchema->cache_size; if( mxCachemxPmaSize = mxCache * pgsz; - /* EVIDENCE-OF: R-26747-61719 When the application provides any amount of - ** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary - ** large heap allocations. + /* If the application has not configure scratch memory using + ** SQLITE_CONFIG_SCRATCH then we assume it is OK to do large memory + ** allocations. If scratch memory has been configured, then assume + ** large memory allocations should be avoided to prevent heap + ** fragmentation. */ if( sqlite3GlobalConfig.pScratch==0 ){ assert( pSorter->iMemory==0 ); pSorter->nMemory = pgsz; pSorter->list.aMemory = (u8*)sqlite3Malloc(pgsz); Index: src/vtab.c ================================================================== --- src/vtab.c +++ src/vtab.c @@ -79,13 +79,10 @@ sqlite3 *db, /* Database in which module is registered */ const char *zName, /* Name assigned to this module */ const sqlite3_module *pModule, /* The definition of the module */ void *pAux /* Context pointer for xCreate/xConnect */ ){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; -#endif return createModule(db, zName, pModule, pAux, 0); } /* ** External API function used to create a new virtual-table module. @@ -95,13 +92,10 @@ const char *zName, /* Name assigned to this module */ const sqlite3_module *pModule, /* The definition of the module */ void *pAux, /* Context pointer for xCreate/xConnect */ void (*xDestroy)(void *) /* Module destructor function */ ){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; -#endif return createModule(db, zName, pModule, pAux, xDestroy); } /* ** Lock the virtual table so that it cannot be disconnected. @@ -702,13 +696,10 @@ int rc = SQLITE_OK; Table *pTab; char *zErr = 0; -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif sqlite3_mutex_enter(db->mutex); if( !db->pVtabCtx || !(pTab = db->pVtabCtx->pTab) ){ sqlite3Error(db, SQLITE_MISUSE); sqlite3_mutex_leave(db->mutex); return SQLITE_MISUSE_BKPT; @@ -1061,13 +1052,10 @@ */ int sqlite3_vtab_on_conflict(sqlite3 *db){ static const unsigned char aMap[] = { SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE }; -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif assert( OE_Rollback==1 && OE_Abort==2 && OE_Fail==3 ); assert( OE_Ignore==4 && OE_Replace==5 ); assert( db->vtabOnConflict>=1 && db->vtabOnConflict<=5 ); return (int)aMap[db->vtabOnConflict-1]; } @@ -1079,14 +1067,12 @@ */ int sqlite3_vtab_config(sqlite3 *db, int op, ...){ va_list ap; int rc = SQLITE_OK; -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif sqlite3_mutex_enter(db->mutex); + va_start(ap, op); switch( op ){ case SQLITE_VTAB_CONSTRAINT_SUPPORT: { VtabCtx *p = db->pVtabCtx; if( !p ){ Index: src/wal.c ================================================================== --- src/wal.c +++ src/wal.c @@ -1502,11 +1502,11 @@ /* ** Free an iterator allocated by walIteratorInit(). */ static void walIteratorFree(WalIterator *p){ - sqlite3_free(p); + sqlite3ScratchFree(p); } /* ** Construct a WalInterator object that can be used to loop over all ** pages in the WAL in ascending order. The caller must hold the checkpoint @@ -1537,21 +1537,21 @@ /* Allocate space for the WalIterator object. */ nSegment = walFramePage(iLast) + 1; nByte = sizeof(WalIterator) + (nSegment-1)*sizeof(struct WalSegment) + iLast*sizeof(ht_slot); - p = (WalIterator *)sqlite3_malloc(nByte); + p = (WalIterator *)sqlite3ScratchMalloc(nByte); if( !p ){ return SQLITE_NOMEM; } memset(p, 0, nByte); p->nSegment = nSegment; /* Allocate temporary space used by the merge-sort routine. This block ** of memory will be freed before this function returns. */ - aTmp = (ht_slot *)sqlite3_malloc( + aTmp = (ht_slot *)sqlite3ScratchMalloc( sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast) ); if( !aTmp ){ rc = SQLITE_NOMEM; } @@ -1584,11 +1584,11 @@ p->aSegment[i].nEntry = nEntry; p->aSegment[i].aIndex = aIndex; p->aSegment[i].aPgno = (u32 *)aPgno; } } - sqlite3_free(aTmp); + sqlite3ScratchFree(aTmp); if( rc!=SQLITE_OK ){ walIteratorFree(p); } *pp = p; Index: src/where.c ================================================================== --- src/where.c +++ src/where.c @@ -223,11 +223,11 @@ } pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]); } pTerm = &pWC->a[idx = pWC->nTerm++]; if( p && ExprHasProperty(p, EP_Unlikely) ){ - pTerm->truthProb = sqlite3LogEst(p->iTable) - 270; + pTerm->truthProb = sqlite3LogEst(p->iTable) - 99; }else{ pTerm->truthProb = 1; } pTerm->pExpr = sqlite3ExprSkipCollate(p); pTerm->wtFlags = wtFlags; @@ -754,19 +754,10 @@ pDerived->flags |= pBase->flags & EP_FromJoin; pDerived->iRightJoinTable = pBase->iRightJoinTable; } } -/* -** Mark term iChild as being a child of term iParent -*/ -static void markTermAsChild(WhereClause *pWC, int iChild, int iParent){ - pWC->a[iChild].iParent = iParent; - pWC->a[iChild].truthProb = pWC->a[iParent].truthProb; - pWC->a[iParent].nChild++; -} - #if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY) /* ** Analyze a term that consists of two or more OR-connected ** subterms. So in: ** @@ -1060,11 +1051,12 @@ pNew->x.pList = pList; idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew==0 ); exprAnalyze(pSrc, pWC, idxNew); pTerm = &pWC->a[idxTerm]; - markTermAsChild(pWC, idxNew, idxTerm); + pWC->a[idxNew].iParent = idxTerm; + pTerm->nChild = 1; }else{ sqlite3ExprListDelete(db, pList); } pTerm->eOperator = WO_NOOP; /* case 1 trumps case 2 */ } @@ -1162,12 +1154,13 @@ return; } idxNew = whereClauseInsert(pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC); if( idxNew==0 ) return; pNew = &pWC->a[idxNew]; - markTermAsChild(pWC, idxNew, idxTerm); + pNew->iParent = idxTerm; pTerm = &pWC->a[idxTerm]; + pTerm->nChild = 1; pTerm->wtFlags |= TERM_COPIED; if( pExpr->op==TK_EQ && !ExprHasProperty(pExpr, EP_FromJoin) && OptimizationEnabled(db, SQLITE_Transitive) ){ @@ -1220,12 +1213,13 @@ transferJoinMarkings(pNewExpr, pExpr); idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew==0 ); exprAnalyze(pSrc, pWC, idxNew); pTerm = &pWC->a[idxTerm]; - markTermAsChild(pWC, idxNew, idxTerm); + pWC->a[idxNew].iParent = idxTerm; } + pTerm->nChild = 2; } #endif /* SQLITE_OMIT_BETWEEN_OPTIMIZATION */ #if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY) /* Analyze a term that is composed of two or more subterms connected by @@ -1296,12 +1290,13 @@ idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew2==0 ); exprAnalyze(pSrc, pWC, idxNew2); pTerm = &pWC->a[idxTerm]; if( isComplete ){ - markTermAsChild(pWC, idxNew1, idxTerm); - markTermAsChild(pWC, idxNew2, idxTerm); + pWC->a[idxNew1].iParent = idxTerm; + pWC->a[idxNew2].iParent = idxTerm; + pTerm->nChild = 2; } } #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */ #ifndef SQLITE_OMIT_VIRTUALTABLE @@ -1330,12 +1325,13 @@ pNewTerm = &pWC->a[idxNew]; pNewTerm->prereqRight = prereqExpr; pNewTerm->leftCursor = pLeft->iTable; pNewTerm->u.leftColumn = pLeft->iColumn; pNewTerm->eOperator = WO_MATCH; - markTermAsChild(pWC, idxNew, idxTerm); + pNewTerm->iParent = idxTerm; pTerm = &pWC->a[idxTerm]; + pTerm->nChild = 1; pTerm->wtFlags |= TERM_COPIED; pNewTerm->prereqAll = pTerm->prereqAll; } } #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -1352,11 +1348,11 @@ ** the start of the loop will prevent any results from being returned. */ if( pExpr->op==TK_NOTNULL && pExpr->pLeft->op==TK_COLUMN && pExpr->pLeft->iColumn>=0 - && OptimizationEnabled(db, SQLITE_Stat34) + && OptimizationEnabled(db, SQLITE_Stat3) ){ Expr *pNewExpr; Expr *pLeft = pExpr->pLeft; int idxNew; WhereTerm *pNewTerm; @@ -1371,12 +1367,13 @@ pNewTerm = &pWC->a[idxNew]; pNewTerm->prereqRight = 0; pNewTerm->leftCursor = pLeft->iTable; pNewTerm->u.leftColumn = pLeft->iColumn; pNewTerm->eOperator = WO_GT; - markTermAsChild(pWC, idxNew, idxTerm); + pNewTerm->iParent = idxTerm; pTerm = &pWC->a[idxTerm]; + pTerm->nChild = 1; pTerm->wtFlags |= TERM_COPIED; pNewTerm->prereqAll = pTerm->prereqAll; } } #endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ @@ -1592,12 +1589,10 @@ WhereLoop *pLoop; /* The Loop object */ char *zNotUsed; /* Extra space on the end of pIdx */ Bitmask idxCols; /* Bitmap of columns used for indexing */ Bitmask extraCols; /* Bitmap of additional columns */ u8 sentWarning = 0; /* True if a warnning has been issued */ - Expr *pPartial = 0; /* Partial Index Expression */ - int iContinue = 0; /* Jump here to skip excluded rows */ /* Generate code to skip over the creation and initialization of the ** transient index on 2nd and subsequent iterations of the loop. */ v = pParse->pVdbe; assert( v!=0 ); @@ -1609,16 +1604,10 @@ pTable = pSrc->pTab; pWCEnd = &pWC->a[pWC->nTerm]; pLoop = pLevel->pWLoop; idxCols = 0; for(pTerm=pWC->a; pTermprereq==0 - && (pTerm->wtFlags & TERM_VIRTUAL)==0 - && sqlite3ExprIsTableConstant(pTerm->pExpr, pSrc->iCursor) ){ - pPartial = sqlite3ExprAnd(pParse->db, pPartial, - sqlite3ExprDup(pParse->db, pTerm->pExpr, 0)); - } if( termCanDriveIndex(pTerm, pSrc, notReady) ){ int iCol = pTerm->u.leftColumn; Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); testcase( iCol==BMS ); testcase( iCol==BMS-1 ); @@ -1627,13 +1616,11 @@ "automatic index on %s(%s)", pTable->zName, pTable->aCol[iCol].zName); sentWarning = 1; } if( (idxCols & cMask)==0 ){ - if( whereLoopResize(pParse->db, pLoop, nKeyCol+1) ){ - goto end_auto_index_create; - } + if( whereLoopResize(pParse->db, pLoop, nKeyCol+1) ) return; pLoop->aLTerm[nKeyCol++] = pTerm; idxCols |= cMask; } } } @@ -1649,23 +1636,24 @@ ** be a covering index because the index will not be updated if the ** original table changes and the index and table cannot both be used ** if they go out of sync. */ extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1)); - mxBitCol = MIN(BMS-1,pTable->nCol); + mxBitCol = (pTable->nCol >= BMS-1) ? BMS-1 : pTable->nCol; testcase( pTable->nCol==BMS-1 ); testcase( pTable->nCol==BMS-2 ); for(i=0; icolUsed & MASKBIT(BMS-1) ){ nKeyCol += pTable->nCol - BMS + 1; } + pLoop->wsFlags |= WHERE_COLUMN_EQ | WHERE_IDX_ONLY; /* Construct the Index object to describe this index */ pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+1, 0, &zNotUsed); - if( pIdx==0 ) goto end_auto_index_create; + if( pIdx==0 ) return; pLoop->u.btree.pIndex = pIdx; pIdx->zName = "auto-index"; pIdx->pTable = pTable; n = 0; idxCols = 0; @@ -1713,33 +1701,22 @@ sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol+1); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "for %s", pTable->zName)); /* Fill the automatic index with content */ - sqlite3ExprCachePush(pParse); addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v); - if( pPartial ){ - iContinue = sqlite3VdbeMakeLabel(v); - sqlite3ExprIfFalse(pParse, pPartial, iContinue, SQLITE_JUMPIFNULL); - pLoop->wsFlags |= WHERE_PARTIALIDX; - } regRecord = sqlite3GetTempReg(pParse); sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0, 0, 0); sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); - if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue); sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v); sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX); sqlite3VdbeJumpHere(v, addrTop); sqlite3ReleaseTempReg(pParse, regRecord); - sqlite3ExprCachePop(pParse); /* Jump here when skipping the initialization */ sqlite3VdbeJumpHere(v, addrInit); - -end_auto_index_create: - sqlite3ExprDelete(pParse->db, pPartial); } #endif /* SQLITE_OMIT_AUTOMATIC_INDEX */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* @@ -1894,23 +1871,23 @@ } return pParse->nErr; } #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */ + #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 /* ** Estimate the location of a particular key among all keys in an ** index. Store the results in aStat as follows: ** ** aStat[0] Est. number of rows less than pVal ** aStat[1] Est. number of rows equal to pVal ** -** Return the index of the sample that is the smallest sample that -** is greater than or equal to pRec. +** Return SQLITE_OK on success. */ -static int whereKeyStats( +static void whereKeyStats( Parse *pParse, /* Database connection */ Index *pIdx, /* Index to consider domain of */ UnpackedRecord *pRec, /* Vector of values to consider */ int roundUp, /* Round up if true. Round down if false */ tRowcnt *aStat /* OUT: stats written here */ @@ -1988,11 +1965,10 @@ }else{ iGap = iGap/3; } aStat[0] = iLower + iGap; } - return i; } #endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ /* ** If it is not NULL, pTerm is a term that provides an upper or lower @@ -2139,11 +2115,11 @@ ** pLower pUpper ** ** If either of the upper or lower bound is not present, then NULL is passed in ** place of the corresponding WhereTerm. ** -** The value in (pBuilder->pNew->u.btree.nEq) is the number of the index +** The value in (pBuilder->pNew->u.btree.nEq) is the index of the index ** column subject to the range constraint. Or, equivalently, the number of ** equality constraints optimized by the proposed index scan. For example, ** assuming index p is on t1(a, b), and the SQL query is: ** ** ... FROM t1 WHERE a = ? AND b > ? AND b < ? ... @@ -2155,11 +2131,11 @@ ** ** then nEq is set to 0. ** ** When this function is called, *pnOut is set to the sqlite3LogEst() of the ** number of rows that the index scan is expected to visit without -** considering the range constraints. If nEq is 0, then *pnOut is the number of +** considering the range constraints. If nEq is 0, this is the number of ** rows in the index. Assuming no error occurs, *pnOut is adjusted (reduced) ** to account for the range constraints pLower and pUpper. ** ** In the absence of sqlite_stat4 ANALYZE data, or if such data cannot be ** used, a single range inequality reduces the search space by a factor of 4. @@ -2179,11 +2155,14 @@ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 Index *p = pLoop->u.btree.pIndex; int nEq = pLoop->u.btree.nEq; - if( p->nSample>0 && nEqnSampleCol ){ + if( p->nSample>0 + && nEqnSampleCol + && OptimizationEnabled(pParse->db, SQLITE_Stat3) + ){ if( nEq==pBuilder->nRecValid ){ UnpackedRecord *pRec = pBuilder->pRec; tRowcnt a[2]; u8 aff; @@ -2195,23 +2174,19 @@ ** ** Or, if pLower is NULL or $L cannot be extracted from it (because it ** is not a simple variable or literal value), the lower bound of the ** range is $P. Due to a quirk in the way whereKeyStats() works, even ** if $L is available, whereKeyStats() is called for both ($P) and - ** ($P:$L) and the larger of the two returned values is used. + ** ($P:$L) and the larger of the two returned values used. ** ** Similarly, iUpper is to be set to the estimate of the number of rows ** less than the upper bound of the range query. Where the upper bound ** is either ($P) or ($P:$U). Again, even if $U is available, both values ** of iUpper are requested of whereKeyStats() and the smaller used. - ** - ** The number of rows between the two bounds is then just iUpper-iLower. */ - tRowcnt iLower; /* Rows less than the lower bound */ - tRowcnt iUpper; /* Rows less than the upper bound */ - int iLwrIdx = -2; /* aSample[] for the lower bound */ - int iUprIdx = -1; /* aSample[] for the upper bound */ + tRowcnt iLower; + tRowcnt iUpper; if( pRec ){ testcase( pRec->nField!=pBuilder->nRecValid ); pRec->nField = pBuilder->nRecValid; } @@ -2221,11 +2196,11 @@ aff = p->pTable->aCol[p->aiColumn[nEq]].affinity; } /* Determine iLower and iUpper using ($P) only. */ if( nEq==0 ){ iLower = 0; - iUpper = p->nRowEst0; + iUpper = sqlite3LogEstToInt(p->aiRowLogEst[0]); }else{ /* Note: this call could be optimized away - since the same values must ** have been requested when testing key $P in whereEqualScanEst(). */ whereKeyStats(pParse, p, pRec, 0, a); iLower = a[0]; @@ -2245,11 +2220,11 @@ int bOk; /* True if value is extracted from pExpr */ Expr *pExpr = pLower->pExpr->pRight; rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); if( rc==SQLITE_OK && bOk ){ tRowcnt iNew; - iLwrIdx = whereKeyStats(pParse, p, pRec, 0, a); + whereKeyStats(pParse, p, pRec, 0, a); iNew = a[0] + ((pLower->eOperator & (WO_GT|WO_LE)) ? a[1] : 0); if( iNew>iLower ) iLower = iNew; nOut--; pLower = 0; } @@ -2260,11 +2235,11 @@ int bOk; /* True if value is extracted from pExpr */ Expr *pExpr = pUpper->pExpr->pRight; rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); if( rc==SQLITE_OK && bOk ){ tRowcnt iNew; - iUprIdx = whereKeyStats(pParse, p, pRec, 1, a); + whereKeyStats(pParse, p, pRec, 1, a); iNew = a[0] + ((pUpper->eOperator & (WO_GT|WO_LE)) ? a[1] : 0); if( iNewpRec = pRec; if( rc==SQLITE_OK ){ if( iUpper>iLower ){ nNew = sqlite3LogEst(iUpper - iLower); - /* TUNING: If both iUpper and iLower are derived from the same - ** sample, then assume they are 4x more selective. This brings - ** the estimated selectivity more in line with what it would be - ** if estimated without the use of STAT3/4 tables. */ - if( iLwrIdx==iUprIdx ) nNew -= 20; assert( 20==sqlite3LogEst(4) ); }else{ nNew = 10; assert( 10==sqlite3LogEst(2) ); } if( nNewwtFlags & TERM_VNULL)==0 ); nNew = whereRangeAdjust(pLower, nOut); nNew = whereRangeAdjust(pUpper, nNew); - /* TUNING: If there is both an upper and lower limit and neither limit - ** has an application-defined likelihood(), assume the range is + /* TUNING: If there is both an upper and lower limit, assume the range is ** reduced by an additional 75%. This means that, by default, an open-ended ** range query (e.g. col > ?) is assumed to match 1/4 of the rows in the ** index. While a closed range (e.g. col BETWEEN ? AND ?) is estimated to ** match 1/64 of the index. */ - if( pLower && pLower->truthProb>0 && pUpper && pUpper->truthProb>0 ){ - nNew -= 20; - } + if( pLower && pUpper ) nNew -= 20; nOut -= (pLower!=0) + (pUpper!=0); if( nNew<10 ) nNew = 10; if( nNewpWLoop; assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ); nEq = pLoop->u.btree.nEq; - nSkip = pLoop->nSkip; + nSkip = pLoop->u.btree.nSkip; pIdx = pLoop->u.btree.pIndex; assert( pIdx!=0 ); /* Figure out how many memory cells we will need then allocate them. */ @@ -2783,11 +2750,11 @@ ** "a=? AND b>?" */ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){ Index *pIndex = pLoop->u.btree.pIndex; u16 nEq = pLoop->u.btree.nEq; - u16 nSkip = pLoop->nSkip; + u16 nSkip = pLoop->u.btree.nSkip; int i, j; Column *aCol = pTab->aCol; i16 *aiColumn = pIndex->aiColumn; if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return; @@ -2814,27 +2781,23 @@ sqlite3StrAccumAppend(pStr, ")", 1); } /* ** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN -** command, or if either SQLITE_DEBUG or SQLITE_ENABLE_STMT_SCANSTATUS was -** defined at compile-time. If it is not a no-op, a single OP_Explain opcode -** is added to the output to describe the table scan strategy in pLevel. -** -** If an OP_Explain opcode is added to the VM, its address is returned. -** Otherwise, if no OP_Explain is coded, zero is returned. +** command. If the query being compiled is an EXPLAIN QUERY PLAN, a single +** record is added to the output to describe the table scan strategy in +** pLevel. */ -static int explainOneScan( +static void explainOneScan( Parse *pParse, /* Parse context */ SrcList *pTabList, /* Table list this loop refers to */ WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ int iLevel, /* Value for "level" column of output */ int iFrom, /* Value for "from" column of output */ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ){ - int ret = 0; -#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS) +#ifndef SQLITE_DEBUG if( pParse->explain==2 ) #endif { struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom]; Vdbe *v = pParse->pVdbe; /* VM being constructed */ @@ -2847,11 +2810,11 @@ StrAccum str; /* EQP output string */ char zBuf[100]; /* Initial space for EQP output string */ pLoop = pLevel->pWLoop; flags = pLoop->wsFlags; - if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return 0; + if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return; isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); @@ -2876,12 +2839,10 @@ assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) ); if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){ if( isSearch ){ zFmt = "PRIMARY KEY"; } - }else if( flags & WHERE_PARTIALIDX ){ - zFmt = "AUTOMATIC PARTIAL COVERING INDEX"; }else if( flags & WHERE_AUTO_INDEX ){ zFmt = "AUTOMATIC COVERING INDEX"; }else if( flags & WHERE_IDX_ONLY ){ zFmt = "COVERING INDEX %s"; }else{ @@ -2919,49 +2880,16 @@ }else{ sqlite3StrAccumAppend(&str, " (~1 row)", 9); } #endif zMsg = sqlite3StrAccumFinish(&str); - ret = sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg,P4_DYNAMIC); - } - return ret; -} -#else -# define explainOneScan(u,v,w,x,y,z) 0 -#endif /* SQLITE_OMIT_EXPLAIN */ - -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS -/* -** Configure the VM passed as the first argument with an -** sqlite3_stmt_scanstatus() entry corresponding to the scan used to -** implement level pLvl. Argument pSrclist is a pointer to the FROM -** clause that the scan reads data from. -** -** If argument addrExplain is not 0, it must be the address of an -** OP_Explain instruction that describes the same loop. -*/ -static void addScanStatus( - Vdbe *v, /* Vdbe to add scanstatus entry to */ - SrcList *pSrclist, /* FROM clause pLvl reads data from */ - WhereLevel *pLvl, /* Level to add scanstatus() entry for */ - int addrExplain /* Address of OP_Explain (or 0) */ -){ - const char *zObj = 0; - WhereLoop *pLoop = pLvl->pWLoop; - if( (pLoop->wsFlags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){ - zObj = pLoop->u.btree.pIndex->zName; - }else{ - zObj = pSrclist->a[pLvl->iFrom].zName; - } - sqlite3VdbeScanStatus( - v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj - ); -} -#else -# define addScanStatus(a, b, c, d) ((void)d) -#endif - + sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC); + } +} +#else +# define explainOneScan(u,v,w,x,y,z) +#endif /* SQLITE_OMIT_EXPLAIN */ /* ** Generate code for the start of the iLevel-th loop in the WHERE clause ** implementation described by pWInfo. @@ -3259,11 +3187,11 @@ u8 bSeekPastNull = 0; /* True to seek past initial nulls */ u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */ pIdx = pLoop->u.btree.pIndex; iIdxCur = pLevel->iIdxCur; - assert( nEq>=pLoop->nSkip ); + assert( nEq>=pLoop->u.btree.nSkip ); /* If this loop satisfies a sort order (pOrderBy) request that ** was passed to this function to implement a "SELECT min(x) ..." ** query, then the caller will only allow the loop to run for ** a single iteration. This means that the first row returned @@ -3276,11 +3204,11 @@ || (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 ); if( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0 && pWInfo->nOBSat>0 && (pIdx->nKeyCol>nEq) ){ - assert( pLoop->nSkip==0 ); + assert( pLoop->u.btree.nSkip==0 ); bSeekPastNull = 1; nExtraReg = 1; } /* Find any inequality constraint terms for the start and end @@ -3625,15 +3553,13 @@ pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, wctrlFlags, iCovCur); assert( pSubWInfo || pParse->nErr || db->mallocFailed ); if( pSubWInfo ){ WhereLoop *pSubLoop; - int addrExplain = explainOneScan( + explainOneScan( pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0 ); - addScanStatus(v, pOrTab, &pSubWInfo->a[0], addrExplain); - /* This is the sub-WHERE clause body. First skip over ** duplicate rows from prior sub-WHERE clauses, and record the ** rowid (or PRIMARY KEY) for the current row so that the same ** row will be skipped in subsequent sub-WHERE clauses. */ @@ -3760,14 +3686,10 @@ VdbeCoverageIf(v, bRev!=0); pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; } } -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS - pLevel->addrVisit = sqlite3VdbeCurrentAddr(v); -#endif - /* Insert code to test every subexpression that can be completely ** computed using the current set of tables. */ for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ Expr *pE; @@ -3903,11 +3825,11 @@ } sqlite3DebugPrintf(" %-19s", z); sqlite3_free(z); } if( p->wsFlags & WHERE_SKIPSCAN ){ - sqlite3DebugPrintf(" f %05x %d-%d", p->wsFlags, p->nLTerm,p->nSkip); + sqlite3DebugPrintf(" f %05x %d-%d", p->wsFlags, p->nLTerm,p->u.btree.nSkip); }else{ sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm); } sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut); if( p->nLTerm && (sqlite3WhereTrace & 0x100)!=0 ){ @@ -4014,41 +3936,34 @@ sqlite3DbFree(db, pWInfo); } } /* -** Return TRUE if all of the following are true: +** Return TRUE if both of the following are true: ** ** (1) X has the same or lower cost that Y ** (2) X is a proper subset of Y -** (3) X skips at least as many columns as Y ** ** By "proper subset" we mean that X uses fewer WHERE clause terms ** than Y and that every WHERE clause term used by X is also used ** by Y. ** ** If X is a proper subset of Y then Y is a better choice and ought ** to have a lower cost. This routine returns TRUE when that cost -** relationship is inverted and needs to be adjusted. The third rule -** was added because if X uses skip-scan less than Y it still might -** deserve a lower cost even if it is a proper subset of Y. +** relationship is inverted and needs to be adjusted. */ static int whereLoopCheaperProperSubset( const WhereLoop *pX, /* First WhereLoop to compare */ const WhereLoop *pY /* Compare against this WhereLoop */ ){ int i, j; - if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){ - return 0; /* X is not a subset of Y */ - } - if( pY->nSkip > pX->nSkip ) return 0; + if( pX->nLTerm >= pY->nLTerm ) return 0; /* X is not a subset of Y */ if( pX->rRun >= pY->rRun ){ if( pX->rRun > pY->rRun ) return 0; /* X costs more than Y */ if( pX->nOut > pY->nOut ) return 0; /* X costs more than Y */ } for(i=pX->nLTerm-1; i>=0; i--){ - if( pX->aLTerm[i]==0 ) continue; for(j=pY->nLTerm-1; j>=0; j--){ if( pY->aLTerm[j]==pX->aLTerm[i] ) break; } if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */ } @@ -4066,28 +3981,37 @@ ** is a proper subset. ** ** To say "WhereLoop X is a proper subset of Y" means that X uses fewer ** WHERE clause terms than Y and that every WHERE clause term used by X is ** also used by Y. +** +** This adjustment is omitted for SKIPSCAN loops. In a SKIPSCAN loop, the +** WhereLoop.nLTerm field is not an accurate measure of the number of WHERE +** clause terms covered, since some of the first nLTerm entries in aLTerm[] +** will be NULL (because they are skipped). That makes it more difficult +** to compare the loops. We could add extra code to do the comparison, and +** perhaps we will someday. But SKIPSCAN is sufficiently uncommon, and this +** adjustment is sufficient minor, that it is very difficult to construct +** a test case where the extra code would improve the query plan. Better +** to avoid the added complexity and just omit cost adjustments to SKIPSCAN +** loops. */ static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){ if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return; + if( (pTemplate->wsFlags & WHERE_SKIPSCAN)!=0 ) return; for(; p; p=p->pNextLoop){ if( p->iTab!=pTemplate->iTab ) continue; if( (p->wsFlags & WHERE_INDEXED)==0 ) continue; + if( (p->wsFlags & WHERE_SKIPSCAN)!=0 ) continue; if( whereLoopCheaperProperSubset(p, pTemplate) ){ /* Adjust pTemplate cost downward so that it is cheaper than its - ** subset p. */ - WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n", - pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut-1)); + ** subset p */ pTemplate->rRun = p->rRun; pTemplate->nOut = p->nOut - 1; }else if( whereLoopCheaperProperSubset(pTemplate, p) ){ /* Adjust pTemplate cost upward so that it is costlier than p since ** pTemplate is a proper subset of p */ - WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n", - pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut+1)); pTemplate->rRun = p->rRun; pTemplate->nOut = p->nOut + 1; } } } @@ -4369,11 +4293,11 @@ int opMask; /* Valid operators for constraints */ WhereScan scan; /* Iterator for WHERE terms */ Bitmask saved_prereq; /* Original value of pNew->prereq */ u16 saved_nLTerm; /* Original value of pNew->nLTerm */ u16 saved_nEq; /* Original value of pNew->u.btree.nEq */ - u16 saved_nSkip; /* Original value of pNew->nSkip */ + u16 saved_nSkip; /* Original value of pNew->u.btree.nSkip */ u32 saved_wsFlags; /* Original value of pNew->wsFlags */ LogEst saved_nOut; /* Original value of pNew->nOut */ int iCol; /* Index of the column in the table */ int rc = SQLITE_OK; /* Return code */ LogEst rSize; /* Number of rows in the table */ @@ -4398,18 +4322,56 @@ iCol = pProbe->aiColumn[pNew->u.btree.nEq]; pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol, opMask, pProbe); saved_nEq = pNew->u.btree.nEq; - saved_nSkip = pNew->nSkip; + saved_nSkip = pNew->u.btree.nSkip; saved_nLTerm = pNew->nLTerm; saved_wsFlags = pNew->wsFlags; saved_prereq = pNew->prereq; saved_nOut = pNew->nOut; pNew->rSetup = 0; rSize = pProbe->aiRowLogEst[0]; rLogSize = estLog(rSize); + + /* Consider using a skip-scan if there are no WHERE clause constraints + ** available for the left-most terms of the index, and if the average + ** number of repeats in the left-most terms is at least 18. + ** + ** The magic number 18 is selected on the basis that scanning 17 rows + ** is almost always quicker than an index seek (even though if the index + ** contains fewer than 2^17 rows we assume otherwise in other parts of + ** the code). And, even if it is not, it should not be too much slower. + ** On the other hand, the extra seeks could end up being significantly + ** more expensive. */ + assert( 42==sqlite3LogEst(18) ); + if( saved_nEq==saved_nSkip + && saved_nEq+1nKeyCol + && pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */ + && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK + ){ + LogEst nIter; + pNew->u.btree.nEq++; + pNew->u.btree.nSkip++; + pNew->aLTerm[pNew->nLTerm++] = 0; + pNew->wsFlags |= WHERE_SKIPSCAN; + nIter = pProbe->aiRowLogEst[saved_nEq] - pProbe->aiRowLogEst[saved_nEq+1]; + if( pTerm ){ + /* TUNING: When estimating skip-scan for a term that is also indexable, + ** multiply the cost of the skip-scan by 2.0, to make it a little less + ** desirable than the regular index lookup. */ + nIter += 10; assert( 10==sqlite3LogEst(2) ); + } + pNew->nOut -= nIter; + /* TUNING: Because uncertainties in the estimates for skip-scan queries, + ** add a 1.375 fudge factor to make skip-scan slightly less likely. */ + nIter += 5; + whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter + nInMul); + pNew->nOut = saved_nOut; + pNew->u.btree.nEq = saved_nEq; + pNew->u.btree.nSkip = saved_nSkip; + } for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){ u16 eOp = pTerm->eOperator; /* Shorthand for pTerm->eOperator */ LogEst rCostIdx; LogEst nOutUnadjusted; /* nOut before IN() and WHERE adjustments */ int nIn = 0; @@ -4500,10 +4462,11 @@ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 tRowcnt nOut = 0; if( nInMul==0 && pProbe->nSample && pNew->u.btree.nEq<=pProbe->nSampleCol + && OptimizationEnabled(db, SQLITE_Stat3) && ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect)) ){ Expr *pExpr = pTerm->pExpr; if( (eOp & (WO_EQ|WO_ISNULL))!=0 ){ testcase( eOp & WO_EQ ); @@ -4567,48 +4530,14 @@ pBuilder->nRecValid = nRecValid; #endif } pNew->prereq = saved_prereq; pNew->u.btree.nEq = saved_nEq; - pNew->nSkip = saved_nSkip; + pNew->u.btree.nSkip = saved_nSkip; pNew->wsFlags = saved_wsFlags; pNew->nOut = saved_nOut; pNew->nLTerm = saved_nLTerm; - - /* Consider using a skip-scan if there are no WHERE clause constraints - ** available for the left-most terms of the index, and if the average - ** number of repeats in the left-most terms is at least 18. - ** - ** The magic number 18 is selected on the basis that scanning 17 rows - ** is almost always quicker than an index seek (even though if the index - ** contains fewer than 2^17 rows we assume otherwise in other parts of - ** the code). And, even if it is not, it should not be too much slower. - ** On the other hand, the extra seeks could end up being significantly - ** more expensive. */ - assert( 42==sqlite3LogEst(18) ); - if( saved_nEq==saved_nSkip - && saved_nEq+1nKeyCol - && pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */ - && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK - ){ - LogEst nIter; - pNew->u.btree.nEq++; - pNew->nSkip++; - pNew->aLTerm[pNew->nLTerm++] = 0; - pNew->wsFlags |= WHERE_SKIPSCAN; - nIter = pProbe->aiRowLogEst[saved_nEq] - pProbe->aiRowLogEst[saved_nEq+1]; - pNew->nOut -= nIter; - /* TUNING: Because uncertainties in the estimates for skip-scan queries, - ** add a 1.375 fudge factor to make skip-scan slightly less likely. */ - nIter += 5; - whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter + nInMul); - pNew->nOut = saved_nOut; - pNew->u.btree.nEq = saved_nEq; - pNew->nSkip = saved_nSkip; - pNew->wsFlags = saved_wsFlags; - } - return rc; } /* ** Return True if it is possible that pIndex might be useful in @@ -4783,11 +4712,11 @@ WhereTerm *pWCEnd = pWC->a + pWC->nTerm; for(pTerm=pWC->a; rc==SQLITE_OK && pTermprereqRight & pNew->maskSelf ) continue; if( termCanDriveIndex(pTerm, pSrc, 0) ){ pNew->u.btree.nEq = 1; - pNew->nSkip = 0; + pNew->u.btree.nSkip = 0; pNew->u.btree.pIndex = 0; pNew->nLTerm = 1; pNew->aLTerm[0] = pTerm; /* TUNING: One-time cost for computing the automatic index is ** estimated to be X*N*log2(N) where N is the number of rows in @@ -4824,11 +4753,11 @@ testcase( pNew->iTab!=pSrc->iCursor ); /* See ticket [98d973b8f5] */ continue; /* Partial index inappropriate for this query */ } rSize = pProbe->aiRowLogEst[0]; pNew->u.btree.nEq = 0; - pNew->nSkip = 0; + pNew->u.btree.nSkip = 0; pNew->nLTerm = 0; pNew->iSortIdx = 0; pNew->rSetup = 0; pNew->prereq = mExtra; pNew->nOut = rSize; @@ -5374,11 +5303,11 @@ for(j=0; ju.btree.nEq - && pLoop->nSkip==0 + && pLoop->u.btree.nSkip==0 && ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL))!=0 ){ if( i & WO_ISNULL ){ testcase( isOrderDistinct ); isOrderDistinct = 0; @@ -5828,11 +5757,11 @@ } } } #ifdef WHERETRACE_ENABLED /* >=2 */ - if( sqlite3WhereTrace & 0x02 ){ + if( sqlite3WhereTrace>=2 ){ sqlite3DebugPrintf("---- after round %d ----\n", iLoop); for(ii=0, pTo=aTo; iirCost, pTo->nRow, pTo->isOrdered>=0 ? (pTo->isOrdered+'0') : '?'); @@ -5947,11 +5876,11 @@ if( pItem->zIndex ) return 0; iCur = pItem->iCursor; pWC = &pWInfo->sWC; pLoop = pBuilder->pNew; pLoop->wsFlags = 0; - pLoop->nSkip = 0; + pLoop->u.btree.nSkip = 0; pTerm = findTerm(pWC, iCur, -1, 0, WO_EQ, 0); if( pTerm ){ pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW; pLoop->aLTerm[0] = pTerm; pLoop->nLTerm = 1; @@ -5959,10 +5888,11 @@ /* TUNING: Cost of a rowid lookup is 10 */ pLoop->rRun = 33; /* 33==sqlite3LogEst(10) */ }else{ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pLoop->aLTermSpace==pLoop->aLTerm ); + assert( ArraySize(pLoop->aLTermSpace)==4 ); if( !IsUniqueIndex(pIdx) || pIdx->pPartIdxWhere!=0 || pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace) ) continue; for(j=0; jnKeyCol; j++){ @@ -6467,30 +6397,22 @@ ** loop below generates code for a single nested loop of the VM ** program. */ notReady = ~(Bitmask)0; for(ii=0; iia[ii]; - wsFlags = pLevel->pWLoop->wsFlags; #ifndef SQLITE_OMIT_AUTOMATIC_INDEX if( (pLevel->pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){ constructAutomaticIndex(pParse, &pWInfo->sWC, &pTabList->a[pLevel->iFrom], notReady, pLevel); if( db->mallocFailed ) goto whereBeginError; } #endif - addrExplain = explainOneScan( - pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags - ); + explainOneScan(pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags); pLevel->addrBody = sqlite3VdbeCurrentAddr(v); notReady = codeOneLoopStart(pWInfo, ii, notReady); pWInfo->iContinue = pLevel->addrCont; - if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_ONETABLE_ONLY)==0 ){ - addScanStatus(v, pTabList, pLevel, addrExplain); - } } /* Done. */ VdbeModuleComment((v, "Begin WHERE-core")); return pWInfo; Index: src/whereInt.h ================================================================== --- src/whereInt.h +++ src/whereInt.h @@ -83,13 +83,10 @@ } in; /* Used when pWLoop->wsFlags&WHERE_IN_ABLE */ Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */ } u; struct WhereLoop *pWLoop; /* The selected WhereLoop object */ Bitmask notReady; /* FROM entries not usable at this level */ -#ifdef SQLITE_ENABLE_STMT_SCANSTATUS - int addrVisit; /* Address at which row is visited */ -#endif }; /* ** Each instance of this object represents an algorithm for evaluating one ** term of a join. Every term of the FROM clause will have at least @@ -116,10 +113,11 @@ LogEst rRun; /* Cost of running each loop */ LogEst nOut; /* Estimated number of output rows */ union { struct { /* Information for internal btree tables */ u16 nEq; /* Number of equality constraints */ + u16 nSkip; /* Number of initial index columns to skip */ Index *pIndex; /* Index used, or NULL */ } btree; struct { /* Information for virtual tables */ int idxNum; /* Index number */ u8 needFree; /* True if sqlite3_free(idxStr) is needed */ @@ -128,17 +126,16 @@ char *idxStr; /* Index identifier string */ } vtab; } u; u32 wsFlags; /* WHERE_* flags describing the plan */ u16 nLTerm; /* Number of entries in aLTerm[] */ - u16 nSkip; /* Number of NULL aLTerm[] entries */ /**** whereLoopXfer() copies fields above ***********************/ # define WHERE_LOOP_XFER_SZ offsetof(WhereLoop,nLSlot) u16 nLSlot; /* Number of slots allocated for aLTerm[] */ WhereTerm **aLTerm; /* WhereTerms used */ WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */ - WhereTerm *aLTermSpace[3]; /* Initial aLTerm[] space */ + WhereTerm *aLTermSpace[4]; /* Initial aLTerm[] space */ }; /* This object holds the prerequisites and the cost of running a ** subquery on one operand of an OR operator in the WHERE clause. ** See WhereOrSet for additional information @@ -460,6 +457,5 @@ #define WHERE_ONEROW 0x00001000 /* Selects no more than one row */ #define WHERE_MULTI_OR 0x00002000 /* OR using multiple indices */ #define WHERE_AUTO_INDEX 0x00004000 /* Uses an ephemeral index */ #define WHERE_SKIPSCAN 0x00008000 /* Uses the skip-scan algorithm */ #define WHERE_UNQ_WANTED 0x00010000 /* WHERE_ONEROW would have been helpful*/ -#define WHERE_PARTIALIDX 0x00020000 /* The automatic index is partial */ Index: test/analyze8.test ================================================================== --- test/analyze8.test +++ test/analyze8.test @@ -84,27 +84,27 @@ # There are many more values of c between 0 and 100000 than there are # between 800000 and 900000. So t1c is more selective for the latter # range. # # Test 3.2 is a little unstable. It depends on the planner estimating -# that (b BETWEEN 30 AND 34) will match more rows than (c BETWEEN +# that (b BETWEEN 50 AND 54) will match more rows than (c BETWEEN # 800000 AND 900000). Which is a pretty close call (50 vs. 32), so # the planner could get it wrong with an unlucky set of samples. This # case happens to work, but others ("b BETWEEN 40 AND 44" for example) # will fail. # do_execsql_test 3.0 { - SELECT count(*) FROM t1 WHERE b BETWEEN 30 AND 34; + SELECT count(*) FROM t1 WHERE b BETWEEN 50 AND 54; SELECT count(*) FROM t1 WHERE c BETWEEN 0 AND 100000; SELECT count(*) FROM t1 WHERE c BETWEEN 800000 AND 900000; } {50 376 32} do_test 3.1 { - eqp {SELECT * FROM t1 WHERE b BETWEEN 30 AND 34 AND c BETWEEN 0 AND 100000} + eqp {SELECT * FROM t1 WHERE b BETWEEN 50 AND 54 AND c BETWEEN 0 AND 100000} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b? AND c6 - } 4 - - # Check the "on the database connecton specified" part of hte - # requirement - changes made by other connections do not show up in - # the return value of sqlite3_changes(). - do_test 1.$tn.5 { - sqlite3 db2 test.db - execsql { INSERT INTO t1 VALUES(-1, -1) } db2 - db2 changes - } 1 - do_test 1.$tn.6 { - db changes - } 4 - db2 close - - # Test that statements that modify no rows because they hit UNIQUE - # constraints set the sqlite3_changes() value to 0. Regardless of - # whether or not they are executed inside an explicit transaction. - # - # 1.$tn.8-9: outside of a transaction - # 1.$tn.10-12: inside a transaction - # - do_changes_test 1.$tn.7 { - CREATE UNIQUE INDEX i2 ON t1(a); - } 4 - do_catchsql_test 1.$tn.8 { - INSERT INTO t1 VALUES('a', 0), ('b', 0), ('c', 0), (0, 11); - } {1 {UNIQUE constraint failed: t1.a}} - do_test 1.$tn.9 { db changes } 0 - do_catchsql_test 1.$tn.10 { - BEGIN; - INSERT INTO t1 VALUES('a', 0), ('b', 0), ('c', 0), (0, 11); - } {1 {UNIQUE constraint failed: t1.a}} - do_test 1.$tn.11 { db changes } 0 - do_changes_test 1.$tn.12 COMMIT 0 - -} - - -#-------------------------------------------------------------------------- -# EVIDENCE-OF: R-44877-05564 Executing any other type of SQL statement -# does not modify the value returned by this function. -# -reset_db -do_changes_test 2.1 { CREATE TABLE t1(x) } 0 -do_changes_test 2.2 { - WITH d(y) AS (SELECT 1 UNION ALL SELECT y+1 FROM d WHERE y<47) - INSERT INTO t1 SELECT y FROM d; -} 47 - -# The statement above set changes() to 47. Check that none of the following -# modify this. -do_changes_test 2.3 { SELECT count(x) FROM t1 } {47 47} -do_changes_test 2.4 { DROP TABLE t1 } 47 -do_changes_test 2.5 { CREATE TABLE t1(x) } 47 -do_changes_test 2.6 { ALTER TABLE t1 ADD COLUMN b } 47 - - -#-------------------------------------------------------------------------- -# EVIDENCE-OF: R-53938-27527 Only changes made directly by the INSERT, -# UPDATE or DELETE statement are considered - auxiliary changes caused -# by triggers, foreign key actions or REPLACE constraint resolution are -# not counted. -# -# 3.1.*: triggers -# 3.2.*: foreign key actions -# 3.3.*: replace constraints -# -reset_db -do_execsql_test 3.1.0 { - CREATE TABLE log(x); - CREATE TABLE p1(one PRIMARY KEY, two); - - CREATE TRIGGER tr_ai AFTER INSERT ON p1 BEGIN - INSERT INTO log VALUES('insert'); - END; - CREATE TRIGGER tr_bd BEFORE DELETE ON p1 BEGIN - INSERT INTO log VALUES('delete'); - END; - CREATE TRIGGER tr_au AFTER UPDATE ON p1 BEGIN - INSERT INTO log VALUES('update'); - END; - -} - -do_changes_test 3.1.1 { - INSERT INTO p1 VALUES('a', 'A'), ('b', 'B'), ('c', 'C'); -} 3 -do_changes_test 3.1.2 { - UPDATE p1 SET two = two||two; -} 3 -do_changes_test 3.1.3 { - DELETE FROM p1 WHERE one IN ('a', 'c'); -} 2 -do_execsql_test 3.1.4 { - -- None of the inserts on table log were counted. - SELECT count(*) FROM log -} 8 - -do_execsql_test 3.2.0 { - DELETE FROM p1; - INSERT INTO p1 VALUES('a', 'A'), ('b', 'B'), ('c', 'C'); - - CREATE TABLE c1(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE SET NULL); - CREATE TABLE c2(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE SET DEFAULT); - CREATE TABLE c3(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE CASCADE); - INSERT INTO c1 VALUES('a', 'aaa'); - INSERT INTO c2 VALUES('b', 'bbb'); - INSERT INTO c3 VALUES('c', 'ccc'); - - INSERT INTO p1 VALUES('d', 'D'), ('e', 'E'), ('f', 'F'); - CREATE TABLE c4(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE SET NULL); - CREATE TABLE c5(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE SET DEFAULT); - CREATE TABLE c6(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE CASCADE); - INSERT INTO c4 VALUES('d', 'aaa'); - INSERT INTO c5 VALUES('e', 'bbb'); - INSERT INTO c6 VALUES('f', 'ccc'); - - PRAGMA foreign_keys = ON; -} - -do_changes_test 3.2.1 { DELETE FROM p1 WHERE one = 'a' } 1 -do_changes_test 3.2.2 { DELETE FROM p1 WHERE one = 'b' } 1 -do_changes_test 3.2.3 { DELETE FROM p1 WHERE one = 'c' } 1 -do_execsql_test 3.2.4 { - SELECT * FROM c1; - SELECT * FROM c2; - SELECT * FROM c3; -} {{} aaa {} bbb} - -do_changes_test 3.2.5 { UPDATE p1 SET one = 'g' WHERE one = 'd' } 1 -do_changes_test 3.2.6 { UPDATE p1 SET one = 'h' WHERE one = 'e' } 1 -do_changes_test 3.2.7 { UPDATE p1 SET one = 'i' WHERE one = 'f' } 1 -do_execsql_test 3.2.8 { - SELECT * FROM c4; - SELECT * FROM c5; - SELECT * FROM c6; -} {{} aaa {} bbb i ccc} - -do_execsql_test 3.3.0 { - CREATE TABLE r1(a UNIQUE, b UNIQUE); - INSERT INTO r1 VALUES('i', 'i'); - INSERT INTO r1 VALUES('ii', 'ii'); - INSERT INTO r1 VALUES('iii', 'iii'); - INSERT INTO r1 VALUES('iv', 'iv'); - INSERT INTO r1 VALUES('v', 'v'); - INSERT INTO r1 VALUES('vi', 'vi'); - INSERT INTO r1 VALUES('vii', 'vii'); -} - -do_changes_test 3.3.1 { INSERT OR REPLACE INTO r1 VALUES('i', 1) } 1 -do_changes_test 3.3.2 { INSERT OR REPLACE INTO r1 VALUES('iv', 'v') } 1 -do_changes_test 3.3.3 { UPDATE OR REPLACE r1 SET b='v' WHERE a='iii' } 1 -do_changes_test 3.3.4 { UPDATE OR REPLACE r1 SET b='vi',a='vii' WHERE a='ii' } 1 -do_execsql_test 3.3.5 { - SELECT * FROM r1 ORDER BY a; -} {i 1 iii v vii vi} - - -#-------------------------------------------------------------------------- -# EVIDENCE-OF: R-09813-48563 The value returned by sqlite3_changes() -# immediately after an INSERT, UPDATE or DELETE statement run on a view -# is always zero. -# -reset_db -do_execsql_test 4.1 { - CREATE TABLE log(log); - CREATE TABLE t1(x, y); - INSERT INTO t1 VALUES(1, 2); - INSERT INTO t1 VALUES(3, 4); - INSERT INTO t1 VALUES(5, 6); - - CREATE VIEW v1 AS SELECT * FROM t1; - CREATE TRIGGER v1_i INSTEAD OF INSERT ON v1 BEGIN - INSERT INTO log VALUES('insert'); - END; - CREATE TRIGGER v1_u INSTEAD OF UPDATE ON v1 BEGIN - INSERT INTO log VALUES('update'), ('update'); - END; - CREATE TRIGGER v1_d INSTEAD OF DELETE ON v1 BEGIN - INSERT INTO log VALUES('delete'), ('delete'), ('delete'); - END; -} - -do_changes_test 4.2.1 { INSERT INTO t1 SELECT * FROM t1 } 3 -do_changes_test 4.2.2 { INSERT INTO v1 VALUES(1, 2) } 0 - -do_changes_test 4.3.1 { INSERT INTO t1 SELECT * FROM t1 } 6 -do_changes_test 4.3.2 { UPDATE v1 SET y='xyz' WHERE x=1 } 0 - -do_changes_test 4.4.1 { INSERT INTO t1 SELECT * FROM t1 } 12 -do_changes_test 4.4.2 { DELETE FROM v1 WHERE x=5 } 0 - - -#-------------------------------------------------------------------------- -# EVIDENCE-OF: R-32918-61474 Before entering a trigger program the value -# returned by sqlite3_changes() function is saved. After the trigger -# program has finished, the original value is restored. -# -reset_db -db func my_changes my_changes -set ::changes [list] -proc my_changes {x} { - set res [db changes] - lappend ::changes $x $res - return $res -} - -do_execsql_test 5.1.0 { - CREATE TABLE t1(a INTEGER PRIMARY KEY, b); - CREATE TABLE t2(x); - INSERT INTO t1 VALUES(1, NULL); - INSERT INTO t1 VALUES(2, NULL); - INSERT INTO t1 VALUES(3, NULL); - CREATE TRIGGER AFTER UPDATE ON t1 BEGIN - INSERT INTO t2 VALUES('a'), ('b'), ('c'); - SELECT my_changes('trigger'); - END; -} - -do_execsql_test 5.1.1 { - INSERT INTO t2 VALUES('a'), ('b'); - UPDATE t1 SET b = my_changes('update'); - SELECT * FROM t1; -} {1 2 2 2 3 2} - -# Value is being restored to "2" when the trigger program exits. -do_test 5.1.2 { - set ::changes -} {update 2 trigger 3 update 2 trigger 3 update 2 trigger 3} - - -reset_db -do_execsql_test 5.2.0 { - CREATE TABLE t1(a, b); - CREATE TABLE log(x); - INSERT INTO t1 VALUES(1, 0); - INSERT INTO t1 VALUES(2, 0); - INSERT INTO t1 VALUES(3, 0); - CREATE TRIGGER t1_a_u AFTER UPDATE ON t1 BEGIN - INSERT INTO log VALUES(old.b || ' -> ' || new.b || ' c = ' || changes() ); - END; - CREATE TABLE t2(a); - INSERT INTO t2 VALUES(1), (2), (3); - UPDATE t1 SET b = changes(); -} -do_execsql_test 5.2.1 { - SELECT * FROM t1; -} {1 3 2 3 3 3} -do_execsql_test 5.2.2 { - SELECT * FROM log; -} {{0 -> 3 c = 3} {0 -> 3 c = 3} {0 -> 3 c = 3}} - - -#-------------------------------------------------------------------------- -# EVIDENCE-OF: R-17146-37073 Within a trigger program each INSERT, -# UPDATE and DELETE statement sets the value returned by -# sqlite3_changes() upon completion as normal. Of course, this value -# will not include any changes performed by sub-triggers, as the -# sqlite3_changes() value will be saved and restored after each -# sub-trigger has run. -reset_db -do_execsql_test 6.0 { - - CREATE TABLE t1(a, b); - CREATE TABLE t2(a, b); - CREATE TABLE t3(a, b); - CREATE TABLE log(x); - - CREATE TRIGGER t1_i BEFORE INSERT ON t1 BEGIN - INSERT INTO t2 VALUES(new.a, new.b), (new.a, new.b); - INSERT INTO log VALUES('t2->' || changes()); - END; - - CREATE TRIGGER t2_i AFTER INSERT ON t2 BEGIN - INSERT INTO t3 VALUES(new.a, new.b), (new.a, new.b), (new.a, new.b); - INSERT INTO log VALUES('t3->' || changes()); - END; - - CREATE TRIGGER t1_u AFTER UPDATE ON t1 BEGIN - UPDATE t2 SET b=new.b WHERE a=old.a; - INSERT INTO log VALUES('t2->' || changes()); - END; - - CREATE TRIGGER t2_u BEFORE UPDATE ON t2 BEGIN - UPDATE t3 SET b=new.b WHERE a=old.a; - INSERT INTO log VALUES('t3->' || changes()); - END; - - CREATE TRIGGER t1_d AFTER DELETE ON t1 BEGIN - DELETE FROM t2 WHERE a=old.a AND b=old.b; - INSERT INTO log VALUES('t2->' || changes()); - END; - - CREATE TRIGGER t2_d BEFORE DELETE ON t2 BEGIN - DELETE FROM t3 WHERE a=old.a AND b=old.b; - INSERT INTO log VALUES('t3->' || changes()); - END; -} - -do_changes_test 6.1 { - INSERT INTO t1 VALUES('+', 'o'); - SELECT * FROM log; -} {t3->3 t3->3 t2->2 1} - -do_changes_test 6.2 { - DELETE FROM log; - UPDATE t1 SET b='*'; - SELECT * FROM log; -} {t3->6 t3->6 t2->2 1} - -do_changes_test 6.3 { - DELETE FROM log; - DELETE FROM t1; - SELECT * FROM log; -} {t3->6 t3->0 t2->2 1} - - -#-------------------------------------------------------------------------- -# EVIDENCE-OF: R-43399-09409 This means that if the changes() SQL -# function (or similar) is used by the first INSERT, UPDATE or DELETE -# statement within a trigger, it returns the value as set when the -# calling statement began executing. -# -# EVIDENCE-OF: R-53215-27584 If it is used by the second or subsequent -# such statement within a trigger program, the value returned reflects -# the number of rows modified by the previous INSERT, UPDATE or DELETE -# statement within the same trigger. -# -reset_db -do_execsql_test 7.1 { - CREATE TABLE q1(t); - CREATE TABLE q2(u, v); - CREATE TABLE q3(w); - - CREATE TRIGGER q2_insert BEFORE INSERT ON q2 BEGIN - - /* changes() returns value from previous I/U/D in callers context */ - INSERT INTO q1 VALUES('1:' || changes()); - - /* changes() returns value of previous I/U/D in this context */ - INSERT INTO q3 VALUES(changes()), (2), (3); - INSERT INTO q1 VALUES('2:' || changes()); - INSERT INTO q3 VALUES(changes() + 3), (changes()+4); - SELECT 'this does not affect things!'; - INSERT INTO q1 VALUES('3:' || changes()); - UPDATE q3 SET w = w+10 WHERE w%2; - INSERT INTO q1 VALUES('4:' || changes()); - DELETE FROM q3; - INSERT INTO q1 VALUES('5:' || changes()); - END; -} - -do_execsql_test 7.2 { - INSERT INTO q2 VALUES('x', 'y'); - SELECT * FROM q1; -} { - 1:0 2:3 3:2 4:3 5:5 -} - -do_execsql_test 7.3 { - DELETE FROM q1; - INSERT INTO q2 VALUES('x', 'y'); - SELECT * FROM q1; -} { - 1:5 2:3 3:2 4:3 5:5 -} - - - -finish_test DELETED test/e_totalchanges.test Index: test/e_totalchanges.test ================================================================== --- test/e_totalchanges.test +++ /dev/null @@ -1,213 +0,0 @@ -# 2011 May 06 -# -# The author disclaims copyright to this source code. In place of -# a legal notice, here is a blessing: -# -# May you do good and not evil. -# May you find forgiveness for yourself and forgive others. -# May you share freely, never taking more than you give. -# -#*********************************************************************** -# - -set testdir [file dirname $argv0] -source $testdir/tester.tcl -set testprefix e_totalchanges - -# Like [do_execsql_test], except it appends the value returned by -# [db total_changes] to the result of executing the SQL script. -# -proc do_tc_test {tn sql res} { - uplevel [list \ - do_test $tn "concat \[execsql {$sql}\] \[db total_changes\]" $res - ] -} - -do_execsql_test 1.0 { - CREATE TABLE t1(a, b); - CREATE INDEX t1_b ON t1(b); - CREATE TABLE t2(x, y, PRIMARY KEY(x, y)) WITHOUT ROWID; - CREATE INDEX t2_y ON t2(y); -} - - -#-------------------------------------------------------------------------- -# EVIDENCE-OF: R-65438-26258 This function returns the total number of -# rows inserted, modified or deleted by all INSERT, UPDATE or DELETE -# statements completed since the database connection was opened, -# including those executed as part of trigger programs. -# -# 1.1.*: different types of I/U/D statements, -# 1.2.*: trigger programs. -# -do_tc_test 1.1.1 { - INSERT INTO t1 VALUES(1, 2); - INSERT INTO t1 VALUES(3, 4); - UPDATE t1 SET a = a+1; - DELETE FROM t1; -} {6} -do_tc_test 1.1.2 { - DELETE FROM t1 -} {6} - -do_tc_test 1.1.3 { - WITH data(a,b) AS ( - SELECT 0, 0 UNION ALL SELECT a+1, b+1 FROM data WHERE a<99 - ) - INSERT INTO t1 SELECT * FROM data; -} {106} - -do_tc_test 1.1.4 { - INSERT INTO t2 SELECT * FROM t1 WHERE a<50; - UPDATE t2 SET y=y+1; -} {206} - -do_tc_test 1.1.5 { - DELETE FROM t2 WHERE y<=25 -} {231} - -do_execsql_test 1.2.1 { - DELETE FROM t1; - DELETE FROM t2; -} -sqlite3 db test.db ; # To reset total_changes -do_tc_test 1.2.2 { - CREATE TABLE log(detail); - CREATE TRIGGER t1_after_insert AFTER INSERT ON t1 BEGIN - INSERT INTO log VALUES('inserted into t1'); - END; - - CREATE TRIGGER t1_before_delete BEFORE DELETE ON t1 BEGIN - INSERT INTO log VALUES('deleting from t1'); - INSERT INTO log VALUES('here we go!'); - END; - - CREATE TRIGGER t1_after_update AFTER UPDATE ON t1 BEGIN - INSERT INTO log VALUES('update'); - DELETE FROM log; - END; - - INSERT INTO t1 VALUES('a', 'b'); -- 1 + 1 - UPDATE t1 SET b='c'; -- 1 + 1 + 2 - DELETE FROM t1; -- 1 + 1 + 1 -} {9} - -#-------------------------------------------------------------------------- -# EVIDENCE-OF: R-61766-15253 Executing any other type of SQL statement -# does not affect the value returned by sqlite3_total_changes(). -do_tc_test 2.1 { - INSERT INTO t1 VALUES(1, 2), (3, 4); - INSERT INTO t2 VALUES(1, 2), (3, 4); -} {15} -do_tc_test 2.2 { - SELECT count(*) FROM t1; -} {2 15} -do_tc_test 2.3 { - CREATE TABLE t4(a, b); - ALTER TABLE t4 ADD COLUMN c; - CREATE INDEX i4 ON t4(c); - ALTER TABLE t4 RENAME TO t5; - ANALYZE; - BEGIN; - DROP TABLE t2; - ROLLBACK; - VACUUM; -} {15} - - -#-------------------------------------------------------------------------- -# EVIDENCE-OF: R-36043-10590 Changes made as part of foreign key -# actions are included in the count, but those made as part of REPLACE -# constraint resolution are not. -# -# 3.1.*: foreign key actions -# 3.2.*: REPLACE constraints. -# -sqlite3 db test.db ; # To reset total_changes -do_tc_test 3.1.1 { - CREATE TABLE p1(c PRIMARY KEY, d); - CREATE TABLE c1(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE SET NULL); - CREATE TABLE c2(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE CASCADE); - CREATE TABLE c3(a, b, FOREIGN KEY(a) REFERENCES p1 ON DELETE SET DEFAULT); - - INSERT INTO p1 VALUES(1, 'one'); - INSERT INTO p1 VALUES(2, 'two'); - INSERT INTO p1 VALUES(3, 'three'); - INSERT INTO p1 VALUES(4, 'four'); - - INSERT INTO c1 VALUES(1, 'i'); - INSERT INTO c2 VALUES(2, 'ii'); - INSERT INTO c3 VALUES(3, 'iii'); - PRAGMA foreign_keys = ON; -} {7} - -do_tc_test 3.1.2 { DELETE FROM p1 WHERE c=1; } {9} -do_tc_test 3.1.3 { DELETE FROM p1 WHERE c=2; } {11} -do_tc_test 3.1.4 { DELETE FROM p1 WHERE c=3; } {13} -do_tc_test 3.1.5 { DELETE FROM p1 WHERE c=4; } {14} ; # only 1 this time. - -sqlite3 db test.db ; # To reset total_changes -do_tc_test 3.1.6 { - DROP TABLE c1; - DROP TABLE c2; - DROP TABLE c3; - CREATE TABLE c1(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE SET NULL); - CREATE TABLE c2(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE CASCADE); - CREATE TABLE c3(a, b, FOREIGN KEY(a) REFERENCES p1 ON UPDATE SET DEFAULT); - - INSERT INTO p1 VALUES(1, 'one'); - INSERT INTO p1 VALUES(2, 'two'); - INSERT INTO p1 VALUES(3, 'three'); - INSERT INTO p1 VALUES(4, 'four'); - - INSERT INTO c1 VALUES(1, 'i'); - INSERT INTO c2 VALUES(2, 'ii'); - INSERT INTO c3 VALUES(3, 'iii'); - PRAGMA foreign_keys = ON; -} {7} - -do_tc_test 3.1.7 { UPDATE p1 SET c=c+4 WHERE c=1; } {9} -do_tc_test 3.1.8 { UPDATE p1 SET c=c+4 WHERE c=2; } {11} -do_tc_test 3.1.9 { UPDATE p1 SET c=c+4 WHERE c=3; } {13} -do_tc_test 3.1.10 { UPDATE p1 SET c=c+4 WHERE c=4; } {14} ; # only 1 this time. - -sqlite3 db test.db ; # To reset total_changes -do_tc_test 3.2.1 { - CREATE TABLE t3(a UNIQUE, b UNIQUE); - INSERT INTO t3 VALUES('one', 'one'); - INSERT INTO t3 VALUES('two', 'two'); - INSERT OR REPLACE INTO t3 VALUES('one', 'two'); -} {3} - -do_tc_test 3.2.2 { - INSERT INTO t3 VALUES('three', 'one'); - UPDATE OR REPLACE t3 SET b='two' WHERE b='one'; - SELECT * FROM t3; -} {three two 5} - -#-------------------------------------------------------------------------- -# EVIDENCE-OF: R-54872-08741 Changes to a view that are intercepted by -# INSTEAD OF triggers are not counted. -# -sqlite3 db test.db ; # To reset total_changes -do_tc_test 4.1 { - CREATE TABLE t6(x); - CREATE VIEW v1 AS SELECT * FROM t6; - CREATE TRIGGER v1_tr1 INSTEAD OF INSERT ON v1 BEGIN - SELECT 'no-op'; - END; - - INSERT INTO v1 VALUES('a'); - INSERT INTO v1 VALUES('b'); -} {0} -do_tc_test 4.2 { - CREATE TRIGGER v1_tr2 INSTEAD OF INSERT ON v1 BEGIN - INSERT INTO t6 VALUES(new.x); - END; - - INSERT INTO v1 VALUES('c'); - INSERT INTO v1 VALUES('d'); -} {2} - - -finish_test DELETED test/e_wal.test Index: test/e_wal.test ================================================================== --- test/e_wal.test +++ /dev/null @@ -1,229 +0,0 @@ -# 2011 May 06 -# -# The author disclaims copyright to this source code. In place of -# a legal notice, here is a blessing: -# -# May you do good and not evil. -# May you find forgiveness for yourself and forgive others. -# May you share freely, never taking more than you give. -# -#*********************************************************************** -# - -set testdir [file dirname $argv0] -source $testdir/tester.tcl -set testprefix e_wal - -db close -testvfs oldvfs -iversion 1 - - -# EVIDENCE-OF: R-58297-14483 WAL databases can be created, read, and -# written even if shared memory is unavailable as long as the -# locking_mode is set to EXCLUSIVE before the first attempted access. -# -# EVIDENCE-OF: R-00449-33772 This feature allows WAL databases to be -# created, read, and written by legacy VFSes that lack the "version 2" -# shared-memory methods xShmMap, xShmLock, xShmBarrier, and xShmUnmap on -# the sqlite3_io_methods object. -# -# 1.1: "create" tests. -# 1.2: "read" tests. -# 1.3: "write" tests. -# -# All three done with VFS "oldvfs", which has iVersion==1 and so does -# not support shared memory. -# -sqlite3 db test.db -vfs oldvfs -do_execsql_test 1.1.1 { - PRAGMA journal_mode = WAL; -} {delete} -do_execsql_test 1.1.2 { - PRAGMA locking_mode = EXCLUSIVE; - PRAGMA journal_mode = WAL; -} {exclusive wal} -do_execsql_test 1.1.3 { - CREATE TABLE t1(x, y); - INSERT INTO t1 VALUES(1, 2); -} {} -do_test 1.1.4 { - list [file exists test.db-shm] [file exists test.db-wal] -} {0 1} - -do_test 1.2.1 { - db close - sqlite3 db test.db -vfs oldvfs - catchsql { SELECT * FROM t1 } -} {1 {unable to open database file}} -do_test 1.2.2 { - execsql { PRAGMA locking_mode = EXCLUSIVE } - execsql { SELECT * FROM t1 } -} {1 2} -do_test 1.2.3 { - list [file exists test.db-shm] [file exists test.db-wal] -} {0 1} - -do_test 1.3.1 { - db close - sqlite3 db test.db -vfs oldvfs - catchsql { INSERT INTO t1 VALUES(3, 4) } -} {1 {unable to open database file}} -do_test 1.3.2 { - execsql { PRAGMA locking_mode = EXCLUSIVE } - execsql { INSERT INTO t1 VALUES(3, 4) } - execsql { SELECT * FROM t1 } -} {1 2 3 4} -do_test 1.3.3 { - list [file exists test.db-shm] [file exists test.db-wal] -} {0 1} - -# EVIDENCE-OF: R-31969-57825 If EXCLUSIVE locking mode is set prior to -# the first WAL-mode database access, then SQLite never attempts to call -# any of the shared-memory methods and hence no shared-memory wal-index -# is ever created. -# -db close -sqlite3 db test.db -do_execsql_test 2.1.1 { - PRAGMA locking_mode = EXCLUSIVE; - SELECT * FROM t1; -} {exclusive 1 2 3 4} -do_test 2.1.2 { - list [file exists test.db-shm] [file exists test.db-wal] -} {0 1} - -# EVIDENCE-OF: R-36328-16367 In that case, the database connection -# remains in EXCLUSIVE mode as long as the journal mode is WAL; attempts -# to change the locking mode using "PRAGMA locking_mode=NORMAL;" are -# no-ops. -# -do_execsql_test 2.2.1 { - PRAGMA locking_mode = NORMAL; - SELECT * FROM t1; -} {exclusive 1 2 3 4} -do_test 2.2.2 { - sqlite3 db2 test.db - catchsql {SELECT * FROM t1} db2 -} {1 {database is locked}} -db2 close - -# EVIDENCE-OF: R-63522-46088 The only way to change out of EXCLUSIVE -# locking mode is to first change out of WAL journal mode. -# -do_execsql_test 2.3.1 { - PRAGMA journal_mode = DELETE; - SELECT * FROM t1; -} {delete 1 2 3 4} -do_test 2.3.2 { - sqlite3 db2 test.db - catchsql {SELECT * FROM t1} db2 -} {1 {database is locked}} -do_execsql_test 2.3.3 { - PRAGMA locking_mode = NORMAL; - SELECT * FROM t1; -} {normal 1 2 3 4} -do_test 2.3.4 { - sqlite3 db2 test.db - catchsql {SELECT * FROM t1} db2 -} {0 {1 2 3 4}} -db2 close -db close - - -# EVIDENCE-OF: R-57239-11845 If NORMAL locking mode is in effect for the -# first WAL-mode database access, then the shared-memory wal-index is -# created. -# -do_test 3.0 { - sqlite3 db test.db - execsql { PRAGMA journal_mode = WAL } - db close -} {} -do_test 3.1 { - sqlite3 db test.db - execsql { SELECT * FROM t1 } - list [file exists test.db-shm] [file exists test.db-wal] -} {1 1} - -# EVIDENCE-OF: R-13779-07711 As long as exactly one connection is using -# a shared-memory wal-index, the locking mode can be changed freely -# between NORMAL and EXCLUSIVE. -# -do_execsql_test 3.2.1 { - PRAGMA locking_mode = EXCLUSIVE; - PRAGMA locking_mode = NORMAL; - PRAGMA locking_mode = EXCLUSIVE; - INSERT INTO t1 VALUES(5, 6); -} {exclusive normal exclusive} -do_test 3.2.2 { - sqlite3 db2 test.db - catchsql { SELECT * FROM t1 } db2 -} {1 {database is locked}} - -# EVIDENCE-OF: R-10993-11647 It is only when the shared-memory wal-index -# is omitted, when the locking mode is EXCLUSIVE prior to the first -# WAL-mode database access, that the locking mode is stuck in EXCLUSIVE. -# -do_execsql_test 3.2.3 { - PRAGMA locking_mode = NORMAL; - SELECT * FROM t1; -} {normal 1 2 3 4 5 6} -do_test 3.2.4 { - catchsql { SELECT * FROM t1 } db2 -} {0 {1 2 3 4 5 6}} - -do_catchsql_test 3.2.5 { - PRAGMA locking_mode = EXCLUSIVE; - INSERT INTO t1 VALUES(7, 8); -} {1 {database is locked}} - -db2 close - -# EVIDENCE-OF: R-46197-42811 This means that the underlying VFS must -# support the "version 2" shared-memory. -# -# EVIDENCE-OF: R-55316-21772 If the VFS does not support shared-memory -# methods, then the attempt to open a database that is already in WAL -# mode, or the attempt convert a database into WAL mode, will fail. -# -db close -do_test 3.4.1 { - sqlite3 db test.db -vfs oldvfs - catchsql { SELECT * FROM t1 } -} {1 {unable to open database file}} -db close -do_test 3.4.2 { - forcedelete test.db2 - sqlite3 db test.db2 -vfs oldvfs - catchsql { PRAGMA journal_mode = WAL } -} {0 delete} -db close - - -# EVIDENCE-OF: R-22428-28959 To prevent older versions of SQLite from -# trying to recover a WAL-mode database (and making matters worse) the -# database file format version numbers (bytes 18 and 19 in the database -# header) are increased from 1 to 2 in WAL mode. -# -reset_db -do_execsql_test 4.1.1 { CREATE TABLE t1(x, y) } -do_test 4.1.2 { hexio_read test.db 18 2 } {0101} -do_execsql_test 4.1.3 { PRAGMA journal_mode = wAL } {wal} -do_test 4.1.4 { hexio_read test.db 18 2 } {0202} - - -# EVIDENCE-OF: R-02535-05811 One can explicitly change out of WAL mode -# using a pragma such as this: PRAGMA journal_mode=DELETE; -# -do_execsql_test 4.2.1 { INSERT INTO t1 VALUES(1, 1); } {} -do_test 4.2.2 { file exists test.db-wal } {1} -do_execsql_test 4.2.3 { PRAGMA journal_mode = delete } {delete} -do_test 4.2.4 { file exists test.db-wal } {0} - -# EVIDENCE-OF: R-60175-02388 Deliberately changing out of WAL mode -# changes the database file format version numbers back to 1 so that -# older versions of SQLite can once again access the database file. -# -do_test 4.3 { hexio_read test.db 18 2 } {0101} - -finish_test Index: test/fkey7.test ================================================================== --- test/fkey7.test +++ test/fkey7.test @@ -48,24 +48,7 @@ do_tblsread_test 1.2 { UPDATE par SET b=? WHERE a=? } {par s1} do_tblsread_test 1.3 { UPDATE par SET a=? WHERE b=? } {c1 c2 par} do_tblsread_test 1.4 { UPDATE par SET c=? WHERE b=? } {c3 par} do_tblsread_test 1.5 { UPDATE par SET a=?,b=?,c=? WHERE b=? } {c1 c2 c3 par s1} -ifcapable incrblob { - do_execsql_test 2.0 { - CREATE TABLE pX(x PRIMARY KEY); - CREATE TABLE cX(a INTEGER PRIMARY KEY, b REFERENCES pX); - } - - do_catchsql_test 2.1 { - INSERT INTO cX VALUES(11, zeroblob(40)); - } {1 {FOREIGN KEY constraint failed}} - - do_test 2.2 { - set stmt [sqlite3_prepare_v2 db "INSERT INTO cX VALUES(11, ?)" -1] - sqlite3_bind_zeroblob $stmt 1 45 - sqlite3_step $stmt - sqlite3_finalize $stmt - } {SQLITE_CONSTRAINT} -} finish_test Index: test/in5.test ================================================================== --- test/in5.test +++ test/in5.test @@ -10,10 +10,11 @@ #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix in5 do_test in5-1.1 { execsql { CREATE TABLE t1x(x INTEGER PRIMARY KEY); INSERT INTO t1x VALUES(1),(3),(5),(7),(9); @@ -132,7 +133,54 @@ do_test in5-5.3 { regexp {OpenEphemeral} [db eval { EXPLAIN SELECT d FROM t2 WHERE a IN t1x AND b IN t1y AND c IN t1z }] } {0} + +#------------------------------------------------------------------------- +# At one point SQLite was removing the DISTINCT keyword from expressions +# similar to: +# +# IN (SELECT DISTINCT FROM...) +# +# However, there are a few obscure cases where this is incorrect. For +# example, if the SELECT features a LIMIT clause, or if the collation +# sequence or affinity used by the DISTINCT does not match the one used +# by the IN(...) expression. +# +do_execsql_test 6.1.1 { + CREATE TABLE t1(a COLLATE nocase); + INSERT INTO t1 VALUES('one'); + INSERT INTO t1 VALUES('ONE'); +} +do_execsql_test 6.1.2 { + SELECT count(*) FROM t1 WHERE a COLLATE BINARY IN (SELECT DISTINCT a FROM t1) +} {1} + +do_execsql_test 6.2.1 { + CREATE TABLE t3(a, b); + INSERT INTO t3 VALUES(1, 1); + INSERT INTO t3 VALUES(1, 2); + INSERT INTO t3 VALUES(1, 3); + INSERT INTO t3 VALUES(2, 4); + INSERT INTO t3 VALUES(2, 5); + INSERT INTO t3 VALUES(2, 6); + INSERT INTO t3 VALUES(3, 7); + INSERT INTO t3 VALUES(3, 8); + INSERT INTO t3 VALUES(3, 9); +} +do_execsql_test 6.2.2 { + SELECT count(*) FROM t3 WHERE b IN (SELECT DISTINCT a FROM t3 LIMIT 5); +} {3} +do_execsql_test 6.2.3 { + SELECT count(*) FROM t3 WHERE b IN (SELECT a FROM t3 LIMIT 5); +} {2} + +do_execsql_test 6.3.1 { + CREATE TABLE x1(a); + CREATE TABLE x2(b); + INSERT INTO x1 VALUES(1), (1), (2); + INSERT INTO x2 VALUES(1), (2); + SELECT count(*) FROM x2 WHERE b IN (SELECT DISTINCT a FROM x1 LIMIT 2); +} {2} finish_test DELETED test/misc8.test Index: test/misc8.test ================================================================== --- test/misc8.test +++ /dev/null @@ -1,61 +0,0 @@ -# 2014-11-10 -# -# The author disclaims copyright to this source code. In place of -# a legal notice, here is a blessing: -# -# May you do good and not evil. -# May you find forgiveness for yourself and forgive others. -# May you share freely, never taking more than you give. -# -#*********************************************************************** -# This file implements regression tests for SQLite library. -# The focus of this script is testing the "eval.c" loadable extension. -# - -set testdir [file dirname $argv0] -source $testdir/tester.tcl - -load_static_extension db eval -do_execsql_test misc8-1.0 { - CREATE TABLE t1(a,b,c); - INSERT INTO t1 VALUES(1,2,3),(4,5,6); - SELECT quote(eval('SELECT * FROM t1 ORDER BY a','-abc-')); -} {'1-abc-2-abc-3-abc-4-abc-5-abc-6'} -do_execsql_test misc8-1.1 { - SELECT quote(eval('SELECT * FROM t1 ORDER BY a')); -} {{'1 2 3 4 5 6'}} -do_catchsql_test misc8-1.2 { - SELECT quote(eval('SELECT d FROM t1 ORDER BY a')); -} {1 {no such column: d}} -do_execsql_test misc8-1.3 { - INSERT INTO t1 VALUES(7,null,9); - SELECT eval('SELECT * FROM t1 ORDER BY a',','); -} {1,2,3,4,5,6,7,,9} -do_catchsql_test misc8-1.4 { - BEGIN; - INSERT INTO t1 VALUES(10,11,12); - SELECT a, coalesce(b, eval('ROLLBACK; SELECT ''bam'';')), c - FROM t1 ORDER BY a; -} {0 {1 2 3 4 5 6 7 bam 9}} -do_catchsql_test misc8-1.5 { - INSERT INTO t1 VALUES(10,11,12); - SELECT a, coalesce(b, eval('SELECT ''bam''')), c - FROM t1 - ORDER BY rowid; -} {0 {1 2 3 4 5 6 7 bam 9 10 11 12}} -do_catchsql_test misc8-1.6 { - SELECT a, coalesce(b, eval('DELETE FROM t1; SELECT ''bam''')), c - FROM t1 - ORDER BY rowid; -} {0 {1 2 3 4 5 6 7 bam {}}} -do_catchsql_test misc8-1.7 { - INSERT INTO t1 VALUES(1,2,3),(4,5,6),(7,null,9); - BEGIN; - CREATE TABLE t2(x); - SELECT a, coalesce(b, eval('ROLLBACK; SELECT ''bam''')), c - FROM t1 - ORDER BY rowid; -} {1 {abort due to ROLLBACK}} - - -finish_test Index: test/mmap1.test ================================================================== --- test/mmap1.test +++ test/mmap1.test @@ -31,20 +31,20 @@ proc register_rblob_code {dbname seed} { return [subst -nocommands { set ::rcnt $seed proc rblob {n} { set ::rcnt [expr (([set ::rcnt] << 3) + [set ::rcnt] + 456) & 0xFFFFFFFF] - set str [format %.8x [expr [set ::rcnt] ^ 0xbdf20da3]] + set str [format %.8x [expr [set ::rcnt] ^ 0xbdf20da3]] string range [string repeat [set str] [expr [set n]/4]] 1 [set n] } $dbname func rblob rblob }] } # For cases 1.1 and 1.4, the number of pages read using xRead() is 4 on # unix and 9 on windows. The difference is that windows only ever maps -# an integer number of OS pages (i.e. creates mappings that are a multiple +# an integer number of OS pages (i.e. creates mappings that are a multiple # of 4KB in size). Whereas on unix any sized mapping may be created. # foreach {t mmap_size nRead c2init} { 1.1 { PRAGMA mmap_size = 67108864 } /[49]/ {PRAGMA mmap_size = 0} 1.2 { PRAGMA mmap_size = 53248 } 150 {PRAGMA mmap_size = 0} @@ -104,56 +104,54 @@ } set ::rcnt 0 proc rblob {n} { set ::rcnt [expr (($::rcnt << 3) + $::rcnt + 456) & 0xFFFFFFFF] - set str [format %.8x [expr $::rcnt ^ 0xbdf20da3]] + set str [format %.8x [expr $::rcnt ^ 0xbdf20da3]] string range [string repeat $str [expr $n/4]] 1 $n } reset_db db func rblob rblob -ifcapable wal { - do_execsql_test 2.1 { - PRAGMA auto_vacuum = 1; - PRAGMA mmap_size = 67108864; - PRAGMA journal_mode = wal; - CREATE TABLE t1(a, b, UNIQUE(a, b)); - INSERT INTO t1 VALUES(rblob(500), rblob(500)); - INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2 - INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4 - INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8 - INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 - INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32 - PRAGMA wal_checkpoint; - } {67108864 wal 0 103 103} - - do_execsql_test 2.2 { - PRAGMA auto_vacuum; - SELECT count(*) FROM t1; - } {1 32} - - if {[permutation] != "inmemory_journal"} { - do_test 2.3 { - sqlite3 db2 test.db - db2 func rblob rblob - db2 eval { - DELETE FROM t1 WHERE (rowid%4); - PRAGMA wal_checkpoint; - } - db2 eval { - INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 - SELECT count(*) FROM t1; - } - } {16} - - do_execsql_test 2.4 { - PRAGMA wal_checkpoint; - } {0 24 24} - db2 close - } +do_execsql_test 2.1 { + PRAGMA auto_vacuum = 1; + PRAGMA mmap_size = 67108864; + PRAGMA journal_mode = wal; + CREATE TABLE t1(a, b, UNIQUE(a, b)); + INSERT INTO t1 VALUES(rblob(500), rblob(500)); + INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2 + INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4 + INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8 + INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 + INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32 + PRAGMA wal_checkpoint; +} {67108864 wal 0 103 103} + +do_execsql_test 2.2 { + PRAGMA auto_vacuum; + SELECT count(*) FROM t1; +} {1 32} + +if {[permutation] != "inmemory_journal"} { + do_test 2.3 { + sqlite3 db2 test.db + db2 func rblob rblob + db2 eval { + DELETE FROM t1 WHERE (rowid%4); + PRAGMA wal_checkpoint; + } + db2 eval { + INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 + SELECT count(*) FROM t1; + } + } {16} + + do_execsql_test 2.4 { + PRAGMA wal_checkpoint; + } {0 24 24} + db2 close } reset_db execsql { PRAGMA mmap_size = 67108864; } db func rblob rblob @@ -227,11 +225,11 @@ } SQLITE_OK do_execsql_test 4.5 { COMMIT } #------------------------------------------------------------------------- -# Ensure that existing cursors holding xFetch() references are not +# Ensure that existing cursors holding xFetch() references are not # confused if those pages are moved to make way for the root page of a # new table or index. # reset_db execsql { PRAGMA mmap_size = 67108864; } @@ -296,11 +294,11 @@ code2 [register_rblob_code db2 444] sql1 "PRAGMA mmap_size = $mmap1" sql2 "PRAGMA mmap_size = $mmap2" - do_test $tn1.$tn { + do_test $tn1.$tn { for {set i 1} {$i <= 100} {incr i} { if {$i % 2} { set c1 sql1 set c2 sql2 } else { @@ -311,11 +309,11 @@ $c1 { INSERT INTO t1 VALUES( rblob(5000) ); UPDATE t2 SET x = (SELECT md5sum(a) FROM t1); } - set res [$c2 { + set res [$c2 { SELECT count(*) FROM t1; SELECT x == (SELECT md5sum(a) FROM t1) FROM t2; PRAGMA integrity_check; }] if {$res != [list $i 1 ok]} { DELETED test/scanstatus.test Index: test/scanstatus.test ================================================================== --- test/scanstatus.test +++ /dev/null @@ -1,398 +0,0 @@ -# 2014 November 1 -# -# The author disclaims copyright to this source code. In place of -# a legal notice, here is a blessing: -# -# May you do good and not evil. -# May you find forgiveness for yourself and forgive others. -# May you share freely, never taking more than you give. -# -#*********************************************************************** -# - -set testdir [file dirname $argv0] -source $testdir/tester.tcl -set testprefix scanstatus - -ifcapable !scanstatus { - finish_test - return -} - -do_execsql_test 1.0 { - CREATE TABLE t1(a, b); - CREATE TABLE t2(x, y); - INSERT INTO t1 VALUES(1, 2); - INSERT INTO t1 VALUES(3, 4); - INSERT INTO t2 VALUES('a', 'b'); - INSERT INTO t2 VALUES('c', 'd'); - INSERT INTO t2 VALUES('e', 'f'); -} - -proc do_scanstatus_test {tn res} { - set stmt [db_last_stmt_ptr db] - set idx 0 - set ret [list] - while {1} { - set r [sqlite3_stmt_scanstatus $stmt $idx] - if {[llength $r]==0} break - lappend ret {*}$r - incr idx - } - - uplevel [list do_test $tn [list set {} $ret] [list {*}$res]] -} - -do_execsql_test 1.1 { SELECT count(*) FROM t1, t2; } 6 -do_scanstatus_test 1.2 { - nLoop 1 nVisit 2 nEst 1048576.0 zName t1 zExplain {SCAN TABLE t1} - nLoop 2 nVisit 6 nEst 1048576.0 zName t2 zExplain {SCAN TABLE t2} -} - -do_execsql_test 1.3 { - ANALYZE; - SELECT count(*) FROM t1, t2; -} 6 -do_scanstatus_test 1.4 { - nLoop 1 nVisit 2 nEst 2.0 zName t1 zExplain {SCAN TABLE t1} - nLoop 2 nVisit 6 nEst 3.0 zName t2 zExplain {SCAN TABLE t2} -} - -do_execsql_test 1.5 { ANALYZE } -do_execsql_test 1.6 { - SELECT count(*) FROM t1, t2 WHERE t2.rowid>1; -} 4 -do_scanstatus_test 1.7 { - nLoop 1 nVisit 2 nEst 2.0 zName t2 zExplain - {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} - nLoop 2 nVisit 4 nEst 2.0 zName t1 zExplain {SCAN TABLE t1} -} - -do_execsql_test 1.8 { - SELECT count(*) FROM t1, t2 WHERE t2.rowid>1; -} 4 - -do_scanstatus_test 1.9 { - nLoop 2 nVisit 4 nEst 2.0 zName t2 zExplain - {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} - nLoop 4 nVisit 8 nEst 2.0 zName t1 zExplain {SCAN TABLE t1} -} - -do_test 1.9 { - sqlite3_stmt_scanstatus_reset [db_last_stmt_ptr db] -} {} - -do_scanstatus_test 1.10 { - nLoop 0 nVisit 0 nEst 2.0 zName t2 zExplain - {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} - nLoop 0 nVisit 0 nEst 2.0 zName t1 zExplain {SCAN TABLE t1} -} - -#------------------------------------------------------------------------- -# Try a few different types of scans. -# -reset_db -do_execsql_test 2.1 { - CREATE TABLE x1(i INTEGER PRIMARY KEY, j); - INSERT INTO x1 VALUES(1, 'one'); - INSERT INTO x1 VALUES(2, 'two'); - INSERT INTO x1 VALUES(3, 'three'); - INSERT INTO x1 VALUES(4, 'four'); - CREATE INDEX x1j ON x1(j); - - SELECT * FROM x1 WHERE i=2; -} {2 two} - -do_scanstatus_test 2.2 { - nLoop 1 nVisit 1 nEst 1.0 zName x1 - zExplain {SEARCH TABLE x1 USING INTEGER PRIMARY KEY (rowid=?)} -} - -do_execsql_test 2.3.1 { - SELECT * FROM x1 WHERE j='two' -} {2 two} -do_scanstatus_test 2.3.2 { - nLoop 1 nVisit 1 nEst 10.0 zName x1j - zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j=?)} -} - -do_execsql_test 2.4.1 { - SELECT * FROM x1 WHERE j<'two' -} {4 four 1 one 3 three} -do_scanstatus_test 2.4.2 { - nLoop 1 nVisit 3 nEst 262144.0 zName x1j - zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j='two' -} {2 two} -do_scanstatus_test 2.5.2 { - nLoop 1 nVisit 1 nEst 262144.0 zName x1j - zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j>?)} -} - -do_execsql_test 2.6.1 { - SELECT * FROM x1 WHERE j BETWEEN 'three' AND 'two' -} {3 three 2 two} -do_scanstatus_test 2.6.2 { - nLoop 1 nVisit 2 nEst 16384.0 zName x1j - zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j>? AND j? AND j? AND a? AND b? AND b? AND a. AND dd<../} - - -# Create a table containing 100 rows. Column "a" contains a copy of the -# rowid value - sequentially increasing integers from 1 to 100. Column -# "b" contains the value of (a % 5). Columns "c" and "d" both contain -# constant values (i.e. the same for every row). -# -# Then create a second table t2. t2 is the same as t3 except for the -# order in which the indexes are created. -# -do_execsql_test 3.0 { - CREATE TABLE t3(a, b, c, d); - CREATE INDEX t3_ba ON t3(b, a, c); - CREATE INDEX t3_a ON t3(a); - - WITH d(a, b) AS ( - SELECT 1, 1 - UNION ALL - SELECT a+1, (a+1) % 5 FROM d WHERE a<100 - ) - INSERT INTO t3 SELECT a, b, 'c', 'd' FROM d; - - CREATE TABLE t2(a, b, c, d); - CREATE INDEX t2_a ON t2(a); - CREATE INDEX t2_ba ON t2(b, a, c); - INSERT INTO t2 SELECT * FROM t3; - - ANALYZE; - SELECT * FROM sqlite_stat1; -} { - t2 t2_ba {100 20 1 1} - t2 t2_a {100 1} - t3 t3_a {100 1} - t3 t3_ba {100 20 1 1} -} - -# Use index "t3_a", as (a=?) is expected to match only a single row. -# -do_eqp_test 3.1 { - SELECT * FROM t3 WHERE a = ? AND c = ? -} { - 0 0 0 {SEARCH TABLE t3 USING INDEX t3_a (a=?)} -} - -# The same query on table t2. This should use index "t2_a", for the -# same reason. At one point though, it was mistakenly using a skip-scan. -# -do_eqp_test 3.2 { - SELECT * FROM t2 WHERE a = ? AND c = ? -} { - 0 0 0 {SEARCH TABLE t2 USING INDEX t2_a (a=?)} -} - -finish_test - - - - -finish_test Index: test/sort2.test ================================================================== --- test/sort2.test +++ test/sort2.test @@ -60,10 +60,11 @@ CREATE UNIQUE INDEX i2 ON t1(a); } do_execsql_test $tn.2.4 { PRAGMA integrity_check } {ok} + breakpoint do_execsql_test $tn.3 { PRAGMA cache_size = 5; WITH r(x,y) AS ( SELECT 1, randomblob(100) UNION ALL Index: test/tkt-f777251dc7a.test ================================================================== --- test/tkt-f777251dc7a.test +++ test/tkt-f777251dc7a.test @@ -36,10 +36,11 @@ catch {db eval {INSERT OR ROLLBACK INTO t1 VALUES(1)}} } db function force_rollback force_rollback do_test tkt-f7772-1.2 { +breakpoint catchsql { BEGIN IMMEDIATE; CREATE TABLE xyzzy(abc); SELECT x, force_rollback(), EXISTS(SELECT 1 FROM t3 WHERE w=x) FROM t2; } Index: test/without_rowid5.test ================================================================== --- test/without_rowid5.test +++ test/without_rowid5.test @@ -183,11 +183,12 @@ } {1} # EVIDENCE-OF: R-12643-30541 The incremental blob I/O mechanism does not # work for WITHOUT ROWID tables. # -# EVIDENCE-OF: R-40134-30296 Table zTable is a WITHOUT ROWID table +# EVIDENCE-OF: R-25760-33257 The sqlite3_blob_open() interface will fail +# for a WITHOUT ROWID table. # do_execsql_test without_rowid5-6.1 { CREATE TABLE b1(a INTEGER PRIMARY KEY, b BLOB) WITHOUT ROWID; INSERT INTO b1 VALUES(1,x'0102030405060708090a0b0c0d0e0f'); } {} Index: tool/showstat4.c ================================================================== --- tool/showstat4.c +++ tool/showstat4.c @@ -37,11 +37,10 @@ int rc, j, x, y, mxHdr; const unsigned char *aSample; int nSample; i64 iVal; const char *zSep; - int iRow = 0; if( argc!=2 ){ fprintf(stderr, "Usage: %s DATABASE-FILE\n", argv[0]); exit(1); } @@ -59,17 +58,17 @@ sqlite3_close(db); exit(1); } while( SQLITE_ROW==sqlite3_step(pStmt) ){ if( zIdx==0 || strcmp(zIdx, (const char*)sqlite3_column_text(pStmt,0))!=0 ){ - if( zIdx ) printf("\n**************************************" - "**************\n\n"); + if( zIdx ) printf("\n"); sqlite3_free(zIdx); zIdx = sqlite3_mprintf("%s", sqlite3_column_text(pStmt,0)); - iRow = 0; + printf("%s:\n", zIdx); + }else{ + printf(" -----------------------------------------------------------\n"); } - printf("%s sample %d ------------------------------------\n", zIdx, ++iRow); printf(" nEq = %s\n", sqlite3_column_text(pStmt,1)); printf(" nLt = %s\n", sqlite3_column_text(pStmt,2)); printf(" nDLt = %s\n", sqlite3_column_text(pStmt,3)); printf(" sample = x'"); aSample = sqlite3_column_blob(pStmt,4); DELETED tool/varint.c Index: tool/varint.c ================================================================== --- tool/varint.c +++ /dev/null @@ -1,123 +0,0 @@ -/* -** A utility program to translate SQLite varints into decimal and decimal -** integers into varints. -*/ -#include -#include -#include - -#if defined(_MSC_VER) || defined(__BORLANDC__) - typedef __int64 i64; - typedef unsigned __int64 u64; -#else - typedef long long int i64; - typedef unsigned long long int u64; -#endif - -static int hexValue(char c){ - if( c>='0' && c<='9' ) return c - '0'; - if( c>='a' && c<='f' ) return c - 'a' + 10; - if( c>='A' && c<='F' ) return c - 'A' + 10; - return -1; -} - -static char toHex(unsigned char c){ - return "0123456789abcdef"[c&0xf]; -} - -static int putVarint(unsigned char *p, u64 v){ - int i, j, n; - unsigned char buf[10]; - if( v & (((u64)0xff000000)<<32) ){ - p[8] = (unsigned char)v; - v >>= 8; - for(i=7; i>=0; i--){ - p[i] = (unsigned char)((v & 0x7f) | 0x80); - v >>= 7; - } - return 9; - } - n = 0; - do{ - buf[n++] = (unsigned char)((v & 0x7f) | 0x80); - v >>= 7; - }while( v!=0 ); - buf[0] &= 0x7f; - for(i=0, j=n-1; j>=0; j--, i++){ - p[i] = buf[j]; - } - return n; -} - - -int main(int argc, char **argv){ - int i; - u64 x; - u64 uX = 0; - i64 iX; - int n; - unsigned char zHex[20]; - - if( argc==1 ){ - fprintf(stderr, - "Usage:\n" - " %s HH HH HH ... Convert varint to decimal\n" - " %s DDDDD Convert decimal to varint\n" - " Add '+' or '-' before DDDDD to disambiguate.\n", - argv[0], argv[0]); - exit(1); - } - if( argc>2 - || (strlen(argv[1])==2 && hexValue(argv[1][0])>=0 && hexValue(argv[1][1])>=0) - ){ - /* Hex to decimal */ - for(i=1; i'9' ){ - fprintf(stderr, "Not a decimal number: %s", argv[1]); - exit(1); - } - uX = uX*10 + z[0] - '0'; - z++; - } - if( sign<0 ){ - memcpy(&iX, &uX, 8); - iX = -iX; - memcpy(&uX, &iX, 8); - } - } - n = putVarint(zHex, uX); - printf("%lld =", (i64)uX); - for(i=0; i>4), toHex(zHex[i]&0x0f)); - } - printf("\n"); - return 0; -}