Index: Doc/Extra/version.html ================================================================== --- Doc/Extra/version.html +++ Doc/Extra/version.html @@ -41,13 +41,14 @@

Version History

-

1.0.84.0 - March XX, 2013 (release scheduled)

+

1.0.84.0 - January 9, 2013

    -
  • Updated to SQLite 3.7.16.
  • +
  • Updated to SQLite 3.7.15.2.
  • +
  • Explicitly dispose of all SQLiteCommand objects managed by the DbDataAdapter class. Fix for [6434e23a0f].
  • Add Cancel method to the SQLiteConnection class to interrupt a long running query.
  • Improve thread safety of the SQLiteLog.LogMessage method.

1.0.83.0 - December 29, 2012

    Index: Doc/SQLite.NET.chm ================================================================== --- Doc/SQLite.NET.chm +++ Doc/SQLite.NET.chm cannot compute difference between binary files Index: Externals/Eagle/lib/Eagle1.0/init.eagle ================================================================== --- Externals/Eagle/lib/Eagle1.0/init.eagle +++ Externals/Eagle/lib/Eagle1.0/init.eagle @@ -141,11 +141,11 @@ proc lappendArgs { args } { # # NOTE: This should work properly in both Tcl and Eagle. # - eval lappend result $args + set result [list]; eval lappend result $args } proc getDictionaryValue { dictionary name {default ""} {wrap ""} } { # # NOTE: Locate the named value we are interested in. The dictionary must @@ -1045,47 +1045,28 @@ # # NOTE: Next, figure out what type of download is being # requested. # switch -exact -nocase -- $type { - source { - # - # NOTE: Source code download. This may be a RAR or an EXE - # file. Append the appropriate file name and then - # join all the URI components to form the final URI. - # - set fileName [appendArgs EagleSource $patchLevel $extension] - lappend components $fileName - - set result [list [eval uri join $components] \ - [file join $directory $fileName]] - } - setup { - # - # NOTE: Windows setup download. Always append an ".exe" - # extension because we never distribute the setup as - # a RAR file. Append the appropriate file name and - # then join all the URI components to form the final - # URI. - # - set fileName [appendArgs EagleSetup $patchLevel .exe] - lappend components $fileName - - set result [list [eval uri join $components] \ - [file join $directory $fileName]] - } - binary { - # - # NOTE: Binary file download. This may be a RAR or an EXE - # file. Append the appropriate file name and then - # join all the URI components to form the final URI. - # - set fileName [appendArgs EagleBinary $patchLevel $extension] - lappend components $fileName - - set result [list [eval uri join $components] \ - [file join $directory $fileName]] + source - + setup - + binary { + # + # NOTE: Source code, setup, or binary download. This may be + # a RAR or an EXE file. Append the appropriate file + # name and then join all the URI components to form the + # final URI. + # + set fileName [appendArgs \ + [info engine] [string totitle $type] $patchLevel \ + [expr {[string tolower $type] eq "setup" ? ".exe" : \ + $extension}]] + + lappend components $fileName + + set result [list [eval uri join $components] [file join \ + $directory $fileName]] } } } } } @@ -1554,25 +1535,48 @@ # # NOTE: This should work properly in both Tcl and Eagle. # catch {puts stderr $string} } + + proc makeVariableFast { name fast } { + # + # NOTE: This should work properly in Eagle only. + # + catch { + uplevel 1 [list object invoke -flags +NonPublic \ + Interpreter.GetActive MakeVariableFast $name $fast] + } + } proc findDirectories { pattern } { + # + # NOTE: Block non-Windows platforms since this is Windows specific. + # + if {$::tcl_platform(platform) ne "windows"} then { + error "not supported on this operating system" + } + # # NOTE: This should work properly in Eagle only. # - set result [list] + set dir ""; set result [list] + + # + # HACK: Optimize the variable access in this procedure to be + # as fast as possible. + # + makeVariableFast dir true; makeVariableFast result true foreach dir [split [exec -unicode $::env(ComSpec) /u /c dir \ /ad /b [appendArgs \" [file nativename $pattern] \"]] \n] { set dir [string trim $dir] if {[string length $dir] > 0} then { set dir [getDirResultPath $pattern $dir] - if {[lsearch -exact -nocase $result $dir] == -1} then { + if {[lsearch -variable -exact -nocase result $dir] == -1} then { lappend result $dir } } } @@ -1581,33 +1585,46 @@ set dir [string trim $dir] if {[string length $dir] > 0} then { set dir [getDirResultPath $pattern $dir] - if {[lsearch -exact -nocase $result $dir] == -1} then { + if {[lsearch -variable -exact -nocase result $dir] == -1} then { lappend result $dir } } } return $result } proc findFiles { pattern } { + # + # NOTE: Block non-Windows platforms since this is Windows specific. + # + if {$::tcl_platform(platform) ne "windows"} then { + error "not supported on this operating system" + } + # # NOTE: This should work properly in Eagle only. # - set result [list] + set fileName ""; set result [list] + + # + # HACK: Optimize the variable access in this procedure to be + # as fast as possible. + # + makeVariableFast fileName true; makeVariableFast result true foreach fileName [split [exec -unicode $::env(ComSpec) /u /c dir \ /a-d /b [appendArgs \" [file nativename $pattern] \"]] \n] { set fileName [string trim $fileName] if {[string length $fileName] > 0} then { set fileName [getDirResultPath $pattern $fileName] - if {[lsearch -exact -nocase $result $fileName] == -1} then { + if {[lsearch -variable -exact -nocase result $fileName] == -1} then { lappend result $fileName } } } @@ -1616,33 +1633,46 @@ set fileName [string trim $fileName] if {[string length $fileName] > 0} then { set fileName [getDirResultPath $pattern $fileName] - if {[lsearch -exact -nocase $result $fileName] == -1} then { + if {[lsearch -variable -exact -nocase result $fileName] == -1} then { lappend result $fileName } } } return $result } proc findFilesRecursive { pattern } { + # + # NOTE: Block non-Windows platforms since this is Windows specific. + # + if {$::tcl_platform(platform) ne "windows"} then { + error "not supported on this operating system" + } + # # NOTE: This should work properly in Eagle only. # - set result [list] + set fileName ""; set result [list] + + # + # HACK: Optimize the variable access in this procedure to be + # as fast as possible. + # + makeVariableFast fileName true; makeVariableFast result true foreach fileName [split [exec -unicode $::env(ComSpec) /u /c dir \ /a-d /s /b [appendArgs \" [file nativename $pattern] \"]] \n] { set fileName [string trim $fileName] if {[string length $fileName] > 0} then { set fileName [getDirResultPath $pattern $fileName] - if {[lsearch -exact -nocase $result $fileName] == -1} then { + if {[lsearch -variable -exact -nocase result $fileName] == -1} then { lappend result $fileName } } } @@ -1651,11 +1681,11 @@ set fileName [string trim $fileName] if {[string length $fileName] > 0} then { set fileName [getDirResultPath $pattern $fileName] - if {[lsearch -exact -nocase $result $fileName] == -1} then { + if {[lsearch -variable -exact -nocase result $fileName] == -1} then { lappend result $fileName } } } @@ -1709,10 +1739,17 @@ return $result } proc findFilesRecursive { pattern } { + # + # NOTE: Block non-Windows platforms since this is Windows specific. + # + if {$::tcl_platform(platform) ne "windows"} then { + error "not supported on this operating system" + } + # # NOTE: This should work properly in Tcl only. # set result [list] @@ -1796,14 +1833,19 @@ # # NOTE: Exports the necessary commands from this package and import them # into the global namespace. # exportAndImportPackageCommands [namespace current] [list \ - exportAndImportPackageCommands isEagle isMono getEnvironmentVariable \ - getPluginPath getDictionaryValue getColumnValue getRowColumnValue \ - appendArgs haveGaruda lappendArgs readFile writeFile filter map \ - reduce getPlatformInfo execShell combineFlags tqputs tqlog] false false + isEagle haveGaruda isMono getEnvironmentVariable combineFlags \ + getCompileInfo getPlatformInfo getPluginPath appendArgs lappendArgs \ + getDictionaryValue getColumnValue getRowColumnValue tqputs tqlog \ + readFile readSharedFile writeFile appendFile appendLogFile \ + appendSharedFile appendSharedLogFile readAsciiFile writeAsciiFile \ + readUnicodeFile writeUnicodeFile getDirResultPath addToPath \ + removeFromPath execShell ldifference filter map reduce \ + getLengthModifier debug findDirectories findFiles findFilesRecursive \ + exportAndImportPackageCommands] false false ########################################################################### ############################## END Tcl ONLY ############################### ########################################################################### } Index: Externals/Eagle/lib/Eagle1.0/test.eagle ================================================================== --- Externals/Eagle/lib/Eagle1.0/test.eagle +++ Externals/Eagle/lib/Eagle1.0/test.eagle @@ -1318,10 +1318,16 @@ # output diagnostics as necessary if they have. # reportTestStatistics $channel $fileName leaks leaked } } else { + # + # NOTE: This entire file has been skipped. Record that fact in the + # test suite log file. + # + tputs $channel [appendArgs "==== \"" $fileName "\" NON_TEST_FILE\n"] + # # NOTE: This file does not actually count towards the total (i.e. # it contains no actual tests). # incr total -1 @@ -1348,12 +1354,12 @@ if {$stop} then { break } } else { # - # NOTE: This entire test file has been skipped. Record that fact in - # the test suite log file. + # NOTE: This entire file has been skipped. Record that fact in the + # test suite log file. # tputs $channel [appendArgs "==== \"" $fileName "\" SKIPPED\n"] # # NOTE: This file does not actually count towards the total (i.e. Index: SQLite.Interop/props/sqlite3.props ================================================================== --- SQLite.Interop/props/sqlite3.props +++ SQLite.Interop/props/sqlite3.props @@ -7,12 +7,12 @@ * Released to the public domain, use at your own risk! * --> - 3.7.16 - 3,7,16 + 3.7.15.2 + 3,7,15,2 _CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;SQLITE_THREADSAFE=1;SQLITE_USE_URI=1;SQLITE_ENABLE_COLUMN_METADATA=1;SQLITE_ENABLE_STAT3=1;SQLITE_ENABLE_FTS3=1;SQLITE_ENABLE_LOAD_EXTENSION=1;SQLITE_ENABLE_RTREE=1;SQLITE_SOUNDEX=1 SQLITE_HAS_CODEC=1 SQLITE_OMIT_WAL=1 SQLITE_DEBUG=1;SQLITE_MEMDEBUG=1;SQLITE_ENABLE_EXPENSIVE_ASSERT=1 SQLITE_WIN32_MALLOC=1 Index: SQLite.Interop/props/sqlite3.vsprops ================================================================== --- SQLite.Interop/props/sqlite3.vsprops +++ SQLite.Interop/props/sqlite3.vsprops @@ -12,16 +12,16 @@ Version="8.00" Name="sqlite3" > pPage1->aData[32]), @@ -56882,16 +56869,11 @@ /* ** Parameter zSrcData points to a buffer containing the data for ** page iSrcPg from the source database. Copy this data into the ** destination database. */ -static int backupOnePage( - sqlite3_backup *p, /* Backup handle */ - Pgno iSrcPg, /* Source database page to backup */ - const u8 *zSrcData, /* Source database page data */ - int bUpdate /* True for an update, false otherwise */ -){ +static int backupOnePage(sqlite3_backup *p, Pgno iSrcPg, const u8 *zSrcData){ Pager * const pDestPager = sqlite3BtreePager(p->pDest); const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc); int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); const int nCopy = MIN(nSrcPgsz, nDestPgsz); const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; @@ -56960,13 +56942,10 @@ ** cached parse of the page). MemPage.isInit is marked ** "MUST BE FIRST" for this purpose. */ memcpy(zOut, zIn, nCopy); ((u8 *)sqlite3PagerGetExtra(pDestPg))[0] = 0; - if( iOff==0 && bUpdate==0 ){ - sqlite3Put4byte(&zOut[28], sqlite3BtreeLastPage(p->pSrc)); - } } sqlite3PagerUnref(pDestPg); } return rc; @@ -57069,11 +57048,11 @@ const Pgno iSrcPg = p->iNext; /* Source page number */ if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){ DbPage *pSrcPg; /* Source page object */ rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg); if( rc==SQLITE_OK ){ - rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg), 0); + rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg)); sqlite3PagerUnref(pSrcPg); } } p->iNext++; } @@ -57317,11 +57296,11 @@ ** the new data into the backup. */ int rc; assert( p->pDestDb ); sqlite3_mutex_enter(p->pDestDb->mutex); - rc = backupOnePage(p, iPage, aData, 1); + rc = backupOnePage(p, iPage, aData); sqlite3_mutex_leave(p->pDestDb->mutex); assert( rc!=SQLITE_BUSY && rc!=SQLITE_LOCKED ); if( rc!=SQLITE_OK ){ p->rc = rc; } @@ -71911,18 +71890,10 @@ p->pReal = pReal; if( p->iSize>0 ){ assert(p->iSize<=p->nBuf); rc = sqlite3OsWrite(p->pReal, p->zBuf, p->iSize, 0); } - if( rc!=SQLITE_OK ){ - /* If an error occurred while writing to the file, close it before - ** returning. This way, SQLite uses the in-memory journal data to - ** roll back changes made to the internal page-cache before this - ** function was called. */ - sqlite3OsClose(pReal); - p->pReal = 0; - } } } return rc; } @@ -72665,39 +72636,10 @@ } } return 0; } -/* -** Subqueries stores the original database, table and column names for their -** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN". -** Check to see if the zSpan given to this routine matches the zDb, zTab, -** and zCol. If any of zDb, zTab, and zCol are NULL then those fields will -** match anything. -*/ -SQLITE_PRIVATE int sqlite3MatchSpanName( - const char *zSpan, - const char *zCol, - const char *zTab, - const char *zDb -){ - int n; - for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){} - if( zDb && sqlite3StrNICmp(zSpan, zDb, n)!=0 ){ - return 0; - } - zSpan += n+1; - for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){} - if( zTab && sqlite3StrNICmp(zSpan, zTab, n)!=0 ){ - return 0; - } - zSpan += n+1; - if( zCol && sqlite3StrICmp(zSpan, zCol)!=0 ){ - return 0; - } - return 1; -} /* ** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up ** that name in the set of source tables in pSrcList and make the pExpr ** expression node refer back to that source column. The following changes @@ -72750,62 +72692,43 @@ /* Initialize the node to no-match */ pExpr->iTable = -1; pExpr->pTab = 0; ExprSetIrreducible(pExpr); - /* Translate the schema name in zDb into a pointer to the corresponding - ** schema. If not found, pSchema will remain NULL and nothing will match - ** resulting in an appropriate error message toward the end of this routine - */ - if( zDb ){ - for(i=0; inDb; i++){ - assert( db->aDb[i].zName ); - if( sqlite3StrICmp(db->aDb[i].zName,zDb)==0 ){ - pSchema = db->aDb[i].pSchema; - break; - } - } - } - /* Start at the inner-most context and move outward until a match is found */ while( pNC && cnt==0 ){ ExprList *pEList; SrcList *pSrcList = pNC->pSrcList; if( pSrcList ){ for(i=0, pItem=pSrcList->a; inSrc; i++, pItem++){ Table *pTab; + int iDb; Column *pCol; pTab = pItem->pTab; assert( pTab!=0 && pTab->zName!=0 ); + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( pTab->nCol>0 ); - if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){ - ExprList *pEList = pItem->pSelect->pEList; - int hit = 0; - for(j=0; jnExpr; j++){ - if( sqlite3MatchSpanName(pEList->a[j].zSpan, zCol, zTab, zDb) ){ - cnt++; - cntTab = 2; - pMatch = pItem; - pExpr->iColumn = j; - hit = 1; - } - } - if( hit || zTab==0 ) continue; - } - if( zDb && pTab->pSchema!=pSchema ){ - continue; - } if( zTab ){ - const char *zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName; - assert( zTabName!=0 ); - if( sqlite3StrICmp(zTabName, zTab)!=0 ){ - continue; + if( pItem->zAlias ){ + char *zTabName = pItem->zAlias; + if( sqlite3StrICmp(zTabName, zTab)!=0 ) continue; + }else{ + char *zTabName = pTab->zName; + if( NEVER(zTabName==0) || sqlite3StrICmp(zTabName, zTab)!=0 ){ + continue; + } + if( zDb!=0 && sqlite3StrICmp(db->aDb[iDb].zName, zDb)!=0 ){ + continue; + } } } if( 0==(cntTab++) ){ + pExpr->iTable = pItem->iCursor; + pExpr->pTab = pTab; + pSchema = pTab->pSchema; pMatch = pItem; } for(j=0, pCol=pTab->aCol; jnCol; j++, pCol++){ if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ /* If there has been exactly one prior match and this match @@ -72815,23 +72738,21 @@ if( cnt==1 ){ if( pItem->jointype & JT_NATURAL ) continue; if( nameInUsingClause(pItem->pUsing, zCol) ) continue; } cnt++; + pExpr->iTable = pItem->iCursor; + pExpr->pTab = pTab; pMatch = pItem; + pSchema = pTab->pSchema; /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j; break; } } } - if( pMatch ){ - pExpr->iTable = pMatch->iCursor; - pExpr->pTab = pMatch->pTab; - pSchema = pExpr->pTab->pSchema; - } - } /* if( pSrcList ) */ + } #ifndef SQLITE_OMIT_TRIGGER /* If we have not already resolved the name, then maybe ** it is a new.* or old.* trigger argument reference */ @@ -73597,10 +73518,27 @@ sNC.pParse = pParse; if( sqlite3ResolveExprNames(&sNC, p->pLimit) || sqlite3ResolveExprNames(&sNC, p->pOffset) ){ return WRC_Abort; } + + /* Set up the local name-context to pass to sqlite3ResolveExprNames() to + ** resolve the result-set expression list. + */ + sNC.ncFlags = NC_AllowAgg; + sNC.pSrcList = p->pSrc; + sNC.pNext = pOuterNC; + + /* Resolve names in the result set. */ + pEList = p->pEList; + assert( pEList!=0 ); + for(i=0; inExpr; i++){ + Expr *pX = pEList->a[i].pExpr; + if( sqlite3ResolveExprNames(&sNC, pX) ){ + return WRC_Abort; + } + } /* Recursively resolve names in all subqueries */ for(i=0; ipSrc->nSrc; i++){ struct SrcList_item *pItem = &p->pSrc->a[i]; @@ -73625,27 +73563,10 @@ assert( pItem->isCorrelated==0 && nRef<=0 ); pItem->isCorrelated = (nRef!=0); } } - /* Set up the local name-context to pass to sqlite3ResolveExprNames() to - ** resolve the result-set expression list. - */ - sNC.ncFlags = NC_AllowAgg; - sNC.pSrcList = p->pSrc; - sNC.pNext = pOuterNC; - - /* Resolve names in the result set. */ - pEList = p->pEList; - assert( pEList!=0 ); - for(i=0; inExpr; i++){ - Expr *pX = pEList->a[i].pExpr; - if( sqlite3ResolveExprNames(&sNC, pX) ){ - return WRC_Abort; - } - } - /* If there are no aggregate functions in the result-set, and no GROUP BY ** expression, do not allow aggregates in any of the other expressions. */ assert( (p->selFlags & SF_Aggregate)==0 ); pGroupBy = p->pGroupBy; @@ -77125,16 +77046,10 @@ for(i=0; inExpr; i++){ sqlite3ExplainPrintf(pOut, "item[%d] = ", i); sqlite3ExplainPush(pOut); sqlite3ExplainExpr(pOut, pList->a[i].pExpr); sqlite3ExplainPop(pOut); - if( pList->a[i].zName ){ - sqlite3ExplainPrintf(pOut, " AS %s", pList->a[i].zName); - } - if( pList->a[i].bSpanIsTab ){ - sqlite3ExplainPrintf(pOut, " (%s)", pList->a[i].zSpan); - } if( inExpr-1 ){ sqlite3ExplainNL(pOut); } } sqlite3ExplainPop(pOut); @@ -87608,11 +87523,11 @@ /* ** A foreign key constraint requires that the key columns in the parent ** table are collectively subject to a UNIQUE or PRIMARY KEY constraint. ** Given that pParent is the parent table for foreign key constraint pFKey, -** search the schema for a unique index on the parent key columns. +** search the schema a unique index on the parent key columns. ** ** If successful, zero is returned. If the parent key is an INTEGER PRIMARY ** KEY column, then output variable *ppIdx is set to NULL. Otherwise, *ppIdx ** is set to point to the unique index. ** @@ -87644,11 +87559,11 @@ ** ** then non-zero is returned, and a "foreign key mismatch" error loaded ** into pParse. If an OOM error occurs, non-zero is returned and the ** pParse->db->mallocFailed flag is set. */ -SQLITE_PRIVATE int sqlite3FkLocateIndex( +static int locateFkeyIndex( Parse *pParse, /* Parse context to store any error in */ Table *pParent, /* Parent table of FK constraint pFKey */ FKey *pFKey, /* Foreign key to find index for */ Index **ppIdx, /* OUT: Unique index on parent table */ int **paiCol /* OUT: Map of index columns in pFKey */ @@ -87741,13 +87656,11 @@ } } if( !pIdx ){ if( !pParse->disableTriggers ){ - sqlite3ErrorMsg(pParse, - "foreign key mismatch - \"%w\" referencing \"%w\"", - pFKey->pFrom->zName, pFKey->zTo); + sqlite3ErrorMsg(pParse, "foreign key mismatch"); } sqlite3DbFree(pParse->db, aiCol); return 1; } @@ -88204,11 +88117,11 @@ if( pParse->disableTriggers ){ pTo = sqlite3FindTable(db, pFKey->zTo, zDb); }else{ pTo = sqlite3LocateTable(pParse, 0, pFKey->zTo, zDb); } - if( !pTo || sqlite3FkLocateIndex(pParse, pTo, pFKey, &pIdx, &aiFree) ){ + if( !pTo || locateFkeyIndex(pParse, pTo, pFKey, &pIdx, &aiFree) ){ assert( isIgnoreErrors==0 || (regOld!=0 && regNew==0) ); if( !isIgnoreErrors || db->mallocFailed ) return; if( pTo==0 ){ /* If isIgnoreErrors is true, then a table is being dropped. In this ** case SQLite runs a "DELETE FROM xxx" on the table being dropped @@ -88284,11 +88197,11 @@ /* Inserting a single row into a parent table cannot cause an immediate ** foreign key violation. So do nothing in this case. */ continue; } - if( sqlite3FkLocateIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ){ + if( locateFkeyIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ){ if( !isIgnoreErrors || db->mallocFailed ) return; continue; } assert( aiCol || pFKey->nCol==1 ); @@ -88339,11 +88252,11 @@ for(p=pTab->pFKey; p; p=p->pNextFrom){ for(i=0; inCol; i++) mask |= COLUMN_MASK(p->aCol[i].iFrom); } for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ Index *pIdx = 0; - sqlite3FkLocateIndex(pParse, pTab, p, &pIdx, 0); + locateFkeyIndex(pParse, pTab, p, &pIdx, 0); if( pIdx ){ for(i=0; inColumn; i++) mask |= COLUMN_MASK(pIdx->aiColumn[i]); } } } @@ -88465,11 +88378,11 @@ ExprList *pList = 0; /* Changes list if ON UPDATE CASCADE */ Select *pSelect = 0; /* If RESTRICT, "SELECT RAISE(...)" */ int i; /* Iterator variable */ Expr *pWhen = 0; /* WHEN clause for the trigger */ - if( sqlite3FkLocateIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ) return 0; + if( locateFkeyIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ) return 0; assert( aiCol || pFKey->nCol==1 ); for(i=0; inCol; i++){ Token tOld = { "old", 3 }; /* Literal "old" token */ Token tNew = { "new", 3 }; /* Literal "new" token */ @@ -92805,15 +92718,13 @@ if( sqlite3StrICmp(zLeft, "table_info")==0 && zRight ){ Table *pTab; if( sqlite3ReadSchema(pParse) ) goto pragma_out; pTab = sqlite3FindTable(db, zRight, zDb); if( pTab ){ - int i, k; + int i; int nHidden = 0; Column *pCol; - Index *pPk; - for(pPk=pTab->pIndex; pPk && pPk->autoIndex!=2; pPk=pPk->pNext){} sqlite3VdbeSetNumCols(v, 6); pParse->nMem = 6; sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", SQLITE_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC); sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", SQLITE_STATIC); @@ -92834,18 +92745,12 @@ if( pCol->zDflt ){ sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pCol->zDflt, 0); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, 5); } - if( (pCol->colFlags & COLFLAG_PRIMKEY)==0 ){ - k = 0; - }else if( pPk==0 ){ - k = 1; - }else{ - for(k=1; ALWAYS(k<=pTab->nCol) && pPk->aiColumn[k-1]!=i; k++){} - } - sqlite3VdbeAddOp2(v, OP_Integer, k, 6); + sqlite3VdbeAddOp2(v, OP_Integer, + (pCol->colFlags&COLFLAG_PRIMKEY)!=0, 6); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6); } } }else @@ -92976,124 +92881,10 @@ ++i; pFK = pFK->pNextFrom; } } } - }else -#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ - -#ifndef SQLITE_OMIT_FOREIGN_KEY - if( sqlite3StrICmp(zLeft, "foreign_key_check")==0 ){ - FKey *pFK; /* A foreign key constraint */ - Table *pTab; /* Child table contain "REFERENCES" keyword */ - Table *pParent; /* Parent table that child points to */ - Index *pIdx; /* Index in the parent table */ - int i; /* Loop counter: Foreign key number for pTab */ - int j; /* Loop counter: Field of the foreign key */ - HashElem *k; /* Loop counter: Next table in schema */ - int x; /* result variable */ - int regResult; /* 3 registers to hold a result row */ - int regKey; /* Register to hold key for checking the FK */ - int regRow; /* Registers to hold a row from pTab */ - int addrTop; /* Top of a loop checking foreign keys */ - int addrOk; /* Jump here if the key is OK */ - int *aiCols; /* child to parent column mapping */ - - if( sqlite3ReadSchema(pParse) ) goto pragma_out; - regResult = pParse->nMem+1; - pParse->nMem += 4; - regKey = ++pParse->nMem; - regRow = ++pParse->nMem; - v = sqlite3GetVdbe(pParse); - sqlite3VdbeSetNumCols(v, 4); - sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "table", SQLITE_STATIC); - sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "rowid", SQLITE_STATIC); - sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "parent", SQLITE_STATIC); - sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "fkid", SQLITE_STATIC); - sqlite3CodeVerifySchema(pParse, iDb); - k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash); - while( k ){ - if( zRight ){ - pTab = sqlite3LocateTable(pParse, 0, zRight, zDb); - k = 0; - }else{ - pTab = (Table*)sqliteHashData(k); - k = sqliteHashNext(k); - } - if( pTab==0 || pTab->pFKey==0 ) continue; - sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); - if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow; - sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead); - sqlite3VdbeAddOp4(v, OP_String8, 0, regResult, 0, pTab->zName, - P4_TRANSIENT); - for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){ - pParent = sqlite3LocateTable(pParse, 0, pFK->zTo, zDb); - if( pParent==0 ) break; - pIdx = 0; - sqlite3TableLock(pParse, iDb, pParent->tnum, 0, pParent->zName); - x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, 0); - if( x==0 ){ - if( pIdx==0 ){ - sqlite3OpenTable(pParse, i, iDb, pParent, OP_OpenRead); - }else{ - KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); - sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iDb); - sqlite3VdbeChangeP4(v, -1, (char*)pKey, P4_KEYINFO_HANDOFF); - } - }else{ - k = 0; - break; - } - } - if( pFK ) break; - if( pParse->nTabnTab = i; - addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, 0); - for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){ - pParent = sqlite3LocateTable(pParse, 0, pFK->zTo, zDb); - assert( pParent!=0 ); - pIdx = 0; - aiCols = 0; - x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, &aiCols); - assert( x==0 ); - addrOk = sqlite3VdbeMakeLabel(v); - if( pIdx==0 ){ - int iKey = pFK->aCol[0].iFrom; - assert( iKey>=0 && iKeynCol ); - if( iKey!=pTab->iPKey ){ - sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow); - sqlite3ColumnDefault(v, pTab, iKey, regRow); - sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk); - sqlite3VdbeAddOp2(v, OP_MustBeInt, regRow, - sqlite3VdbeCurrentAddr(v)+3); - }else{ - sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow); - } - sqlite3VdbeAddOp3(v, OP_NotExists, i, 0, regRow); - sqlite3VdbeAddOp2(v, OP_Goto, 0, addrOk); - sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); - }else{ - for(j=0; jnCol; j++){ - sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, - aiCols ? aiCols[j] : pFK->aCol[0].iFrom, regRow+j); - sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); - } - sqlite3VdbeAddOp3(v, OP_MakeRecord, regRow, pFK->nCol, regKey); - sqlite3VdbeChangeP4(v, -1, - sqlite3IndexAffinityStr(v,pIdx), P4_TRANSIENT); - sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0); - } - sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1); - sqlite3VdbeAddOp4(v, OP_String8, 0, regResult+2, 0, - pFK->zTo, P4_TRANSIENT); - sqlite3VdbeAddOp2(v, OP_Integer, i-1, regResult+3); - sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 4); - sqlite3VdbeResolveLabel(v, addrOk); - sqlite3DbFree(db, aiCols); - } - sqlite3VdbeAddOp2(v, OP_Next, 0, addrTop+1); - sqlite3VdbeJumpHere(v, addrTop); - } }else #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ #ifndef NDEBUG if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){ @@ -94549,11 +94340,11 @@ SrcList *pSrc, /* the FROM clause -- which tables to scan */ Expr *pWhere, /* the WHERE clause */ ExprList *pGroupBy, /* the GROUP BY clause */ Expr *pHaving, /* the HAVING clause */ ExprList *pOrderBy, /* the ORDER BY clause */ - u16 selFlags, /* Flag parameters, such as SF_Distinct */ + int isDistinct, /* true if the DISTINCT keyword is present */ Expr *pLimit, /* LIMIT value. NULL means not used */ Expr *pOffset /* OFFSET value. NULL means no offset */ ){ Select *pNew; Select standin; @@ -94573,11 +94364,11 @@ pNew->pSrc = pSrc; pNew->pWhere = pWhere; pNew->pGroupBy = pGroupBy; pNew->pHaving = pHaving; pNew->pOrderBy = pOrderBy; - pNew->selFlags = selFlags; + pNew->selFlags = isDistinct ? SF_Distinct : 0; pNew->op = TK_SELECT; pNew->pLimit = pLimit; pNew->pOffset = pOffset; assert( pOffset==0 || pLimit!=0 ); pNew->addrOpenEphm[0] = -1; @@ -95830,10 +95621,12 @@ for(i=0, pCol=aCol; ia[i].pExpr); + assert( p->pRight==0 || ExprHasProperty(p->pRight, EP_IntValue) + || p->pRight->u.zToken==0 || p->pRight->u.zToken[0]!=0 ); if( (zName = pEList->a[i].zName)!=0 ){ /* If the column contains an "AS " phrase, use as the name */ zName = sqlite3DbStrDup(db, zName); }else{ Expr *pColExpr = p; /* The expression that is the result column name */ @@ -95867,13 +95660,10 @@ */ nName = sqlite3Strlen30(zName); for(j=cnt=0; j1 && sqlite3Isdigit(zName[k]); k--){} - if( zName[k]==':' ) nName = k; zName[nName] = 0; zNewName = sqlite3MPrintf(db, "%s:%d", zName, ++cnt); sqlite3DbFree(db, zName); zName = zNewName; j = -1; @@ -97655,47 +97445,38 @@ return 1; } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ /* -** Based on the contents of the AggInfo structure indicated by the first -** argument, this function checks if the following are true: -** -** * the query contains just a single aggregate function, -** * the aggregate function is either min() or max(), and -** * the argument to the aggregate function is a column value. -** -** If all of the above are true, then WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX -** is returned as appropriate. Also, *ppMinMax is set to point to the -** list of arguments passed to the aggregate before returning. -** -** Or, if the conditions above are not met, *ppMinMax is set to 0 and -** WHERE_ORDERBY_NORMAL is returned. -*/ -static u8 minMaxQuery(AggInfo *pAggInfo, ExprList **ppMinMax){ - int eRet = WHERE_ORDERBY_NORMAL; /* Return value */ - - *ppMinMax = 0; - if( pAggInfo->nFunc==1 ){ - Expr *pExpr = pAggInfo->aFunc[0].pExpr; /* Aggregate function */ - ExprList *pEList = pExpr->x.pList; /* Arguments to agg function */ - - assert( pExpr->op==TK_AGG_FUNCTION ); - if( pEList && pEList->nExpr==1 && pEList->a[0].pExpr->op==TK_AGG_COLUMN ){ - const char *zFunc = pExpr->u.zToken; - if( sqlite3StrICmp(zFunc, "min")==0 ){ - eRet = WHERE_ORDERBY_MIN; - *ppMinMax = pEList; - }else if( sqlite3StrICmp(zFunc, "max")==0 ){ - eRet = WHERE_ORDERBY_MAX; - *ppMinMax = pEList; - } - } - } - - assert( *ppMinMax==0 || (*ppMinMax)->nExpr==1 ); - return eRet; +** Analyze the SELECT statement passed as an argument to see if it +** is a min() or max() query. Return WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX if +** it is, or 0 otherwise. At present, a query is considered to be +** a min()/max() query if: +** +** 1. There is a single object in the FROM clause. +** +** 2. There is a single expression in the result set, and it is +** either min(x) or max(x), where x is a column reference. +*/ +static u8 minMaxQuery(Select *p){ + Expr *pExpr; + ExprList *pEList = p->pEList; + + if( pEList->nExpr!=1 ) return WHERE_ORDERBY_NORMAL; + pExpr = pEList->a[0].pExpr; + if( pExpr->op!=TK_AGG_FUNCTION ) return 0; + if( NEVER(ExprHasProperty(pExpr, EP_xIsSelect)) ) return 0; + pEList = pExpr->x.pList; + if( pEList==0 || pEList->nExpr!=1 ) return 0; + if( pEList->a[0].pExpr->op!=TK_AGG_COLUMN ) return WHERE_ORDERBY_NORMAL; + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + if( sqlite3StrICmp(pExpr->u.zToken,"min")==0 ){ + return WHERE_ORDERBY_MIN; + }else if( sqlite3StrICmp(pExpr->u.zToken,"max")==0 ){ + return WHERE_ORDERBY_MAX; + } + return WHERE_ORDERBY_NORMAL; } /* ** The select statement passed as the first argument is an aggregate query. ** The second argment is the associated aggregate-info object. This @@ -97786,11 +97567,10 @@ int i, j, k; SrcList *pTabList; ExprList *pEList; struct SrcList_item *pFrom; sqlite3 *db = pParse->db; - Expr *pE, *pRight, *pExpr; if( db->mallocFailed ){ return WRC_Abort; } if( NEVER(p->pSrc==0) || (p->selFlags & SF_Expanded)!=0 ){ @@ -97872,11 +97652,11 @@ ** ** The first loop just checks to see if there are any "*" operators ** that need expanding. */ for(k=0; knExpr; k++){ - pE = pEList->a[k].pExpr; + Expr *pE = pEList->a[k].pExpr; if( pE->op==TK_ALL ) break; assert( pE->op!=TK_DOT || pE->pRight!=0 ); assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) ); if( pE->op==TK_DOT && pE->pRight->op==TK_ALL ) break; } @@ -97890,22 +97670,14 @@ ExprList *pNew = 0; int flags = pParse->db->flags; int longNames = (flags & SQLITE_FullColNames)!=0 && (flags & SQLITE_ShortColNames)==0; - /* When processing FROM-clause subqueries, it is always the case - ** that full_column_names=OFF and short_column_names=ON. The - ** sqlite3ResultSetOfSelect() routine makes it so. */ - assert( (p->selFlags & SF_NestedFrom)==0 - || ((flags & SQLITE_FullColNames)==0 && - (flags & SQLITE_ShortColNames)!=0) ); - for(k=0; knExpr; k++){ - pE = a[k].pExpr; - pRight = pE->pRight; - assert( pE->op!=TK_DOT || pRight!=0 ); - if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pRight->op!=TK_ALL) ){ + Expr *pE = a[k].pExpr; + assert( pE->op!=TK_DOT || pE->pRight!=0 ); + if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pE->pRight->op!=TK_ALL) ){ /* This particular expression does not need to be expanded. */ pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr); if( pNew ){ pNew->a[pNew->nExpr-1].zName = a[k].zName; @@ -97916,56 +97688,44 @@ a[k].pExpr = 0; }else{ /* This expression is a "*" or a "TABLE.*" and needs to be ** expanded. */ int tableSeen = 0; /* Set to 1 when TABLE matches */ - char *zTName = 0; /* text of name of TABLE */ + char *zTName; /* text of name of TABLE */ if( pE->op==TK_DOT ){ assert( pE->pLeft!=0 ); assert( !ExprHasProperty(pE->pLeft, EP_IntValue) ); zTName = pE->pLeft->u.zToken; + }else{ + zTName = 0; } for(i=0, pFrom=pTabList->a; inSrc; i++, pFrom++){ Table *pTab = pFrom->pTab; - Select *pSub = pFrom->pSelect; char *zTabName = pFrom->zAlias; - const char *zSchemaName = 0; - int iDb; if( zTabName==0 ){ zTabName = pTab->zName; } if( db->mallocFailed ) break; - if( pSub==0 || (pSub->selFlags & SF_NestedFrom)==0 ){ - pSub = 0; - if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){ - continue; - } - iDb = sqlite3SchemaToIndex(db, pTab->pSchema); - zSchemaName = iDb>=0 ? db->aDb[iDb].zName : "*"; - } + if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){ + continue; + } + tableSeen = 1; for(j=0; jnCol; j++){ + Expr *pExpr, *pRight; char *zName = pTab->aCol[j].zName; char *zColname; /* The computed column name */ char *zToFree; /* Malloced string that needs to be freed */ Token sColname; /* Computed column name as a token */ - assert( zName ); - if( zTName && pSub - && sqlite3MatchSpanName(pSub->pEList->a[j].zSpan, 0, zTName, 0)==0 - ){ - continue; - } - /* If a column is marked as 'hidden' (currently only possible ** for virtual tables), do not include it in the expanded ** result-set list. */ if( IsHiddenColumn(&pTab->aCol[j]) ){ assert(IsVirtual(pTab)); continue; } - tableSeen = 1; if( i>0 && zTName==0 ){ if( (pFrom->jointype & JT_NATURAL)!=0 && tableAndColumnIndex(pTabList, i, zName, 0, 0) ){ @@ -97984,14 +97744,10 @@ zToFree = 0; if( longNames || pTabList->nSrc>1 ){ Expr *pLeft; pLeft = sqlite3Expr(db, TK_ID, zTabName); pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0); - if( zSchemaName ){ - pLeft = sqlite3Expr(db, TK_ID, zSchemaName); - pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr, 0); - } if( longNames ){ zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName); zToFree = zColname; } }else{ @@ -97999,22 +97755,10 @@ } pNew = sqlite3ExprListAppend(pParse, pNew, pExpr); sColname.z = zColname; sColname.n = sqlite3Strlen30(zColname); sqlite3ExprListSetName(pParse, pNew, &sColname, 0); - if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){ - struct ExprList_item *pX = &pNew->a[pNew->nExpr-1]; - if( pSub ){ - pX->zSpan = sqlite3DbStrDup(db, pSub->pEList->a[j].zSpan); - testcase( pX->zSpan==0 ); - }else{ - pX->zSpan = sqlite3MPrintf(db, "%s.%s.%s", - zSchemaName, zTabName, zColname); - testcase( pX->zSpan==0 ); - } - pX->bSpanIsTab = 1; - } sqlite3DbFree(db, zToFree); } } if( !tableSeen ){ if( zTName ){ @@ -99068,21 +98812,15 @@ ** index or indices to use) should place a different priority on ** satisfying the 'ORDER BY' clause than it does in other cases. ** Refer to code and comments in where.c for details. */ ExprList *pMinMax = 0; - u8 flag = WHERE_ORDERBY_NORMAL; - - assert( p->pGroupBy==0 ); - assert( flag==0 ); - if( p->pHaving==0 ){ - flag = minMaxQuery(&sAggInfo, &pMinMax); - } - assert( flag==0 || (pMinMax!=0 && pMinMax->nExpr==1) ); - + u8 flag = minMaxQuery(p); if( flag ){ - pMinMax = sqlite3ExprListDup(db, pMinMax, 0); + assert( !ExprHasProperty(p->pEList->a[0].pExpr, EP_xIsSelect) ); + assert( p->pEList->a[0].pExpr->x.pList->nExpr==1 ); + pMinMax = sqlite3ExprListDup(db, p->pEList->a[0].pExpr->x.pList,0); pDel = pMinMax; if( pMinMax && !db->mallocFailed ){ pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0; pMinMax->a[0].pExpr->op = TK_COLUMN; } @@ -102966,11 +102704,11 @@ #define WHERE_COLUMN_RANGE 0x00020000 /* xEXPR */ #define WHERE_COLUMN_IN 0x00040000 /* x IN (...) */ #define WHERE_COLUMN_NULL 0x00080000 /* x IS NULL */ #define WHERE_INDEXED 0x000f0000 /* Anything that uses an index */ #define WHERE_NOT_FULLSCAN 0x100f3000 /* Does not do a full table scan */ -#define WHERE_IN_ABLE 0x080f1000 /* Able to support an IN operator */ +#define WHERE_IN_ABLE 0x000f1000 /* Able to support an IN operator */ #define WHERE_TOP_LIMIT 0x00100000 /* xEXPR or x>=EXPR constraint */ #define WHERE_BOTH_LIMIT 0x00300000 /* Both x>EXPR and xa; inTerm; i++, pTerm++){ if( pTerm->leftCursor != pSrc->iCursor ) continue; assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 ); testcase( pTerm->eOperator==WO_IN ); testcase( pTerm->eOperator==WO_ISNULL ); - if( pTerm->eOperator & (WO_ISNULL) ) continue; + if( pTerm->eOperator & (WO_IN|WO_ISNULL) ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; nTerm++; } /* If the ORDER BY clause contains only columns in the current @@ -104818,32 +104556,29 @@ *(struct sqlite3_index_orderby**)&pIdxInfo->aOrderBy = pIdxOrderBy; *(struct sqlite3_index_constraint_usage**)&pIdxInfo->aConstraintUsage = pUsage; for(i=j=0, pTerm=pWC->a; inTerm; i++, pTerm++){ - u8 op; if( pTerm->leftCursor != pSrc->iCursor ) continue; assert( (pTerm->eOperator&(pTerm->eOperator-1))==0 ); testcase( pTerm->eOperator==WO_IN ); testcase( pTerm->eOperator==WO_ISNULL ); - if( pTerm->eOperator & (WO_ISNULL) ) continue; + if( pTerm->eOperator & (WO_IN|WO_ISNULL) ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; pIdxCons[j].iColumn = pTerm->u.leftColumn; pIdxCons[j].iTermOffset = i; - op = (u8)pTerm->eOperator; - if( op==WO_IN ) op = WO_EQ; - pIdxCons[j].op = op; + pIdxCons[j].op = (u8)pTerm->eOperator; /* The direct assignment in the previous line is possible only because ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The ** following asserts verify this fact. */ assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ ); assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT ); assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE ); assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT ); assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE ); assert( WO_MATCH==SQLITE_INDEX_CONSTRAINT_MATCH ); - assert( pTerm->eOperator & (WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) ); + assert( pTerm->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) ); j++; } for(i=0; ia[i].pExpr; pIdxOrderBy[i].iColumn = pExpr->iColumn; @@ -104925,11 +104660,10 @@ struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_constraint_usage *pUsage; WhereTerm *pTerm; int i, j; int nOrderBy; - int bAllowIN; /* Allow IN optimizations */ double rCost; /* Make sure wsFlags is initialized to some sane value. Otherwise, if the ** malloc in allocateIndexInfo() fails and this function returns leaving ** wsFlags in an uninitialized state, the caller may behave unpredictably. @@ -104960,91 +104694,63 @@ ** sqlite3ViewGetColumnNames() would have picked up the error. */ assert( pTab->azModuleArg && pTab->azModuleArg[0] ); assert( sqlite3GetVTable(pParse->db, pTab) ); - /* Try once or twice. On the first attempt, allow IN optimizations. - ** If an IN optimization is accepted by the virtual table xBestIndex - ** method, but the pInfo->aConstrainUsage.omit flag is not set, then - ** the query will not work because it might allow duplicate rows in - ** output. In that case, run the xBestIndex method a second time - ** without the IN constraints. Usually this loop only runs once. - ** The loop will exit using a "break" statement. - */ - for(bAllowIN=1; 1; bAllowIN--){ - assert( bAllowIN==0 || bAllowIN==1 ); - - /* Set the aConstraint[].usable fields and initialize all - ** output variables to zero. - ** - ** aConstraint[].usable is true for constraints where the right-hand - ** side contains only references to tables to the left of the current - ** table. In other words, if the constraint is of the form: - ** - ** column = expr - ** - ** and we are evaluating a join, then the constraint on column is - ** only valid if all tables referenced in expr occur to the left - ** of the table containing column. - ** - ** The aConstraints[] array contains entries for all constraints - ** on the current table. That way we only have to compute it once - ** even though we might try to pick the best index multiple times. - ** For each attempt at picking an index, the order of tables in the - ** join might be different so we have to recompute the usable flag - ** each time. - */ - pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; - pUsage = pIdxInfo->aConstraintUsage; - for(i=0; inConstraint; i++, pIdxCons++){ - j = pIdxCons->iTermOffset; - pTerm = &pWC->a[j]; - if( (pTerm->prereqRight&p->notReady)==0 - && (bAllowIN || pTerm->eOperator!=WO_IN) - ){ - pIdxCons->usable = 1; - }else{ - pIdxCons->usable = 0; - } - } - memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint); - if( pIdxInfo->needToFreeIdxStr ){ - sqlite3_free(pIdxInfo->idxStr); - } - pIdxInfo->idxStr = 0; - pIdxInfo->idxNum = 0; - pIdxInfo->needToFreeIdxStr = 0; - pIdxInfo->orderByConsumed = 0; - /* ((double)2) In case of SQLITE_OMIT_FLOATING_POINT... */ - pIdxInfo->estimatedCost = SQLITE_BIG_DBL / ((double)2); - nOrderBy = pIdxInfo->nOrderBy; - if( !p->pOrderBy ){ - pIdxInfo->nOrderBy = 0; - } - - if( vtabBestIndex(pParse, pTab, pIdxInfo) ){ - return; - } - - pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; - for(i=0; inConstraint; i++, pIdxCons++){ - if( pUsage[i].argvIndex>0 ){ - j = pIdxCons->iTermOffset; - pTerm = &pWC->a[j]; - p->cost.used |= pTerm->prereqRight; - if( pTerm->eOperator==WO_IN && pUsage[i].omit==0 ){ - /* Do not attempt to use an IN constraint if the virtual table - ** says that the equivalent EQ constraint cannot be safely omitted. - ** If we do attempt to use such a constraint, some rows might be - ** repeated in the output. */ - break; - } - } - } - if( i>=pIdxInfo->nConstraint ) break; - } - + /* Set the aConstraint[].usable fields and initialize all + ** output variables to zero. + ** + ** aConstraint[].usable is true for constraints where the right-hand + ** side contains only references to tables to the left of the current + ** table. In other words, if the constraint is of the form: + ** + ** column = expr + ** + ** and we are evaluating a join, then the constraint on column is + ** only valid if all tables referenced in expr occur to the left + ** of the table containing column. + ** + ** The aConstraints[] array contains entries for all constraints + ** on the current table. That way we only have to compute it once + ** even though we might try to pick the best index multiple times. + ** For each attempt at picking an index, the order of tables in the + ** join might be different so we have to recompute the usable flag + ** each time. + */ + pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; + pUsage = pIdxInfo->aConstraintUsage; + for(i=0; inConstraint; i++, pIdxCons++){ + j = pIdxCons->iTermOffset; + pTerm = &pWC->a[j]; + pIdxCons->usable = (pTerm->prereqRight&p->notReady) ? 0 : 1; + } + memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint); + if( pIdxInfo->needToFreeIdxStr ){ + sqlite3_free(pIdxInfo->idxStr); + } + pIdxInfo->idxStr = 0; + pIdxInfo->idxNum = 0; + pIdxInfo->needToFreeIdxStr = 0; + pIdxInfo->orderByConsumed = 0; + /* ((double)2) In case of SQLITE_OMIT_FLOATING_POINT... */ + pIdxInfo->estimatedCost = SQLITE_BIG_DBL / ((double)2); + nOrderBy = pIdxInfo->nOrderBy; + if( !p->pOrderBy ){ + pIdxInfo->nOrderBy = 0; + } + + if( vtabBestIndex(pParse, pTab, pIdxInfo) ){ + return; + } + + pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; + for(i=0; inConstraint; i++){ + if( pUsage[i].argvIndex>0 ){ + p->cost.used |= pWC->a[pIdxCons[i].iTermOffset].prereqRight; + } + } + /* If there is an ORDER BY clause, and the selected virtual table index ** does not satisfy it, increase the cost of the scan accordingly. This ** matches the processing for non-virtual tables in bestBtreeIndex(). */ rCost = pIdxInfo->estimatedCost; @@ -106015,11 +105721,11 @@ int bRev = 2; WHERETRACE((" --> before isSortingIndex: nPriorSat=%d\n",nPriorSat)); pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev); WHERETRACE((" --> after isSortingIndex: bRev=%d nOBSat=%d\n", bRev, pc.plan.nOBSat)); - if( nPriorSatplan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){ /* Case 0: The table is a virtual-table. Use the VFilter and VNext ** to access the data. */ int iReg; /* P3 Value for OP_VFilter */ - int addrNotFound; sqlite3_index_info *pVtabIdx = pLevel->plan.u.pVtabIdx; int nConstraint = pVtabIdx->nConstraint; struct sqlite3_index_constraint_usage *aUsage = pVtabIdx->aConstraintUsage; const struct sqlite3_index_constraint *aConstraint = pVtabIdx->aConstraint; sqlite3ExprCachePush(pParse); iReg = sqlite3GetTempRange(pParse, nConstraint+2); - addrNotFound = pLevel->addrBrk; for(j=1; j<=nConstraint; j++){ for(k=0; ka[aConstraint[k].iTermOffset]; - int iTarget = iReg+j+1; - if( pTerm->eOperator & WO_IN ){ - codeEqualityTerm(pParse, pTerm, pLevel, iTarget); - addrNotFound = pLevel->addrNxt; - }else{ - sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget); - } + int iTerm = aConstraint[k].iTermOffset; + sqlite3ExprCode(pParse, pWC->a[iTerm].pExpr->pRight, iReg+j+1); break; } } if( k==nConstraint ) break; } sqlite3VdbeAddOp2(v, OP_Integer, pVtabIdx->idxNum, iReg); sqlite3VdbeAddOp2(v, OP_Integer, j-1, iReg+1); - sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg, pVtabIdx->idxStr, + sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrBrk, iReg, pVtabIdx->idxStr, pVtabIdx->needToFreeIdxStr ? P4_MPRINTF : P4_STATIC); pVtabIdx->needToFreeIdxStr = 0; for(j=0; jnSrc==1 ){ - yygotominor.yy347 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy347,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy122,yymsp[0].minor.yy180); - if( yygotominor.yy347 ){ - struct SrcList_item *pNew = &yygotominor.yy347->a[yygotominor.yy347->nSrc-1]; - struct SrcList_item *pOld = yymsp[-4].minor.yy347->a; - pNew->zName = pOld->zName; - pNew->zDatabase = pOld->zDatabase; - pOld->zName = pOld->zDatabase = 0; - } - sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy347); }else{ Select *pSubquery; sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy347); - pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy347,0,0,0,0,SF_NestedFrom,0,0); + pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy347,0,0,0,0,0,0,0); yygotominor.yy347 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy347,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy122,yymsp[0].minor.yy180); } } break; case 137: /* dbnm ::= */ @@ -111008,11 +110691,11 @@ if( yymsp[-1].minor.yy442 && yymsp[-1].minor.yy442->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){ sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0); } yygotominor.yy342.pExpr = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy442, &yymsp[-4].minor.yy0); spanSet(&yygotominor.yy342,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); - if( yymsp[-2].minor.yy305 && yygotominor.yy342.pExpr ){ + if( yymsp[-2].minor.yy392 && yygotominor.yy342.pExpr ){ yygotominor.yy342.pExpr->flags |= EP_Distinct; } } break; case 197: /* expr ::= ID LP STAR RP */ Index: SQLite.Interop/src/core/sqlite3.h ================================================================== --- SQLite.Interop/src/core/sqlite3.h +++ SQLite.Interop/src/core/sqlite3.h @@ -105,13 +105,13 @@ ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.7.16" -#define SQLITE_VERSION_NUMBER 3007016 -#define SQLITE_SOURCE_ID "2013-01-04 19:22:33 8285b15a058811a9a8b452837f52e6a065868115" +#define SQLITE_VERSION "3.7.15.2" +#define SQLITE_VERSION_NUMBER 3007015 +#define SQLITE_SOURCE_ID "2013-01-09 11:53:05 c0e09560d26f0a6456be9dd3447f5311eb4f238f" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version, sqlite3_sourceid ** Index: readme.htm ================================================================== --- readme.htm +++ readme.htm @@ -3,12 +3,12 @@ ADO.NET SQLite Data Provider
    -Version 1.0.84.0 March XX, 2013 (release scheduled)
    -Using SQLite 3.7.16
    +Version 1.0.84.0 January 9, 2013
    +Using SQLite 3.7.15.2
    Originally written by Robert Simpson
    Released to the public domain, use at your own risk!
    Official provider website: http://system.data.sqlite.org/
    Legacy versions: http://sqlite.phxsoftware.com/

    @@ -185,14 +185,15 @@

    Version History

    - 1.0.84.0 - March XX, 2013 (release scheduled) + 1.0.84.0 - January 9, 2013

      -
    • Updated to SQLite 3.7.16.
    • +
    • Updated to SQLite 3.7.15.2.
    • +
    • Explicitly dispose of all SQLiteCommand objects managed by the DbDataAdapter class. Fix for [6434e23a0f].
    • Add Cancel method to the SQLiteConnection class to interrupt a long running query.
    • Improve thread safety of the SQLiteLog.LogMessage method.

    1.0.83.0 - December 29, 2012 Index: www/news.wiki ================================================================== --- www/news.wiki +++ www/news.wiki @@ -1,14 +1,15 @@ News Version History

    - 1.0.84.0 - March XX, 2013 (release scheduled) + 1.0.84.0 - January 9, 2013

      -
    • Updated to SQLite 3.7.16.
    • +
    • Updated to SQLite 3.7.15.2.
    • +
    • Explicitly dispose of all SQLiteCommand objects managed by the DbDataAdapter class. Fix for [6434e23a0f].
    • Add Cancel method to the SQLiteConnection class to interrupt a long running query.
    • Improve thread safety of the SQLiteLog.LogMessage method.

    1.0.83.0 - December 29, 2012