Index: Makefile.msc ================================================================== --- Makefile.msc +++ Makefile.msc @@ -269,10 +269,12 @@ # These are the "extended" SQLite compilation options used when compiling for # the Windows 10 platform. # !IFNDEF EXT_FEATURE_FLAGS !IF $(FOR_WIN10)!=0 +EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_STAT4=1 +EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS4=1 EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_SYSTEM_MALLOC=1 EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_OMIT_LOCALTIME=1 !ELSE EXT_FEATURE_FLAGS = Index: VERSION ================================================================== --- VERSION +++ VERSION @@ -1,1 +1,1 @@ -3.12.0 +3.12.2 Index: autoconf/Makefile.msc ================================================================== --- autoconf/Makefile.msc +++ autoconf/Makefile.msc @@ -254,10 +254,12 @@ # These are the "extended" SQLite compilation options used when compiling for # the Windows 10 platform. # !IFNDEF EXT_FEATURE_FLAGS !IF $(FOR_WIN10)!=0 +EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_STAT4=1 +EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS4=1 EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_SYSTEM_MALLOC=1 EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_OMIT_LOCALTIME=1 !ELSE EXT_FEATURE_FLAGS = Index: configure ================================================================== --- configure +++ configure @@ -1,8 +1,8 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for sqlite 3.12.0. +# Generated by GNU Autoconf 2.69 for sqlite 3.12.2. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # @@ -724,12 +724,12 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' -PACKAGE_VERSION='3.12.0' -PACKAGE_STRING='sqlite 3.12.0' +PACKAGE_VERSION='3.12.2' +PACKAGE_STRING='sqlite 3.12.2' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ @@ -1458,11 +1458,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.12.0 to adapt to many kinds of systems. +\`configure' configures sqlite 3.12.2 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. @@ -1523,11 +1523,11 @@ _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of sqlite 3.12.0:";; + short | recursive ) echo "Configuration of sqlite 3.12.2:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options @@ -1644,11 +1644,11 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -sqlite configure 3.12.0 +sqlite configure 3.12.2 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. @@ -2063,11 +2063,11 @@ } # ac_fn_c_check_header_mongrel 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.12.0, which was +It was created by sqlite $as_me 3.12.2, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF @@ -12077,11 +12077,11 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # 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.12.0, which was +This file was extended by sqlite $as_me 3.12.2, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS @@ -12143,11 +12143,11 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -sqlite config.status 3.12.0 +sqlite config.status 3.12.2 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation Index: src/btree.c ================================================================== --- src/btree.c +++ src/btree.c @@ -8137,10 +8137,32 @@ iCellDepth = pCur->iPage; iCellIdx = pCur->aiIdx[iCellDepth]; pPage = pCur->apPage[iCellDepth]; pCell = findCell(pPage, iCellIdx); + + /* If the bPreserve flag is set to true, then the cursor position must + ** be preserved following this delete operation. If the current delete + ** will cause a b-tree rebalance, then this is done by saving the cursor + ** key and leaving the cursor in CURSOR_REQUIRESEEK state before + ** returning. + ** + ** Or, if the current delete will not cause a rebalance, then the cursor + ** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately + ** before or after the deleted entry. In this case set bSkipnext to true. */ + if( bPreserve ){ + if( !pPage->leaf + || (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3) + ){ + /* A b-tree rebalance will be required after deleting this entry. + ** Save the cursor key. */ + rc = saveCursorKey(pCur); + if( rc ) return rc; + }else{ + bSkipnext = 1; + } + } /* If the page containing the entry to delete is not a leaf page, move ** the cursor to the largest entry in the tree that is smaller than ** the entry being deleted. This cell will replace the cell being deleted ** from the internal node. The 'previous' entry is used for this instead @@ -8164,32 +8186,10 @@ ** invalidate any incrblob cursors open on the row being deleted. */ if( pCur->pKeyInfo==0 ){ invalidateIncrblobCursors(p, pCur->info.nKey, 0); } - /* If the bPreserve flag is set to true, then the cursor position must - ** be preserved following this delete operation. If the current delete - ** will cause a b-tree rebalance, then this is done by saving the cursor - ** key and leaving the cursor in CURSOR_REQUIRESEEK state before - ** returning. - ** - ** Or, if the current delete will not cause a rebalance, then the cursor - ** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately - ** before or after the deleted entry. In this case set bSkipnext to true. */ - if( bPreserve ){ - if( !pPage->leaf - || (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3) - ){ - /* A b-tree rebalance will be required after deleting this entry. - ** Save the cursor key. */ - rc = saveCursorKey(pCur); - if( rc ) return rc; - }else{ - bSkipnext = 1; - } - } - /* Make the page containing the entry to be deleted writable. Then free any ** overflow pages associated with the entry and finally remove the cell ** itself from within the page. */ rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ) return rc; Index: src/build.c ================================================================== --- src/build.c +++ src/build.c @@ -1084,10 +1084,11 @@ pCol->szEst = 1; }else{ zType = z + sqlite3Strlen30(z) + 1; memcpy(zType, pType->z, pType->n); zType[pType->n] = 0; + sqlite3Dequote(zType); pCol->affinity = sqlite3AffinityType(zType, &pCol->szEst); pCol->colFlags |= COLFLAG_HASTYPE; } p->nCol++; pParse->constraintName.n = 0; @@ -2174,48 +2175,59 @@ ** to the elements of the FROM clause. But we do not want these changes ** to be permanent. So the computation is done on a copy of the SELECT ** statement that defines the view. */ assert( pTable->pSelect ); - if( pTable->pCheck ){ - db->lookaside.bDisable++; - sqlite3ColumnsFromExprList(pParse, pTable->pCheck, - &pTable->nCol, &pTable->aCol); - db->lookaside.bDisable--; - }else{ - pSel = sqlite3SelectDup(db, pTable->pSelect, 0); - if( pSel ){ - n = pParse->nTab; - sqlite3SrcListAssignCursors(pParse, pSel->pSrc); - pTable->nCol = -1; - db->lookaside.bDisable++; -#ifndef SQLITE_OMIT_AUTHORIZATION - xAuth = db->xAuth; - db->xAuth = 0; - pSelTab = sqlite3ResultSetOfSelect(pParse, pSel); - db->xAuth = xAuth; -#else - pSelTab = sqlite3ResultSetOfSelect(pParse, pSel); -#endif - db->lookaside.bDisable--; - pParse->nTab = n; - if( pSelTab ){ - assert( pTable->aCol==0 ); - pTable->nCol = pSelTab->nCol; - pTable->aCol = pSelTab->aCol; - pSelTab->nCol = 0; - pSelTab->aCol = 0; - sqlite3DeleteTable(db, pSelTab); - assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) ); - }else{ - pTable->nCol = 0; - nErr++; - } - sqlite3SelectDelete(db, pSel); - } else { - nErr++; - } + pSel = sqlite3SelectDup(db, pTable->pSelect, 0); + if( pSel ){ + n = pParse->nTab; + sqlite3SrcListAssignCursors(pParse, pSel->pSrc); + pTable->nCol = -1; + db->lookaside.bDisable++; +#ifndef SQLITE_OMIT_AUTHORIZATION + xAuth = db->xAuth; + db->xAuth = 0; + pSelTab = sqlite3ResultSetOfSelect(pParse, pSel); + db->xAuth = xAuth; +#else + pSelTab = sqlite3ResultSetOfSelect(pParse, pSel); +#endif + pParse->nTab = n; + if( pTable->pCheck ){ + /* CREATE VIEW name(arglist) AS ... + ** The names of the columns in the table are taken from + ** arglist which is stored in pTable->pCheck. The pCheck field + ** normally holds CHECK constraints on an ordinary table, but for + ** a VIEW it holds the list of column names. + */ + sqlite3ColumnsFromExprList(pParse, pTable->pCheck, + &pTable->nCol, &pTable->aCol); + if( db->mallocFailed==0 + && pParse->nErr==0 + && pTable->nCol==pSel->pEList->nExpr + ){ + sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel); + } + }else if( pSelTab ){ + /* CREATE VIEW name AS... without an argument list. Construct + ** the column names from the SELECT statement that defines the view. + */ + assert( pTable->aCol==0 ); + pTable->nCol = pSelTab->nCol; + pTable->aCol = pSelTab->aCol; + pSelTab->nCol = 0; + pSelTab->aCol = 0; + assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) ); + }else{ + pTable->nCol = 0; + nErr++; + } + if( pSelTab ) sqlite3DeleteTable(db, pSelTab); + sqlite3SelectDelete(db, pSel); + db->lookaside.bDisable--; + } else { + nErr++; } pTable->pSchema->schemaFlags |= DB_UnresetViews; #endif /* SQLITE_OMIT_VIEW */ return nErr; } Index: src/memjournal.c ================================================================== --- src/memjournal.c +++ src/memjournal.c @@ -92,10 +92,11 @@ return SQLITE_IOERR_SHORT_READ; } #endif assert( (iAmt+iOfst)<=p->endpoint.iOffset ); + assert( p->readpoint.iOffset==0 || p->readpoint.pChunk!=0 ); if( p->readpoint.iOffset!=iOfst || iOfst==0 ){ sqlite3_int64 iOff = 0; for(pChunk=p->pFirst; ALWAYS(pChunk) && (iOff+p->nChunkSize)<=iOfst; pChunk=pChunk->pNext @@ -102,10 +103,11 @@ ){ iOff += p->nChunkSize; } }else{ pChunk = p->readpoint.pChunk; + assert( pChunk!=0 ); } iChunkOffset = (int)(iOfst%p->nChunkSize); do { int iSpace = p->nChunkSize - iChunkOffset; @@ -113,11 +115,11 @@ memcpy(zOut, (u8*)pChunk->zChunk + iChunkOffset, nCopy); zOut += nCopy; nRead -= iSpace; iChunkOffset = 0; } while( nRead>=0 && (pChunk=pChunk->pNext)!=0 && nRead>0 ); - p->readpoint.iOffset = iOfst+iAmt; + p->readpoint.iOffset = pChunk ? iOfst+iAmt : 0; p->readpoint.pChunk = pChunk; return SQLITE_OK; } Index: src/select.c ================================================================== --- src/select.c +++ src/select.c @@ -1702,11 +1702,11 @@ ** routine goes through and adds the types and collations. ** ** This routine requires that all identifiers in the SELECT ** statement be resolved. */ -static void selectAddColumnTypeAndCollation( +void sqlite3SelectAddColumnTypeAndCollation( Parse *pParse, /* Parsing contexts */ Table *pTab, /* Add column type information to this table */ Select *pSelect /* SELECT used to determine types and collations */ ){ sqlite3 *db = pParse->db; @@ -1724,14 +1724,24 @@ if( db->mallocFailed ) return; memset(&sNC, 0, sizeof(sNC)); sNC.pSrcList = pSelect->pSrc; a = pSelect->pEList->a; for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){ + const char *zType; + int n, m; p = a[i].pExpr; - columnType(&sNC, p, 0, 0, 0, &pCol->szEst); + zType = columnType(&sNC, p, 0, 0, 0, &pCol->szEst); szAll += pCol->szEst; pCol->affinity = sqlite3ExprAffinity(p); + if( zType && (m = sqlite3Strlen30(zType))>0 ){ + n = sqlite3Strlen30(pCol->zName); + pCol->zName = sqlite3DbReallocOrFree(db, pCol->zName, n+m+2); + if( pCol->zName ){ + memcpy(&pCol->zName[n+1], zType, m+1); + pCol->colFlags |= COLFLAG_HASTYPE; + } + } if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_BLOB; pColl = sqlite3ExprCollSeq(pParse, p); if( pColl && pCol->zColl==0 ){ pCol->zColl = sqlite3DbStrDup(db, pColl->zName); } @@ -1764,11 +1774,11 @@ assert( db->lookaside.bDisable ); pTab->nRef = 1; pTab->zName = 0; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol); - selectAddColumnTypeAndCollation(pParse, pTab, pSelect); + sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect); pTab->iPKey = -1; if( db->mallocFailed ){ sqlite3DeleteTable(db, pTab); return 0; } @@ -4548,11 +4558,11 @@ if( (pTab->tabFlags & TF_Ephemeral)!=0 ){ /* A sub-query in the FROM clause of a SELECT */ Select *pSel = pFrom->pSelect; if( pSel ){ while( pSel->pPrior ) pSel = pSel->pPrior; - selectAddColumnTypeAndCollation(pParse, pTab, pSel); + sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel); } } } } #endif Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -3455,10 +3455,11 @@ void sqlite3ResetOneSchema(sqlite3*,int); void sqlite3CollapseDatabaseArray(sqlite3*); void sqlite3CommitInternalChanges(sqlite3*); void sqlite3DeleteColumnNames(sqlite3*,Table*); int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**); +void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*); Table *sqlite3ResultSetOfSelect(Parse*,Select*); void sqlite3OpenMasterTable(Parse *, int); Index *sqlite3PrimaryKeyIndex(Table*); i16 sqlite3ColumnOfIndex(Index*, i16); void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int); Index: src/vdbesort.c ================================================================== --- src/vdbesort.c +++ src/vdbesort.c @@ -929,11 +929,10 @@ int nField, /* Number of key fields in each record */ VdbeCursor *pCsr /* Cursor that holds the new sorter */ ){ int pgsz; /* Page size of main database */ int i; /* Used to iterate through aTask[] */ - int mxCache; /* Cache size */ VdbeSorter *pSorter; /* The new sorter */ KeyInfo *pKeyInfo; /* Copy of pCsr->pKeyInfo with db==0 */ int szKeyInfo; /* Size of pCsr->pKeyInfo in bytes */ int sz; /* Size of pSorter in bytes */ int rc = SQLITE_OK; @@ -986,15 +985,24 @@ SortSubtask *pTask = &pSorter->aTask[i]; pTask->pSorter = pSorter; } if( !sqlite3TempInMemory(db) ){ + i64 mxCache; /* Cache size in bytes*/ u32 szPma = sqlite3GlobalConfig.szPma; pSorter->mnPmaSize = szPma * pgsz; + mxCache = db->aDb[0].pSchema->cache_size; - if( mxCache<(int)szPma ) mxCache = (int)szPma; - pSorter->mxPmaSize = MIN((i64)mxCache*pgsz, SQLITE_MAX_PMASZ); + if( mxCache<0 ){ + /* A negative cache-size value C indicates that the cache is abs(C) + ** KiB in size. */ + mxCache = mxCache * -1024; + }else{ + mxCache = mxCache * pgsz; + } + mxCache = MIN(mxCache, SQLITE_MAX_PMASZ); + pSorter->mxPmaSize = MAX(pSorter->mnPmaSize, (int)mxCache); /* EVIDENCE-OF: R-26747-61719 When the application provides any amount of ** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary ** large heap allocations. */ Index: src/where.c ================================================================== --- src/where.c +++ src/where.c @@ -2199,12 +2199,10 @@ assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 ); assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 ); if( pNew->wsFlags & WHERE_BTM_LIMIT ){ opMask = WO_LT|WO_LE; - }else if( /*pProbe->tnum<=0 ||*/ (pSrc->fg.jointype & JT_LEFT)!=0 ){ - opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE; }else{ opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS; } if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); @@ -2237,10 +2235,22 @@ if( pTerm->prereqRight & pNew->maskSelf ) continue; /* Do not allow the upper bound of a LIKE optimization range constraint ** to mix with a lower range bound from some other source */ if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue; + + /* Do not allow IS constraints from the WHERE clause to be used by the + ** right table of a LEFT JOIN. Only constraints in the ON clause are + ** allowed */ + if( (pSrc->fg.jointype & JT_LEFT)!=0 + && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) + && (eOp & (WO_IS|WO_ISNULL))!=0 + ){ + testcase( eOp & WO_IS ); + testcase( eOp & WO_ISNULL ); + continue; + } pNew->wsFlags = saved_wsFlags; pNew->u.btree.nEq = saved_nEq; pNew->nLTerm = saved_nLTerm; if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */ Index: src/wherecode.c ================================================================== --- src/wherecode.c +++ src/wherecode.c @@ -939,11 +939,17 @@ pCompare->pLeft = 0; sqlite3ExprDelete(db, pCompare); } } } - sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); + /* These registers need to be preserved in case there is an IN operator + ** loop. So we could deallocate the registers here (and potentially + ** reuse them later) if (pLoop->wsFlags & WHERE_IN_ABLE)==0. But it seems + ** simpler and safer to simply not reuse the registers. + ** + ** sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); + */ sqlite3ExprCachePop(pParse); }else #endif /* SQLITE_OMIT_VIRTUALTABLE */ if( (pLoop->wsFlags & WHERE_IPK)!=0 Index: test/bestindex1.test ================================================================== --- test/bestindex1.test +++ test/bestindex1.test @@ -162,7 +162,114 @@ do_eqp_test 2.2.$mode.6 { SELECT rowid FROM t1 WHERE a IN ('one', 'four') ORDER BY +rowid } $plan($mode) } + +# 2016-04-09. +# Demonstrate a register overwrite problem when using two virtual +# tables where the outer loop uses the IN operator. +# +set G(collist) [list PrimaryKey flagA columnA] +set G(cols) [join $G(collist) ,] +set G(nulls) "NULL" + +proc vtab_command {method args} { + global G + + switch -- $method { + xConnect { + return "CREATE TABLE t1($G(cols))" + } + + xBestIndex { + set clist [lindex $args 0] + #puts $clist + set W [list] + set U [list] + + set i 0 + for {set idx 0} {$idx < [llength $clist]} {incr idx} { + array set c [lindex $clist $idx] + if {$c(op)=="eq" && $c(usable)} { + lappend W "[lindex $G(collist) $c(column)] = %$i%" + lappend U use $idx + incr i + } + } + + if {$W==""} { + set sql "SELECT rowid, * FROM t1" + } else { + set sql "SELECT rowid, * FROM t1 WHERE [join $W { AND }]" + } + + return [concat [list idxstr $sql] $U] + } + + xFilter { + foreach {idxnum idxstr vals} $args {} + + set map [list] + for {set i 0} {$i < [llength $vals]} {incr i} { + lappend map "%$i%" + set v [lindex $vals $i] + if {[string is integer $v]} { + lappend map $v + } else { + lappend map "'$v'" + } + } + set sql [string map $map $idxstr] + + #puts "SQL: $sql" + return [list sql $sql] + } + } + + return {} +} + +db close +forcedelete test.db +sqlite3 db test.db +register_tcl_module db + +do_execsql_test 3.1 " + CREATE TABLE t1($G(cols)); + INSERT INTO t1 VALUES(1, 0, 'ValueA'); + INSERT INTO t1 VALUES(2, 0, 'ValueA'); + INSERT INTO t1 VALUES(3, 0, 'ValueB'); + INSERT INTO t1 VALUES(4, 0, 'ValueB'); +" + +do_execsql_test 3.2 { + CREATE VIRTUAL TABLE VirtualTableA USING tcl(vtab_command); + CREATE VIRTUAL TABLE VirtualTableB USING tcl(vtab_command); +} + +do_execsql_test 3.3 { SELECT primarykey FROM VirtualTableA } {1 2 3 4} + +do_execsql_test 3.4 { + SELECT * FROM + VirtualTableA a CROSS JOIN VirtualTableB b ON b.PrimaryKey=a.PrimaryKey + WHERE a.ColumnA IN ('ValueA', 'ValueB') AND a.FlagA=0 +} { + 1 0 ValueA 1 0 ValueA + 2 0 ValueA 2 0 ValueA + 3 0 ValueB 3 0 ValueB + 4 0 ValueB 4 0 ValueB +} + +do_execsql_test 3.5 { + SELECT * FROM + VirtualTableA a CROSS JOIN VirtualTableB b ON b.PrimaryKey=a.PrimaryKey + WHERE a.FlagA=0 AND a.ColumnA IN ('ValueA', 'ValueB') +} { + 1 0 ValueA 1 0 ValueA + 2 0 ValueA 2 0 ValueA + 3 0 ValueB 3 0 ValueB + 4 0 ValueB 4 0 ValueB +} + finish_test Index: test/delete4.test ================================================================== --- test/delete4.test +++ test/delete4.test @@ -137,9 +137,28 @@ CREATE INDEX idx_t4_0 ON t4 (col1, col0); DELETE FROM t4 WHERE col0=69 OR col0>7; PRAGMA integrity_check; } {ok} - - +# 2016-04-09 +# Ticket https://sqlite.org/src/info/a306e56ff68b8fa5 +# Failure to completely delete when reverse_unordered_selects is +# engaged. +# +db close +forcedelete test.db +sqlite3 db test.db +do_execsql_test 5.0 { + PRAGMA page_size=1024; + CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); + CREATE INDEX x1 ON t1(b, c); + INSERT INTO t1(a,b,c) VALUES(1, 1, zeroblob(80)); + INSERT INTO t1(a,b,c) SELECT a+1, 1, c FROM t1; + INSERT INTO t1(a,b,c) SELECT a+2, 1, c FROM t1; + INSERT INTO t1(a,b,c) SELECT a+10, 2, c FROM t1 WHERE b=1; + INSERT INTO t1(a,b,c) SELECT a+20, 3, c FROM t1 WHERE b=1; + PRAGMA reverse_unordered_selects = ON; + DELETE FROM t1 WHERE b=2; + SELECT a FROM t1 WHERE b=2; +} {} finish_test Index: test/intpkey.test ================================================================== --- test/intpkey.test +++ test/intpkey.test @@ -601,8 +601,19 @@ do_test intpkey-15.7 { execsql { SELECT b FROM t1 WHERE a>12345678901; } } {} + +# 2016-04-18 ticket https://www.sqlite.org/src/tktview/7d7525cb01b68712495d3a +# Be sure to escape quoted typenames. +# +do_execsql_test intpkey-16.0 { + CREATE TABLE t16a(id "INTEGER" PRIMARY KEY AUTOINCREMENT, b [TEXT], c `INT`); +} {} +do_execsql_test intpkey-16.1 { + PRAGMA table_info=t16a; +} {0 id INTEGER 0 {} 1 1 b TEXT 0 {} 0 2 c INT 0 {} 0} + finish_test Index: test/pragma.test ================================================================== --- test/pragma.test +++ test/pragma.test @@ -626,14 +626,14 @@ set res } {0 main 1 temp 2 aux} } do_test pragma-6.2 { execsql { - CREATE TABLE t2(a,b,c); + CREATE TABLE t2(a TYPE_X, b [TYPE_Y], c "TYPE_Z"); pragma table_info(t2) } -} {0 a {} 0 {} 0 1 b {} 0 {} 0 2 c {} 0 {} 0} +} {0 a TYPE_X 0 {} 0 1 b TYPE_Y 0 {} 0 2 c TYPE_Z 0 {} 0} do_test pragma-6.2.1 { execsql { pragma table_info; } } {} Index: test/sort5.test ================================================================== --- test/sort5.test +++ test/sort5.test @@ -39,6 +39,78 @@ CREATE INDEX i1 ON t1(b); } db close tvfs delete + +#------------------------------------------------------------------------- +# Test that the PMA size is determined correctly. The PMA size should be +# roughly the same amount of memory allocated to the main pager cache, or +# 250 pages if this is larger. +# +testvfs tvfs +tvfs script tv_callback +tvfs filter {xOpen xWrite} + +proc tv_callback {method args} { + global iTemp + global F + switch $method { + xOpen { + if {[lindex $args 0]==""} { return "temp[incr iTemp]" } + return "SQLITE_OK" + } + + xWrite { + foreach {filename id off amt} $args {} + if {[info exists F($id)]==0 || $F($id)<($off + $amt)} { + set F($id) [expr $off+$amt] + } + } + } +} + +catch { db close } +forcedelete test.db +sqlite3 db test.db -vfs tvfs +execsql { CREATE TABLE t1(x) } + +# Each iteration of the following loop attempts to sort 10001 records +# each a bit over 100 bytes in size. In total a little more than 1MiB +# of data. +# +breakpoint +foreach {tn pgsz cachesz bTemp} { + 2 1024 1000 1 + + 1 4096 1000 0 + 2 1024 1000 1 + + 3 4096 -1000 1 + 4 1024 -1000 1 + + 5 4096 -9000 0 + 6 1024 -9000 0 +} { + do_execsql_test 2.$tn.0 " + PRAGMA page_size = $pgsz; + VACUUM; + PRAGMA cache_size = $cachesz; + " + + do_test 2.$tn.1 { + set ::iTemp 0 + catch { array unset F } + execsql { + WITH x(i, j) AS ( + SELECT 1, randomblob(100) + UNION ALL + SELECT i+1, randomblob(100) FROM x WHERE i<10000 + ) + SELECT * FROM x ORDER BY j; + } + expr {[array names F]!=""} + } $bTemp +} + finish_test + Index: test/view.test ================================================================== --- test/view.test +++ test/view.test @@ -89,10 +89,30 @@ sqlite3 db test.db execsql { SELECT * FROM v1 ORDER BY a; } } {2 3 5 6 8 9} + +do_execsql_test view-1.10 { + CREATE TABLE t9(x INTEGER); + CREATE VIEW v9a AS SELECT x FROM t9; + CREATE VIEW v9b AS SELECT * FROM t9; + CREATE VIEW v9c(x) AS SELECT x FROM t9; + CREATE VIEW v9d(x) AS SELECT * FROM t9; +} {} +do_execsql_test view-1.11 { + PRAGMA table_info(v9a); +} {0 x INTEGER 0 {} 0} +do_execsql_test view-1.12 { + PRAGMA table_info(v9b); +} {0 x INTEGER 0 {} 0} +do_execsql_test view-1.13 { + PRAGMA table_info(v9c); +} {0 x INTEGER 0 {} 0} +do_execsql_test view-1.14 { + PRAGMA table_info(v9d); +} {0 x INTEGER 0 {} 0} do_test view-2.1 { execsql { CREATE VIEW v2 AS SELECT * FROM t1 WHERE a>5 }; # No semicolon