summaryrefslogtreecommitdiffstats
path: root/lib/libsqlite3/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libsqlite3/src')
-rw-r--r--lib/libsqlite3/src/alter.c6
-rw-r--r--lib/libsqlite3/src/attach.c8
-rw-r--r--lib/libsqlite3/src/backup.c19
-rw-r--r--lib/libsqlite3/src/btree.c36
-rw-r--r--lib/libsqlite3/src/btree.h5
-rw-r--r--lib/libsqlite3/src/build.c72
-rw-r--r--lib/libsqlite3/src/callback.c12
-rw-r--r--lib/libsqlite3/src/ctime.c3
-rw-r--r--lib/libsqlite3/src/delete.c7
-rw-r--r--lib/libsqlite3/src/expr.c216
-rw-r--r--lib/libsqlite3/src/fkey.c8
-rw-r--r--lib/libsqlite3/src/func.c120
-rw-r--r--lib/libsqlite3/src/global.c9
-rw-r--r--lib/libsqlite3/src/hash.c2
-rw-r--r--lib/libsqlite3/src/insert.c144
-rw-r--r--lib/libsqlite3/src/journal.c10
-rw-r--r--lib/libsqlite3/src/lempar.c1
-rw-r--r--lib/libsqlite3/src/main.c52
-rw-r--r--lib/libsqlite3/src/os_unix.c149
-rw-r--r--lib/libsqlite3/src/os_win.c336
-rw-r--r--lib/libsqlite3/src/pager.c49
-rw-r--r--lib/libsqlite3/src/pager.h14
-rw-r--r--lib/libsqlite3/src/pragma.c25
-rw-r--r--lib/libsqlite3/src/prepare.c2
-rw-r--r--lib/libsqlite3/src/resolve.c66
-rw-r--r--lib/libsqlite3/src/select.c266
-rw-r--r--lib/libsqlite3/src/sqlite.h.in65
-rw-r--r--lib/libsqlite3/src/sqliteInt.h249
-rw-r--r--lib/libsqlite3/src/status.c3
-rw-r--r--lib/libsqlite3/src/tclsqlite.c21
-rw-r--r--lib/libsqlite3/src/test1.c47
-rw-r--r--lib/libsqlite3/src/test6.c23
-rw-r--r--lib/libsqlite3/src/test_intarray.c5
-rw-r--r--lib/libsqlite3/src/test_intarray.h11
-rw-r--r--lib/libsqlite3/src/test_malloc.c48
-rw-r--r--lib/libsqlite3/src/test_multiplex.h8
-rw-r--r--lib/libsqlite3/src/test_quota.c17
-rw-r--r--lib/libsqlite3/src/test_sqllog.c472
-rw-r--r--lib/libsqlite3/src/test_vfstrace.c4
-rw-r--r--lib/libsqlite3/src/trigger.c9
-rw-r--r--lib/libsqlite3/src/utf.c16
-rw-r--r--lib/libsqlite3/src/vacuum.c1
-rw-r--r--lib/libsqlite3/src/vdbe.c112
-rw-r--r--lib/libsqlite3/src/vdbe.h2
-rw-r--r--lib/libsqlite3/src/vdbeInt.h27
-rw-r--r--lib/libsqlite3/src/vdbeapi.c2
-rw-r--r--lib/libsqlite3/src/vdbeaux.c86
-rw-r--r--lib/libsqlite3/src/vdbesort.c7
-rw-r--r--lib/libsqlite3/src/vtab.c12
-rw-r--r--lib/libsqlite3/src/wal.c4
-rw-r--r--lib/libsqlite3/src/where.c1281
51 files changed, 2897 insertions, 1272 deletions
diff --git a/lib/libsqlite3/src/alter.c b/lib/libsqlite3/src/alter.c
index 7f56ce7e0bc..a49d3349d7e 100644
--- a/lib/libsqlite3/src/alter.c
+++ b/lib/libsqlite3/src/alter.c
@@ -414,7 +414,7 @@ void sqlite3AlterRenameTable(
assert( pSrc->nSrc==1 );
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
- pTab = sqlite3LocateTable(pParse, 0, pSrc->a[0].zName, pSrc->a[0].zDatabase);
+ pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
if( !pTab ) goto exit_rename_table;
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
zDb = db->aDb[iDb].zName;
@@ -664,7 +664,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
** If there is a NOT NULL constraint, then the default value for the
** column must not be NULL.
*/
- if( pCol->isPrimKey ){
+ if( pCol->colFlags & COLFLAG_PRIMKEY ){
sqlite3ErrorMsg(pParse, "Cannot add a PRIMARY KEY column");
return;
}
@@ -757,7 +757,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
assert( pParse->pNewTable==0 );
assert( sqlite3BtreeHoldsAllMutexes(db) );
if( db->mallocFailed ) goto exit_begin_add_column;
- pTab = sqlite3LocateTable(pParse, 0, pSrc->a[0].zName, pSrc->a[0].zDatabase);
+ pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
if( !pTab ) goto exit_begin_add_column;
#ifndef SQLITE_OMIT_VIRTUALTABLE
diff --git a/lib/libsqlite3/src/attach.c b/lib/libsqlite3/src/attach.c
index e295c30111b..6682c914754 100644
--- a/lib/libsqlite3/src/attach.c
+++ b/lib/libsqlite3/src/attach.c
@@ -434,6 +434,7 @@ int sqlite3FixInit(
assert( db->nDb>iDb );
pFix->pParse = pParse;
pFix->zDb = db->aDb[iDb].zName;
+ pFix->pSchema = db->aDb[iDb].pSchema;
pFix->zType = zType;
pFix->pName = pName;
return 1;
@@ -464,14 +465,15 @@ int sqlite3FixSrcList(
if( NEVER(pList==0) ) return 0;
zDb = pFix->zDb;
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
- if( pItem->zDatabase==0 ){
- pItem->zDatabase = sqlite3DbStrDup(pFix->pParse->db, zDb);
- }else if( sqlite3StrICmp(pItem->zDatabase,zDb)!=0 ){
+ if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){
sqlite3ErrorMsg(pFix->pParse,
"%s %T cannot reference objects in database %s",
pFix->zType, pFix->pName, pItem->zDatabase);
return 1;
}
+ sqlite3DbFree(pFix->pParse->db, pItem->zDatabase);
+ pItem->zDatabase = 0;
+ pItem->pSchema = pFix->pSchema;
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
diff --git a/lib/libsqlite3/src/backup.c b/lib/libsqlite3/src/backup.c
index 4881215e961..b234716d61d 100644
--- a/lib/libsqlite3/src/backup.c
+++ b/lib/libsqlite3/src/backup.c
@@ -219,13 +219,16 @@ static int backupOnePage(sqlite3_backup *p, Pgno iSrcPg, const u8 *zSrcData){
const int nCopy = MIN(nSrcPgsz, nDestPgsz);
const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz;
#ifdef SQLITE_HAS_CODEC
- int nSrcReserve = sqlite3BtreeGetReserve(p->pSrc);
+ /* Use BtreeGetReserveNoMutex() for the source b-tree, as although it is
+ ** guaranteed that the shared-mutex is held by this thread, handle
+ ** p->pSrc may not actually be the owner. */
+ int nSrcReserve = sqlite3BtreeGetReserveNoMutex(p->pSrc);
int nDestReserve = sqlite3BtreeGetReserve(p->pDest);
#endif
-
int rc = SQLITE_OK;
i64 iOff;
+ assert( sqlite3BtreeGetReserveNoMutex(p->pSrc)>=0 );
assert( p->bDestLocked );
assert( !isFatalError(p->rc) );
assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) );
@@ -410,7 +413,13 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
** same schema version.
*/
if( rc==SQLITE_DONE ){
- rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1);
+ if( nSrcPage==0 ){
+ rc = sqlite3BtreeNewDb(p->pDest);
+ nSrcPage = 1;
+ }
+ if( rc==SQLITE_OK || rc==SQLITE_DONE ){
+ rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1);
+ }
if( rc==SQLITE_OK ){
if( p->pDestDb ){
sqlite3ResetAllSchemasOfConnection(p->pDestDb);
@@ -444,6 +453,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
}else{
nDestTruncate = nSrcPage * (pgszSrc/pgszDest);
}
+ assert( nDestTruncate>0 );
sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
if( pgszSrc<pgszDest ){
@@ -462,7 +472,8 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
i64 iEnd;
assert( pFile );
- assert( (i64)nDestTruncate*(i64)pgszDest >= iSize || (
+ assert( nDestTruncate==0
+ || (i64)nDestTruncate*(i64)pgszDest >= iSize || (
nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
&& iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
));
diff --git a/lib/libsqlite3/src/btree.c b/lib/libsqlite3/src/btree.c
index d34d6ee0b19..246843b79e3 100644
--- a/lib/libsqlite3/src/btree.c
+++ b/lib/libsqlite3/src/btree.c
@@ -2200,6 +2200,24 @@ int sqlite3BtreeGetPageSize(Btree *p){
return p->pBt->pageSize;
}
+#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_DEBUG)
+/*
+** This function is similar to sqlite3BtreeGetReserve(), except that it
+** may only be called if it is guaranteed that the b-tree mutex is already
+** held.
+**
+** This is useful in one special case in the backup API code where it is
+** known that the shared b-tree mutex is held, but the mutex on the
+** database handle that owns *p is not. In this case if sqlite3BtreeEnter()
+** were to be called, it might collide with some other operation on the
+** database handle that owns *p, causing undefined behaviour.
+*/
+int sqlite3BtreeGetReserveNoMutex(Btree *p){
+ assert( sqlite3_mutex_held(p->pBt->mutex) );
+ return p->pBt->pageSize - p->pBt->usableSize;
+}
+#endif /* SQLITE_HAS_CODEC || SQLITE_DEBUG */
+
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM)
/*
** Return the number of bytes of space at the end of every page that
@@ -2514,6 +2532,20 @@ static int newDatabase(BtShared *pBt){
}
/*
+** Initialize the first page of the database file (creating a database
+** consisting of a single page and no schema objects). Return SQLITE_OK
+** if successful, or an SQLite error code otherwise.
+*/
+int sqlite3BtreeNewDb(Btree *p){
+ int rc;
+ sqlite3BtreeEnter(p);
+ p->pBt->nPage = 0;
+ rc = newDatabase(p->pBt);
+ sqlite3BtreeLeave(p);
+ return rc;
+}
+
+/*
** Attempt to start a new transaction. A write-transaction
** is started if the second argument is nonzero, otherwise a read-
** transaction. If the second argument is 2 or more and exclusive
@@ -5256,7 +5288,7 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){
return SQLITE_OK; /* No overflow pages. Return without doing anything */
}
if( pCell+info.iOverflow+3 > pPage->aData+pPage->maskPage ){
- return SQLITE_CORRUPT; /* Cell extends past end of page */
+ return SQLITE_CORRUPT_BKPT; /* Cell extends past end of page */
}
ovflPgno = get4byte(&pCell[info.iOverflow]);
assert( pBt->usableSize > 4 );
@@ -5712,7 +5744,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
assert( pPage->nOverflow==1 );
/* This error condition is now caught prior to reaching this function */
- if( pPage->nCell<=0 ) return SQLITE_CORRUPT_BKPT;
+ if( pPage->nCell==0 ) return SQLITE_CORRUPT_BKPT;
/* Allocate a new page. This page will become the right-sibling of
** pPage. Make the parent page writable, so that the new divider cell
diff --git a/lib/libsqlite3/src/btree.h b/lib/libsqlite3/src/btree.h
index 95897d56622..d4c9fe37d78 100644
--- a/lib/libsqlite3/src/btree.h
+++ b/lib/libsqlite3/src/btree.h
@@ -71,6 +71,9 @@ int sqlite3BtreeMaxPageCount(Btree*,int);
u32 sqlite3BtreeLastPage(Btree*);
int sqlite3BtreeSecureDelete(Btree*,int);
int sqlite3BtreeGetReserve(Btree*);
+#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_DEBUG)
+int sqlite3BtreeGetReserveNoMutex(Btree *p);
+#endif
int sqlite3BtreeSetAutoVacuum(Btree *, int);
int sqlite3BtreeGetAutoVacuum(Btree *);
int sqlite3BtreeBeginTrans(Btree*,int);
@@ -114,6 +117,8 @@ void sqlite3BtreeTripAllCursors(Btree*, int);
void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue);
int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
+int sqlite3BtreeNewDb(Btree *p);
+
/*
** The second parameter to sqlite3BtreeGetMeta or sqlite3BtreeUpdateMeta
** should be one of the following values. The integer values are assigned
diff --git a/lib/libsqlite3/src/build.c b/lib/libsqlite3/src/build.c
index 25e474031fb..c21f0172a9b 100644
--- a/lib/libsqlite3/src/build.c
+++ b/lib/libsqlite3/src/build.c
@@ -127,6 +127,7 @@ void sqlite3FinishCoding(Parse *pParse){
sqlite3 *db;
Vdbe *v;
+ assert( pParse->pToplevel==0 );
db = pParse->db;
if( db->mallocFailed ) return;
if( pParse->nested ) return;
@@ -320,6 +321,31 @@ Table *sqlite3LocateTable(
}
/*
+** Locate the table identified by *p.
+**
+** This is a wrapper around sqlite3LocateTable(). The difference between
+** sqlite3LocateTable() and this function is that this function restricts
+** the search to schema (p->pSchema) if it is not NULL. p->pSchema may be
+** non-NULL if it is part of a view or trigger program definition. See
+** sqlite3FixSrcList() for details.
+*/
+Table *sqlite3LocateTableItem(
+ Parse *pParse,
+ int isView,
+ struct SrcList_item *p
+){
+ const char *zDb;
+ assert( p->pSchema==0 || p->zDatabase==0 );
+ if( p->pSchema ){
+ int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
+ zDb = pParse->db->aDb[iDb].zName;
+ }else{
+ zDb = p->zDatabase;
+ }
+ return sqlite3LocateTable(pParse, isView, p->zName, zDb);
+}
+
+/*
** Locate the in-memory structure that describes
** a particular index given the name of that index
** and the name of the database that contains the index.
@@ -1169,7 +1195,7 @@ void sqlite3AddPrimaryKey(
pTab->tabFlags |= TF_HasPrimaryKey;
if( pList==0 ){
iCol = pTab->nCol - 1;
- pTab->aCol[iCol].isPrimKey = 1;
+ pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
}else{
for(i=0; i<pList->nExpr; i++){
for(iCol=0; iCol<pTab->nCol; iCol++){
@@ -1178,7 +1204,7 @@ void sqlite3AddPrimaryKey(
}
}
if( iCol<pTab->nCol ){
- pTab->aCol[iCol].isPrimKey = 1;
+ pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
}
}
if( pList->nExpr>1 ) iCol = -1;
@@ -1295,10 +1321,7 @@ CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){
pColl = sqlite3FindCollSeq(db, enc, zName, initbusy);
if( !initbusy && (!pColl || !pColl->xCmp) ){
- pColl = sqlite3GetCollSeq(db, enc, pColl, zName);
- if( !pColl ){
- sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
- }
+ pColl = sqlite3GetCollSeq(pParse, enc, pColl, zName);
}
return pColl;
@@ -1997,6 +2020,7 @@ static void destroyTable(Parse *pParse, Table *pTab){
return;
}else{
int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+ assert( iDb>=0 && iDb<pParse->db->nDb );
destroyRootPage(pParse, iLargest, iDb);
iDestroyed = iLargest;
}
@@ -2114,8 +2138,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
assert( pParse->nErr==0 );
assert( pName->nSrc==1 );
if( noErr ) db->suppressErr++;
- pTab = sqlite3LocateTable(pParse, isView,
- pName->a[0].zName, pName->a[0].zDatabase);
+ pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
if( noErr ) db->suppressErr--;
if( pTab==0 ){
@@ -2555,9 +2578,9 @@ Index *sqlite3CreateIndex(
** sqlite3FixSrcList can never fail. */
assert(0);
}
- pTab = sqlite3LocateTable(pParse, 0, pTblName->a[0].zName,
- pTblName->a[0].zDatabase);
- if( !pTab || db->mallocFailed ) goto exit_create_index;
+ pTab = sqlite3LocateTableItem(pParse, 0, &pTblName->a[0]);
+ assert( db->mallocFailed==0 || pTab==0 );
+ if( pTab==0 ) goto exit_create_index;
assert( db->aDb[iDb].pSchema==pTab->pSchema );
}else{
assert( pName==0 );
@@ -2668,10 +2691,8 @@ Index *sqlite3CreateIndex(
for(i=0; i<pList->nExpr; i++){
Expr *pExpr = pList->a[i].pExpr;
if( pExpr ){
- CollSeq *pColl = pExpr->pColl;
- /* Either pColl!=0 or there was an OOM failure. But if an OOM
- ** failure we have quit before reaching this point. */
- if( ALWAYS(pColl) ){
+ CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr);
+ if( pColl ){
nExtra += (1 + sqlite3Strlen30(pColl->zName));
}
}
@@ -2734,6 +2755,7 @@ Index *sqlite3CreateIndex(
const char *zColName = pListItem->zName;
Column *pTabCol;
int requestedSortOrder;
+ CollSeq *pColl; /* Collating sequence */
char *zColl; /* Collation sequence name */
for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){
@@ -2746,14 +2768,11 @@ Index *sqlite3CreateIndex(
goto exit_create_index;
}
pIndex->aiColumn[i] = j;
- /* Justification of the ALWAYS(pListItem->pExpr->pColl): Because of
- ** the way the "idxlist" non-terminal is constructed by the parser,
- ** if pListItem->pExpr is not null then either pListItem->pExpr->pColl
- ** must exist or else there must have been an OOM error. But if there
- ** was an OOM error, we would never reach this point. */
- if( pListItem->pExpr && ALWAYS(pListItem->pExpr->pColl) ){
+ if( pListItem->pExpr
+ && (pColl = sqlite3ExprCollSeq(pParse, pListItem->pExpr))!=0
+ ){
int nColl;
- zColl = pListItem->pExpr->pColl->zName;
+ zColl = pColl->zName;
nColl = sqlite3Strlen30(zColl) + 1;
assert( nExtra>=nColl );
memcpy(zExtra, zColl, nColl);
@@ -3567,6 +3586,15 @@ int sqlite3OpenTempDatabase(Parse *pParse){
void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
+#ifndef SQLITE_OMIT_TRIGGER
+ if( pToplevel!=pParse ){
+ /* This branch is taken if a trigger is currently being coded. In this
+ ** case, set cookieGoto to a non-zero value to show that this function
+ ** has been called. This is used by the sqlite3ExprCodeConstants()
+ ** function. */
+ pParse->cookieGoto = -1;
+ }
+#endif
if( pToplevel->cookieGoto==0 ){
Vdbe *v = sqlite3GetVdbe(pToplevel);
if( v==0 ) return; /* This only happens if there was a prior error */
diff --git a/lib/libsqlite3/src/callback.c b/lib/libsqlite3/src/callback.c
index a515e05e2a0..d40c65cb924 100644
--- a/lib/libsqlite3/src/callback.c
+++ b/lib/libsqlite3/src/callback.c
@@ -75,17 +75,18 @@ static int synthCollSeq(sqlite3 *db, CollSeq *pColl){
**
** The return value is either the collation sequence to be used in database
** db for collation type name zName, length nName, or NULL, if no collation
-** sequence can be found.
+** sequence can be found. If no collation is found, leave an error message.
**
** See also: sqlite3LocateCollSeq(), sqlite3FindCollSeq()
*/
CollSeq *sqlite3GetCollSeq(
- sqlite3* db, /* The database connection */
+ Parse *pParse, /* Parsing context */
u8 enc, /* The desired encoding for the collating sequence */
CollSeq *pColl, /* Collating sequence with native encoding, or NULL */
const char *zName /* Collating sequence name */
){
CollSeq *p;
+ sqlite3 *db = pParse->db;
p = pColl;
if( !p ){
@@ -102,6 +103,9 @@ CollSeq *sqlite3GetCollSeq(
p = 0;
}
assert( !p || p->xCmp );
+ if( p==0 ){
+ sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
+ }
return p;
}
@@ -120,10 +124,8 @@ int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
if( pColl ){
const char *zName = pColl->zName;
sqlite3 *db = pParse->db;
- CollSeq *p = sqlite3GetCollSeq(db, ENC(db), pColl, zName);
+ CollSeq *p = sqlite3GetCollSeq(pParse, ENC(db), pColl, zName);
if( !p ){
- sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
- pParse->nErr++;
return SQLITE_ERROR;
}
assert( p==pColl );
diff --git a/lib/libsqlite3/src/ctime.c b/lib/libsqlite3/src/ctime.c
index 61cf4e3df12..5dee7247478 100644
--- a/lib/libsqlite3/src/ctime.c
+++ b/lib/libsqlite3/src/ctime.c
@@ -338,6 +338,9 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_PROXY_DEBUG
"PROXY_DEBUG",
#endif
+#ifdef SQLITE_RTREE_INT_ONLY
+ "RTREE_INT_ONLY",
+#endif
#ifdef SQLITE_SECURE_DELETE
"SECURE_DELETE",
#endif
diff --git a/lib/libsqlite3/src/delete.c b/lib/libsqlite3/src/delete.c
index 44e5995a697..01a130d65b4 100644
--- a/lib/libsqlite3/src/delete.c
+++ b/lib/libsqlite3/src/delete.c
@@ -32,7 +32,7 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
struct SrcList_item *pItem = pSrc->a;
Table *pTab;
assert( pItem && pSrc->nSrc==1 );
- pTab = sqlite3LocateTable(pParse, 0, pItem->zName, pItem->zDatabase);
+ pTab = sqlite3LocateTableItem(pParse, 0, pItem);
sqlite3DeleteTable(pParse->db, pItem->pTab);
pItem->pTab = pTab;
if( pTab ){
@@ -112,6 +112,7 @@ void sqlite3MaterializeView(
sqlite3SelectDelete(db, pDup);
}
pDup = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0);
+ if( pDup ) pDup->selFlags |= SF_Materialize;
}
sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
sqlite3Select(pParse, pDup, &dest);
@@ -638,7 +639,9 @@ int sqlite3GenerateIndexKey(
}
if( doMakeRec ){
const char *zAff;
- if( pTab->pSelect || (pParse->db->flags & SQLITE_IdxRealAsInt)!=0 ){
+ if( pTab->pSelect
+ || OptimizationDisabled(pParse->db, SQLITE_IdxRealAsInt)
+ ){
zAff = 0;
}else{
zAff = sqlite3IndexAffinityStr(v, pIdx);
diff --git a/lib/libsqlite3/src/expr.c b/lib/libsqlite3/src/expr.c
index 89172f94bf5..9ca34ec7b7f 100644
--- a/lib/libsqlite3/src/expr.c
+++ b/lib/libsqlite3/src/expr.c
@@ -31,7 +31,9 @@
** SELECT * FROM t1 WHERE (select a from t1);
*/
char sqlite3ExprAffinity(Expr *pExpr){
- int op = pExpr->op;
+ int op;
+ pExpr = sqlite3ExprSkipCollate(pExpr);
+ op = pExpr->op;
if( op==TK_SELECT ){
assert( pExpr->flags&EP_xIsSelect );
return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
@@ -56,66 +58,94 @@ char sqlite3ExprAffinity(Expr *pExpr){
}
/*
-** Set the explicit collating sequence for an expression to the
-** collating sequence supplied in the second argument.
+** Set the collating sequence for expression pExpr to be the collating
+** sequence named by pToken. Return a pointer to a new Expr node that
+** implements the COLLATE operator.
+**
+** If a memory allocation error occurs, that fact is recorded in pParse->db
+** and the pExpr parameter is returned unchanged.
*/
-Expr *sqlite3ExprSetColl(Expr *pExpr, CollSeq *pColl){
- if( pExpr && pColl ){
- pExpr->pColl = pColl;
- pExpr->flags |= EP_ExpCollate;
+Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr *pExpr, Token *pCollName){
+ if( pCollName->n>0 ){
+ Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1);
+ if( pNew ){
+ pNew->pLeft = pExpr;
+ pNew->flags |= EP_Collate;
+ pExpr = pNew;
+ }
}
return pExpr;
}
+Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){
+ Token s;
+ assert( zC!=0 );
+ s.z = zC;
+ s.n = sqlite3Strlen30(s.z);
+ return sqlite3ExprAddCollateToken(pParse, pExpr, &s);
+}
/*
-** Set the collating sequence for expression pExpr to be the collating
-** sequence named by pToken. Return a pointer to the revised expression.
-** The collating sequence is marked as "explicit" using the EP_ExpCollate
-** flag. An explicit collating sequence will override implicit
-** collating sequences.
+** Skip over any TK_COLLATE and/or TK_AS operators at the root of
+** an expression.
*/
-Expr *sqlite3ExprSetCollByToken(Parse *pParse, Expr *pExpr, Token *pCollName){
- char *zColl = 0; /* Dequoted name of collation sequence */
- CollSeq *pColl;
- sqlite3 *db = pParse->db;
- zColl = sqlite3NameFromToken(db, pCollName);
- pColl = sqlite3LocateCollSeq(pParse, zColl);
- sqlite3ExprSetColl(pExpr, pColl);
- sqlite3DbFree(db, zColl);
+Expr *sqlite3ExprSkipCollate(Expr *pExpr){
+ while( pExpr && (pExpr->op==TK_COLLATE || pExpr->op==TK_AS) ){
+ pExpr = pExpr->pLeft;
+ }
return pExpr;
}
/*
-** Return the default collation sequence for the expression pExpr. If
-** there is no default collation type, return 0.
+** Return the collation sequence for the expression pExpr. If
+** there is no defined collating sequence, return NULL.
+**
+** The collating sequence might be determined by a COLLATE operator
+** or by the presence of a column with a defined collating sequence.
+** COLLATE operators take first precedence. Left operands take
+** precedence over right operands.
*/
CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
+ sqlite3 *db = pParse->db;
CollSeq *pColl = 0;
Expr *p = pExpr;
while( p ){
- int op;
- pColl = p->pColl;
- if( pColl ) break;
- op = p->op;
- if( p->pTab!=0 && (
- op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_REGISTER || op==TK_TRIGGER
- )){
+ int op = p->op;
+ if( op==TK_CAST || op==TK_UPLUS ){
+ p = p->pLeft;
+ continue;
+ }
+ assert( op!=TK_REGISTER || p->op2!=TK_COLLATE );
+ if( op==TK_COLLATE ){
+ if( db->init.busy ){
+ /* Do not report errors when parsing while the schema */
+ pColl = sqlite3FindCollSeq(db, ENC(db), p->u.zToken, 0);
+ }else{
+ pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
+ }
+ break;
+ }
+ if( p->pTab!=0
+ && (op==TK_AGG_COLUMN || op==TK_COLUMN
+ || op==TK_REGISTER || op==TK_TRIGGER)
+ ){
/* op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally
** a TK_COLUMN but was previously evaluated and cached in a register */
- const char *zColl;
int j = p->iColumn;
if( j>=0 ){
- sqlite3 *db = pParse->db;
- zColl = p->pTab->aCol[j].zColl;
+ const char *zColl = p->pTab->aCol[j].zColl;
pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0);
- pExpr->pColl = pColl;
}
break;
}
- if( op!=TK_CAST && op!=TK_UPLUS ){
+ if( p->flags & EP_Collate ){
+ if( ALWAYS(p->pLeft) && (p->pLeft->flags & EP_Collate)!=0 ){
+ p = p->pLeft;
+ }else{
+ p = p->pRight;
+ }
+ }else{
break;
}
- p = p->pLeft;
}
if( sqlite3CheckCollSeq(pParse, pColl) ){
pColl = 0;
@@ -219,12 +249,10 @@ CollSeq *sqlite3BinaryCompareCollSeq(
){
CollSeq *pColl;
assert( pLeft );
- if( pLeft->flags & EP_ExpCollate ){
- assert( pLeft->pColl );
- pColl = pLeft->pColl;
- }else if( pRight && pRight->flags & EP_ExpCollate ){
- assert( pRight->pColl );
- pColl = pRight->pColl;
+ if( pLeft->flags & EP_Collate ){
+ pColl = sqlite3ExprCollSeq(pParse, pLeft);
+ }else if( pRight && (pRight->flags & EP_Collate)!=0 ){
+ pColl = sqlite3ExprCollSeq(pParse, pRight);
}else{
pColl = sqlite3ExprCollSeq(pParse, pLeft);
if( !pColl ){
@@ -454,17 +482,11 @@ void sqlite3ExprAttachSubtrees(
}else{
if( pRight ){
pRoot->pRight = pRight;
- if( pRight->flags & EP_ExpCollate ){
- pRoot->flags |= EP_ExpCollate;
- pRoot->pColl = pRight->pColl;
- }
+ pRoot->flags |= EP_Collate & pRight->flags;
}
if( pLeft ){
pRoot->pLeft = pLeft;
- if( pLeft->flags & EP_ExpCollate ){
- pRoot->flags |= EP_ExpCollate;
- pRoot->pColl = pLeft->pColl;
- }
+ pRoot->flags |= EP_Collate & pLeft->flags;
}
exprSetHeight(pRoot);
}
@@ -722,7 +744,7 @@ static int dupedExprStructSize(Expr *p, int flags){
assert( !ExprHasProperty(p, EP_FromJoin) );
assert( (p->flags2 & EP2_MallocedToken)==0 );
assert( (p->flags2 & EP2_Irreducible)==0 );
- if( p->pLeft || p->pRight || p->pColl || p->x.pList ){
+ if( p->pLeft || p->pRight || p->x.pList ){
nSize = EXPR_REDUCEDSIZE | EP_Reduced;
}else{
nSize = EXPR_TOKENONLYSIZE | EP_TokenOnly;
@@ -930,6 +952,7 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
struct SrcList_item *pNewItem = &pNew->a[i];
struct SrcList_item *pOldItem = &p->a[i];
Table *pTab;
+ pNewItem->pSchema = pOldItem->pSchema;
pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase);
pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias);
@@ -938,6 +961,7 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
pNewItem->addrFillSub = pOldItem->addrFillSub;
pNewItem->regReturn = pOldItem->regReturn;
pNewItem->isCorrelated = pOldItem->isCorrelated;
+ pNewItem->viaCoroutine = pOldItem->viaCoroutine;
pNewItem->zIndex = sqlite3DbStrDup(db, pOldItem->zIndex);
pNewItem->notIndexed = pOldItem->notIndexed;
pNewItem->pIndex = pOldItem->pIndex;
@@ -1420,12 +1444,16 @@ int sqlite3CodeOnce(Parse *pParse){
/*
** This function is used by the implementation of the IN (...) operator.
-** It's job is to find or create a b-tree structure that may be used
-** either to test for membership of the (...) set or to iterate through
-** its members, skipping duplicates.
+** The pX parameter is the expression on the RHS of the IN operator, which
+** might be either a list of expressions or a subquery.
+**
+** The job of this routine is to find or create a b-tree object that can
+** be used either to test for membership in the RHS set or to iterate through
+** all members of the RHS set, skipping duplicates.
+**
+** A cursor is opened on the b-tree object that the RHS of the IN operator
+** and pX->iTable is set to the index of that cursor.
**
-** The index of the cursor opened on the b-tree (database table, database index
-** or ephermal table) is stored in pX->iTable before this function returns.
** The returned value of this function indicates the b-tree type, as follows:
**
** IN_INDEX_ROWID - The cursor was opened on a database table.
@@ -1433,11 +1461,16 @@ int sqlite3CodeOnce(Parse *pParse){
** IN_INDEX_EPH - The cursor was opened on a specially created and
** populated epheremal table.
**
-** An existing b-tree may only be used if the SELECT is of the simple
-** form:
+** An existing b-tree might be used if the RHS expression pX is a simple
+** subquery such as:
**
** SELECT <column> FROM <table>
**
+** If the RHS of the IN operator is a list or a more complex subquery, then
+** an ephemeral table might need to be generated from the RHS and then
+** pX->iTable made to point to the ephermeral table instead of an
+** existing table.
+**
** If the prNotFound parameter is 0, then the b-tree will be used to iterate
** through the set members, skipping any duplicates. In this case an
** epheremal table must be used unless the selected <column> is guaranteed
@@ -1533,8 +1566,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
** comparison is the same as the affinity of the column. If
** it is not, it is not possible to use any index.
*/
- char aff = comparisonAffinity(pX);
- int affinity_ok = (pTab->aCol[iCol].affinity==aff||aff==SQLITE_AFF_NONE);
+ int affinity_ok = sqlite3IndexAffinityOk(pX, pTab->aCol[iCol].affinity);
for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){
if( (pIdx->aiColumn[0]==iCol)
@@ -1662,6 +1694,7 @@ int sqlite3CodeSubselect(
case TK_IN: {
char affinity; /* Affinity of the LHS of the IN */
KeyInfo keyInfo; /* Keyinfo for the generated table */
+ static u8 sortOrder = 0; /* Fake aSortOrder for keyInfo */
int addr; /* Address of OP_OpenEphemeral instruction */
Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */
@@ -1689,6 +1722,7 @@ int sqlite3CodeSubselect(
if( rMayHaveNull==0 ) sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
memset(&keyInfo, 0, sizeof(keyInfo));
keyInfo.nField = 1;
+ keyInfo.aSortOrder = &sortOrder;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
/* Case 1: expr IN (SELECT ...)
@@ -1729,6 +1763,7 @@ int sqlite3CodeSubselect(
affinity = SQLITE_AFF_NONE;
}
keyInfo.aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
+ keyInfo.aSortOrder = &sortOrder;
/* Loop through each expression in <exprlist>. */
r1 = sqlite3GetTempReg(pParse);
@@ -2055,7 +2090,7 @@ void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){
** for testing only - to verify that SQLite always gets the same answer
** with and without the column cache.
*/
- if( pParse->db->flags & SQLITE_ColumnCache ) return;
+ if( OptimizationDisabled(pParse->db, SQLITE_ColumnCache) ) return;
/* First replace any existing entry.
**
@@ -2252,8 +2287,8 @@ void sqlite3ExprCacheAffinityChange(Parse *pParse, int iStart, int iCount){
void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
int i;
struct yColCache *p;
- if( NEVER(iFrom==iTo) ) return;
- sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);
+ assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo );
+ sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg-1);
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
int x = p->iReg;
if( x>=iFrom && x<iFrom+nReg ){
@@ -2262,18 +2297,6 @@ void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
}
}
-/*
-** Generate code to copy content from registers iFrom...iFrom+nReg-1
-** over to iTo..iTo+nReg-1.
-*/
-void sqlite3ExprCodeCopy(Parse *pParse, int iFrom, int iTo, int nReg){
- int i;
- if( NEVER(iFrom==iTo) ) return;
- for(i=0; i<nReg; i++){
- sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, iFrom+i, iTo+i);
- }
-}
-
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
/*
** Return true if any register in the range iFrom..iTo (inclusive)
@@ -2745,6 +2768,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
sqlite3ReleaseTempReg(pParse, r4);
break;
}
+ case TK_COLLATE:
case TK_UPLUS: {
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
break;
@@ -3114,6 +3138,12 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){
case TK_ISNULL: zUniOp = "ISNULL"; break;
case TK_NOTNULL: zUniOp = "NOTNULL"; break;
+ case TK_COLLATE: {
+ sqlite3ExplainExpr(pOut, pExpr->pLeft);
+ sqlite3ExplainPrintf(pOut,".COLLATE(%s)",pExpr->u.zToken);
+ break;
+ }
+
case TK_AGG_FUNCTION:
case TK_CONST_FUNC:
case TK_FUNCTION: {
@@ -3332,6 +3362,9 @@ static int evalConstExpr(Walker *pWalker, Expr *pExpr){
case TK_REGISTER: {
return WRC_Prune;
}
+ case TK_COLLATE: {
+ return WRC_Continue;
+ }
case TK_FUNCTION:
case TK_AGG_FUNCTION:
case TK_CONST_FUNC: {
@@ -3353,9 +3386,11 @@ static int evalConstExpr(Walker *pWalker, Expr *pExpr){
}
if( isAppropriateForFactoring(pExpr) ){
int r1 = ++pParse->nMem;
- int r2;
- r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
- if( NEVER(r1!=r2) ) sqlite3ReleaseTempReg(pParse, r1);
+ int r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
+ /* If r2!=r1, it means that register r1 is never used. That is harmless
+ ** but suboptimal, so we want to know about the situation to fix it.
+ ** Hence the following assert: */
+ assert( r2==r1 );
pExpr->op2 = pExpr->op;
pExpr->op = TK_REGISTER;
pExpr->iTable = r2;
@@ -3383,7 +3418,7 @@ static int evalConstExpr(Walker *pWalker, Expr *pExpr){
void sqlite3ExprCodeConstants(Parse *pParse, Expr *pExpr){
Walker w;
if( pParse->cookieGoto ) return;
- if( (pParse->db->flags & SQLITE_FactorOutConst)!=0 ) return;
+ if( OptimizationDisabled(pParse->db, SQLITE_FactorOutConst) ) return;
w.xExprCallback = evalConstExpr;
w.xSelectCallback = 0;
w.pParse = pParse;
@@ -3772,7 +3807,15 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
return 2;
}
if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2;
- if( pA->op!=pB->op ) return 2;
+ if( pA->op!=pB->op ){
+ if( pA->op==TK_COLLATE && sqlite3ExprCompare(pA->pLeft, pB)<2 ){
+ return 1;
+ }
+ if( pB->op==TK_COLLATE && sqlite3ExprCompare(pA, pB->pLeft)<2 ){
+ return 1;
+ }
+ return 2;
+ }
if( sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 2;
if( sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 2;
if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList) ) return 2;
@@ -3784,11 +3827,9 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
}else if( pA->op!=TK_COLUMN && ALWAYS(pA->op!=TK_AGG_COLUMN) && pA->u.zToken){
if( ExprHasProperty(pB, EP_IntValue) || NEVER(pB->u.zToken==0) ) return 2;
if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){
- return 2;
+ return pA->op==TK_COLLATE ? 1 : 2;
}
}
- if( (pA->flags & EP_ExpCollate)!=(pB->flags & EP_ExpCollate) ) return 1;
- if( (pA->flags & EP_ExpCollate)!=0 && pA->pColl!=pB->pColl ) return 2;
return 0;
}
@@ -4029,8 +4070,10 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
ExprSetIrreducible(pExpr);
pExpr->iAgg = (i16)i;
pExpr->pAggInfo = pAggInfo;
+ return WRC_Prune;
+ }else{
+ return WRC_Continue;
}
- return WRC_Prune;
}
}
return WRC_Continue;
@@ -4042,9 +4085,10 @@ static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
}
/*
-** Analyze the given expression looking for aggregate functions and
-** for variables that need to be added to the pParse->aAgg[] array.
-** Make additional entries to the pParse->aAgg[] array as necessary.
+** Analyze the pExpr expression looking for aggregate functions and
+** for variables that need to be added to AggInfo object that pNC->pAggInfo
+** points to. Additional entries are made on the AggInfo object as
+** necessary.
**
** This routine should only be called after the expression has been
** analyzed by sqlite3ResolveExprNames().
diff --git a/lib/libsqlite3/src/fkey.c b/lib/libsqlite3/src/fkey.c
index 9db3a71c383..2d01e2524b3 100644
--- a/lib/libsqlite3/src/fkey.c
+++ b/lib/libsqlite3/src/fkey.c
@@ -511,12 +511,15 @@ static void fkScanChildren(
** expression to the parent key column defaults. */
if( pIdx ){
Column *pCol;
+ const char *zColl;
iCol = pIdx->aiColumn[i];
pCol = &pTab->aCol[iCol];
if( pTab->iPKey==iCol ) iCol = -1;
pLeft->iTable = regData+iCol+1;
pLeft->affinity = pCol->affinity;
- pLeft->pColl = sqlite3LocateCollSeq(pParse, pCol->zColl);
+ zColl = pCol->zColl;
+ if( zColl==0 ) zColl = db->pDfltColl->zName;
+ pLeft = sqlite3ExprAddCollateString(pParse, pLeft, zColl);
}else{
pLeft->iTable = regData;
pLeft->affinity = SQLITE_AFF_INTEGER;
@@ -925,7 +928,8 @@ int sqlite3FkRequired(
int iKey;
for(iKey=0; iKey<pTab->nCol; iKey++){
Column *pCol = &pTab->aCol[iKey];
- if( (zKey ? !sqlite3StrICmp(pCol->zName, zKey) : pCol->isPrimKey) ){
+ if( (zKey ? !sqlite3StrICmp(pCol->zName, zKey)
+ : (pCol->colFlags & COLFLAG_PRIMKEY)!=0) ){
if( aChange[iKey]>=0 ) return 1;
if( iKey==pTab->iPKey && chngRowid ) return 1;
}
diff --git a/lib/libsqlite3/src/func.c b/lib/libsqlite3/src/func.c
index e56561e4ecb..d4655ad7e96 100644
--- a/lib/libsqlite3/src/func.c
+++ b/lib/libsqlite3/src/func.c
@@ -169,6 +169,56 @@ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
}
/*
+** Implementation of the instr() function.
+**
+** instr(haystack,needle) finds the first occurrence of needle
+** in haystack and returns the number of previous characters plus 1,
+** or 0 if needle does not occur within haystack.
+**
+** If both haystack and needle are BLOBs, then the result is one more than
+** the number of bytes in haystack prior to the first occurrence of needle,
+** or 0 if needle never occurs in haystack.
+*/
+static void instrFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const unsigned char *zHaystack;
+ const unsigned char *zNeedle;
+ int nHaystack;
+ int nNeedle;
+ int typeHaystack, typeNeedle;
+ int N = 1;
+ int isText;
+
+ UNUSED_PARAMETER(argc);
+ typeHaystack = sqlite3_value_type(argv[0]);
+ typeNeedle = sqlite3_value_type(argv[1]);
+ if( typeHaystack==SQLITE_NULL || typeNeedle==SQLITE_NULL ) return;
+ nHaystack = sqlite3_value_bytes(argv[0]);
+ nNeedle = sqlite3_value_bytes(argv[1]);
+ if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){
+ zHaystack = sqlite3_value_blob(argv[0]);
+ zNeedle = sqlite3_value_blob(argv[1]);
+ isText = 0;
+ }else{
+ zHaystack = sqlite3_value_text(argv[0]);
+ zNeedle = sqlite3_value_text(argv[1]);
+ isText = 1;
+ }
+ while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){
+ N++;
+ do{
+ nHaystack--;
+ zHaystack++;
+ }while( isText && (zHaystack[0]&0xc0)==0x80 );
+ }
+ if( nNeedle>nHaystack ) N = 0;
+ sqlite3_result_int(context, N);
+}
+
+/*
** Implementation of the substr() function.
**
** substr(x,p1,p2) returns p2 characters of x[] beginning with p1.
@@ -367,33 +417,14 @@ static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
}
}
-
-#if 0 /* This function is never used. */
-/*
-** The COALESCE() and IFNULL() functions used to be implemented as shown
-** here. But now they are implemented as VDBE code so that unused arguments
-** do not have to be computed. This legacy implementation is retained as
-** comment.
-*/
/*
-** Implementation of the IFNULL(), NVL(), and COALESCE() functions.
-** All three do the same thing. They return the first non-NULL
-** argument.
+** The COALESCE() and IFNULL() functions are implemented as VDBE code so
+** that unused argument values do not have to be computed. However, we
+** still need some kind of function implementation for this routines in
+** the function table. That function implementation will never be called
+** so it doesn't matter what the implementation is. We might as well use
+** the "version()" function as a substitute.
*/
-static void ifnullFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- int i;
- for(i=0; i<argc; i++){
- if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){
- sqlite3_result_value(context, argv[i]);
- break;
- }
- }
-}
-#endif /* NOT USED */
#define ifnullFunc versionFunc /* Substitute function - never called */
/*
@@ -512,7 +543,7 @@ struct compareInfo {
** whereas only characters less than 0x80 do in ASCII.
*/
#if defined(SQLITE_EBCDIC)
-# define sqlite3Utf8Read(A,C) (*(A++))
+# define sqlite3Utf8Read(A) (*((*A)++))
# define GlogUpperToLower(A) A = sqlite3UpperToLower[A]
#else
# define GlogUpperToLower(A) if( !((A)&~0x7f) ){ A = sqlite3UpperToLower[A]; }
@@ -569,18 +600,18 @@ static int patternCompare(
u8 noCase = pInfo->noCase;
int prevEscape = 0; /* True if the previous character was 'escape' */
- while( (c = sqlite3Utf8Read(zPattern,&zPattern))!=0 ){
- if( !prevEscape && c==matchAll ){
- while( (c=sqlite3Utf8Read(zPattern,&zPattern)) == matchAll
+ while( (c = sqlite3Utf8Read(&zPattern))!=0 ){
+ if( c==matchAll && !prevEscape ){
+ while( (c=sqlite3Utf8Read(&zPattern)) == matchAll
|| c == matchOne ){
- if( c==matchOne && sqlite3Utf8Read(zString, &zString)==0 ){
+ if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){
return 0;
}
}
if( c==0 ){
return 1;
}else if( c==esc ){
- c = sqlite3Utf8Read(zPattern, &zPattern);
+ c = sqlite3Utf8Read(&zPattern);
if( c==0 ){
return 0;
}
@@ -592,25 +623,25 @@ static int patternCompare(
}
return *zString!=0;
}
- while( (c2 = sqlite3Utf8Read(zString,&zString))!=0 ){
+ while( (c2 = sqlite3Utf8Read(&zString))!=0 ){
if( noCase ){
GlogUpperToLower(c2);
GlogUpperToLower(c);
while( c2 != 0 && c2 != c ){
- c2 = sqlite3Utf8Read(zString, &zString);
+ c2 = sqlite3Utf8Read(&zString);
GlogUpperToLower(c2);
}
}else{
while( c2 != 0 && c2 != c ){
- c2 = sqlite3Utf8Read(zString, &zString);
+ c2 = sqlite3Utf8Read(&zString);
}
}
if( c2==0 ) return 0;
if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
}
return 0;
- }else if( !prevEscape && c==matchOne ){
- if( sqlite3Utf8Read(zString, &zString)==0 ){
+ }else if( c==matchOne && !prevEscape ){
+ if( sqlite3Utf8Read(&zString)==0 ){
return 0;
}
}else if( c==matchSet ){
@@ -618,20 +649,20 @@ static int patternCompare(
assert( esc==0 ); /* This only occurs for GLOB, not LIKE */
seen = 0;
invert = 0;
- c = sqlite3Utf8Read(zString, &zString);
+ c = sqlite3Utf8Read(&zString);
if( c==0 ) return 0;
- c2 = sqlite3Utf8Read(zPattern, &zPattern);
+ c2 = sqlite3Utf8Read(&zPattern);
if( c2=='^' ){
invert = 1;
- c2 = sqlite3Utf8Read(zPattern, &zPattern);
+ c2 = sqlite3Utf8Read(&zPattern);
}
if( c2==']' ){
if( c==']' ) seen = 1;
- c2 = sqlite3Utf8Read(zPattern, &zPattern);
+ c2 = sqlite3Utf8Read(&zPattern);
}
while( c2 && c2!=']' ){
if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){
- c2 = sqlite3Utf8Read(zPattern, &zPattern);
+ c2 = sqlite3Utf8Read(&zPattern);
if( c>=prior_c && c<=c2 ) seen = 1;
prior_c = 0;
}else{
@@ -640,7 +671,7 @@ static int patternCompare(
}
prior_c = c2;
}
- c2 = sqlite3Utf8Read(zPattern, &zPattern);
+ c2 = sqlite3Utf8Read(&zPattern);
}
if( c2==0 || (seen ^ invert)==0 ){
return 0;
@@ -648,7 +679,7 @@ static int patternCompare(
}else if( esc==c && !prevEscape ){
prevEscape = 1;
}else{
- c2 = sqlite3Utf8Read(zString, &zString);
+ c2 = sqlite3Utf8Read(&zString);
if( noCase ){
GlogUpperToLower(c);
GlogUpperToLower(c2);
@@ -720,7 +751,7 @@ static void likeFunc(
"ESCAPE expression must be a single character", -1);
return;
}
- escape = sqlite3Utf8Read(zEsc, &zEsc);
+ escape = sqlite3Utf8Read(&zEsc);
}
if( zA && zB ){
struct compareInfo *pInfo = sqlite3_user_data(context);
@@ -1555,6 +1586,7 @@ void sqlite3RegisterGlobalFunctions(void){
AGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize ),
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
+ FUNCTION(instr, 2, 0, 0, instrFunc ),
FUNCTION(substr, 2, 0, 0, substrFunc ),
FUNCTION(substr, 3, 0, 0, substrFunc ),
FUNCTION(abs, 1, 0, 0, absFunc ),
diff --git a/lib/libsqlite3/src/global.c b/lib/libsqlite3/src/global.c
index 7de06682501..f5da7e7f1f4 100644
--- a/lib/libsqlite3/src/global.c
+++ b/lib/libsqlite3/src/global.c
@@ -133,6 +133,10 @@ const unsigned char sqlite3CtypeMap[256] = {
# define SQLITE_USE_URI 0
#endif
+#ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN
+# define SQLITE_ALLOW_COVERING_INDEX_SCAN 1
+#endif
+
/*
** The following singleton contains the global configuration for
** the SQLite library.
@@ -142,6 +146,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
1, /* bCoreMutex */
SQLITE_THREADSAFE==1, /* bFullMutex */
SQLITE_USE_URI, /* bOpenUri */
+ SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */
0x7ffffffe, /* mxStrlen */
128, /* szLookaside */
500, /* nLookaside */
@@ -170,6 +175,10 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
0, /* xLog */
0, /* pLogArg */
0, /* bLocaltimeFault */
+#ifdef SQLITE_ENABLE_SQLLOG
+ 0, /* xSqllog */
+ 0 /* pSqllogArg */
+#endif
};
diff --git a/lib/libsqlite3/src/hash.c b/lib/libsqlite3/src/hash.c
index d7625d3913a..e81dcf95e43 100644
--- a/lib/libsqlite3/src/hash.c
+++ b/lib/libsqlite3/src/hash.c
@@ -193,7 +193,7 @@ static void removeElementGivenHash(
}
sqlite3_free( elem );
pH->count--;
- if( pH->count<=0 ){
+ if( pH->count==0 ){
assert( pH->first==0 );
assert( pH->count==0 );
sqlite3HashClear(pH);
diff --git a/lib/libsqlite3/src/insert.c b/lib/libsqlite3/src/insert.c
index a24e8f9481a..89a5dc8a13e 100644
--- a/lib/libsqlite3/src/insert.c
+++ b/lib/libsqlite3/src/insert.c
@@ -25,7 +25,7 @@ void sqlite3OpenTable(
int opcode /* OP_OpenRead or OP_OpenWrite */
){
Vdbe *v;
- if( IsVirtual(pTab) ) return;
+ assert( !IsVirtual(pTab) );
v = sqlite3GetVdbe(p);
assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite)?1:0, pTab->zName);
@@ -320,6 +320,97 @@ void sqlite3AutoincrementEnd(Parse *pParse){
#endif /* SQLITE_OMIT_AUTOINCREMENT */
+/*
+** Generate code for a co-routine that will evaluate a subquery one
+** row at a time.
+**
+** The pSelect parameter is the subquery that the co-routine will evaluation.
+** Information about the location of co-routine and the registers it will use
+** is returned by filling in the pDest object.
+**
+** Registers are allocated as follows:
+**
+** pDest->iSDParm The register holding the next entry-point of the
+** co-routine. Run the co-routine to its next breakpoint
+** by calling "OP_Yield $X" where $X is pDest->iSDParm.
+**
+** pDest->iSDParm+1 The register holding the "completed" flag for the
+** co-routine. This register is 0 if the previous Yield
+** generated a new result row, or 1 if the subquery
+** has completed. If the Yield is called again
+** after this register becomes 1, then the VDBE will
+** halt with an SQLITE_INTERNAL error.
+**
+** pDest->iSdst First result register.
+**
+** pDest->nSdst Number of result registers.
+**
+** This routine handles all of the register allocation and fills in the
+** pDest structure appropriately.
+**
+** Here is a schematic of the generated code assuming that X is the
+** co-routine entry-point register reg[pDest->iSDParm], that EOF is the
+** completed flag reg[pDest->iSDParm+1], and R and S are the range of
+** registers that hold the result set, reg[pDest->iSdst] through
+** reg[pDest->iSdst+pDest->nSdst-1]:
+**
+** X <- A
+** EOF <- 0
+** goto B
+** A: setup for the SELECT
+** loop rows in the SELECT
+** load results into registers R..S
+** yield X
+** end loop
+** cleanup after the SELECT
+** EOF <- 1
+** yield X
+** halt-error
+** B:
+**
+** To use this subroutine, the caller generates code as follows:
+**
+** [ Co-routine generated by this subroutine, shown above ]
+** S: yield X
+** if EOF goto E
+** if skip this row, goto C
+** if terminate loop, goto E
+** deal with this row
+** C: goto S
+** E:
+*/
+int sqlite3CodeCoroutine(Parse *pParse, Select *pSelect, SelectDest *pDest){
+ int regYield; /* Register holding co-routine entry-point */
+ int regEof; /* Register holding co-routine completion flag */
+ int addrTop; /* Top of the co-routine */
+ int j1; /* Jump instruction */
+ int rc; /* Result code */
+ Vdbe *v; /* VDBE under construction */
+
+ regYield = ++pParse->nMem;
+ regEof = ++pParse->nMem;
+ v = sqlite3GetVdbe(pParse);
+ addrTop = sqlite3VdbeCurrentAddr(v);
+ sqlite3VdbeAddOp2(v, OP_Integer, addrTop+2, regYield); /* X <- A */
+ VdbeComment((v, "Co-routine entry point"));
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, regEof); /* EOF <- 0 */
+ VdbeComment((v, "Co-routine completion flag"));
+ sqlite3SelectDestInit(pDest, SRT_Coroutine, regYield);
+ j1 = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
+ rc = sqlite3Select(pParse, pSelect, pDest);
+ assert( pParse->nErr==0 || rc );
+ if( pParse->db->mallocFailed && rc==SQLITE_OK ) rc = SQLITE_NOMEM;
+ if( rc ) return rc;
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, regEof); /* EOF <- 1 */
+ sqlite3VdbeAddOp1(v, OP_Yield, regYield); /* yield X */
+ sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_INTERNAL, OE_Abort);
+ VdbeComment((v, "End of coroutine"));
+ sqlite3VdbeJumpHere(v, j1); /* label B: */
+ return rc;
+}
+
+
+
/* Forward declaration */
static int xferOptimization(
Parse *pParse, /* Parser context */
@@ -568,51 +659,12 @@ void sqlite3Insert(
** co-routine is the common header to the 3rd and 4th templates.
*/
if( pSelect ){
- /* Data is coming from a SELECT. Generate code to implement that SELECT
- ** as a co-routine. The code is common to both the 3rd and 4th
- ** templates:
- **
- ** EOF <- 0
- ** X <- A
- ** goto B
- ** A: setup for the SELECT
- ** loop over the tables in the SELECT
- ** load value into register R..R+n
- ** yield X
- ** end loop
- ** cleanup after the SELECT
- ** EOF <- 1
- ** yield X
- ** halt-error
- **
- ** On each invocation of the co-routine, it puts a single row of the
- ** SELECT result into registers dest.iMem...dest.iMem+dest.nMem-1.
- ** (These output registers are allocated by sqlite3Select().) When
- ** the SELECT completes, it sets the EOF flag stored in regEof.
- */
- int rc, j1;
-
- regEof = ++pParse->nMem;
- sqlite3VdbeAddOp2(v, OP_Integer, 0, regEof); /* EOF <- 0 */
- VdbeComment((v, "SELECT eof flag"));
- sqlite3SelectDestInit(&dest, SRT_Coroutine, ++pParse->nMem);
- addrSelect = sqlite3VdbeCurrentAddr(v)+2;
- sqlite3VdbeAddOp2(v, OP_Integer, addrSelect-1, dest.iSDParm);
- j1 = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
- VdbeComment((v, "Jump over SELECT coroutine"));
-
- /* Resolve the expressions in the SELECT statement and execute it. */
- rc = sqlite3Select(pParse, pSelect, &dest);
- assert( pParse->nErr==0 || rc );
- if( rc || NEVER(pParse->nErr) || db->mallocFailed ){
- goto insert_cleanup;
- }
- sqlite3VdbeAddOp2(v, OP_Integer, 1, regEof); /* EOF <- 1 */
- sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); /* yield X */
- sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_INTERNAL, OE_Abort);
- VdbeComment((v, "End of SELECT coroutine"));
- sqlite3VdbeJumpHere(v, j1); /* label B: */
+ /* Data is coming from a SELECT. Generate a co-routine to run that
+ ** SELECT. */
+ int rc = sqlite3CodeCoroutine(pParse, pSelect, &dest);
+ if( rc ) goto insert_cleanup;
+ regEof = dest.iSDParm + 1;
regFromSelect = dest.iSdst;
assert( pSelect->pEList );
nColumn = pSelect->pEList->nExpr;
@@ -1691,7 +1743,7 @@ static int xferOptimization(
** we have to check the semantics.
*/
pItem = pSelect->pSrc->a;
- pSrc = sqlite3LocateTable(pParse, 0, pItem->zName, pItem->zDatabase);
+ pSrc = sqlite3LocateTableItem(pParse, 0, pItem);
if( pSrc==0 ){
return 0; /* FROM clause does not contain a real table */
}
diff --git a/lib/libsqlite3/src/journal.c b/lib/libsqlite3/src/journal.c
index 2f9e222089d..06605cc9566 100644
--- a/lib/libsqlite3/src/journal.c
+++ b/lib/libsqlite3/src/journal.c
@@ -228,6 +228,16 @@ int sqlite3JournalCreate(sqlite3_file *p){
return createFile((JournalFile *)p);
}
+/*
+** The file-handle passed as the only argument is guaranteed to be an open
+** file. It may or may not be of class JournalFile. If the file is a
+** JournalFile, and the underlying file on disk has not yet been opened,
+** return 0. Otherwise, return 1.
+*/
+int sqlite3JournalExists(sqlite3_file *p){
+ return (p->pMethods!=&JournalFileMethods || ((JournalFile *)p)->pReal!=0);
+}
+
/*
** Return the number of bytes required to store a JournalFile that uses vfs
** pVfs to create the underlying on-disk files.
diff --git a/lib/libsqlite3/src/lempar.c b/lib/libsqlite3/src/lempar.c
index cb6025e87bb..2afaa6cea6d 100644
--- a/lib/libsqlite3/src/lempar.c
+++ b/lib/libsqlite3/src/lempar.c
@@ -608,6 +608,7 @@ static void yy_reduce(
*/
%%
};
+ assert( yyruleno>=0 && yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) );
yygoto = yyRuleInfo[yyruleno].lhs;
yysize = yyRuleInfo[yyruleno].nrhs;
yypParser->yyidx -= yysize;
diff --git a/lib/libsqlite3/src/main.c b/lib/libsqlite3/src/main.c
index 16294a61997..b52d4744431 100644
--- a/lib/libsqlite3/src/main.c
+++ b/lib/libsqlite3/src/main.c
@@ -132,6 +132,13 @@ int sqlite3_initialize(void){
*/
if( sqlite3GlobalConfig.isInit ) return SQLITE_OK;
+#ifdef SQLITE_ENABLE_SQLLOG
+ {
+ extern void sqlite3_init_sqllog(void);
+ sqlite3_init_sqllog();
+ }
+#endif
+
/* Make sure the mutex subsystem is initialized. If unable to
** initialize the mutex subsystem, return early with the error.
** If the system is so sick that we are unable to allocate a mutex,
@@ -475,6 +482,20 @@ int sqlite3_config(int op, ...){
break;
}
+ case SQLITE_CONFIG_COVERING_INDEX_SCAN: {
+ sqlite3GlobalConfig.bUseCis = va_arg(ap, int);
+ break;
+ }
+
+#ifdef SQLITE_ENABLE_SQLLOG
+ case SQLITE_CONFIG_SQLLOG: {
+ typedef void(*SQLLOGFUNC_t)(void*, sqlite3*, const char*, int);
+ sqlite3GlobalConfig.xSqllog = va_arg(ap, SQLLOGFUNC_t);
+ sqlite3GlobalConfig.pSqllogArg = va_arg(ap, void *);
+ break;
+ }
+#endif
+
default: {
rc = SQLITE_ERROR;
break;
@@ -814,6 +835,13 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
return SQLITE_BUSY;
}
+#ifdef SQLITE_ENABLE_SQLLOG
+ if( sqlite3GlobalConfig.xSqllog ){
+ /* Closing the handle. Fourth parameter is passed the value 2. */
+ sqlite3GlobalConfig.xSqllog(sqlite3GlobalConfig.pSqllogArg, db, 0, 2);
+ }
+#endif
+
/* Convert the connection into a zombie and then close it.
*/
db->magic = SQLITE_MAGIC_ZOMBIE;
@@ -1116,6 +1144,7 @@ int sqlite3_busy_handler(
db->busyHandler.xFunc = xBusy;
db->busyHandler.pArg = pArg;
db->busyHandler.nBusy = 0;
+ db->busyTimeout = 0;
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
@@ -1153,8 +1182,8 @@ void sqlite3_progress_handler(
*/
int sqlite3_busy_timeout(sqlite3 *db, int ms){
if( ms>0 ){
- db->busyTimeout = ms;
sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db);
+ db->busyTimeout = ms;
}else{
sqlite3_busy_handler(db, 0, 0);
}
@@ -1768,6 +1797,15 @@ int sqlite3_extended_errcode(sqlite3 *db){
}
/*
+** Return a string that describes the kind of error specified in the
+** argument. For now, this simply calls the internal sqlite3ErrStr()
+** function.
+*/
+const char *sqlite3_errstr(int rc){
+ return sqlite3ErrStr(rc);
+}
+
+/*
** Create a new collating function for database "db". The name is zName
** and the encoding is enc.
*/
@@ -2436,6 +2474,13 @@ opendb_out:
db->magic = SQLITE_MAGIC_SICK;
}
*ppDb = db;
+#ifdef SQLITE_ENABLE_SQLLOG
+ if( sqlite3GlobalConfig.xSqllog ){
+ /* Opening a db handle. Fourth parameter is passed 0. */
+ void *pArg = sqlite3GlobalConfig.pSqllogArg;
+ sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0);
+ }
+#endif
return sqlite3ApiExit(0, rc);
}
@@ -2741,7 +2786,7 @@ int sqlite3_table_column_metadata(
zDataType = pCol->zType;
zCollSeq = pCol->zColl;
notnull = pCol->notNull!=0;
- primarykey = pCol->isPrimKey!=0;
+ primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0;
autoinc = pTab->iPKey==iCol && (pTab->tabFlags & TF_Autoincrement)!=0;
}else{
zDataType = "INTEGER";
@@ -3004,8 +3049,7 @@ int sqlite3_test_control(int op, ...){
*/
case SQLITE_TESTCTRL_OPTIMIZATIONS: {
sqlite3 *db = va_arg(ap, sqlite3*);
- int x = va_arg(ap,int);
- db->flags = (x & SQLITE_OptMask) | (db->flags & ~SQLITE_OptMask);
+ db->dbOptFlags = (u16)(va_arg(ap, int) & 0xffff);
break;
}
diff --git a/lib/libsqlite3/src/os_unix.c b/lib/libsqlite3/src/os_unix.c
index c0df66e8e07..315f1501888 100644
--- a/lib/libsqlite3/src/os_unix.c
+++ b/lib/libsqlite3/src/os_unix.c
@@ -46,6 +46,13 @@
#include "sqliteInt.h"
#if SQLITE_OS_UNIX /* This file is used on unix only */
+/* Use posix_fallocate() if it is available
+*/
+#if !defined(HAVE_POSIX_FALLOCATE) \
+ && (_XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L)
+# define HAVE_POSIX_FALLOCATE 1
+#endif
+
/*
** There are various methods for file locking used for concurrency
** control:
@@ -218,6 +225,10 @@ struct unixFile {
const char *zPath; /* Name of the file */
unixShm *pShm; /* Shared memory segment information */
int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
+#ifdef __QNXNTO__
+ int sectorSize; /* Device sector size */
+ int deviceCharacteristics; /* Precomputed device characteristics */
+#endif
#if SQLITE_ENABLE_LOCKING_STYLE
int openFlags; /* The flags specified at open() */
#endif
@@ -2086,13 +2097,13 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
** Close a file. Make sure the lock has been released before closing.
*/
static int dotlockClose(sqlite3_file *id) {
- int rc;
+ int rc = SQLITE_OK;
if( id ){
unixFile *pFile = (unixFile*)id;
dotlockUnlock(id, NO_LOCK);
sqlite3_free(pFile->lockingContext);
+ rc = closeUnixFile(id);
}
- rc = closeUnixFile(id);
return rc;
}
/****************** End of the dot-file lock implementation *******************
@@ -2296,10 +2307,12 @@ static int flockUnlock(sqlite3_file *id, int eFileLock) {
** Close a file.
*/
static int flockClose(sqlite3_file *id) {
+ int rc = SQLITE_OK;
if( id ){
flockUnlock(id, NO_LOCK);
+ rc = closeUnixFile(id);
}
- return closeUnixFile(id);
+ return rc;
}
#endif /* SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORK */
@@ -3010,6 +3023,8 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
i64 newOffset;
#endif
TIMER_START;
+ assert( cnt==(cnt&0x1ffff) );
+ cnt &= 0x1ffff;
do{
#if defined(USE_PREAD)
got = osPread(id->h, pBuf, cnt, offset);
@@ -3099,6 +3114,8 @@ static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){
#if (!defined(USE_PREAD) && !defined(USE_PREAD64))
i64 newOffset;
#endif
+ assert( cnt==(cnt&0x1ffff) );
+ cnt &= 0x1ffff;
TIMER_START;
#if defined(USE_PREAD)
do{ got = osPwrite(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
@@ -3564,6 +3581,9 @@ static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){
}
}
+/* Forward declaration */
+static int unixGetTempname(int nBuf, char *zBuf);
+
/*
** Information and control of an open file handle.
*/
@@ -3601,6 +3621,14 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
*(char**)pArg = sqlite3_mprintf("%s", pFile->pVfs->zName);
return SQLITE_OK;
}
+ case SQLITE_FCNTL_TEMPFILENAME: {
+ char *zTFile = sqlite3_malloc( pFile->pVfs->mxPathname );
+ if( zTFile ){
+ unixGetTempname(pFile->pVfs->mxPathname, zTFile);
+ *(char**)pArg = zTFile;
+ }
+ return SQLITE_OK;
+ }
#ifdef SQLITE_DEBUG
/* The pager calls this method to signal that it has done
** a rollback and that the database is therefore unchanged and
@@ -3632,10 +3660,92 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
** a database and its journal file) that the sector size will be the
** same for both.
*/
-static int unixSectorSize(sqlite3_file *pFile){
- (void)pFile;
+#ifndef __QNXNTO__
+static int unixSectorSize(sqlite3_file *NotUsed){
+ UNUSED_PARAMETER(NotUsed);
return SQLITE_DEFAULT_SECTOR_SIZE;
}
+#endif
+
+/*
+** The following version of unixSectorSize() is optimized for QNX.
+*/
+#ifdef __QNXNTO__
+#include <sys/dcmd_blk.h>
+#include <sys/statvfs.h>
+static int unixSectorSize(sqlite3_file *id){
+ unixFile *pFile = (unixFile*)id;
+ if( pFile->sectorSize == 0 ){
+ struct statvfs fsInfo;
+
+ /* Set defaults for non-supported filesystems */
+ pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
+ pFile->deviceCharacteristics = 0;
+ if( fstatvfs(pFile->h, &fsInfo) == -1 ) {
+ return pFile->sectorSize;
+ }
+
+ if( !strcmp(fsInfo.f_basetype, "tmp") ) {
+ pFile->sectorSize = fsInfo.f_bsize;
+ pFile->deviceCharacteristics =
+ SQLITE_IOCAP_ATOMIC4K | /* All ram filesystem writes are atomic */
+ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until
+ ** the write succeeds */
+ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
+ ** so it is ordered */
+ 0;
+ }else if( strstr(fsInfo.f_basetype, "etfs") ){
+ pFile->sectorSize = fsInfo.f_bsize;
+ pFile->deviceCharacteristics =
+ /* etfs cluster size writes are atomic */
+ (pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) |
+ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until
+ ** the write succeeds */
+ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
+ ** so it is ordered */
+ 0;
+ }else if( !strcmp(fsInfo.f_basetype, "qnx6") ){
+ pFile->sectorSize = fsInfo.f_bsize;
+ pFile->deviceCharacteristics =
+ SQLITE_IOCAP_ATOMIC | /* All filesystem writes are atomic */
+ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until
+ ** the write succeeds */
+ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
+ ** so it is ordered */
+ 0;
+ }else if( !strcmp(fsInfo.f_basetype, "qnx4") ){
+ pFile->sectorSize = fsInfo.f_bsize;
+ pFile->deviceCharacteristics =
+ /* full bitset of atomics from max sector size and smaller */
+ ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 |
+ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
+ ** so it is ordered */
+ 0;
+ }else if( strstr(fsInfo.f_basetype, "dos") ){
+ pFile->sectorSize = fsInfo.f_bsize;
+ pFile->deviceCharacteristics =
+ /* full bitset of atomics from max sector size and smaller */
+ ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 |
+ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
+ ** so it is ordered */
+ 0;
+ }else{
+ pFile->deviceCharacteristics =
+ SQLITE_IOCAP_ATOMIC512 | /* blocks are atomic */
+ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until
+ ** the write succeeds */
+ 0;
+ }
+ }
+ /* Last chance verification. If the sector size isn't a multiple of 512
+ ** then it isn't valid.*/
+ if( pFile->sectorSize % 512 != 0 ){
+ pFile->deviceCharacteristics = 0;
+ pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
+ }
+ return pFile->sectorSize;
+}
+#endif /* __QNXNTO__ */
/*
** Return the device characteristics for the file.
@@ -3652,11 +3762,15 @@ static int unixSectorSize(sqlite3_file *pFile){
*/
static int unixDeviceCharacteristics(sqlite3_file *id){
unixFile *p = (unixFile*)id;
+ int rc = 0;
+#ifdef __QNXNTO__
+ if( p->sectorSize==0 ) unixSectorSize(id);
+ rc = p->deviceCharacteristics;
+#endif
if( p->ctrlFlags & UNIXFILE_PSOW ){
- return SQLITE_IOCAP_POWERSAFE_OVERWRITE;
- }else{
- return 0;
+ rc |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
}
+ return rc;
}
#ifndef SQLITE_OMIT_WAL
@@ -4072,11 +4186,19 @@ static int unixShmMap(
** the requested memory region.
*/
if( !bExtend ) goto shmpage_out;
+#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
+ if( osFallocate(pShmNode->h, sStat.st_size, nByte)!=0 ){
+ rc = unixLogError(SQLITE_IOERR_SHMSIZE, "fallocate",
+ pShmNode->zFilename);
+ goto shmpage_out;
+ }
+#else
if( robust_ftruncate(pShmNode->h, nByte) ){
rc = unixLogError(SQLITE_IOERR_SHMSIZE, "ftruncate",
pShmNode->zFilename);
goto shmpage_out;
}
+#endif
}
}
@@ -4094,7 +4216,7 @@ static int unixShmMap(
if( pShmNode->h>=0 ){
pMem = mmap(0, szRegion,
pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE,
- MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion
+ MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion
);
if( pMem==MAP_FAILED ){
rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename);
@@ -5278,8 +5400,13 @@ static int unixDelete(
int rc = SQLITE_OK;
UNUSED_PARAMETER(NotUsed);
SimulateIOError(return SQLITE_IOERR_DELETE);
- if( osUnlink(zPath)==(-1) && errno!=ENOENT ){
- return unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath);
+ if( osUnlink(zPath)==(-1) ){
+ if( errno==ENOENT ){
+ rc = SQLITE_IOERR_DELETE_NOENT;
+ }else{
+ rc = unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath);
+ }
+ return rc;
}
#ifndef SQLITE_DISABLE_DIRSYNC
if( (dirSync & 1)!=0 ){
diff --git a/lib/libsqlite3/src/os_win.c b/lib/libsqlite3/src/os_win.c
index cbf17b1517e..107370c41be 100644
--- a/lib/libsqlite3/src/os_win.c
+++ b/lib/libsqlite3/src/os_win.c
@@ -25,6 +25,66 @@
#include "os_common.h"
/*
+** Compiling and using WAL mode requires several APIs that are only
+** available in Windows platforms based on the NT kernel.
+*/
+#if !SQLITE_OS_WINNT && !defined(SQLITE_OMIT_WAL)
+# error "WAL mode requires support from the Windows NT kernel, compile\
+ with SQLITE_OMIT_WAL."
+#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
+# define SQLITE_WIN32_HAS_ANSI
+#endif
+
+/*
+** Are most of the Win32 Unicode APIs available (i.e. with certain exceptions
+** based on the sub-platform)?
+*/
+#if SQLITE_OS_WINCE || SQLITE_OS_WINNT || SQLITE_OS_WINRT
+# define SQLITE_WIN32_HAS_WIDE
+#endif
+
+/*
+** Do we need to manually define the Win32 file mapping APIs for use with WAL
+** 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)
+/*
+** Two of the file mapping APIs are different under WinRT. Figure out which
+** set we need.
+*/
+#if SQLITE_OS_WINRT
+WINBASEAPI HANDLE WINAPI CreateFileMappingFromApp(HANDLE, \
+ LPSECURITY_ATTRIBUTES, ULONG, ULONG64, LPCWSTR);
+
+WINBASEAPI LPVOID WINAPI MapViewOfFileFromApp(HANDLE, ULONG, ULONG64, SIZE_T);
+#else
+#if defined(SQLITE_WIN32_HAS_ANSI)
+WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE, LPSECURITY_ATTRIBUTES, \
+ DWORD, DWORD, DWORD, LPCSTR);
+#endif /* defined(SQLITE_WIN32_HAS_ANSI) */
+
+#if defined(SQLITE_WIN32_HAS_WIDE)
+WINBASEAPI HANDLE WINAPI CreateFileMappingW(HANDLE, LPSECURITY_ATTRIBUTES, \
+ DWORD, DWORD, DWORD, LPCWSTR);
+#endif /* defined(SQLITE_WIN32_HAS_WIDE) */
+
+WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, SIZE_T);
+#endif /* SQLITE_OS_WINRT */
+
+/*
+** This file mapping API is common to both Win32 and WinRT.
+*/
+WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID);
+#endif /* SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL) */
+
+/*
** Macro to find the minimum of two numeric values.
*/
#ifndef MIN
@@ -229,14 +289,6 @@ int sqlite3_os_type = 0;
static int sqlite3_os_type = 0;
#endif
-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
-# define SQLITE_WIN32_HAS_ANSI
-#endif
-
-#if SQLITE_OS_WINCE || SQLITE_OS_WINNT || SQLITE_OS_WINRT
-# define SQLITE_WIN32_HAS_WIDE
-#endif
-
#ifndef SYSCALL
# define SYSCALL sqlite3_syscall_ptr
#endif
@@ -308,6 +360,16 @@ static struct win_syscall {
#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))
+ { "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))
{ "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 },
@@ -316,7 +378,7 @@ static struct win_syscall {
#endif
#define osCreateFileMappingW ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \
- DWORD,DWORD,DWORD,LPCWSTR))aSyscall[6].pCurrent)
+ DWORD,DWORD,DWORD,LPCWSTR))aSyscall[7].pCurrent)
#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
{ "CreateMutexW", (SYSCALL)CreateMutexW, 0 },
@@ -325,7 +387,7 @@ static struct win_syscall {
#endif
#define osCreateMutexW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,BOOL, \
- LPCWSTR))aSyscall[7].pCurrent)
+ LPCWSTR))aSyscall[8].pCurrent)
#if defined(SQLITE_WIN32_HAS_ANSI)
{ "DeleteFileA", (SYSCALL)DeleteFileA, 0 },
@@ -333,7 +395,7 @@ static struct win_syscall {
{ "DeleteFileA", (SYSCALL)0, 0 },
#endif
-#define osDeleteFileA ((BOOL(WINAPI*)(LPCSTR))aSyscall[8].pCurrent)
+#define osDeleteFileA ((BOOL(WINAPI*)(LPCSTR))aSyscall[9].pCurrent)
#if defined(SQLITE_WIN32_HAS_WIDE)
{ "DeleteFileW", (SYSCALL)DeleteFileW, 0 },
@@ -341,7 +403,7 @@ static struct win_syscall {
{ "DeleteFileW", (SYSCALL)0, 0 },
#endif
-#define osDeleteFileW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[9].pCurrent)
+#define osDeleteFileW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[10].pCurrent)
#if SQLITE_OS_WINCE
{ "FileTimeToLocalFileTime", (SYSCALL)FileTimeToLocalFileTime, 0 },
@@ -350,7 +412,7 @@ static struct win_syscall {
#endif
#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(CONST FILETIME*, \
- LPFILETIME))aSyscall[10].pCurrent)
+ LPFILETIME))aSyscall[11].pCurrent)
#if SQLITE_OS_WINCE
{ "FileTimeToSystemTime", (SYSCALL)FileTimeToSystemTime, 0 },
@@ -359,11 +421,11 @@ static struct win_syscall {
#endif
#define osFileTimeToSystemTime ((BOOL(WINAPI*)(CONST FILETIME*, \
- LPSYSTEMTIME))aSyscall[11].pCurrent)
+ LPSYSTEMTIME))aSyscall[12].pCurrent)
{ "FlushFileBuffers", (SYSCALL)FlushFileBuffers, 0 },
-#define osFlushFileBuffers ((BOOL(WINAPI*)(HANDLE))aSyscall[12].pCurrent)
+#define osFlushFileBuffers ((BOOL(WINAPI*)(HANDLE))aSyscall[13].pCurrent)
#if defined(SQLITE_WIN32_HAS_ANSI)
{ "FormatMessageA", (SYSCALL)FormatMessageA, 0 },
@@ -372,7 +434,7 @@ static struct win_syscall {
#endif
#define osFormatMessageA ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPSTR, \
- DWORD,va_list*))aSyscall[13].pCurrent)
+ DWORD,va_list*))aSyscall[14].pCurrent)
#if defined(SQLITE_WIN32_HAS_WIDE)
{ "FormatMessageW", (SYSCALL)FormatMessageW, 0 },
@@ -381,15 +443,19 @@ static struct win_syscall {
#endif
#define osFormatMessageW ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPWSTR, \
- DWORD,va_list*))aSyscall[14].pCurrent)
+ DWORD,va_list*))aSyscall[15].pCurrent)
+#if !defined(SQLITE_OMIT_LOAD_EXTENSION)
{ "FreeLibrary", (SYSCALL)FreeLibrary, 0 },
+#else
+ { "FreeLibrary", (SYSCALL)0, 0 },
+#endif
-#define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[15].pCurrent)
+#define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[16].pCurrent)
{ "GetCurrentProcessId", (SYSCALL)GetCurrentProcessId, 0 },
-#define osGetCurrentProcessId ((DWORD(WINAPI*)(VOID))aSyscall[16].pCurrent)
+#define osGetCurrentProcessId ((DWORD(WINAPI*)(VOID))aSyscall[17].pCurrent)
#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI)
{ "GetDiskFreeSpaceA", (SYSCALL)GetDiskFreeSpaceA, 0 },
@@ -398,7 +464,7 @@ static struct win_syscall {
#endif
#define osGetDiskFreeSpaceA ((BOOL(WINAPI*)(LPCSTR,LPDWORD,LPDWORD,LPDWORD, \
- LPDWORD))aSyscall[17].pCurrent)
+ LPDWORD))aSyscall[18].pCurrent)
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
{ "GetDiskFreeSpaceW", (SYSCALL)GetDiskFreeSpaceW, 0 },
@@ -407,7 +473,7 @@ static struct win_syscall {
#endif
#define osGetDiskFreeSpaceW ((BOOL(WINAPI*)(LPCWSTR,LPDWORD,LPDWORD,LPDWORD, \
- LPDWORD))aSyscall[18].pCurrent)
+ LPDWORD))aSyscall[19].pCurrent)
#if defined(SQLITE_WIN32_HAS_ANSI)
{ "GetFileAttributesA", (SYSCALL)GetFileAttributesA, 0 },
@@ -415,7 +481,7 @@ static struct win_syscall {
{ "GetFileAttributesA", (SYSCALL)0, 0 },
#endif
-#define osGetFileAttributesA ((DWORD(WINAPI*)(LPCSTR))aSyscall[19].pCurrent)
+#define osGetFileAttributesA ((DWORD(WINAPI*)(LPCSTR))aSyscall[20].pCurrent)
#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
{ "GetFileAttributesW", (SYSCALL)GetFileAttributesW, 0 },
@@ -423,7 +489,7 @@ static struct win_syscall {
{ "GetFileAttributesW", (SYSCALL)0, 0 },
#endif
-#define osGetFileAttributesW ((DWORD(WINAPI*)(LPCWSTR))aSyscall[20].pCurrent)
+#define osGetFileAttributesW ((DWORD(WINAPI*)(LPCWSTR))aSyscall[21].pCurrent)
#if defined(SQLITE_WIN32_HAS_WIDE)
{ "GetFileAttributesExW", (SYSCALL)GetFileAttributesExW, 0 },
@@ -432,7 +498,7 @@ static struct win_syscall {
#endif
#define osGetFileAttributesExW ((BOOL(WINAPI*)(LPCWSTR,GET_FILEEX_INFO_LEVELS, \
- LPVOID))aSyscall[21].pCurrent)
+ LPVOID))aSyscall[22].pCurrent)
#if !SQLITE_OS_WINRT
{ "GetFileSize", (SYSCALL)GetFileSize, 0 },
@@ -440,7 +506,7 @@ static struct win_syscall {
{ "GetFileSize", (SYSCALL)0, 0 },
#endif
-#define osGetFileSize ((DWORD(WINAPI*)(HANDLE,LPDWORD))aSyscall[22].pCurrent)
+#define osGetFileSize ((DWORD(WINAPI*)(HANDLE,LPDWORD))aSyscall[23].pCurrent)
#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI)
{ "GetFullPathNameA", (SYSCALL)GetFullPathNameA, 0 },
@@ -449,7 +515,7 @@ static struct win_syscall {
#endif
#define osGetFullPathNameA ((DWORD(WINAPI*)(LPCSTR,DWORD,LPSTR, \
- LPSTR*))aSyscall[23].pCurrent)
+ LPSTR*))aSyscall[24].pCurrent)
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
{ "GetFullPathNameW", (SYSCALL)GetFullPathNameW, 0 },
@@ -458,12 +524,13 @@ static struct win_syscall {
#endif
#define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \
- LPWSTR*))aSyscall[24].pCurrent)
+ LPWSTR*))aSyscall[25].pCurrent)
{ "GetLastError", (SYSCALL)GetLastError, 0 },
-#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[25].pCurrent)
+#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent)
+#if !defined(SQLITE_OMIT_LOAD_EXTENSION)
#if SQLITE_OS_WINCE
/* The GetProcAddressA() routine is only available on Windows CE. */
{ "GetProcAddressA", (SYSCALL)GetProcAddressA, 0 },
@@ -472,9 +539,12 @@ static struct win_syscall {
** an ANSI string regardless of the _UNICODE setting */
{ "GetProcAddressA", (SYSCALL)GetProcAddress, 0 },
#endif
+#else
+ { "GetProcAddressA", (SYSCALL)0, 0 },
+#endif
#define osGetProcAddressA ((FARPROC(WINAPI*)(HMODULE, \
- LPCSTR))aSyscall[26].pCurrent)
+ LPCSTR))aSyscall[27].pCurrent)
#if !SQLITE_OS_WINRT
{ "GetSystemInfo", (SYSCALL)GetSystemInfo, 0 },
@@ -482,11 +552,11 @@ static struct win_syscall {
{ "GetSystemInfo", (SYSCALL)0, 0 },
#endif
-#define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[27].pCurrent)
+#define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[28].pCurrent)
{ "GetSystemTime", (SYSCALL)GetSystemTime, 0 },
-#define osGetSystemTime ((VOID(WINAPI*)(LPSYSTEMTIME))aSyscall[28].pCurrent)
+#define osGetSystemTime ((VOID(WINAPI*)(LPSYSTEMTIME))aSyscall[29].pCurrent)
#if !SQLITE_OS_WINCE
{ "GetSystemTimeAsFileTime", (SYSCALL)GetSystemTimeAsFileTime, 0 },
@@ -495,7 +565,7 @@ static struct win_syscall {
#endif
#define osGetSystemTimeAsFileTime ((VOID(WINAPI*)( \
- LPFILETIME))aSyscall[29].pCurrent)
+ LPFILETIME))aSyscall[30].pCurrent)
#if defined(SQLITE_WIN32_HAS_ANSI)
{ "GetTempPathA", (SYSCALL)GetTempPathA, 0 },
@@ -503,7 +573,7 @@ static struct win_syscall {
{ "GetTempPathA", (SYSCALL)0, 0 },
#endif
-#define osGetTempPathA ((DWORD(WINAPI*)(DWORD,LPSTR))aSyscall[30].pCurrent)
+#define osGetTempPathA ((DWORD(WINAPI*)(DWORD,LPSTR))aSyscall[31].pCurrent)
#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
{ "GetTempPathW", (SYSCALL)GetTempPathW, 0 },
@@ -511,7 +581,7 @@ static struct win_syscall {
{ "GetTempPathW", (SYSCALL)0, 0 },
#endif
-#define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[31].pCurrent)
+#define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[32].pCurrent)
#if !SQLITE_OS_WINRT
{ "GetTickCount", (SYSCALL)GetTickCount, 0 },
@@ -519,7 +589,7 @@ static struct win_syscall {
{ "GetTickCount", (SYSCALL)0, 0 },
#endif
-#define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[32].pCurrent)
+#define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent)
#if defined(SQLITE_WIN32_HAS_ANSI)
{ "GetVersionExA", (SYSCALL)GetVersionExA, 0 },
@@ -528,12 +598,12 @@ static struct win_syscall {
#endif
#define osGetVersionExA ((BOOL(WINAPI*)( \
- LPOSVERSIONINFOA))aSyscall[33].pCurrent)
+ LPOSVERSIONINFOA))aSyscall[34].pCurrent)
{ "HeapAlloc", (SYSCALL)HeapAlloc, 0 },
#define osHeapAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD, \
- SIZE_T))aSyscall[34].pCurrent)
+ SIZE_T))aSyscall[35].pCurrent)
#if !SQLITE_OS_WINRT
{ "HeapCreate", (SYSCALL)HeapCreate, 0 },
@@ -542,7 +612,7 @@ static struct win_syscall {
#endif
#define osHeapCreate ((HANDLE(WINAPI*)(DWORD,SIZE_T, \
- SIZE_T))aSyscall[35].pCurrent)
+ SIZE_T))aSyscall[36].pCurrent)
#if !SQLITE_OS_WINRT
{ "HeapDestroy", (SYSCALL)HeapDestroy, 0 },
@@ -550,21 +620,21 @@ static struct win_syscall {
{ "HeapDestroy", (SYSCALL)0, 0 },
#endif
-#define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[36].pCurrent)
+#define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[37].pCurrent)
{ "HeapFree", (SYSCALL)HeapFree, 0 },
-#define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[37].pCurrent)
+#define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[38].pCurrent)
{ "HeapReAlloc", (SYSCALL)HeapReAlloc, 0 },
#define osHeapReAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD,LPVOID, \
- SIZE_T))aSyscall[38].pCurrent)
+ SIZE_T))aSyscall[39].pCurrent)
{ "HeapSize", (SYSCALL)HeapSize, 0 },
#define osHeapSize ((SIZE_T(WINAPI*)(HANDLE,DWORD, \
- LPCVOID))aSyscall[39].pCurrent)
+ LPCVOID))aSyscall[40].pCurrent)
#if !SQLITE_OS_WINRT
{ "HeapValidate", (SYSCALL)HeapValidate, 0 },
@@ -573,23 +643,24 @@ static struct win_syscall {
#endif
#define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \
- LPCVOID))aSyscall[40].pCurrent)
+ LPCVOID))aSyscall[41].pCurrent)
-#if defined(SQLITE_WIN32_HAS_ANSI)
+#if defined(SQLITE_WIN32_HAS_ANSI) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
{ "LoadLibraryA", (SYSCALL)LoadLibraryA, 0 },
#else
{ "LoadLibraryA", (SYSCALL)0, 0 },
#endif
-#define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[41].pCurrent)
+#define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[42].pCurrent)
-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
+#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
+ !defined(SQLITE_OMIT_LOAD_EXTENSION)
{ "LoadLibraryW", (SYSCALL)LoadLibraryW, 0 },
#else
{ "LoadLibraryW", (SYSCALL)0, 0 },
#endif
-#define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[42].pCurrent)
+#define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[43].pCurrent)
#if !SQLITE_OS_WINRT
{ "LocalFree", (SYSCALL)LocalFree, 0 },
@@ -597,7 +668,7 @@ static struct win_syscall {
{ "LocalFree", (SYSCALL)0, 0 },
#endif
-#define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[43].pCurrent)
+#define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[44].pCurrent)
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
{ "LockFile", (SYSCALL)LockFile, 0 },
@@ -607,7 +678,7 @@ static struct win_syscall {
#ifndef osLockFile
#define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
- DWORD))aSyscall[44].pCurrent)
+ DWORD))aSyscall[45].pCurrent)
#endif
#if !SQLITE_OS_WINCE
@@ -618,7 +689,7 @@ static struct win_syscall {
#ifndef osLockFileEx
#define osLockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD,DWORD, \
- LPOVERLAPPED))aSyscall[45].pCurrent)
+ LPOVERLAPPED))aSyscall[46].pCurrent)
#endif
#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL))
@@ -628,26 +699,26 @@ static struct win_syscall {
#endif
#define osMapViewOfFile ((LPVOID(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
- SIZE_T))aSyscall[46].pCurrent)
+ SIZE_T))aSyscall[47].pCurrent)
{ "MultiByteToWideChar", (SYSCALL)MultiByteToWideChar, 0 },
#define osMultiByteToWideChar ((int(WINAPI*)(UINT,DWORD,LPCSTR,int,LPWSTR, \
- int))aSyscall[47].pCurrent)
+ int))aSyscall[48].pCurrent)
{ "QueryPerformanceCounter", (SYSCALL)QueryPerformanceCounter, 0 },
#define osQueryPerformanceCounter ((BOOL(WINAPI*)( \
- LARGE_INTEGER*))aSyscall[48].pCurrent)
+ LARGE_INTEGER*))aSyscall[49].pCurrent)
{ "ReadFile", (SYSCALL)ReadFile, 0 },
#define osReadFile ((BOOL(WINAPI*)(HANDLE,LPVOID,DWORD,LPDWORD, \
- LPOVERLAPPED))aSyscall[49].pCurrent)
+ LPOVERLAPPED))aSyscall[50].pCurrent)
{ "SetEndOfFile", (SYSCALL)SetEndOfFile, 0 },
-#define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[50].pCurrent)
+#define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[51].pCurrent)
#if !SQLITE_OS_WINRT
{ "SetFilePointer", (SYSCALL)SetFilePointer, 0 },
@@ -656,7 +727,7 @@ static struct win_syscall {
#endif
#define osSetFilePointer ((DWORD(WINAPI*)(HANDLE,LONG,PLONG, \
- DWORD))aSyscall[51].pCurrent)
+ DWORD))aSyscall[52].pCurrent)
#if !SQLITE_OS_WINRT
{ "Sleep", (SYSCALL)Sleep, 0 },
@@ -664,12 +735,12 @@ static struct win_syscall {
{ "Sleep", (SYSCALL)0, 0 },
#endif
-#define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[52].pCurrent)
+#define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[53].pCurrent)
{ "SystemTimeToFileTime", (SYSCALL)SystemTimeToFileTime, 0 },
#define osSystemTimeToFileTime ((BOOL(WINAPI*)(CONST SYSTEMTIME*, \
- LPFILETIME))aSyscall[53].pCurrent)
+ LPFILETIME))aSyscall[54].pCurrent)
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
{ "UnlockFile", (SYSCALL)UnlockFile, 0 },
@@ -679,7 +750,7 @@ static struct win_syscall {
#ifndef osUnlockFile
#define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
- DWORD))aSyscall[54].pCurrent)
+ DWORD))aSyscall[55].pCurrent)
#endif
#if !SQLITE_OS_WINCE
@@ -689,7 +760,7 @@ static struct win_syscall {
#endif
#define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
- LPOVERLAPPED))aSyscall[55].pCurrent)
+ LPOVERLAPPED))aSyscall[56].pCurrent)
#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL)
{ "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 },
@@ -697,17 +768,17 @@ static struct win_syscall {
{ "UnmapViewOfFile", (SYSCALL)0, 0 },
#endif
-#define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[56].pCurrent)
+#define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[57].pCurrent)
{ "WideCharToMultiByte", (SYSCALL)WideCharToMultiByte, 0 },
#define osWideCharToMultiByte ((int(WINAPI*)(UINT,DWORD,LPCWSTR,int,LPSTR,int, \
- LPCSTR,LPBOOL))aSyscall[57].pCurrent)
+ LPCSTR,LPBOOL))aSyscall[58].pCurrent)
{ "WriteFile", (SYSCALL)WriteFile, 0 },
#define osWriteFile ((BOOL(WINAPI*)(HANDLE,LPCVOID,DWORD,LPDWORD, \
- LPOVERLAPPED))aSyscall[58].pCurrent)
+ LPOVERLAPPED))aSyscall[59].pCurrent)
#if SQLITE_OS_WINRT
{ "CreateEventExW", (SYSCALL)CreateEventExW, 0 },
@@ -716,7 +787,7 @@ static struct win_syscall {
#endif
#define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \
- DWORD,DWORD))aSyscall[59].pCurrent)
+ DWORD,DWORD))aSyscall[60].pCurrent)
#if !SQLITE_OS_WINRT
{ "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 },
@@ -725,7 +796,7 @@ static struct win_syscall {
#endif
#define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \
- DWORD))aSyscall[60].pCurrent)
+ DWORD))aSyscall[61].pCurrent)
#if SQLITE_OS_WINRT
{ "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 },
@@ -734,7 +805,7 @@ static struct win_syscall {
#endif
#define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \
- BOOL))aSyscall[61].pCurrent)
+ BOOL))aSyscall[62].pCurrent)
#if SQLITE_OS_WINRT
{ "SetFilePointerEx", (SYSCALL)SetFilePointerEx, 0 },
@@ -743,7 +814,7 @@ static struct win_syscall {
#endif
#define osSetFilePointerEx ((BOOL(WINAPI*)(HANDLE,LARGE_INTEGER, \
- PLARGE_INTEGER,DWORD))aSyscall[62].pCurrent)
+ PLARGE_INTEGER,DWORD))aSyscall[63].pCurrent)
#if SQLITE_OS_WINRT
{ "GetFileInformationByHandleEx", (SYSCALL)GetFileInformationByHandleEx, 0 },
@@ -752,7 +823,7 @@ static struct win_syscall {
#endif
#define osGetFileInformationByHandleEx ((BOOL(WINAPI*)(HANDLE, \
- FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[63].pCurrent)
+ FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[64].pCurrent)
#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL)
{ "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 },
@@ -761,7 +832,7 @@ static struct win_syscall {
#endif
#define osMapViewOfFileFromApp ((LPVOID(WINAPI*)(HANDLE,ULONG,ULONG64, \
- SIZE_T))aSyscall[64].pCurrent)
+ SIZE_T))aSyscall[65].pCurrent)
#if SQLITE_OS_WINRT
{ "CreateFile2", (SYSCALL)CreateFile2, 0 },
@@ -770,16 +841,16 @@ static struct win_syscall {
#endif
#define osCreateFile2 ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD,DWORD, \
- LPCREATEFILE2_EXTENDED_PARAMETERS))aSyscall[65].pCurrent)
+ LPCREATEFILE2_EXTENDED_PARAMETERS))aSyscall[66].pCurrent)
-#if SQLITE_OS_WINRT
+#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_LOAD_EXTENSION)
{ "LoadPackagedLibrary", (SYSCALL)LoadPackagedLibrary, 0 },
#else
{ "LoadPackagedLibrary", (SYSCALL)0, 0 },
#endif
#define osLoadPackagedLibrary ((HMODULE(WINAPI*)(LPCWSTR, \
- DWORD))aSyscall[66].pCurrent)
+ DWORD))aSyscall[67].pCurrent)
#if SQLITE_OS_WINRT
{ "GetTickCount64", (SYSCALL)GetTickCount64, 0 },
@@ -787,7 +858,7 @@ static struct win_syscall {
{ "GetTickCount64", (SYSCALL)0, 0 },
#endif
-#define osGetTickCount64 ((ULONGLONG(WINAPI*)(VOID))aSyscall[67].pCurrent)
+#define osGetTickCount64 ((ULONGLONG(WINAPI*)(VOID))aSyscall[68].pCurrent)
#if SQLITE_OS_WINRT
{ "GetNativeSystemInfo", (SYSCALL)GetNativeSystemInfo, 0 },
@@ -796,7 +867,7 @@ static struct win_syscall {
#endif
#define osGetNativeSystemInfo ((VOID(WINAPI*)( \
- LPSYSTEM_INFO))aSyscall[68].pCurrent)
+ LPSYSTEM_INFO))aSyscall[69].pCurrent)
#if defined(SQLITE_WIN32_HAS_ANSI)
{ "OutputDebugStringA", (SYSCALL)OutputDebugStringA, 0 },
@@ -804,7 +875,7 @@ static struct win_syscall {
{ "OutputDebugStringA", (SYSCALL)0, 0 },
#endif
-#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[69].pCurrent)
+#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[70].pCurrent)
#if defined(SQLITE_WIN32_HAS_WIDE)
{ "OutputDebugStringW", (SYSCALL)OutputDebugStringW, 0 },
@@ -812,11 +883,11 @@ static struct win_syscall {
{ "OutputDebugStringW", (SYSCALL)0, 0 },
#endif
-#define osOutputDebugStringW ((VOID(WINAPI*)(LPCWSTR))aSyscall[70].pCurrent)
+#define osOutputDebugStringW ((VOID(WINAPI*)(LPCWSTR))aSyscall[71].pCurrent)
{ "GetProcessHeap", (SYSCALL)GetProcessHeap, 0 },
-#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[71].pCurrent)
+#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[72].pCurrent)
#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_WAL)
{ "CreateFileMappingFromApp", (SYSCALL)CreateFileMappingFromApp, 0 },
@@ -825,7 +896,7 @@ static struct win_syscall {
#endif
#define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \
- LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[72].pCurrent)
+ LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[73].pCurrent)
}; /* End of the overrideable system calls */
@@ -983,6 +1054,8 @@ void sqlite3_win32_sleep(DWORD milliseconds){
*/
#if SQLITE_OS_WINCE || SQLITE_OS_WINRT
# define isNT() (1)
+#elif !defined(SQLITE_WIN32_HAS_WIDE)
+# define isNT() (0)
#else
static int isNT(void){
if( sqlite3_os_type==0 ){
@@ -993,7 +1066,7 @@ void sqlite3_win32_sleep(DWORD milliseconds){
}
return sqlite3_os_type==2;
}
-#endif /* SQLITE_OS_WINCE */
+#endif
#ifdef SQLITE_WIN32_MALLOC
/*
@@ -1203,7 +1276,7 @@ static LPWSTR utf8ToUnicode(const char *zFilename){
if( nChar==0 ){
return 0;
}
- zWideFilename = sqlite3_malloc( nChar*sizeof(zWideFilename[0]) );
+ zWideFilename = sqlite3MallocZero( nChar*sizeof(zWideFilename[0]) );
if( zWideFilename==0 ){
return 0;
}
@@ -1228,7 +1301,7 @@ static char *unicodeToUtf8(LPCWSTR zWideFilename){
if( nByte == 0 ){
return 0;
}
- zFilename = sqlite3_malloc( nByte );
+ zFilename = sqlite3MallocZero( nByte );
if( zFilename==0 ){
return 0;
}
@@ -1258,7 +1331,7 @@ static LPWSTR mbcsToUnicode(const char *zFilename){
if( nByte==0 ){
return 0;
}
- zMbcsFilename = sqlite3_malloc( nByte*sizeof(zMbcsFilename[0]) );
+ zMbcsFilename = sqlite3MallocZero( nByte*sizeof(zMbcsFilename[0]) );
if( zMbcsFilename==0 ){
return 0;
}
@@ -1287,7 +1360,7 @@ static char *unicodeToMbcs(LPCWSTR zWideFilename){
if( nByte == 0 ){
return 0;
}
- zFilename = sqlite3_malloc( nByte );
+ zFilename = sqlite3MallocZero( nByte );
if( zFilename==0 ){
return 0;
}
@@ -2119,7 +2192,8 @@ static int winWrite(
if( retryIoerr(&nRetry, &lastErrno) ) continue;
break;
}
- if( nWrite<=0 ){
+ assert( nWrite==0 || nWrite<=(DWORD)nRem );
+ if( nWrite==0 || nWrite>(DWORD)nRem ){
lastErrno = osGetLastError();
break;
}
@@ -2617,6 +2691,9 @@ static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){
}
}
+/* Forward declaration */
+static int getTempname(int nBuf, char *zBuf);
+
/*
** Control and query of the open file handle.
*/
@@ -2677,6 +2754,14 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
}
return SQLITE_OK;
}
+ case SQLITE_FCNTL_TEMPFILENAME: {
+ char *zTFile = sqlite3_malloc( pFile->pVfs->mxPathname );
+ if( zTFile ){
+ getTempname(pFile->pVfs->mxPathname, zTFile);
+ *(char**)pArg = zTFile;
+ }
+ return SQLITE_OK;
+ }
}
return SQLITE_NOTFOUND;
}
@@ -2934,16 +3019,14 @@ static int winOpenSharedMemory(winFile *pDbFd){
/* Allocate space for the new sqlite3_shm object. Also speculatively
** allocate space for a new winShmNode and filename.
*/
- p = sqlite3_malloc( sizeof(*p) );
+ p = sqlite3MallocZero( sizeof(*p) );
if( p==0 ) return SQLITE_IOERR_NOMEM;
- memset(p, 0, sizeof(*p));
nName = sqlite3Strlen30(pDbFd->zPath);
- pNew = sqlite3_malloc( sizeof(*pShmNode) + nName + 17 );
+ pNew = sqlite3MallocZero( sizeof(*pShmNode) + nName + 17 );
if( pNew==0 ){
sqlite3_free(p);
return SQLITE_IOERR_NOMEM;
}
- memset(pNew, 0, sizeof(*pNew) + nName + 17);
pNew->zFilename = (char*)&pNew[1];
sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename);
@@ -3280,17 +3363,21 @@ static int winShmMap(
pShmNode->aRegion = apNew;
while( pShmNode->nRegion<=iRegion ){
- HANDLE hMap; /* file-mapping handle */
+ HANDLE hMap = NULL; /* file-mapping handle */
void *pMap = 0; /* Mapped memory region */
#if SQLITE_OS_WINRT
hMap = osCreateFileMappingFromApp(pShmNode->hFile.h,
NULL, PAGE_READWRITE, nByte, NULL
);
-#else
+#elif defined(SQLITE_WIN32_HAS_WIDE)
hMap = osCreateFileMappingW(pShmNode->hFile.h,
NULL, PAGE_READWRITE, 0, nByte, NULL
);
+#elif defined(SQLITE_WIN32_HAS_ANSI)
+ hMap = osCreateFileMappingA(pShmNode->hFile.h,
+ NULL, PAGE_READWRITE, 0, nByte, NULL
+ );
#endif
OSTRACE(("SHM-MAP pid-%d create region=%d nbyte=%d %s\n",
(int)osGetCurrentProcessId(), pShmNode->nRegion, nByte,
@@ -3812,14 +3899,24 @@ static int winDelete(
&sAttrData) ){
attr = sAttrData.dwFileAttributes;
}else{
- rc = SQLITE_OK; /* Already gone? */
+ lastErrno = osGetLastError();
+ if( lastErrno==ERROR_FILE_NOT_FOUND || lastErrno==ERROR_PATH_NOT_FOUND ){
+ rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
+ }else{
+ rc = SQLITE_ERROR;
+ }
break;
}
#else
attr = osGetFileAttributesW(zConverted);
#endif
if ( attr==INVALID_FILE_ATTRIBUTES ){
- rc = SQLITE_OK; /* Already gone? */
+ lastErrno = osGetLastError();
+ if( lastErrno==ERROR_FILE_NOT_FOUND || lastErrno==ERROR_PATH_NOT_FOUND ){
+ rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
+ }else{
+ rc = SQLITE_ERROR;
+ }
break;
}
if ( attr&FILE_ATTRIBUTE_DIRECTORY ){
@@ -3841,7 +3938,12 @@ static int winDelete(
do {
attr = osGetFileAttributesA(zConverted);
if ( attr==INVALID_FILE_ATTRIBUTES ){
- rc = SQLITE_OK; /* Already gone? */
+ lastErrno = osGetLastError();
+ if( lastErrno==ERROR_FILE_NOT_FOUND || lastErrno==ERROR_PATH_NOT_FOUND ){
+ rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
+ }else{
+ rc = SQLITE_ERROR;
+ }
break;
}
if ( attr&FILE_ATTRIBUTE_DIRECTORY ){
@@ -3859,7 +3961,7 @@ static int winDelete(
} while(1);
}
#endif
- if( rc ){
+ if( rc && rc!=SQLITE_IOERR_DELETE_NOENT ){
rc = winLogError(SQLITE_IOERR_DELETE, lastErrno,
"winDelete", zFilename);
}else{
@@ -4039,7 +4141,7 @@ static int winFullPathname(
#endif
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__)
- int nByte;
+ DWORD nByte;
void *zConverted;
char *zOut;
@@ -4073,13 +4175,27 @@ static int winFullPathname(
}
if( isNT() ){
LPWSTR zTemp;
- nByte = osGetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0) + 3;
- zTemp = sqlite3_malloc( nByte*sizeof(zTemp[0]) );
+ nByte = osGetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0);
+ if( nByte==0 ){
+ winLogError(SQLITE_ERROR, osGetLastError(),
+ "GetFullPathNameW1", zConverted);
+ sqlite3_free(zConverted);
+ return SQLITE_CANTOPEN_FULLPATH;
+ }
+ nByte += 3;
+ zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
if( zTemp==0 ){
sqlite3_free(zConverted);
return SQLITE_IOERR_NOMEM;
}
- osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0);
+ nByte = osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0);
+ if( nByte==0 ){
+ winLogError(SQLITE_ERROR, osGetLastError(),
+ "GetFullPathNameW2", zConverted);
+ sqlite3_free(zConverted);
+ sqlite3_free(zTemp);
+ return SQLITE_CANTOPEN_FULLPATH;
+ }
sqlite3_free(zConverted);
zOut = unicodeToUtf8(zTemp);
sqlite3_free(zTemp);
@@ -4087,13 +4203,27 @@ static int winFullPathname(
#ifdef SQLITE_WIN32_HAS_ANSI
else{
char *zTemp;
- nByte = osGetFullPathNameA((char*)zConverted, 0, 0, 0) + 3;
- zTemp = sqlite3_malloc( nByte*sizeof(zTemp[0]) );
+ nByte = osGetFullPathNameA((char*)zConverted, 0, 0, 0);
+ if( nByte==0 ){
+ winLogError(SQLITE_ERROR, osGetLastError(),
+ "GetFullPathNameA1", zConverted);
+ sqlite3_free(zConverted);
+ return SQLITE_CANTOPEN_FULLPATH;
+ }
+ nByte += 3;
+ zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
if( zTemp==0 ){
sqlite3_free(zConverted);
return SQLITE_IOERR_NOMEM;
}
- osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
+ nByte = osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
+ if( nByte==0 ){
+ winLogError(SQLITE_ERROR, osGetLastError(),
+ "GetFullPathNameA2", zConverted);
+ sqlite3_free(zConverted);
+ sqlite3_free(zTemp);
+ return SQLITE_CANTOPEN_FULLPATH;
+ }
sqlite3_free(zConverted);
zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
sqlite3_free(zTemp);
@@ -4351,7 +4481,7 @@ int sqlite3_os_init(void){
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
- assert( ArraySize(aSyscall)==73 );
+ assert( ArraySize(aSyscall)==74 );
#ifndef SQLITE_OMIT_WAL
/* get memory map allocation granularity */
@@ -4370,7 +4500,7 @@ int sqlite3_os_init(void){
int sqlite3_os_end(void){
#if SQLITE_OS_WINRT
- if( sleepObj != NULL ){
+ if( sleepObj!=NULL ){
osCloseHandle(sleepObj);
sleepObj = NULL;
}
diff --git a/lib/libsqlite3/src/pager.c b/lib/libsqlite3/src/pager.c
index 09c2a5f90d4..5879cf760af 100644
--- a/lib/libsqlite3/src/pager.c
+++ b/lib/libsqlite3/src/pager.c
@@ -1941,12 +1941,13 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
** file should be closed and deleted. If this connection writes to
** the database file, it will do so using an in-memory journal.
*/
+ int bDelete = (!pPager->tempFile && sqlite3JournalExists(pPager->jfd));
assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE
|| pPager->journalMode==PAGER_JOURNALMODE_MEMORY
|| pPager->journalMode==PAGER_JOURNALMODE_WAL
);
sqlite3OsClose(pPager->jfd);
- if( !pPager->tempFile ){
+ if( bDelete ){
rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
}
}
@@ -2510,6 +2511,21 @@ static int pager_truncate(Pager *pPager, Pgno nPage){
}
/*
+** Return a sanitized version of the sector-size of OS file pFile. The
+** return value is guaranteed to lie between 32 and MAX_SECTOR_SIZE.
+*/
+int sqlite3SectorSize(sqlite3_file *pFile){
+ int iRet = sqlite3OsSectorSize(pFile);
+ if( iRet<32 ){
+ iRet = 512;
+ }else if( iRet>MAX_SECTOR_SIZE ){
+ assert( MAX_SECTOR_SIZE>=512 );
+ iRet = MAX_SECTOR_SIZE;
+ }
+ return iRet;
+}
+
+/*
** Set the value of the Pager.sectorSize variable for the given
** pager based on the value returned by the xSectorSize method
** of the open database file. The sector size will be used used
@@ -2544,14 +2560,7 @@ static void setSectorSize(Pager *pPager){
** call will segfault. */
pPager->sectorSize = 512;
}else{
- pPager->sectorSize = sqlite3OsSectorSize(pPager->fd);
- if( pPager->sectorSize<32 ){
- pPager->sectorSize = 512;
- }
- if( pPager->sectorSize>MAX_SECTOR_SIZE ){
- assert( MAX_SECTOR_SIZE>=512 );
- pPager->sectorSize = MAX_SECTOR_SIZE;
- }
+ pPager->sectorSize = sqlite3SectorSize(pPager->fd);
}
}
@@ -3151,6 +3160,7 @@ static int pagerOpenWalIfPresent(Pager *pPager){
if( rc ) return rc;
if( nPage==0 ){
rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0);
+ if( rc==SQLITE_IOERR_DELETE_NOENT ) rc = SQLITE_OK;
isWal = 0;
}else{
rc = sqlite3OsAccess(
@@ -3468,9 +3478,16 @@ void sqlite3PagerSetBusyhandler(
Pager *pPager, /* Pager object */
int (*xBusyHandler)(void *), /* Pointer to busy-handler function */
void *pBusyHandlerArg /* Argument to pass to xBusyHandler */
-){
+){
pPager->xBusyHandler = xBusyHandler;
pPager->pBusyHandlerArg = pBusyHandlerArg;
+
+ if( isOpen(pPager->fd) ){
+ void **ap = (void **)&pPager->xBusyHandler;
+ assert( ((int(*)(void *))(ap[0]))==xBusyHandler );
+ assert( ap[1]==pBusyHandlerArg );
+ sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_BUSYHANDLER, (void *)ap);
+ }
}
/*
@@ -4448,7 +4465,7 @@ int sqlite3PagerOpen(
memcpy(pPager->zFilename, zPathname, nPathname);
if( nUri ) memcpy(&pPager->zFilename[nPathname+1], zUri, nUri);
memcpy(pPager->zJournal, zPathname, nPathname);
- memcpy(&pPager->zJournal[nPathname], "-journal\000", 8+1);
+ memcpy(&pPager->zJournal[nPathname], "-journal\000", 8+2);
sqlite3FileSuffix3(pPager->zFilename, pPager->zJournal);
#ifndef SQLITE_OMIT_WAL
pPager->zWal = &pPager->zJournal[nPathname+8+1];
@@ -5650,7 +5667,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
# define DIRECT_MODE isDirectMode
#endif
- if( !pPager->changeCountDone && pPager->dbSize>0 ){
+ if( !pPager->changeCountDone && ALWAYS(pPager->dbSize>0) ){
PgHdr *pPgHdr; /* Reference to page 1 */
assert( !pPager->tempFile && isOpen(pPager->fd) );
@@ -5870,7 +5887,7 @@ int sqlite3PagerCommitPhaseOne(
/* If this transaction has made the database smaller, then all pages
** being discarded by the truncation must be written to the journal
- ** file. This can only happen in auto-vacuum mode.
+ ** file.
**
** Before reading the pages with page numbers larger than the
** current value of Pager.dbSize, set dbSize back to the value
@@ -5878,7 +5895,6 @@ int sqlite3PagerCommitPhaseOne(
** calls to sqlite3PagerGet() return zeroed pages instead of
** reading data from the database file.
*/
- #ifndef SQLITE_OMIT_AUTOVACUUM
if( pPager->dbSize<pPager->dbOrigSize
&& pPager->journalMode!=PAGER_JOURNALMODE_OFF
){
@@ -5898,7 +5914,6 @@ int sqlite3PagerCommitPhaseOne(
}
pPager->dbSize = dbSize;
}
- #endif
/* Write the master journal name into the journal file. If a master
** journal file name has already been written to the journal file,
@@ -6901,6 +6916,8 @@ int sqlite3PagerCloseWal(Pager *pPager){
return rc;
}
+#endif /* !SQLITE_OMIT_WAL */
+
#ifdef SQLITE_ENABLE_ZIPVFS
/*
** A read-lock must be held on the pager when this function is called. If
@@ -6930,6 +6947,4 @@ void *sqlite3PagerCodec(PgHdr *pPg){
}
#endif /* SQLITE_HAS_CODEC */
-#endif /* !SQLITE_OMIT_WAL */
-
#endif /* SQLITE_OMIT_DISKIO */
diff --git a/lib/libsqlite3/src/pager.h b/lib/libsqlite3/src/pager.h
index 2b60e058dad..90f8e6af787 100644
--- a/lib/libsqlite3/src/pager.h
+++ b/lib/libsqlite3/src/pager.h
@@ -138,11 +138,14 @@ int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
int sqlite3PagerSharedLock(Pager *pPager);
-int sqlite3PagerCheckpoint(Pager *pPager, int, int*, int*);
-int sqlite3PagerWalSupported(Pager *pPager);
-int sqlite3PagerWalCallback(Pager *pPager);
-int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
-int sqlite3PagerCloseWal(Pager *pPager);
+#ifndef SQLITE_OMIT_WAL
+ int sqlite3PagerCheckpoint(Pager *pPager, int, int*, int*);
+ int sqlite3PagerWalSupported(Pager *pPager);
+ int sqlite3PagerWalCallback(Pager *pPager);
+ int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
+ int sqlite3PagerCloseWal(Pager *pPager);
+#endif
+
#ifdef SQLITE_ENABLE_ZIPVFS
int sqlite3PagerWalFramesize(Pager *pPager);
#endif
@@ -160,6 +163,7 @@ void *sqlite3PagerTempSpace(Pager*);
int sqlite3PagerIsMemdb(Pager*);
void sqlite3PagerCacheStat(Pager *, int, int, int *);
void sqlite3PagerClearCache(Pager *);
+int sqlite3SectorSize(sqlite3_file *);
/* Functions used to truncate the database file. */
void sqlite3PagerTruncateImage(Pager*,Pgno);
diff --git a/lib/libsqlite3/src/pragma.c b/lib/libsqlite3/src/pragma.c
index a41e0e433f2..d3061b234f9 100644
--- a/lib/libsqlite3/src/pragma.c
+++ b/lib/libsqlite3/src/pragma.c
@@ -357,6 +357,7 @@ void sqlite3Pragma(
aFcntl[1] = zLeft;
aFcntl[2] = zRight;
aFcntl[3] = 0;
+ db->busyHandler.nBusy = 0;
rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl);
if( rc==SQLITE_OK ){
if( aFcntl[0] ){
@@ -974,7 +975,8 @@ void sqlite3Pragma(
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
}
- sqlite3VdbeAddOp2(v, OP_Integer, pCol->isPrimKey, 6);
+ sqlite3VdbeAddOp2(v, OP_Integer,
+ (pCol->colFlags&COLFLAG_PRIMKEY)!=0, 6);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
}
}
@@ -1233,7 +1235,7 @@ void sqlite3Pragma(
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
P4_DYNAMIC);
- sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
+ sqlite3VdbeAddOp2(v, OP_Move, 2, 4);
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1);
sqlite3VdbeJumpHere(v, addr);
@@ -1536,6 +1538,22 @@ void sqlite3Pragma(
sqlite3_db_release_memory(db);
}else
+ /*
+ ** PRAGMA busy_timeout
+ ** PRAGMA busy_timeout = N
+ **
+ ** Call sqlite3_busy_timeout(db, N). Return the current timeout value
+ ** if one is set. If no busy handler or a different busy handler is set
+ ** then 0 is returned. Setting the busy_timeout to 0 or negative
+ ** disables the timeout.
+ */
+ if( sqlite3StrICmp(zLeft, "busy_timeout")==0 ){
+ if( zRight ){
+ sqlite3_busy_timeout(db, sqlite3Atoi(zRight));
+ }
+ returnSingleInt(pParse, "timeout", db->busyTimeout);
+ }else
+
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
/*
** Report the current state of file logs for all databases
@@ -1551,13 +1569,12 @@ void sqlite3Pragma(
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "status", SQLITE_STATIC);
for(i=0; i<db->nDb; i++){
Btree *pBt;
- Pager *pPager;
const char *zState = "unknown";
int j;
if( db->aDb[i].zName==0 ) continue;
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, db->aDb[i].zName, P4_STATIC);
pBt = db->aDb[i].pBt;
- if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){
+ if( pBt==0 || sqlite3BtreePager(pBt)==0 ){
zState = "closed";
}else if( sqlite3_file_control(db, i ? db->aDb[i].zName : 0,
SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){
diff --git a/lib/libsqlite3/src/prepare.c b/lib/libsqlite3/src/prepare.c
index bd2cf7aafc7..5ac8de7296f 100644
--- a/lib/libsqlite3/src/prepare.c
+++ b/lib/libsqlite3/src/prepare.c
@@ -134,7 +134,9 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
int rc;
int i;
+#ifndef SQLITE_OMIT_DEPRECATED
int size;
+#endif
Table *pTab;
Db *pDb;
char const *azArg[4];
diff --git a/lib/libsqlite3/src/resolve.c b/lib/libsqlite3/src/resolve.c
index b87d231ac2e..51aab7792b8 100644
--- a/lib/libsqlite3/src/resolve.c
+++ b/lib/libsqlite3/src/resolve.c
@@ -68,6 +68,15 @@ static void incrAggFunctionDepth(Expr *pExpr, int N){
** from the result in the result-set. We might fix this someday. Or
** then again, we might not...
**
+** If the reference is followed by a COLLATE operator, then make sure
+** the COLLATE operator is preserved. For example:
+**
+** SELECT a+b, c+d FROM t1 ORDER BY 1 COLLATE nocase;
+**
+** Should be transformed into:
+**
+** SELECT a+b, c+d FROM t1 ORDER BY (a+b) COLLATE nocase;
+**
** The nSubquery parameter specifies how many levels of subquery the
** alias is removed from the original expression. The usually value is
** zero but it might be more if the alias is contained within a subquery
@@ -91,8 +100,9 @@ static void resolveAlias(
assert( pOrig!=0 );
assert( pOrig->flags & EP_Resolved );
db = pParse->db;
+ pDup = sqlite3ExprDup(db, pOrig, 0);
+ if( pDup==0 ) return;
if( pOrig->op!=TK_COLUMN && zType[0]!='G' ){
- pDup = sqlite3ExprDup(db, pOrig, 0);
incrAggFunctionDepth(pDup, nSubquery);
pDup = sqlite3PExpr(pParse, TK_AS, pDup, 0, 0);
if( pDup==0 ) return;
@@ -100,32 +110,26 @@ static void resolveAlias(
pEList->a[iCol].iAlias = (u16)(++pParse->nAlias);
}
pDup->iTable = pEList->a[iCol].iAlias;
- }else if( ExprHasProperty(pOrig, EP_IntValue) || pOrig->u.zToken==0 ){
- pDup = sqlite3ExprDup(db, pOrig, 0);
- if( pDup==0 ) return;
- }else{
- char *zToken = pOrig->u.zToken;
- assert( zToken!=0 );
- pOrig->u.zToken = 0;
- pDup = sqlite3ExprDup(db, pOrig, 0);
- pOrig->u.zToken = zToken;
- if( pDup==0 ) return;
- assert( (pDup->flags & (EP_Reduced|EP_TokenOnly))==0 );
- pDup->flags2 |= EP2_MallocedToken;
- pDup->u.zToken = sqlite3DbStrDup(db, zToken);
}
- if( pExpr->flags & EP_ExpCollate ){
- pDup->pColl = pExpr->pColl;
- pDup->flags |= EP_ExpCollate;
+ if( pExpr->op==TK_COLLATE ){
+ pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken);
}
/* Before calling sqlite3ExprDelete(), set the EP_Static flag. This
** prevents ExprDelete() from deleting the Expr structure itself,
** allowing it to be repopulated by the memcpy() on the following line.
+ ** The pExpr->u.zToken might point into memory that will be freed by the
+ ** sqlite3DbFree(db, pDup) on the last line of this block, so be sure to
+ ** make a copy of the token before doing the sqlite3DbFree().
*/
ExprSetProperty(pExpr, EP_Static);
sqlite3ExprDelete(db, pExpr);
memcpy(pExpr, pDup, sizeof(*pExpr));
+ if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){
+ assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 );
+ pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken);
+ pExpr->flags2 |= EP2_MallocedToken;
+ }
sqlite3DbFree(db, pDup);
}
@@ -195,7 +199,7 @@ static int lookupName(
assert( pNC ); /* the name context cannot be NULL. */
assert( zCol ); /* The Z in X.Y.Z cannot be NULL */
- assert( ~ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) );
+ assert( !ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) );
/* Initialize the node to no-match */
pExpr->iTable = -1;
@@ -812,7 +816,7 @@ static int resolveCompoundOrderBy(
int iCol = -1;
Expr *pE, *pDup;
if( pItem->done ) continue;
- pE = pItem->pExpr;
+ pE = sqlite3ExprSkipCollate(pItem->pExpr);
if( sqlite3ExprIsInteger(pE, &iCol) ){
if( iCol<=0 || iCol>pEList->nExpr ){
resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr);
@@ -830,14 +834,20 @@ static int resolveCompoundOrderBy(
}
}
if( iCol>0 ){
- CollSeq *pColl = pE->pColl;
- int flags = pE->flags & EP_ExpCollate;
+ /* Convert the ORDER BY term into an integer column number iCol,
+ ** taking care to preserve the COLLATE clause if it exists */
+ Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
+ if( pNew==0 ) return 1;
+ pNew->flags |= EP_IntValue;
+ pNew->u.iValue = iCol;
+ if( pItem->pExpr==pE ){
+ pItem->pExpr = pNew;
+ }else{
+ assert( pItem->pExpr->op==TK_COLLATE );
+ assert( pItem->pExpr->pLeft==pE );
+ pItem->pExpr->pLeft = pNew;
+ }
sqlite3ExprDelete(db, pE);
- pItem->pExpr = pE = sqlite3Expr(db, TK_INTEGER, 0);
- if( pE==0 ) return 1;
- pE->pColl = pColl;
- pE->flags |= EP_IntValue | flags;
- pE->u.iValue = iCol;
pItem->iOrderByCol = (u16)iCol;
pItem->done = 1;
}else{
@@ -942,11 +952,11 @@ static int resolveOrderGroupBy(
pItem->iOrderByCol = (u16)iCol;
continue;
}
- if( sqlite3ExprIsInteger(pE, &iCol) ){
+ if( sqlite3ExprIsInteger(sqlite3ExprSkipCollate(pE), &iCol) ){
/* The ORDER BY term is an integer constant. Again, set the column
** number so that sqlite3ResolveOrderGroupBy() will convert the
** order-by term to a copy of the result-set expression */
- if( iCol<1 ){
+ if( iCol<1 || iCol>0xffff ){
resolveOutOfRangeError(pParse, zType, i+1, nResult);
return 1;
}
diff --git a/lib/libsqlite3/src/select.c b/lib/libsqlite3/src/select.c
index 6ec9da39a19..a90877dc612 100644
--- a/lib/libsqlite3/src/select.c
+++ b/lib/libsqlite3/src/select.c
@@ -526,6 +526,19 @@ static int checkForMultiColumnSelectError(
#endif
/*
+** An instance of the following object is used to record information about
+** how to process the DISTINCT keyword, to simplify passing that information
+** into the selectInnerLoop() routine.
+*/
+typedef struct DistinctCtx DistinctCtx;
+struct DistinctCtx {
+ u8 isTnct; /* True if the DISTINCT keyword is present */
+ u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */
+ int tabTnct; /* Ephemeral table used for DISTINCT processing */
+ int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */
+};
+
+/*
** This routine generates the code for the inside of the inner loop
** of a SELECT.
**
@@ -541,7 +554,7 @@ static void selectInnerLoop(
int srcTab, /* Pull data from this table */
int nColumn, /* Number of columns in the source table */
ExprList *pOrderBy, /* If not NULL, sort results using this key */
- int distinct, /* If >=0, make sure results are distinct */
+ DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */
SelectDest *pDest, /* How to dispose of the results */
int iContinue, /* Jump here to continue with next row */
int iBreak /* Jump here to break out of the inner loop */
@@ -557,7 +570,7 @@ static void selectInnerLoop(
assert( v );
if( NEVER(v==0) ) return;
assert( pEList!=0 );
- hasDistinct = distinct>=0;
+ hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP;
if( pOrderBy==0 && !hasDistinct ){
codeOffset(v, p, iContinue);
}
@@ -597,7 +610,55 @@ static void selectInnerLoop(
if( hasDistinct ){
assert( pEList!=0 );
assert( pEList->nExpr==nColumn );
- codeDistinct(pParse, distinct, iContinue, nColumn, regResult);
+ switch( pDistinct->eTnctType ){
+ case WHERE_DISTINCT_ORDERED: {
+ VdbeOp *pOp; /* No longer required OpenEphemeral instr. */
+ int iJump; /* Jump destination */
+ int regPrev; /* Previous row content */
+
+ /* Allocate space for the previous row */
+ regPrev = pParse->nMem+1;
+ pParse->nMem += nColumn;
+
+ /* Change the OP_OpenEphemeral coded earlier to an OP_Null
+ ** sets the MEM_Cleared bit on the first register of the
+ ** previous value. This will cause the OP_Ne below to always
+ ** fail on the first iteration of the loop even if the first
+ ** row is all NULLs.
+ */
+ sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct);
+ pOp = sqlite3VdbeGetOp(v, pDistinct->addrTnct);
+ pOp->opcode = OP_Null;
+ pOp->p1 = 1;
+ pOp->p2 = regPrev;
+
+ iJump = sqlite3VdbeCurrentAddr(v) + nColumn;
+ for(i=0; i<nColumn; i++){
+ CollSeq *pColl = sqlite3ExprCollSeq(pParse, pEList->a[i].pExpr);
+ if( i<nColumn-1 ){
+ sqlite3VdbeAddOp3(v, OP_Ne, regResult+i, iJump, regPrev+i);
+ }else{
+ sqlite3VdbeAddOp3(v, OP_Eq, regResult+i, iContinue, regPrev+i);
+ }
+ sqlite3VdbeChangeP4(v, -1, (const char *)pColl, P4_COLLSEQ);
+ sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
+ }
+ assert( sqlite3VdbeCurrentAddr(v)==iJump );
+ sqlite3VdbeAddOp3(v, OP_Copy, regResult, regPrev, nColumn-1);
+ break;
+ }
+
+ case WHERE_DISTINCT_UNIQUE: {
+ sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct);
+ break;
+ }
+
+ default: {
+ assert( pDistinct->eTnctType==WHERE_DISTINCT_UNORDERED );
+ codeDistinct(pParse, pDistinct->tabTnct, iContinue, nColumn, regResult);
+ break;
+ }
+ }
if( pOrderBy==0 ){
codeOffset(v, p, iContinue);
}
@@ -655,7 +716,8 @@ static void selectInnerLoop(
*/
case SRT_Set: {
assert( nColumn==1 );
- p->affinity = sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst);
+ pDest->affSdst =
+ sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst);
if( pOrderBy ){
/* At first glance you would think we could optimize out the
** ORDER BY in this case since the order of entries in the set
@@ -664,7 +726,7 @@ static void selectInnerLoop(
pushOntoSorter(pParse, pOrderBy, p, regResult);
}else{
int r1 = sqlite3GetTempReg(pParse);
- sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, 1, r1, &p->affinity, 1);
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1);
sqlite3ExprCacheAffinityChange(pParse, regResult, 1);
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
sqlite3ReleaseTempReg(pParse, r1);
@@ -931,7 +993,8 @@ static void generateSortTail(
#ifndef SQLITE_OMIT_SUBQUERY
case SRT_Set: {
assert( nColumn==1 );
- sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, 1, regRowid, &p->affinity, 1);
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, 1, regRowid,
+ &pDest->affSdst, 1);
sqlite3ExprCacheAffinityChange(pParse, regRow, 1);
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRowid);
break;
@@ -1246,7 +1309,7 @@ static void generateColumnNames(
static int selectColumnsFromExprList(
Parse *pParse, /* Parsing context */
ExprList *pEList, /* Expr list from which to derive column names */
- int *pnCol, /* Write the number of columns here */
+ i16 *pnCol, /* Write the number of columns here */
Column **paCol /* Write the new column list here */
){
sqlite3 *db = pParse->db; /* Database connection */
@@ -1272,7 +1335,7 @@ static int selectColumnsFromExprList(
for(i=0, pCol=aCol; i<nCol; i++, pCol++){
/* Get an appropriate name for the column
*/
- p = pEList->a[i].pExpr;
+ p = sqlite3ExprSkipCollate(pEList->a[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 ){
@@ -1768,7 +1831,7 @@ static int multiSelect(
sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak);
iStart = sqlite3VdbeCurrentAddr(v);
selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr,
- 0, -1, &dest, iCont, iBreak);
+ 0, 0, &dest, iCont, iBreak);
sqlite3VdbeResolveLabel(v, iCont);
sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart);
sqlite3VdbeResolveLabel(v, iBreak);
@@ -1846,7 +1909,7 @@ static int multiSelect(
sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0);
sqlite3ReleaseTempReg(pParse, r1);
selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr,
- 0, -1, &dest, iCont, iBreak);
+ 0, 0, &dest, iCont, iBreak);
sqlite3VdbeResolveLabel(v, iCont);
sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart);
sqlite3VdbeResolveLabel(v, iBreak);
@@ -1892,6 +1955,7 @@ static int multiSelect(
*apColl = db->pDfltColl;
}
}
+ pKeyInfo->aSortOrder = (u8*)apColl;
for(pLoop=p; pLoop; pLoop=pLoop->pPrior){
for(i=0; i<2; i++){
@@ -1965,7 +2029,7 @@ static int generateOutputSubroutine(
(char*)pKeyInfo, p4type);
sqlite3VdbeAddOp3(v, OP_Jump, j2+2, iContinue, j2+2);
sqlite3VdbeJumpHere(v, j1);
- sqlite3ExprCodeCopy(pParse, pIn->iSdst, regPrev+1, pIn->nSdst);
+ sqlite3VdbeAddOp3(v, OP_Copy, pIn->iSdst, regPrev+1, pIn->nSdst-1);
sqlite3VdbeAddOp2(v, OP_Integer, 1, regPrev);
}
if( pParse->db->mallocFailed ) return 0;
@@ -2000,10 +2064,10 @@ static int generateOutputSubroutine(
case SRT_Set: {
int r1;
assert( pIn->nSdst==1 );
- p->affinity =
+ pDest->affSdst =
sqlite3CompareAffinity(p->pEList->a[0].pExpr, pDest->affSdst);
r1 = sqlite3GetTempReg(pParse);
- sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, 1, r1, &p->affinity, 1);
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, 1, r1, &pDest->affSdst,1);
sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, 1);
sqlite3VdbeAddOp2(v, OP_IdxInsert, pDest->iSDParm, r1);
sqlite3ReleaseTempReg(pParse, r1);
@@ -2269,12 +2333,13 @@ static int multiSelectOrderBy(
for(i=0; i<nOrderBy; i++){
CollSeq *pColl;
Expr *pTerm = pOrderBy->a[i].pExpr;
- if( pTerm->flags & EP_ExpCollate ){
- pColl = pTerm->pColl;
+ if( pTerm->flags & EP_Collate ){
+ pColl = sqlite3ExprCollSeq(pParse, pTerm);
}else{
pColl = multiSelectCollSeq(pParse, p, aPermute[i]);
- pTerm->flags |= EP_ExpCollate;
- pTerm->pColl = pColl;
+ if( pColl==0 ) pColl = db->pDfltColl;
+ pOrderBy->a[i].pExpr =
+ sqlite3ExprAddCollateString(pParse, pTerm, pColl->zName);
}
pKeyMerge->aColl[i] = pColl;
pKeyMerge->aSortOrder[i] = pOrderBy->a[i].sortOrder;
@@ -2477,6 +2542,7 @@ static int multiSelectOrderBy(
sqlite3VdbeAddOp4(v, OP_Permutation, 0, 0, 0, (char*)aPermute, P4_INTARRAY);
sqlite3VdbeAddOp4(v, OP_Compare, destA.iSdst, destB.iSdst, nOrderBy,
(char*)pKeyMerge, P4_KEYINFO_HANDOFF);
+ sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE);
sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB);
/* Release temporary registers
@@ -2544,9 +2610,6 @@ static Expr *substExpr(
assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
pNew = sqlite3ExprDup(db, pEList->a[pExpr->iColumn].pExpr, 0);
- if( pNew && pExpr->pColl ){
- pNew->pColl = pExpr->pColl;
- }
sqlite3ExprDelete(db, pExpr);
pExpr = pNew;
}
@@ -2745,7 +2808,7 @@ static int flattenSubquery(
*/
assert( p!=0 );
assert( p->pPrior==0 ); /* Unable to flatten compound queries */
- if( db->flags & SQLITE_QueryFlattener ) return 0;
+ if( OptimizationDisabled(db, SQLITE_QueryFlattener) ) return 0;
pSrc = p->pSrc;
assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
pSubitem = &pSrc->a[iFrom];
@@ -3034,10 +3097,9 @@ static int flattenSubquery(
pList = pParent->pEList;
for(i=0; i<pList->nExpr; i++){
if( pList->a[i].zName==0 ){
- const char *zSpan = pList->a[i].zSpan;
- if( ALWAYS(zSpan) ){
- pList->a[i].zName = sqlite3DbStrDup(db, zSpan);
- }
+ char *zName = sqlite3DbStrDup(db, pList->a[i].zSpan);
+ sqlite3Dequote(zName);
+ pList->a[i].zName = zName;
}
}
substExprList(db, pParent->pEList, iParent, pSub->pEList);
@@ -3268,8 +3330,7 @@ static int selectExpander(Walker *pWalker, Select *p){
}else{
/* An ordinary table or view name in the FROM clause */
assert( pFrom->pTab==0 );
- pFrom->pTab = pTab =
- sqlite3LocateTable(pParse,0,pFrom->zName,pFrom->zDatabase);
+ pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
if( pTab==0 ) return WRC_Abort;
pTab->nRef++;
#if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE)
@@ -3785,11 +3846,9 @@ int sqlite3Select(
ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */
ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
Expr *pHaving; /* The HAVING clause. May be NULL */
- int isDistinct; /* True if the DISTINCT keyword is present */
- int distinct; /* Table to use for the distinct set */
int rc = 1; /* Value to return from this function */
int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */
- int addrDistinctIndex; /* Address of an OP_OpenEphemeral instruction */
+ DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */
AggInfo sAggInfo; /* Information used by aggregate queries */
int iEnd; /* Address of the end of the query */
sqlite3 *db; /* The database connection */
@@ -3849,8 +3908,17 @@ int sqlite3Select(
int isAggSub;
if( pSub==0 ) continue;
+
+ /* Sometimes the code for a subquery will be generated more than
+ ** once, if the subquery is part of the WHERE clause in a LEFT JOIN,
+ ** for example. In that case, do not regenerate the code to manifest
+ ** a view or the co-routine to implement a view. The first instance
+ ** is sufficient, though the subroutine to manifest the view does need
+ ** to be invoked again. */
if( pItem->addrFillSub ){
- sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub);
+ if( pItem->viaCoroutine==0 ){
+ sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub);
+ }
continue;
}
@@ -3871,6 +3939,44 @@ int sqlite3Select(
p->selFlags |= SF_Aggregate;
}
i = -1;
+ }else if( pTabList->nSrc==1 && (p->selFlags & SF_Materialize)==0
+ && OptimizationEnabled(db, SQLITE_SubqCoroutine)
+ ){
+ /* Implement a co-routine that will return a single row of the result
+ ** set on each invocation.
+ */
+ int addrTop;
+ int addrEof;
+ pItem->regReturn = ++pParse->nMem;
+ addrEof = ++pParse->nMem;
+ /* Before coding the OP_Goto to jump to the start of the main routine,
+ ** ensure that the jump to the verify-schema routine has already
+ ** been coded. Otherwise, the verify-schema would likely be coded as
+ ** part of the co-routine. If the main routine then accessed the
+ ** database before invoking the co-routine for the first time (for
+ ** example to initialize a LIMIT register from a sub-select), it would
+ ** be doing so without having verified the schema version and obtained
+ ** the required db locks. See ticket d6b36be38. */
+ sqlite3CodeVerifySchema(pParse, -1);
+ sqlite3VdbeAddOp0(v, OP_Goto);
+ addrTop = sqlite3VdbeAddOp1(v, OP_OpenPseudo, pItem->iCursor);
+ sqlite3VdbeChangeP5(v, 1);
+ VdbeComment((v, "coroutine for %s", pItem->pTab->zName));
+ pItem->addrFillSub = addrTop;
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, addrEof);
+ sqlite3VdbeChangeP5(v, 1);
+ sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
+ explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
+ sqlite3Select(pParse, pSub, &dest);
+ pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
+ pItem->viaCoroutine = 1;
+ sqlite3VdbeChangeP2(v, addrTop, dest.iSdst);
+ sqlite3VdbeChangeP3(v, addrTop, dest.nSdst);
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, addrEof);
+ sqlite3VdbeAddOp1(v, OP_Yield, pItem->regReturn);
+ VdbeComment((v, "end %s", pItem->pTab->zName));
+ sqlite3VdbeJumpHere(v, addrTop-1);
+ sqlite3ClearTempRegCache(pParse);
}else{
/* Generate a subroutine that will fill an ephemeral table with
** the content of this subquery. pItem->addrFillSub will point
@@ -3915,7 +4021,7 @@ int sqlite3Select(
pWhere = p->pWhere;
pGroupBy = p->pGroupBy;
pHaving = p->pHaving;
- isDistinct = (p->selFlags & SF_Distinct)!=0;
+ sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0;
#ifndef SQLITE_OMIT_COMPOUND_SELECT
/* If there is are a sequence of queries, do the earlier ones first.
@@ -3950,7 +4056,7 @@ int sqlite3Select(
** to disable this optimization for testing purposes.
*/
if( sqlite3ExprListCompare(p->pGroupBy, pOrderBy)==0
- && (db->flags & SQLITE_GroupByOrder)==0 ){
+ && OptimizationEnabled(db, SQLITE_GroupByOrder) ){
pOrderBy = 0;
}
@@ -3976,6 +4082,10 @@ int sqlite3Select(
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
pGroupBy = p->pGroupBy;
pOrderBy = 0;
+ /* Notice that even thought SF_Distinct has been cleared from p->selFlags,
+ ** the sDistinct.isTnct is still set. Hence, isTnct represents the
+ ** original setting of the SF_Distinct flag, not the current setting */
+ assert( sDistinct.isTnct );
}
/* If there is an ORDER BY clause, then this sorting
@@ -4016,24 +4126,27 @@ int sqlite3Select(
/* Open a virtual index to use for the distinct set.
*/
if( p->selFlags & SF_Distinct ){
- KeyInfo *pKeyInfo;
- distinct = pParse->nTab++;
- pKeyInfo = keyInfoFromExprList(pParse, p->pEList);
- addrDistinctIndex = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, distinct, 0, 0,
- (char*)pKeyInfo, P4_KEYINFO_HANDOFF);
+ sDistinct.tabTnct = pParse->nTab++;
+ sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
+ sDistinct.tabTnct, 0, 0,
+ (char*)keyInfoFromExprList(pParse, p->pEList),
+ P4_KEYINFO_HANDOFF);
sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
+ sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED;
}else{
- distinct = addrDistinctIndex = -1;
+ sDistinct.eTnctType = WHERE_DISTINCT_NOOP;
}
- /* Aggregate and non-aggregate queries are handled differently */
if( !isAgg && pGroupBy==0 ){
- ExprList *pDist = (isDistinct ? p->pEList : 0);
+ /* No aggregate functions and no GROUP BY clause */
+ ExprList *pDist = (sDistinct.isTnct ? p->pEList : 0);
/* Begin the database scan. */
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, pDist, 0,0);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pOrderBy, pDist, 0,0);
if( pWInfo==0 ) goto select_end;
if( pWInfo->nRowOut < p->nSelectRow ) p->nSelectRow = pWInfo->nRowOut;
+ if( pWInfo->eDistinct ) sDistinct.eTnctType = pWInfo->eDistinct;
+ if( pOrderBy && pWInfo->nOBSat==pOrderBy->nExpr ) pOrderBy = 0;
/* If sorting index that was created by a prior OP_OpenEphemeral
** instruction ended up not being needed, then change the OP_OpenEphemeral
@@ -4044,59 +4157,16 @@ int sqlite3Select(
p->addrOpenEphm[2] = -1;
}
- if( pWInfo->eDistinct ){
- VdbeOp *pOp; /* No longer required OpenEphemeral instr. */
-
- assert( addrDistinctIndex>=0 );
- pOp = sqlite3VdbeGetOp(v, addrDistinctIndex);
-
- assert( isDistinct );
- assert( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED
- || pWInfo->eDistinct==WHERE_DISTINCT_UNIQUE
- );
- distinct = -1;
- if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED ){
- int iJump;
- int iExpr;
- int iFlag = ++pParse->nMem;
- int iBase = pParse->nMem+1;
- int iBase2 = iBase + pEList->nExpr;
- pParse->nMem += (pEList->nExpr*2);
-
- /* Change the OP_OpenEphemeral coded earlier to an OP_Integer. The
- ** OP_Integer initializes the "first row" flag. */
- pOp->opcode = OP_Integer;
- pOp->p1 = 1;
- pOp->p2 = iFlag;
-
- sqlite3ExprCodeExprList(pParse, pEList, iBase, 1);
- iJump = sqlite3VdbeCurrentAddr(v) + 1 + pEList->nExpr + 1 + 1;
- sqlite3VdbeAddOp2(v, OP_If, iFlag, iJump-1);
- for(iExpr=0; iExpr<pEList->nExpr; iExpr++){
- CollSeq *pColl = sqlite3ExprCollSeq(pParse, pEList->a[iExpr].pExpr);
- sqlite3VdbeAddOp3(v, OP_Ne, iBase+iExpr, iJump, iBase2+iExpr);
- sqlite3VdbeChangeP4(v, -1, (const char *)pColl, P4_COLLSEQ);
- sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
- }
- sqlite3VdbeAddOp2(v, OP_Goto, 0, pWInfo->iContinue);
-
- sqlite3VdbeAddOp2(v, OP_Integer, 0, iFlag);
- assert( sqlite3VdbeCurrentAddr(v)==iJump );
- sqlite3VdbeAddOp3(v, OP_Move, iBase, iBase2, pEList->nExpr);
- }else{
- pOp->opcode = OP_Noop;
- }
- }
-
/* Use the standard inner loop. */
- selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, pDest,
+ selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, &sDistinct, pDest,
pWInfo->iContinue, pWInfo->iBreak);
/* End the database scan loop.
*/
sqlite3WhereEnd(pWInfo);
}else{
- /* This is the processing for aggregate queries */
+ /* This case when there exist aggregate functions or a GROUP BY clause
+ ** or both */
NameContext sNC; /* Name context for processing aggregate information */
int iAMem; /* First Mem address for storing current GROUP BY */
int iBMem; /* First Mem address for previous GROUP BY */
@@ -4204,14 +4274,13 @@ int sqlite3Select(
** in the right order to begin with.
*/
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0, 0, 0);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0, 0, 0);
if( pWInfo==0 ) goto select_end;
- if( pGroupBy==0 ){
+ if( pWInfo->nOBSat==pGroupBy->nExpr ){
/* The optimizer is able to deliver rows in group by order so
** we do not have to sort. The OP_OpenEphemeral table will be
** cancelled later because we still need to use the pKeyInfo
*/
- pGroupBy = p->pGroupBy;
groupBySort = 0;
}else{
/* Rows are coming out in undetermined order. We have to push
@@ -4225,7 +4294,8 @@ int sqlite3Select(
int nGroupBy;
explainTempTable(pParse,
- isDistinct && !(p->selFlags&SF_Distinct)?"DISTINCT":"GROUP BY");
+ (sDistinct.isTnct && (p->selFlags&SF_Distinct)==0) ?
+ "DISTINCT" : "GROUP BY");
groupBySort = 1;
nGroupBy = pGroupBy->nExpr;
@@ -4357,7 +4427,7 @@ int sqlite3Select(
finalizeAggFunctions(pParse, &sAggInfo);
sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
selectInnerLoop(pParse, p, p->pEList, 0, 0, pOrderBy,
- distinct, pDest,
+ &sDistinct, pDest,
addrOutputRow+1, addrSetAbort);
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
VdbeComment((v, "end groupby result generator"));
@@ -4460,6 +4530,7 @@ int sqlite3Select(
u8 flag = minMaxQuery(p);
if( flag ){
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 ){
@@ -4473,13 +4544,14 @@ int sqlite3Select(
** of output.
*/
resetAccumulator(pParse, &sAggInfo);
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax,0,flag,0);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMax,0,flag,0);
if( pWInfo==0 ){
sqlite3ExprListDelete(db, pDel);
goto select_end;
}
updateAccumulator(pParse, &sAggInfo);
- if( !pMinMax && flag ){
+ assert( pMinMax==0 || pMinMax->nExpr==1 );
+ if( pWInfo->nOBSat>0 ){
sqlite3VdbeAddOp2(v, OP_Goto, 0, pWInfo->iBreak);
VdbeComment((v, "%s() by index",
(flag==WHERE_ORDERBY_MIN?"min":"max")));
@@ -4490,7 +4562,7 @@ int sqlite3Select(
pOrderBy = 0;
sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
- selectInnerLoop(pParse, p, p->pEList, 0, 0, 0, -1,
+ selectInnerLoop(pParse, p, p->pEList, 0, 0, 0, 0,
pDest, addrEnd, addrEnd);
sqlite3ExprListDelete(db, pDel);
}
@@ -4498,7 +4570,7 @@ int sqlite3Select(
} /* endif aggregate query */
- if( distinct>=0 ){
+ if( sDistinct.eTnctType==WHERE_DISTINCT_UNORDERED ){
explainTempTable(pParse, "DISTINCT");
}
diff --git a/lib/libsqlite3/src/sqlite.h.in b/lib/libsqlite3/src/sqlite.h.in
index 9a31e22773d..48f7381212b 100644
--- a/lib/libsqlite3/src/sqlite.h.in
+++ b/lib/libsqlite3/src/sqlite.h.in
@@ -469,10 +469,12 @@ int sqlite3_exec(
#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8))
#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8))
#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8))
+#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
+#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
@@ -850,6 +852,26 @@ struct sqlite3_io_methods {
** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA]
** file control occurs at the beginning of pragma statement analysis and so
** it is able to override built-in [PRAGMA] statements.
+**
+** <li>[[SQLITE_FCNTL_BUSYHANDLER]]
+** ^This file-control may be invoked by SQLite on the database file handle
+** shortly after it is opened in order to provide a custom VFS with access
+** to the connections busy-handler callback. The argument is of type (void **)
+** - an array of two (void *) values. The first (void *) actually points
+** to a function of type (int (*)(void *)). In order to invoke the connections
+** busy-handler, this function should be invoked with the second (void *) in
+** the array as the only argument. If it returns non-zero, then the operation
+** should be retried. If it returns zero, the custom VFS should abandon the
+** current operation.
+**
+** <li>[[SQLITE_FCNTL_TEMPFILENAME]]
+** ^Application can invoke this file-control to have SQLite generate a
+** temporary filename using the same algorithm that is followed to generate
+** temporary filenames for TEMP tables and other internal uses. The
+** argument should be a char** which will be filled with the filename
+** written into memory obtained from [sqlite3_malloc()]. The caller should
+** invoke [sqlite3_free()] on the result to avoid a memory leak.
+**
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@@ -866,6 +888,8 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_VFSNAME 12
#define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13
#define SQLITE_FCNTL_PRAGMA 14
+#define SQLITE_FCNTL_BUSYHANDLER 15
+#define SQLITE_FCNTL_TEMPFILENAME 16
/*
** CAPI3REF: Mutex Handle
@@ -1562,11 +1586,39 @@ struct sqlite3_mem_methods {
** disabled. The default value may be changed by compiling with the
** [SQLITE_USE_URI] symbol defined.
**
+** [[SQLITE_CONFIG_COVERING_INDEX_SCAN]] <dt>SQLITE_CONFIG_COVERING_INDEX_SCAN
+** <dd> 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
+** malfunction when the optimization is enabled. Providing the ability to
+** disable the optimization allows the older, buggy application code to work
+** without change even with newer versions of SQLite.
+**
** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]]
** <dt>SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE
** <dd> These options are obsolete and should not be used by new code.
** They are retained for backwards compatibility but are now no-ops.
** </dl>
+**
+** [[SQLITE_CONFIG_SQLLOG]]
+** <dt>SQLITE_CONFIG_SQLLOG
+** <dd>This option is only available if sqlite is compiled with the
+** SQLITE_ENABLE_SQLLOG pre-processor macro defined. The first argument should
+** be a pointer to a function of type void(*)(void*,sqlite3*,const char*, int).
+** The second should be of type (void*). The callback is invoked by the library
+** in three separate circumstances, identified by the value passed as the
+** fourth parameter. If the fourth parameter is 0, then the database connection
+** passed as the second argument has just been opened. The third argument
+** points to a buffer containing the name of the main database file. If the
+** fourth parameter is 1, then the SQL statement that the third parameter
+** points to has just been executed. Or, if the fourth parameter is 2, then
+** the connection being passed as the second parameter is being closed. The
+** third parameter is passed NULL In this case.
+** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
@@ -1587,6 +1639,8 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_URI 17 /* int */
#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
+#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -2595,7 +2649,7 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** an error)^.
** ^If "ro" is specified, then the database is opened for read-only
** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the
-** third argument to sqlite3_prepare_v2(). ^If the mode option is set to
+** third argument to sqlite3_open_v2(). ^If the mode option is set to
** "rw", then the database is opened for read-write (but not create)
** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had
** been set. ^Value "rwc" is equivalent to setting both
@@ -2747,6 +2801,11 @@ sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
** However, the error string might be overwritten or deallocated by
** subsequent calls to other SQLite interface functions.)^
**
+** ^The sqlite3_errstr() interface returns the English-language text
+** that describes the [result code], as UTF-8.
+** ^(Memory to hold the error message string is managed internally
+** and must not be freed by the application)^.
+**
** When the serialized [threading mode] is in use, it might be the
** case that a second error occurs on a separate thread in between
** the time of the first error and the call to these interfaces.
@@ -2765,6 +2824,7 @@ int sqlite3_errcode(sqlite3 *db);
int sqlite3_extended_errcode(sqlite3 *db);
const char *sqlite3_errmsg(sqlite3*);
const void *sqlite3_errmsg16(sqlite3*);
+const char *sqlite3_errstr(int);
/*
** CAPI3REF: SQL Statement Object
@@ -4727,6 +4787,9 @@ void *sqlite3_update_hook(
** future releases of SQLite. Applications that care about shared
** cache setting should set it explicitly.
**
+** This interface is threadsafe on processors where writing a
+** 32-bit integer is atomic.
+**
** See Also: [SQLite Shared-Cache Mode]
*/
int sqlite3_enable_shared_cache(int);
diff --git a/lib/libsqlite3/src/sqliteInt.h b/lib/libsqlite3/src/sqliteInt.h
index 09163bf69c9..2b58a808fb4 100644
--- a/lib/libsqlite3/src/sqliteInt.h
+++ b/lib/libsqlite3/src/sqliteInt.h
@@ -661,6 +661,7 @@ typedef struct Parse Parse;
typedef struct RowSet RowSet;
typedef struct Savepoint Savepoint;
typedef struct Select Select;
+typedef struct SelectDest SelectDest;
typedef struct SrcList SrcList;
typedef struct StrAccum StrAccum;
typedef struct Table Table;
@@ -826,6 +827,7 @@ struct sqlite3 {
unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
int errCode; /* Most recent error code (SQLITE_*) */
int errMask; /* & result codes with this before returning */
+ u16 dbOptFlags; /* Flags to enable/disable optimizations */
u8 autoCommit; /* The auto-commit flag. */
u8 temp_store; /* 1: file 2: memory 0: default */
u8 mallocFailed; /* True if we have seen a malloc failure */
@@ -930,48 +932,59 @@ struct sqlite3 {
/*
** Possible values for the sqlite3.flags.
*/
-#define SQLITE_VdbeTrace 0x00000100 /* True to trace VDBE execution */
-#define SQLITE_InternChanges 0x00000200 /* Uncommitted Hash table changes */
-#define SQLITE_FullColNames 0x00000400 /* Show full column names on SELECT */
-#define SQLITE_ShortColNames 0x00000800 /* Show short columns names */
-#define SQLITE_CountRows 0x00001000 /* Count rows changed by INSERT, */
+#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */
+#define SQLITE_InternChanges 0x00000002 /* Uncommitted Hash table changes */
+#define SQLITE_FullColNames 0x00000004 /* Show full column names on SELECT */
+#define SQLITE_ShortColNames 0x00000008 /* Show short columns names */
+#define SQLITE_CountRows 0x00000010 /* Count rows changed by INSERT, */
/* DELETE, or UPDATE and return */
/* the count using a callback. */
-#define SQLITE_NullCallback 0x00002000 /* Invoke the callback once if the */
+#define SQLITE_NullCallback 0x00000020 /* Invoke the callback once if the */
/* result set is empty */
-#define SQLITE_SqlTrace 0x00004000 /* Debug print SQL as it executes */
-#define SQLITE_VdbeListing 0x00008000 /* Debug listings of VDBE programs */
-#define SQLITE_WriteSchema 0x00010000 /* OK to update SQLITE_MASTER */
- /* 0x00020000 Unused */
-#define SQLITE_IgnoreChecks 0x00040000 /* Do not enforce check constraints */
-#define SQLITE_ReadUncommitted 0x0080000 /* For shared-cache mode */
-#define SQLITE_LegacyFileFmt 0x00100000 /* Create new databases in format 1 */
-#define SQLITE_FullFSync 0x00200000 /* Use full fsync on the backend */
-#define SQLITE_CkptFullFSync 0x00400000 /* Use full fsync for checkpoint */
-#define SQLITE_RecoveryMode 0x00800000 /* Ignore schema errors */
-#define SQLITE_ReverseOrder 0x01000000 /* Reverse unordered SELECTs */
-#define SQLITE_RecTriggers 0x02000000 /* Enable recursive triggers */
-#define SQLITE_ForeignKeys 0x04000000 /* Enforce foreign key constraints */
-#define SQLITE_AutoIndex 0x08000000 /* Enable automatic indexes */
-#define SQLITE_PreferBuiltin 0x10000000 /* Preference to built-in funcs */
-#define SQLITE_LoadExtension 0x20000000 /* Enable load_extension */
-#define SQLITE_EnableTrigger 0x40000000 /* True to enable triggers */
-
-/*
-** Bits of the sqlite3.flags field that are used by the
-** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface.
-** These must be the low-order bits of the flags field.
-*/
-#define SQLITE_QueryFlattener 0x01 /* Disable query flattening */
-#define SQLITE_ColumnCache 0x02 /* Disable the column cache */
-#define SQLITE_IndexSort 0x04 /* Disable indexes for sorting */
-#define SQLITE_IndexSearch 0x08 /* Disable indexes for searching */
-#define SQLITE_IndexCover 0x10 /* Disable index covering table */
-#define SQLITE_GroupByOrder 0x20 /* Disable GROUPBY cover of ORDERBY */
-#define SQLITE_FactorOutConst 0x40 /* Disable factoring out constants */
-#define SQLITE_IdxRealAsInt 0x80 /* Store REAL as INT in indices */
-#define SQLITE_DistinctOpt 0x80 /* DISTINCT using indexes */
-#define SQLITE_OptMask 0xff /* Mask of all disablable opts */
+#define SQLITE_SqlTrace 0x00000040 /* Debug print SQL as it executes */
+#define SQLITE_VdbeListing 0x00000080 /* Debug listings of VDBE programs */
+#define SQLITE_WriteSchema 0x00000100 /* OK to update SQLITE_MASTER */
+ /* 0x00000200 Unused */
+#define SQLITE_IgnoreChecks 0x00000400 /* Do not enforce check constraints */
+#define SQLITE_ReadUncommitted 0x0000800 /* For shared-cache mode */
+#define SQLITE_LegacyFileFmt 0x00001000 /* Create new databases in format 1 */
+#define SQLITE_FullFSync 0x00002000 /* Use full fsync on the backend */
+#define SQLITE_CkptFullFSync 0x00004000 /* Use full fsync for checkpoint */
+#define SQLITE_RecoveryMode 0x00008000 /* Ignore schema errors */
+#define SQLITE_ReverseOrder 0x00010000 /* Reverse unordered SELECTs */
+#define SQLITE_RecTriggers 0x00020000 /* Enable recursive triggers */
+#define SQLITE_ForeignKeys 0x00040000 /* Enforce foreign key constraints */
+#define SQLITE_AutoIndex 0x00080000 /* Enable automatic indexes */
+#define SQLITE_PreferBuiltin 0x00100000 /* Preference to built-in funcs */
+#define SQLITE_LoadExtension 0x00200000 /* Enable load_extension */
+#define SQLITE_EnableTrigger 0x00400000 /* True to enable triggers */
+
+/*
+** Bits of the sqlite3.dbOptFlags field that are used by the
+** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to
+** selectively disable various optimizations.
+*/
+#define SQLITE_QueryFlattener 0x0001 /* Query flattening */
+#define SQLITE_ColumnCache 0x0002 /* Column cache */
+#define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */
+#define SQLITE_FactorOutConst 0x0008 /* Constant factoring */
+#define SQLITE_IdxRealAsInt 0x0010 /* Store REAL as INT in indices */
+#define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */
+#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_AllOpts 0xffff /* All optimizations */
+
+/*
+** Macros for testing whether or not optimizations are enabled or disabled.
+*/
+#ifndef SQLITE_OMIT_BUILTIN_TEST
+#define OptimizationDisabled(db, mask) (((db)->dbOptFlags&(mask))!=0)
+#define OptimizationEnabled(db, mask) (((db)->dbOptFlags&(mask))==0)
+#else
+#define OptimizationDisabled(db, mask) 0
+#define OptimizationEnabled(db, mask) 1
+#endif
/*
** Possible values for the sqlite.magic field.
@@ -1122,32 +1135,22 @@ struct Column {
char *zDflt; /* Original text of the default value */
char *zType; /* Data type for this column */
char *zColl; /* Collating sequence. If NULL, use the default */
- u8 notNull; /* True if there is a NOT NULL constraint */
- u8 isPrimKey; /* True if this column is part of the PRIMARY KEY */
+ u8 notNull; /* An OE_ code for handling a NOT NULL constraint */
char affinity; /* One of the SQLITE_AFF_... values */
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- u8 isHidden; /* True if this column is 'hidden' */
-#endif
+ u16 colFlags; /* Boolean properties. See COLFLAG_ defines below */
};
+/* Allowed values for Column.colFlags:
+*/
+#define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */
+#define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */
+
/*
** A "Collating Sequence" is defined by an instance of the following
** structure. Conceptually, a collating sequence consists of a name and
** a comparison routine that defines the order of that sequence.
**
-** There may two separate implementations of the collation function, one
-** that processes text in UTF-8 encoding (CollSeq.xCmp) and another that
-** processes text encoded in UTF-16 (CollSeq.xCmp16), using the machine
-** native byte order. When a collation sequence is invoked, SQLite selects
-** the version that will require the least expensive encoding
-** translations, if any.
-**
-** The CollSeq.pUser member variable is an extra parameter that passed in
-** as the first argument to the UTF-8 comparison function, xCmp.
-** CollSeq.pUser16 is the equivalent for the UTF-16 comparison function,
-** xCmp16.
-**
-** If both CollSeq.xCmp and CollSeq.xCmp16 are NULL, it means that the
+** If CollSeq.xCmp is NULL, it means that the
** collating sequence is undefined. Indices built on an undefined
** collating sequence may not be read or written.
*/
@@ -1285,28 +1288,28 @@ struct VTable {
*/
struct Table {
char *zName; /* Name of the table or view */
- int iPKey; /* If not negative, use aCol[iPKey] as the primary key */
- int nCol; /* Number of columns in this table */
Column *aCol; /* Information about each column */
Index *pIndex; /* List of SQL indexes on this table. */
- int tnum; /* Root BTree node for this table (see note above) */
- tRowcnt nRowEst; /* Estimated rows in table - from sqlite_stat1 table */
Select *pSelect; /* NULL for tables. Points to definition if a view. */
- u16 nRef; /* Number of pointers to this Table */
- u8 tabFlags; /* Mask of TF_* values */
- u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
FKey *pFKey; /* Linked list of all foreign keys in this table */
char *zColAff; /* String defining the affinity of each column */
#ifndef SQLITE_OMIT_CHECK
ExprList *pCheck; /* All CHECK constraints */
#endif
+ tRowcnt nRowEst; /* Estimated rows in table - from sqlite_stat1 table */
+ int tnum; /* Root BTree node for this table (see note above) */
+ i16 iPKey; /* If not negative, use aCol[iPKey] as the primary key */
+ i16 nCol; /* Number of columns in this table */
+ u16 nRef; /* Number of pointers to this Table */
+ u8 tabFlags; /* Mask of TF_* values */
+ u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
#ifndef SQLITE_OMIT_ALTERTABLE
int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
- VTable *pVTable; /* List of VTable objects. */
int nModuleArg; /* Number of arguments to the module */
char **azModuleArg; /* Text of all module args. [0] is module name */
+ VTable *pVTable; /* List of VTable objects. */
#endif
Trigger *pTrigger; /* List of triggers stored in pSchema */
Schema *pSchema; /* Schema that contains this table */
@@ -1330,7 +1333,7 @@ struct Table {
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
# define IsVirtual(X) (((X)->tabFlags & TF_Virtual)!=0)
-# define IsHiddenColumn(X) ((X)->isHidden)
+# define IsHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0)
#else
# define IsVirtual(X) 0
# define IsHiddenColumn(X) 0
@@ -1675,13 +1678,15 @@ struct Expr {
ExprList *pList; /* Function arguments or in "<expr> IN (<expr-list)" */
Select *pSelect; /* Used for sub-selects and "<expr> IN (<select>)" */
} x;
- CollSeq *pColl; /* The collation type of the column or 0 */
/* If the EP_Reduced flag is set in the Expr.flags mask, then no
** space is allocated for the fields below this point. An attempt to
** access them will result in a segfault or malfunction.
*********************************************************************/
+#if SQLITE_MAX_EXPR_DEPTH>0
+ 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 */
@@ -1695,9 +1700,6 @@ struct Expr {
** TK_AGG_FUNCTION: nesting depth */
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
Table *pTab; /* Table for TK_COLUMN expressions. */
-#if SQLITE_MAX_EXPR_DEPTH>0
- int nHeight; /* Height of the tree headed by this node */
-#endif
};
/*
@@ -1711,7 +1713,7 @@ struct Expr {
#define EP_VarSelect 0x0020 /* pSelect is correlated, not constant */
#define EP_DblQuoted 0x0040 /* token.z was originally in "..." */
#define EP_InfixFunc 0x0080 /* True for an infix function: LIKE, GLOB, etc */
-#define EP_ExpCollate 0x0100 /* Collating sequence specified explicitly */
+#define EP_Collate 0x0100 /* Tree contains a TK_COLLATE opeartor */
#define EP_FixedDest 0x0200 /* Result needed in a specific register */
#define EP_IntValue 0x0400 /* Integer value contained in u.iValue */
#define EP_xIsSelect 0x0800 /* x.pSelect is valid (otherwise x.pList is) */
@@ -1855,6 +1857,7 @@ struct SrcList {
i16 nSrc; /* Number of tables or subqueries in the FROM clause */
i16 nAlloc; /* Number of entries allocated in a[] below */
struct SrcList_item {
+ Schema *pSchema; /* Schema to which this item is fixed */
char *zDatabase; /* Name of database holding this table */
char *zName; /* Name of the table */
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
@@ -1863,8 +1866,9 @@ struct SrcList {
int addrFillSub; /* Address of subroutine to manifest a subquery */
int regReturn; /* Register holding return address of addrFillSub */
u8 jointype; /* Type of join between this able and the previous */
- u8 notIndexed; /* True if there is a NOT INDEXED clause */
- u8 isCorrelated; /* True if sub-query is correlated */
+ unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */
+ unsigned isCorrelated :1; /* True if sub-query is correlated */
+ unsigned viaCoroutine :1; /* Implemented as a co-routine */
#ifndef SQLITE_OMIT_EXPLAIN
u8 iSelectId; /* If pSelect!=0, the id of the sub-select in EQP */
#endif
@@ -1905,7 +1909,8 @@ struct SrcList {
*/
struct WherePlan {
u32 wsFlags; /* WHERE_* flags that describe the strategy */
- u32 nEq; /* Number of == constraints */
+ u16 nEq; /* Number of == constraints */
+ u16 nOBSat; /* Number of ORDER BY terms satisfied */
double nRow; /* Estimated number of rows (for EQP) */
union {
Index *pIdx; /* Index when WHERE_INDEXED is true */
@@ -1949,6 +1954,7 @@ struct WhereLevel {
} in; /* Used when plan.wsFlags&WHERE_IN_ABLE */
Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */
} u;
+ double rOptCost; /* "Optimal" cost for this level */
/* The following field is really not part of the current level. But
** we need a place to cache virtual table index information for each
@@ -1981,24 +1987,28 @@ struct WhereLevel {
** into the second half to give some continuity.
*/
struct WhereInfo {
- Parse *pParse; /* Parsing and code generating context */
- u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
- u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE or DELETE */
- u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
- u8 eDistinct;
- SrcList *pTabList; /* List of tables in the join */
- int iTop; /* The very beginning of the WHERE loop */
- int iContinue; /* Jump here to continue with next record */
- int iBreak; /* Jump here to break out of the loop */
- int nLevel; /* Number of nested loop */
- struct WhereClause *pWC; /* Decomposition of the WHERE clause */
- double savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */
- double nRowOut; /* Estimated number of output rows */
- WhereLevel a[1]; /* Information about each nest loop in WHERE */
+ Parse *pParse; /* Parsing and code generating context */
+ SrcList *pTabList; /* List of tables in the join */
+ u16 nOBSat; /* Number of ORDER BY terms satisfied by indices */
+ u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
+ u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */
+ u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
+ u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */
+ int iTop; /* The very beginning of the WHERE loop */
+ int iContinue; /* Jump here to continue with next record */
+ int iBreak; /* Jump here to break out of the loop */
+ int nLevel; /* Number of nested loop */
+ struct WhereClause *pWC; /* Decomposition of the WHERE clause */
+ double savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */
+ double nRowOut; /* Estimated number of output rows */
+ WhereLevel a[1]; /* Information about each nest loop in WHERE */
};
-#define WHERE_DISTINCT_UNIQUE 1
-#define WHERE_DISTINCT_ORDERED 2
+/* Allowed values for WhereInfo.eDistinct and DistinctCtx.eTnctType */
+#define WHERE_DISTINCT_NOOP 0 /* DISTINCT keyword not used */
+#define WHERE_DISTINCT_UNIQUE 1 /* No duplicates */
+#define WHERE_DISTINCT_ORDERED 2 /* All duplicates are adjacent */
+#define WHERE_DISTINCT_UNORDERED 3 /* Duplicates are scattered */
/*
** A NameContext defines a context in which to resolve table and column
@@ -2057,13 +2067,12 @@ struct NameContext {
** as the OP_OpenEphm instruction is coded because not
** enough information about the compound query is known at that point.
** The KeyInfo for addrOpenTran[0] and [1] contains collating sequences
-** for the result set. The KeyInfo for addrOpenTran[2] contains collating
+** for the result set. The KeyInfo for addrOpenEphm[2] contains collating
** sequences for the ORDER BY clause.
*/
struct Select {
ExprList *pEList; /* The fields of the result */
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
- char affinity; /* MakeRecord with this affinity for SRT_Set */
u16 selFlags; /* Various SF_* values */
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */
@@ -2084,14 +2093,15 @@ struct Select {
** Allowed values for Select.selFlags. The "SF" prefix stands for
** "Select Flag".
*/
-#define SF_Distinct 0x01 /* Output should be DISTINCT */
-#define SF_Resolved 0x02 /* Identifiers have been resolved */
-#define SF_Aggregate 0x04 /* Contains aggregate functions */
-#define SF_UsesEphemeral 0x08 /* Uses the OpenEphemeral opcode */
-#define SF_Expanded 0x10 /* sqlite3SelectExpand() called on this */
-#define SF_HasTypeInfo 0x20 /* FROM subqueries have Table metadata */
-#define SF_UseSorter 0x40 /* Sort using a sorter */
-#define SF_Values 0x80 /* Synthesized from VALUES clause */
+#define SF_Distinct 0x0001 /* Output should be DISTINCT */
+#define SF_Resolved 0x0002 /* Identifiers have been resolved */
+#define SF_Aggregate 0x0004 /* Contains aggregate functions */
+#define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */
+#define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */
+#define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
+#define SF_UseSorter 0x0040 /* Sort using a sorter */
+#define SF_Values 0x0080 /* Synthesized from VALUES clause */
+#define SF_Materialize 0x0100 /* Force materialization of views */
/*
@@ -2114,13 +2124,12 @@ struct Select {
#define SRT_Coroutine 10 /* Generate a single row of result */
/*
-** A structure used to customize the behavior of sqlite3Select(). See
-** comments above sqlite3Select() for details.
+** An instance of this object describes where to put of the results of
+** a SELECT statement.
*/
-typedef struct SelectDest SelectDest;
struct SelectDest {
- u8 eDest; /* How to dispose of the results */
- u8 affSdst; /* Affinity used when eDest==SRT_Set */
+ u8 eDest; /* How to dispose of the results. On of SRT_* above. */
+ char affSdst; /* Affinity used when eDest==SRT_Set */
int iSDParm; /* A parameter used by the eDest disposal method */
int iSdst; /* Base register where results are written */
int nSdst; /* Number of registers allocated */
@@ -2321,6 +2330,7 @@ struct AuthContext {
#define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */
#define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */
#define OPFLAG_P2ISREG 0x02 /* P2 to OP_Open** is a register number */
+#define OPFLAG_PERMUTE 0x01 /* OP_Compare: use the permutation */
/*
* Each trigger present in the database schema is stored as an instance of
@@ -2420,6 +2430,7 @@ struct TriggerStep {
typedef struct DbFixer DbFixer;
struct DbFixer {
Parse *pParse; /* The parsing context. Error messages written here */
+ Schema *pSchema; /* Fix items to this schema */
const char *zDb; /* Make sure all objects are contained in this database */
const char *zType; /* Type of the container - used for error messages */
const Token *pName; /* Name of the container - used for error messages */
@@ -2462,6 +2473,7 @@ struct Sqlite3Config {
int bCoreMutex; /* True to enable core mutexing */
int bFullMutex; /* True to enable full mutexing */
int bOpenUri; /* True to interpret filenames as URIs */
+ int bUseCis; /* Use covering indices for full-scans */
int mxStrlen; /* Maximum string length */
int szLookaside; /* Default lookaside buffer size */
int nLookaside; /* Default lookaside buffer count */
@@ -2491,6 +2503,10 @@ struct Sqlite3Config {
void (*xLog)(void*,int,const char*); /* Function for logging */
void *pLogArg; /* First argument to xLog() */
int bLocaltimeFault; /* True to fail localtime() calls */
+#ifdef SQLITE_ENABLE_SQLLOG
+ void(*xSqllog)(void*,sqlite3*,const char*, int);
+ void *pSqllogArg;
+#endif
};
/*
@@ -2778,6 +2794,7 @@ void sqlite3DeleteTable(sqlite3*, Table*);
# define sqlite3AutoincrementBegin(X)
# define sqlite3AutoincrementEnd(X)
#endif
+int sqlite3CodeCoroutine(Parse*, Select*, SelectDest*);
void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*);
IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*);
@@ -2807,13 +2824,11 @@ Expr *sqlite3LimitWhere(Parse *, SrcList *, Expr *, ExprList *, Expr *, Expr *,
#endif
void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
-WhereInfo *sqlite3WhereBegin(
- Parse*,SrcList*,Expr*,ExprList**,ExprList*,u16,int);
+WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int);
void sqlite3WhereEnd(WhereInfo*);
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
void sqlite3ExprCodeMove(Parse*, int, int, int);
-void sqlite3ExprCodeCopy(Parse*, int, int, int);
void sqlite3ExprCacheStore(Parse*, int, int, int);
void sqlite3ExprCachePush(Parse*);
void sqlite3ExprCachePop(Parse*, int);
@@ -2830,6 +2845,7 @@ void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
Table *sqlite3FindTable(sqlite3*,const char*, const char*);
Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*);
+Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *);
Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
@@ -2953,7 +2969,7 @@ int sqlite3GetInt32(const char *, int*);
int sqlite3Atoi(const char*);
int sqlite3Utf16ByteLen(const void *pData, int nChar);
int sqlite3Utf8CharLen(const char *pData, int nByte);
-u32 sqlite3Utf8Read(const u8*, const u8**);
+u32 sqlite3Utf8Read(const u8**);
/*
** Routines to read and write variable-length integers. These used to
@@ -3006,8 +3022,9 @@ int sqlite3ReadSchema(Parse *pParse);
CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
-Expr *sqlite3ExprSetColl(Expr*, CollSeq*);
-Expr *sqlite3ExprSetCollByToken(Parse *pParse, Expr*, Token*);
+Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, Token*);
+Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
+Expr *sqlite3ExprSkipCollate(Expr*);
int sqlite3CheckCollSeq(Parse *, CollSeq *);
int sqlite3CheckObjectName(Parse *, const char *);
void sqlite3VdbeSetChanges(sqlite3 *, int);
@@ -3060,7 +3077,7 @@ int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
void sqlite3AlterFinishAddColumn(Parse *, Token *);
void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
-CollSeq *sqlite3GetCollSeq(sqlite3*, u8, CollSeq *, const char*);
+CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
char sqlite3AffinityType(const char*);
void sqlite3Analyze(Parse*, Token*, Token*);
int sqlite3InvokeBusyHandler(BusyHandler*);
@@ -3164,8 +3181,10 @@ void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
int sqlite3TempInMemory(const sqlite3*);
const char *sqlite3JournalModename(int);
-int sqlite3Checkpoint(sqlite3*, int, int, int*, int*);
-int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int);
+#ifndef SQLITE_OMIT_WAL
+ int sqlite3Checkpoint(sqlite3*, int, int, int*, int*);
+ int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int);
+#endif
/* Declarations for functions in fkey.c. All of these are replaced by
** no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign
@@ -3223,8 +3242,10 @@ int sqlite3FindInIndex(Parse *, Expr *, int*);
int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
int sqlite3JournalSize(sqlite3_vfs *);
int sqlite3JournalCreate(sqlite3_file *);
+ int sqlite3JournalExists(sqlite3_file *p);
#else
#define sqlite3JournalSize(pVfs) ((pVfs)->szOsFile)
+ #define sqlite3JournalExists(p) 1
#endif
void sqlite3MemJournalOpen(sqlite3_file *);
diff --git a/lib/libsqlite3/src/status.c b/lib/libsqlite3/src/status.c
index 04b7656afe8..28349e6d3d2 100644
--- a/lib/libsqlite3/src/status.c
+++ b/lib/libsqlite3/src/status.c
@@ -208,7 +208,8 @@ int sqlite3_db_status(
db->pnBytesFreed = &nByte;
for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
- sqlite3VdbeDeleteObject(db, pVdbe);
+ sqlite3VdbeClearObject(db, pVdbe);
+ sqlite3DbFree(db, pVdbe);
}
db->pnBytesFreed = 0;
diff --git a/lib/libsqlite3/src/tclsqlite.c b/lib/libsqlite3/src/tclsqlite.c
index a2072f8624d..57dab85d4b5 100644
--- a/lib/libsqlite3/src/tclsqlite.c
+++ b/lib/libsqlite3/src/tclsqlite.c
@@ -1489,7 +1489,7 @@ static Tcl_Obj *dbEvalColumnValue(DbEvalContext *p, int iCol){
}
}
- return Tcl_NewStringObj(sqlite3_column_text(pStmt, iCol), -1);
+ return Tcl_NewStringObj((char*)sqlite3_column_text(pStmt, iCol), -1);
}
/*
@@ -2343,7 +2343,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
const char *zDb = "main";
const char *zTable;
const char *zColumn;
- sqlite_int64 iRow;
+ Tcl_WideInt iRow;
/* Check for the -readonly option */
if( objc>3 && strcmp(Tcl_GetString(objv[2]), "-readonly")==0 ){
@@ -2534,7 +2534,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey);
rc = sqlite3_rekey(pDb->db, pKey, nKey);
if( rc ){
- Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);
+ Tcl_AppendResult(interp, sqlite3_errstr(rc), 0);
rc = TCL_ERROR;
}
#endif
@@ -2905,6 +2905,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
void *pKey = 0;
int nKey = 0;
#endif
+ int rc;
/* In normal use, each TCL interpreter runs in a single thread. So
** by default, we can turn of mutexing on SQLite database connections.
@@ -3009,12 +3010,16 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
memset(p, 0, sizeof(*p));
zFile = Tcl_GetStringFromObj(objv[2], 0);
zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename);
- sqlite3_open_v2(zFile, &p->db, flags, zVfs);
+ rc = sqlite3_open_v2(zFile, &p->db, flags, zVfs);
Tcl_DStringFree(&translatedFilename);
- if( SQLITE_OK!=sqlite3_errcode(p->db) ){
- zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db));
- sqlite3_close(p->db);
- p->db = 0;
+ if( p->db ){
+ if( SQLITE_OK!=sqlite3_errcode(p->db) ){
+ zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db));
+ sqlite3_close(p->db);
+ p->db = 0;
+ }
+ }else{
+ zErrMsg = sqlite3_mprintf("%s", sqlite3_errstr(rc));
}
#ifdef SQLITE_HAS_CODEC
if( p->db ){
diff --git a/lib/libsqlite3/src/test1.c b/lib/libsqlite3/src/test1.c
index c3dac062123..bb8d186c121 100644
--- a/lib/libsqlite3/src/test1.c
+++ b/lib/libsqlite3/src/test1.c
@@ -3067,7 +3067,7 @@ static int test_bind_int64(
){
sqlite3_stmt *pStmt;
int idx;
- i64 value;
+ Tcl_WideInt value;
int rc;
if( objc!=4 ){
@@ -4703,7 +4703,7 @@ static int test_soft_heap_limit(
Tcl_Obj *CONST objv[]
){
sqlite3_int64 amt;
- sqlite3_int64 N = -1;
+ Tcl_WideInt N = -1;
if( objc!=1 && objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "?N?");
return TCL_ERROR;
@@ -5096,7 +5096,7 @@ static int file_control_sizehint_test(
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
- sqlite3_int64 nSize; /* Hinted size */
+ Tcl_WideInt nSize; /* Hinted size */
char *zDb; /* Db name ("main", "temp" etc.) */
sqlite3 *db; /* Database handle */
int rc; /* file_control() return code */
@@ -5321,6 +5321,38 @@ static int file_control_vfsname(
return TCL_OK;
}
+/*
+** tclcmd: file_control_tempfilename DB ?AUXDB?
+**
+** Return a string that is a temporary filename
+*/
+static int file_control_tempfilename(
+ ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int objc, /* Number of arguments */
+ Tcl_Obj *CONST objv[] /* Command arguments */
+){
+ sqlite3 *db;
+ const char *zDbName = "main";
+ char *zTName = 0;
+
+ if( objc!=2 && objc!=3 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ Tcl_GetStringFromObj(objv[0], 0), " DB ?AUXDB?", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
+ return TCL_ERROR;
+ }
+ if( objc==3 ){
+ zDbName = Tcl_GetString(objv[2]);
+ }
+ sqlite3_file_control(db, zDbName, SQLITE_FCNTL_TEMPFILENAME, (void*)&zTName);
+ Tcl_AppendResult(interp, zTName, (char*)0);
+ sqlite3_free(zTName);
+ return TCL_OK;
+}
+
/*
** tclcmd: sqlite3_vfs_list
@@ -5933,15 +5965,15 @@ static int optimization_control(
const char *zOptName;
int mask;
} aOpt[] = {
- { "all", SQLITE_OptMask },
+ { "all", SQLITE_AllOpts },
{ "query-flattener", SQLITE_QueryFlattener },
{ "column-cache", SQLITE_ColumnCache },
- { "index-sort", SQLITE_IndexSort },
- { "index-search", SQLITE_IndexSearch },
- { "index-cover", SQLITE_IndexCover },
{ "groupby-order", SQLITE_GroupByOrder },
{ "factor-constants", SQLITE_FactorOutConst },
{ "real-as-int", SQLITE_IdxRealAsInt },
+ { "distinct-opt", SQLITE_DistinctOpt },
+ { "cover-idx-scan", SQLITE_CoverIdxScan },
+ { "order-by-idx-join",SQLITE_OrderByIdxJoin },
};
if( objc!=4 ){
@@ -6150,6 +6182,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "file_control_persist_wal", file_control_persist_wal, 0 },
{ "file_control_powersafe_overwrite",file_control_powersafe_overwrite,0},
{ "file_control_vfsname", file_control_vfsname, 0 },
+ { "file_control_tempfilename", file_control_tempfilename, 0 },
{ "sqlite3_vfs_list", vfs_list, 0 },
{ "sqlite3_create_function_v2", test_create_function_v2, 0 },
diff --git a/lib/libsqlite3/src/test6.c b/lib/libsqlite3/src/test6.c
index bae6b65dc25..f511be9def8 100644
--- a/lib/libsqlite3/src/test6.c
+++ b/lib/libsqlite3/src/test6.c
@@ -312,8 +312,8 @@ static int writeListSync(CrashFile *pFile, int isCrash){
assert(pWrite->zBuf);
#ifdef TRACE_CRASHTEST
- printf("Trashing %d sectors @ sector %d (%s)\n",
- 1+iLast-iFirst, iFirst, pWrite->pFile->zName
+ printf("Trashing %d sectors @ %lld (sector %d) (%s)\n",
+ 1+iLast-iFirst, pWrite->iOffset, iFirst, pWrite->pFile->zName
);
#endif
@@ -628,18 +628,19 @@ static int cfOpen(
** to read data from the 512-byte locking region of a file opened
** with the SQLITE_OPEN_MAIN_DB flag. This region of a database file
** never contains valid data anyhow. So avoid doing such a read here.
+ **
+ ** UPDATE: It also contains an assert() verifying that each call
+ ** to the xRead() method reads less than 128KB of data.
*/
const int isDb = (flags&SQLITE_OPEN_MAIN_DB);
- i64 iChunk = pWrapper->iSize;
- if( iChunk>PENDING_BYTE && isDb ){
- iChunk = PENDING_BYTE;
- }
+ i64 iOff;
+
memset(pWrapper->zData, 0, pWrapper->nData);
- rc = sqlite3OsRead(pReal, pWrapper->zData, (int)iChunk, 0);
- if( SQLITE_OK==rc && pWrapper->iSize>(PENDING_BYTE+512) && isDb ){
- i64 iOff = PENDING_BYTE+512;
- iChunk = pWrapper->iSize - iOff;
- rc = sqlite3OsRead(pReal, &pWrapper->zData[iOff], (int)iChunk, iOff);
+ for(iOff=0; iOff<pWrapper->iSize; iOff += 512){
+ int nRead = pWrapper->iSize - (int)iOff;
+ if( nRead>512 ) nRead = 512;
+ if( isDb && iOff==PENDING_BYTE ) continue;
+ rc = sqlite3OsRead(pReal, &pWrapper->zData[iOff], nRead, iOff);
}
}else{
rc = SQLITE_NOMEM;
diff --git a/lib/libsqlite3/src/test_intarray.c b/lib/libsqlite3/src/test_intarray.c
index 8651d01cfac..6ea77561768 100644
--- a/lib/libsqlite3/src/test_intarray.c
+++ b/lib/libsqlite3/src/test_intarray.c
@@ -346,8 +346,9 @@ static int test_intarray_bind(
return TCL_ERROR;
}
for(i=0; i<n; i++){
- a[i] = 0;
- Tcl_GetWideIntFromObj(0, objv[i+2], &a[i]);
+ Tcl_WideInt x = 0;
+ Tcl_GetWideIntFromObj(0, objv[i+2], &x);
+ a[i] = x;
}
rc = sqlite3_intarray_bind(pArray, n, a, sqlite3_free);
if( rc!=SQLITE_OK ){
diff --git a/lib/libsqlite3/src/test_intarray.h b/lib/libsqlite3/src/test_intarray.h
index e994367c093..691337d1aed 100644
--- a/lib/libsqlite3/src/test_intarray.h
+++ b/lib/libsqlite3/src/test_intarray.h
@@ -77,6 +77,13 @@
#include "sqlite3.h"
/*
+** Make sure we can call this stuff from C++.
+*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
** An sqlite3_intarray is an abstract type to stores an instance of
** an integer array.
*/
@@ -112,3 +119,7 @@ int sqlite3_intarray_bind(
sqlite3_int64 *aElements, /* Content of the intarray */
void (*xFree)(void*) /* How to dispose of the intarray when done */
);
+
+#ifdef __cplusplus
+} /* End of the 'extern "C"' block */
+#endif
diff --git a/lib/libsqlite3/src/test_malloc.c b/lib/libsqlite3/src/test_malloc.c
index 09b8f738e84..33de859d274 100644
--- a/lib/libsqlite3/src/test_malloc.c
+++ b/lib/libsqlite3/src/test_malloc.c
@@ -720,8 +720,8 @@ static int test_memdebug_settitle(
#ifdef SQLITE_MEMDEBUG
{
const char *zTitle;
- zTitle = Tcl_GetString(objv[1]);
extern int sqlite3MemdebugSettitle(const char*);
+ zTitle = Tcl_GetString(objv[1]);
sqlite3MemdebugSettitle(zTitle);
}
#endif
@@ -1094,9 +1094,7 @@ static int test_db_config_lookaside(
}
/*
-** Usage:
-**
-** sqlite3_config_heap NBYTE NMINALLOC
+** Usage: sqlite3_config_heap NBYTE NMINALLOC
*/
static int test_config_heap(
void * clientData,
@@ -1133,7 +1131,7 @@ static int test_config_heap(
}
/*
-** tclcmd: sqlite3_config_error [DB]
+** Usage: sqlite3_config_error [DB]
**
** Invoke sqlite3_config() or sqlite3_db_config() with invalid
** opcodes and verify that they return errors.
@@ -1171,10 +1169,10 @@ static int test_config_error(
}
/*
-** tclcmd: sqlite3_config_uri BOOLEAN
+** Usage: sqlite3_config_uri BOOLEAN
**
-** Invoke sqlite3_config() or sqlite3_db_config() with invalid
-** opcodes and verify that they return errors.
+** Enables or disables interpretation of URI parameters by default using
+** SQLITE_CONFIG_URI.
*/
static int test_config_uri(
void * clientData,
@@ -1200,10 +1198,37 @@ static int test_config_uri(
}
/*
-** Usage:
+** Usage: sqlite3_config_cis BOOLEAN
**
-** sqlite3_dump_memsys3 FILENAME
-** sqlite3_dump_memsys5 FILENAME
+** Enables or disables the use of the covering-index scan optimization.
+** SQLITE_CONFIG_COVERING_INDEX_SCAN.
+*/
+static int test_config_cis(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ int rc;
+ int bUseCis;
+
+ if( objc!=2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
+ return TCL_ERROR;
+ }
+ if( Tcl_GetBooleanFromObj(interp, objv[1], &bUseCis) ){
+ return TCL_ERROR;
+ }
+
+ rc = sqlite3_config(SQLITE_CONFIG_COVERING_INDEX_SCAN, bUseCis);
+ Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
+
+ return TCL_OK;
+}
+
+/*
+** Usage: sqlite3_dump_memsys3 FILENAME
+** sqlite3_dump_memsys5 FILENAME
**
** Write a summary of unfreed memsys3 allocations to FILENAME.
*/
@@ -1451,6 +1476,7 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){
{ "sqlite3_config_lookaside", test_config_lookaside ,0 },
{ "sqlite3_config_error", test_config_error ,0 },
{ "sqlite3_config_uri", test_config_uri ,0 },
+ { "sqlite3_config_cis", test_config_cis ,0 },
{ "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 },
{ "sqlite3_dump_memsys3", test_dump_memsys3 ,3 },
{ "sqlite3_dump_memsys5", test_dump_memsys3 ,5 },
diff --git a/lib/libsqlite3/src/test_multiplex.h b/lib/libsqlite3/src/test_multiplex.h
index ec1ba9bb211..b7e1afea5fd 100644
--- a/lib/libsqlite3/src/test_multiplex.h
+++ b/lib/libsqlite3/src/test_multiplex.h
@@ -46,6 +46,10 @@
#define MULTIPLEX_CTRL_SET_CHUNK_SIZE 214015
#define MULTIPLEX_CTRL_SET_MAX_CHUNKS 214016
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
** CAPI: Initialize the multiplex VFS shim - sqlite3_multiplex_initialize()
**
@@ -88,4 +92,8 @@ extern int sqlite3_multiplex_initialize(const char *zOrigVfsName, int makeDefaul
*/
extern int sqlite3_multiplex_shutdown(void);
+#ifdef __cplusplus
+} /* End of the 'extern "C"' block */
+#endif
+
#endif
diff --git a/lib/libsqlite3/src/test_quota.c b/lib/libsqlite3/src/test_quota.c
index 2ce46acdc06..166a512f18c 100644
--- a/lib/libsqlite3/src/test_quota.c
+++ b/lib/libsqlite3/src/test_quota.c
@@ -1073,7 +1073,7 @@ size_t sqlite3_quota_fwrite(
/* If the write was incomplete, adjust the file size and group size
** downward */
if( rc<nmemb && pFile ){
- size_t nWritten = rc>=0 ? rc : 0;
+ size_t nWritten = rc;
sqlite3_int64 iNewEnd = iOfst + size*nWritten;
if( iNewEnd<iEnd ) iNewEnd = iEnd;
quotaEnter();
@@ -1179,7 +1179,13 @@ int sqlite3_quota_ftruncate(quota_FILE *p, sqlite3_int64 szNew){
rc = ftruncate(fileno(p->f), szNew);
#endif
#if SQLITE_OS_WIN
- rc = _chsize_s(_fileno(p->f), szNew);
+# if defined(__MINGW32__) && defined(SQLITE_TEST)
+ /* _chsize_s() is missing from MingW (as of 2012-11-06). Use
+ ** _chsize() as a work-around for testing purposes. */
+ rc = _chsize(_fileno(p->f), (long)szNew);
+# else
+ rc = _chsize_s(_fileno(p->f), szNew);
+# endif
#endif
if( pFile && rc==0 ){
quotaGroup *pGroup = pFile->pGroup;
@@ -1354,8 +1360,10 @@ static void tclQuotaCallback(
rc = Tcl_EvalObjEx(p->interp, pEval, TCL_EVAL_GLOBAL);
if( rc==TCL_OK ){
+ Tcl_WideInt x;
Tcl_Obj *pLimit = Tcl_ObjGetVar2(p->interp, pVarname, 0, 0);
- rc = Tcl_GetWideIntFromObj(p->interp, pLimit, piLimit);
+ rc = Tcl_GetWideIntFromObj(p->interp, pLimit, &x);
+ *piLimit = x;
Tcl_UnsetVar(p->interp, Tcl_GetString(pVarname), 0);
}
@@ -1437,7 +1445,7 @@ static int test_quota_set(
Tcl_Obj *CONST objv[]
){
const char *zPattern; /* File pattern to configure */
- sqlite3_int64 iLimit; /* Initial quota in bytes */
+ Tcl_WideInt iLimit; /* Initial quota in bytes */
Tcl_Obj *pScript; /* Tcl script to invoke to increase quota */
int rc; /* Value returned by quota_set() */
TclQuotaCallback *p; /* Callback object */
@@ -1613,7 +1621,6 @@ static int test_quota_fread(
return TCL_ERROR;
}
got = sqlite3_quota_fread(zBuf, sz, nElem, p);
- if( got<0 ) got = 0;
zBuf[got*sz] = 0;
Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
sqlite3_free(zBuf);
diff --git a/lib/libsqlite3/src/test_sqllog.c b/lib/libsqlite3/src/test_sqllog.c
new file mode 100644
index 00000000000..7cb570bcf22
--- /dev/null
+++ b/lib/libsqlite3/src/test_sqllog.c
@@ -0,0 +1,472 @@
+/*
+** 2012 November 26
+**
+** 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.
+**
+*************************************************************************
+**
+** OVERVIEW
+**
+** This file contains experimental code used to record data from live
+** SQLite applications that may be useful for offline analysis. Specifically:
+**
+** 1) The initial contents of all database files opened by the
+** application, and
+**
+** 2) All SQL statements executed by the application.
+**
+** USAGE
+**
+** To use this module, SQLite must be compiled with the SQLITE_ENABLE_SQLLOG
+** pre-processor symbol defined and this file linked into the application
+** somehow.
+**
+** At runtime, logging is enabled by setting environment variable
+** SQLITE_SQLLOG_DIR to the name of a directory in which to store logged
+** data. The directory must already exist.
+**
+** Usually, if the application opens the same database file more than once
+** (either by attaching it or by using more than one database handle), only
+** a single copy is made. This behaviour may be overridden (so that a
+** separate copy is taken each time the database file is opened or attached)
+** by setting the environment variable SQLITE_SQLLOG_REUSE_FILES to 0.
+**
+** OUTPUT:
+**
+** The SQLITE_SQLLOG_DIR is populated with three types of files:
+**
+** sqllog_N.db - Copies of database files. N may be any integer.
+**
+** sqllog_N.sql - A list of SQL statements executed by a single
+** connection. N may be any integer.
+**
+** sqllog.idx - An index mapping from integer N to a database
+** file name - indicating the full path of the
+** database from which sqllog_N.db was copied.
+**
+** ERROR HANDLING:
+**
+** This module attempts to make a best effort to continue logging if an
+** IO or other error is encountered. For example, if a log file cannot
+** be opened logs are not collected for that connection, but other
+** logging proceeds as expected. Errors are logged by calling sqlite3_log().
+*/
+
+#include "sqlite3.h"
+#include "stdio.h"
+#include "stdlib.h"
+#include "string.h"
+#include "assert.h"
+
+#include "sys/types.h"
+#include "unistd.h"
+static int getProcessId(void){
+#if SQLITE_OS_WIN
+ return (int)_getpid();
+#else
+ return (int)getpid();
+#endif
+}
+
+
+#define ENVIRONMENT_VARIABLE1_NAME "SQLITE_SQLLOG_DIR"
+#define ENVIRONMENT_VARIABLE2_NAME "SQLITE_SQLLOG_REUSE_FILES"
+
+/* Assume that all database and database file names are shorted than this. */
+#define SQLLOG_NAMESZ 512
+
+/* Maximum number of simultaneous database connections the process may
+** open (if any more are opened an error is logged using sqlite3_log()
+** and processing is halted).
+*/
+#define MAX_CONNECTIONS 256
+
+struct SLConn {
+ int isErr; /* True if an error has occurred */
+ sqlite3 *db; /* Connection handle */
+ int iLog; /* First integer value used in file names */
+ FILE *fd; /* File descriptor for log file */
+};
+
+struct SLGlobal {
+ /* Protected by MUTEX_STATIC_MASTER */
+ sqlite3_mutex *mutex; /* Recursive mutex */
+ int nConn; /* Size of aConn[] array */
+
+ /* Protected by SLGlobal.mutex */
+ int bReuse; /* True to avoid extra copies of db files */
+ char zPrefix[SQLLOG_NAMESZ]; /* Prefix for all created files */
+ char zIdx[SQLLOG_NAMESZ]; /* Full path to *.idx file */
+ int iNextLog; /* Used to allocate file names */
+ int iNextDb; /* Used to allocate database file names */
+ int bRec; /* True if testSqllog() is called rec. */
+ int iClock; /* Clock value */
+ struct SLConn aConn[MAX_CONNECTIONS];
+} sqllogglobal;
+
+/*
+** Return true if c is an ASCII whitespace character.
+*/
+static int sqllog_isspace(char c){
+ return (c==' ' || c=='\t' || c=='\n' || c=='\v' || c=='\f' || c=='\r');
+}
+
+/*
+** The first argument points to a nul-terminated string containing an SQL
+** command. Before returning, this function sets *pz to point to the start
+** of the first token in this command, and *pn to the number of bytes in
+** the token. This is used to check if the SQL command is an "ATTACH" or
+** not.
+*/
+static void sqllogTokenize(const char *z, const char **pz, int *pn){
+ const char *p = z;
+ int n;
+
+ /* Skip past any whitespace */
+ while( sqllog_isspace(*p) ){
+ p++;
+ }
+
+ /* Figure out how long the first token is */
+ *pz = p;
+ n = 0;
+ while( (p[n]>='a' && p[n]<='z') || (p[n]>='A' && p[n]<='Z') ) n++;
+ *pn = n;
+}
+
+/*
+** Check if the logs directory already contains a copy of database file
+** zFile. If so, return a pointer to the full path of the copy. Otherwise,
+** return NULL.
+**
+** If a non-NULL value is returned, then the caller must arrange to
+** eventually free it using sqlite3_free().
+*/
+static char *sqllogFindFile(const char *zFile){
+ char *zRet = 0;
+ FILE *fd = 0;
+
+ /* Open the index file for reading */
+ fd = fopen(sqllogglobal.zIdx, "r");
+ if( fd==0 ){
+ sqlite3_log(SQLITE_IOERR, "sqllogFindFile(): error in fopen()");
+ return 0;
+ }
+
+ /* Loop through each entry in the index file. If zFile is not NULL and the
+ ** entry is a match, then set zRet to point to the filename of the existing
+ ** copy and break out of the loop. */
+ while( feof(fd)==0 ){
+ char zLine[SQLLOG_NAMESZ*2+5];
+ if( fgets(zLine, sizeof(zLine), fd) ){
+ int n;
+ char *z;
+
+ zLine[sizeof(zLine)-1] = '\0';
+ z = zLine;
+ while( *z>='0' && *z<='9' ) z++;
+ while( *z==' ' ) z++;
+
+ n = strlen(z);
+ while( n>0 && sqllog_isspace(z[n-1]) ) n--;
+
+ if( n==strlen(zFile) && 0==memcmp(zFile, z, n) ){
+ char zBuf[16];
+ memset(zBuf, 0, sizeof(zBuf));
+ z = zLine;
+ while( *z>='0' && *z<='9' ){
+ zBuf[z-zLine] = *z;
+ z++;
+ }
+ zRet = sqlite3_mprintf("%s_%s.db", sqllogglobal.zPrefix, zBuf);
+ break;
+ }
+ }
+ }
+
+ if( ferror(fd) ){
+ sqlite3_log(SQLITE_IOERR, "sqllogFindFile(): error reading index file");
+ }
+
+ fclose(fd);
+ return zRet;
+}
+
+static int sqllogFindAttached(
+ struct SLConn *p, /* Database connection */
+ const char *zSearch, /* Name to search for (or NULL) */
+ char *zName, /* OUT: Name of attached database */
+ char *zFile /* OUT: Name of attached file */
+){
+ sqlite3_stmt *pStmt;
+ int rc;
+
+ /* The "PRAGMA database_list" command returns a list of databases in the
+ ** order that they were attached. So a newly attached database is
+ ** described by the last row returned. */
+ assert( sqllogglobal.bRec==0 );
+ sqllogglobal.bRec = 1;
+ rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
+ if( rc==SQLITE_OK ){
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ const char *zVal1; int nVal1;
+ const char *zVal2; int nVal2;
+
+ zVal1 = (const char*)sqlite3_column_text(pStmt, 1);
+ nVal1 = sqlite3_column_bytes(pStmt, 1);
+ memcpy(zName, zVal1, nVal1+1);
+
+ zVal2 = (const char*)sqlite3_column_text(pStmt, 2);
+ nVal2 = sqlite3_column_bytes(pStmt, 2);
+ memcpy(zFile, zVal2, nVal2+1);
+
+ if( zSearch && strlen(zSearch)==nVal1
+ && 0==sqlite3_strnicmp(zSearch, zVal1, nVal1)
+ ){
+ break;
+ }
+ }
+ rc = sqlite3_finalize(pStmt);
+ }
+ sqllogglobal.bRec = 0;
+
+ if( rc!=SQLITE_OK ){
+ sqlite3_log(rc, "sqllogFindAttached(): error in \"PRAGMA database_list\"");
+ }
+ return rc;
+}
+
+
+/*
+** Parameter zSearch is the name of a database attached to the database
+** connection associated with the first argument. This function creates
+** a backup of this database in the logs directory.
+**
+** The name used for the backup file is automatically generated. Call
+** it zFile.
+**
+** If the bLog parameter is true, then a statement of the following form
+** is written to the log file associated with *p:
+**
+** ATTACH 'zFile' AS 'zName';
+**
+** Otherwise, if bLog is false, a comment is added to the log file:
+**
+** -- Main database file is 'zFile'
+**
+** The SLGlobal.mutex mutex is always held when this function is called.
+*/
+static void sqllogCopydb(struct SLConn *p, const char *zSearch, int bLog){
+ char zName[SQLLOG_NAMESZ]; /* Attached database name */
+ char zFile[SQLLOG_NAMESZ]; /* Database file name */
+ char *zFree;
+ char *zInit = 0;
+ int rc;
+
+ rc = sqllogFindAttached(p, zSearch, zName, zFile);
+ if( rc!=SQLITE_OK ) return;
+
+ if( zFile[0]=='\0' ){
+ zInit = sqlite3_mprintf("");
+ }else{
+ if( sqllogglobal.bReuse ){
+ zInit = sqllogFindFile(zFile);
+ }else{
+ zInit = 0;
+ }
+ if( zInit==0 ){
+ int rc;
+ sqlite3 *copy = 0;
+ int iDb;
+
+ /* Generate a file-name to use for the copy of this database */
+ iDb = sqllogglobal.iNextDb++;
+ zInit = sqlite3_mprintf("%s_%d.db", sqllogglobal.zPrefix, iDb);
+
+ /* Create the backup */
+ assert( sqllogglobal.bRec==0 );
+ sqllogglobal.bRec = 1;
+ rc = sqlite3_open(zInit, &copy);
+ if( rc==SQLITE_OK ){
+ sqlite3_backup *pBak;
+ sqlite3_exec(copy, "PRAGMA synchronous = 0", 0, 0, 0);
+ pBak = sqlite3_backup_init(copy, "main", p->db, zName);
+ if( pBak ){
+ sqlite3_backup_step(pBak, -1);
+ rc = sqlite3_backup_finish(pBak);
+ }else{
+ rc = sqlite3_errcode(copy);
+ }
+ sqlite3_close(copy);
+ }
+ sqllogglobal.bRec = 0;
+
+ if( rc==SQLITE_OK ){
+ /* Write an entry into the database index file */
+ FILE *fd = fopen(sqllogglobal.zIdx, "a");
+ if( fd ){
+ fprintf(fd, "%d %s\n", iDb, zFile);
+ fclose(fd);
+ }
+ }else{
+ sqlite3_log(rc, "sqllogCopydb(): error backing up database");
+ }
+ }
+ }
+
+ if( bLog ){
+ zFree = sqlite3_mprintf("ATTACH '%q' AS '%q'; -- clock=%d\n",
+ zInit, zName, sqllogglobal.iClock++
+ );
+ }else{
+ zFree = sqlite3_mprintf("-- Main database is '%q'\n", zInit);
+ }
+ fprintf(p->fd, "%s", zFree);
+ sqlite3_free(zFree);
+
+ sqlite3_free(zInit);
+}
+
+/*
+** If it is not already open, open the log file for connection *p.
+**
+** The SLGlobal.mutex mutex is always held when this function is called.
+*/
+static void sqllogOpenlog(struct SLConn *p){
+ /* If the log file has not yet been opened, open it now. */
+ if( p->fd==0 ){
+ char *zLog;
+
+ /* If it is still NULL, have global.zPrefix point to a copy of
+ ** environment variable $ENVIRONMENT_VARIABLE1_NAME. */
+ if( sqllogglobal.zPrefix[0]==0 ){
+ FILE *fd;
+ char *zVar = getenv(ENVIRONMENT_VARIABLE1_NAME);
+ if( zVar==0 || strlen(zVar)+10>=(sizeof(sqllogglobal.zPrefix)) ) return;
+ sprintf(sqllogglobal.zPrefix, "%s/sqllog_%d", zVar, getProcessId());
+ sprintf(sqllogglobal.zIdx, "%s.idx", sqllogglobal.zPrefix);
+ if( getenv(ENVIRONMENT_VARIABLE2_NAME) ){
+ sqllogglobal.bReuse = atoi(getenv(ENVIRONMENT_VARIABLE2_NAME));
+ }
+ fd = fopen(sqllogglobal.zIdx, "w");
+ if( fd ) fclose(fd);
+ }
+
+ /* Open the log file */
+ zLog = sqlite3_mprintf("%s_%d.sql", sqllogglobal.zPrefix, p->iLog);
+ p->fd = fopen(zLog, "w");
+ sqlite3_free(zLog);
+ if( p->fd==0 ){
+ sqlite3_log(SQLITE_IOERR, "sqllogOpenlog(): Failed to open log file");
+ }
+ }
+}
+
+/*
+** This function is called if the SQLLOG callback is invoked to report
+** execution of an SQL statement. Parameter p is the connection the statement
+** was executed by and parameter zSql is the text of the statement itself.
+*/
+static void testSqllogStmt(struct SLConn *p, const char *zSql){
+ const char *zFirst; /* Pointer to first token in zSql */
+ int nFirst; /* Size of token zFirst in bytes */
+
+ sqllogTokenize(zSql, &zFirst, &nFirst);
+ if( nFirst!=6 || 0!=sqlite3_strnicmp("ATTACH", zFirst, 6) ){
+ /* Not an ATTACH statement. Write this directly to the log. */
+ fprintf(p->fd, "%s; -- clock=%d\n", zSql, sqllogglobal.iClock++);
+ }else{
+ /* This is an ATTACH statement. Copy the database. */
+ sqllogCopydb(p, 0, 1);
+ }
+}
+
+/*
+** The SQLITE_CONFIG_SQLLOG callback registered by sqlite3_init_sqllog().
+*/
+static void testSqllog(void *pCtx, sqlite3 *db, const char *zSql, int eType){
+ struct SLConn *p = 0;
+ sqlite3_mutex *master = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
+
+ assert( eType==0 || eType==1 || eType==2 );
+ assert( (eType==2)==(zSql==0) );
+
+ /* This is a database open command. */
+ if( eType==0 ){
+ sqlite3_mutex_enter(master);
+ if( sqllogglobal.mutex==0 ){
+ sqllogglobal.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE);
+ }
+ p = &sqllogglobal.aConn[sqllogglobal.nConn++];
+ p->fd = 0;
+ p->db = db;
+ p->iLog = sqllogglobal.iNextLog++;
+ sqlite3_mutex_leave(master);
+
+ /* Open the log and take a copy of the main database file */
+ sqlite3_mutex_enter(sqllogglobal.mutex);
+ if( sqllogglobal.bRec==0 ){
+ sqllogOpenlog(p);
+ if( p->fd ) sqllogCopydb(p, "main", 0);
+ }
+ sqlite3_mutex_leave(sqllogglobal.mutex);
+ }
+
+ else{
+
+ int i;
+ for(i=0; i<sqllogglobal.nConn; i++){
+ p = &sqllogglobal.aConn[i];
+ if( p->db==db ) break;
+ }
+ if( i==sqllogglobal.nConn ) return;
+
+ /* A database handle close command */
+ if( eType==2 ){
+ sqlite3_mutex_enter(master);
+ if( p->fd ) fclose(p->fd);
+ p->db = 0;
+ p->fd = 0;
+
+ sqllogglobal.nConn--;
+ if( sqllogglobal.nConn==0 ){
+ sqlite3_mutex_free(sqllogglobal.mutex);
+ sqllogglobal.mutex = 0;
+ }else{
+ int nShift = &sqllogglobal.aConn[sqllogglobal.nConn] - p;
+ if( nShift>0 ){
+ memmove(p, &p[1], nShift*sizeof(struct SLConn));
+ }
+ }
+ sqlite3_mutex_leave(master);
+
+ /* An ordinary SQL command. */
+ }else if( p->fd ){
+ sqlite3_mutex_enter(sqllogglobal.mutex);
+ if( sqllogglobal.bRec==0 ){
+ testSqllogStmt(p, zSql);
+ }
+ sqlite3_mutex_leave(sqllogglobal.mutex);
+ }
+ }
+}
+
+/*
+** This function is called either before sqlite3_initialized() or by it.
+** It checks if the SQLITE_SQLLOG_DIR variable is defined, and if so
+** registers an SQLITE_CONFIG_SQLLOG callback to record the applications
+** database activity.
+*/
+void sqlite3_init_sqllog(void){
+ if( getenv(ENVIRONMENT_VARIABLE1_NAME) ){
+ if( SQLITE_OK==sqlite3_config(SQLITE_CONFIG_SQLLOG, testSqllog, 0) ){
+ memset(&sqllogglobal, 0, sizeof(sqllogglobal));
+ sqllogglobal.bReuse = 1;
+ }
+ }
+}
diff --git a/lib/libsqlite3/src/test_vfstrace.c b/lib/libsqlite3/src/test_vfstrace.c
index d2f7455e3d6..0aacc01fe42 100644
--- a/lib/libsqlite3/src/test_vfstrace.c
+++ b/lib/libsqlite3/src/test_vfstrace.c
@@ -475,6 +475,7 @@ static int vfstraceFileControl(sqlite3_file *pFile, int op, void *pArg){
case SQLITE_FCNTL_PERSIST_WAL: zOp = "PERSIST_WAL"; break;
case SQLITE_FCNTL_OVERWRITE: zOp = "OVERWRITE"; break;
case SQLITE_FCNTL_VFSNAME: zOp = "VFSNAME"; break;
+ case SQLITE_FCNTL_TEMPFILENAME: zOp = "TEMPFILENAME"; break;
case 0xca093fa0: zOp = "DB_UNCHANGED"; break;
case SQLITE_FCNTL_PRAGMA: {
const char *const* a = (const char*const*)pArg;
@@ -496,7 +497,8 @@ static int vfstraceFileControl(sqlite3_file *pFile, int op, void *pArg){
*(char**)pArg = sqlite3_mprintf("vfstrace.%s/%z",
pInfo->zVfsName, *(char**)pArg);
}
- if( op==SQLITE_FCNTL_PRAGMA && rc==SQLITE_OK && *(char**)pArg ){
+ if( (op==SQLITE_FCNTL_PRAGMA || op==SQLITE_FCNTL_TEMPFILENAME)
+ && rc==SQLITE_OK && *(char**)pArg ){
vfstrace_printf(pInfo, "%s.xFileControl(%s,%s) returns %s",
pInfo->zVfsName, p->zFName, zOp, *(char**)pArg);
}
diff --git a/lib/libsqlite3/src/trigger.c b/lib/libsqlite3/src/trigger.c
index 8985ec6eb87..f1ff766e202 100644
--- a/lib/libsqlite3/src/trigger.c
+++ b/lib/libsqlite3/src/trigger.c
@@ -729,6 +729,15 @@ static int codeTriggerProgram(
*/
pParse->eOrconf = (orconf==OE_Default)?pStep->orconf:(u8)orconf;
+ /* Clear the cookieGoto flag. When coding triggers, the cookieGoto
+ ** variable is used as a flag to indicate to sqlite3ExprCodeConstants()
+ ** that it is not safe to refactor constants (this happens after the
+ ** start of the first loop in the SQL statement is coded - at that
+ ** point code may be conditionally executed, so it is no longer safe to
+ ** initialize constant register values). */
+ assert( pParse->cookieGoto==0 || pParse->cookieGoto==-1 );
+ pParse->cookieGoto = 0;
+
switch( pStep->op ){
case TK_UPDATE: {
sqlite3Update(pParse,
diff --git a/lib/libsqlite3/src/utf.c b/lib/libsqlite3/src/utf.c
index e94815b5ab6..6d5b1bfe400 100644
--- a/lib/libsqlite3/src/utf.c
+++ b/lib/libsqlite3/src/utf.c
@@ -164,25 +164,23 @@ static const unsigned char sqlite3Utf8Trans1[] = {
|| (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \
}
u32 sqlite3Utf8Read(
- const unsigned char *zIn, /* First byte of UTF-8 character */
- const unsigned char **pzNext /* Write first byte past UTF-8 char here */
+ const unsigned char **pz /* Pointer to string from which to read char */
){
unsigned int c;
/* Same as READ_UTF8() above but without the zTerm parameter.
** For this routine, we assume the UTF8 string is always zero-terminated.
*/
- c = *(zIn++);
+ c = *((*pz)++);
if( c>=0xc0 ){
c = sqlite3Utf8Trans1[c-0xc0];
- while( (*zIn & 0xc0)==0x80 ){
- c = (c<<6) + (0x3f & *(zIn++));
+ while( (*(*pz) & 0xc0)==0x80 ){
+ c = (c<<6) + (0x3f & *((*pz)++));
}
if( c<0x80
|| (c&0xFFFFF800)==0xD800
|| (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; }
}
- *pzNext = zIn;
return c;
}
@@ -283,7 +281,6 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
if( desiredEnc==SQLITE_UTF16LE ){
/* UTF-8 -> UTF-16 Little-endian */
while( zIn<zTerm ){
- /* c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn); */
READ_UTF8(zIn, zTerm, c);
WRITE_UTF16LE(z, c);
}
@@ -291,7 +288,6 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
assert( desiredEnc==SQLITE_UTF16BE );
/* UTF-8 -> UTF-16 Big-endian */
while( zIn<zTerm ){
- /* c = sqlite3Utf8Read(zIn, zTerm, (const u8**)&zIn); */
READ_UTF8(zIn, zTerm, c);
WRITE_UTF16BE(z, c);
}
@@ -419,7 +415,7 @@ int sqlite3Utf8To8(unsigned char *zIn){
u32 c;
while( zIn[0] && zOut<=zIn ){
- c = sqlite3Utf8Read(zIn, (const u8**)&zIn);
+ c = sqlite3Utf8Read((const u8**)&zIn);
if( c!=0xfffd ){
WRITE_UTF8(zOut, c);
}
@@ -524,7 +520,7 @@ void sqlite3UtfSelfTest(void){
assert( n>0 && n<=4 );
z[0] = 0;
z = zBuf;
- c = sqlite3Utf8Read(z, (const u8**)&z);
+ c = sqlite3Utf8Read((const u8**)&z);
t = i;
if( i>=0xD800 && i<=0xDFFF ) t = 0xFFFD;
if( (i&0xFFFFFFFE)==0xFFFE ) t = 0xFFFD;
diff --git a/lib/libsqlite3/src/vacuum.c b/lib/libsqlite3/src/vacuum.c
index 401d41dfb77..7ed2478326c 100644
--- a/lib/libsqlite3/src/vacuum.c
+++ b/lib/libsqlite3/src/vacuum.c
@@ -85,6 +85,7 @@ void sqlite3Vacuum(Parse *pParse){
Vdbe *v = sqlite3GetVdbe(pParse);
if( v ){
sqlite3VdbeAddOp2(v, OP_Vacuum, 0, 0);
+ sqlite3VdbeUsesBtree(v, 0);
}
return;
}
diff --git a/lib/libsqlite3/src/vdbe.c b/lib/libsqlite3/src/vdbe.c
index 1a3c412a789..a2ab31e879a 100644
--- a/lib/libsqlite3/src/vdbe.c
+++ b/lib/libsqlite3/src/vdbe.c
@@ -422,7 +422,9 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
** Print the value of a register for tracing purposes:
*/
static void memTracePrint(FILE *out, Mem *p){
- if( p->flags & MEM_Null ){
+ if( p->flags & MEM_Invalid ){
+ fprintf(out, " undefined");
+ }else if( p->flags & MEM_Null ){
fprintf(out, " NULL");
}else if( (p->flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){
fprintf(out, " si:%lld", p->u.i);
@@ -956,23 +958,28 @@ case OP_String: { /* out2-prerelease */
break;
}
-/* Opcode: Null * P2 P3 * *
+/* Opcode: Null P1 P2 P3 * *
**
** Write a NULL into registers P2. If P3 greater than P2, then also write
-** NULL into register P3 and ever register in between P2 and P3. If P3
+** NULL into register P3 and every register in between P2 and P3. If P3
** is less than P2 (typically P3 is zero) then only register P2 is
-** set to NULL
+** set to NULL.
+**
+** If the P1 value is non-zero, then also set the MEM_Cleared flag so that
+** NULL values will not compare equal even if SQLITE_NULLEQ is set on
+** OP_Ne or OP_Eq.
*/
case OP_Null: { /* out2-prerelease */
int cnt;
+ u16 nullFlag;
cnt = pOp->p3-pOp->p2;
assert( pOp->p3<=p->nMem );
- pOut->flags = MEM_Null;
+ pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null;
while( cnt>0 ){
pOut++;
memAboutToChange(p, pOut);
VdbeMemRelease(pOut);
- pOut->flags = MEM_Null;
+ pOut->flags = nullFlag;
cnt--;
}
break;
@@ -1015,10 +1022,10 @@ case OP_Variable: { /* out2-prerelease */
/* Opcode: Move P1 P2 P3 * *
**
-** Move the values in register P1..P1+P3-1 over into
-** registers P2..P2+P3-1. Registers P1..P1+P1-1 are
+** Move the values in register P1..P1+P3 over into
+** registers P2..P2+P3. Registers P1..P1+P3 are
** left holding a NULL. It is an error for register ranges
-** P1..P1+P3-1 and P2..P2+P3-1 to overlap.
+** P1..P1+P3 and P2..P2+P3 to overlap.
*/
case OP_Move: {
char *zMalloc; /* Holding variable for allocated memory */
@@ -1026,7 +1033,7 @@ case OP_Move: {
int p1; /* Register to copy from */
int p2; /* Register to copy to */
- n = pOp->p3;
+ n = pOp->p3 + 1;
p1 = pOp->p1;
p2 = pOp->p2;
assert( n>0 && p1>0 && p2>0 );
@@ -1055,20 +1062,31 @@ case OP_Move: {
break;
}
-/* Opcode: Copy P1 P2 * * *
+/* Opcode: Copy P1 P2 P3 * *
**
-** Make a copy of register P1 into register P2.
+** Make a copy of registers P1..P1+P3 into registers P2..P2+P3.
**
** This instruction makes a deep copy of the value. A duplicate
** is made of any string or blob constant. See also OP_SCopy.
*/
-case OP_Copy: { /* in1, out2 */
+case OP_Copy: {
+ int n;
+
+ n = pOp->p3;
pIn1 = &aMem[pOp->p1];
pOut = &aMem[pOp->p2];
assert( pOut!=pIn1 );
- sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem);
- Deephemeralize(pOut);
- REGISTER_TRACE(pOp->p2, pOut);
+ while( 1 ){
+ sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem);
+ Deephemeralize(pOut);
+#ifdef SQLITE_DEBUG
+ pOut->pScopyFrom = 0;
+#endif
+ REGISTER_TRACE(pOp->p2+pOp->p3-n, pOut);
+ if( (n--)==0 ) break;
+ pOut++;
+ pIn1++;
+ }
break;
}
@@ -1252,6 +1270,7 @@ case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */
case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */
case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */
case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
+ char bIntint; /* Started out as two integer operands */
int flags; /* Combined MEM_* flags from both inputs */
i64 iA; /* Integer value of left operand */
i64 iB; /* Integer value of right operand */
@@ -1268,6 +1287,7 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
if( (pIn1->flags & pIn2->flags & MEM_Int)==MEM_Int ){
iA = pIn1->u.i;
iB = pIn2->u.i;
+ bIntint = 1;
switch( pOp->opcode ){
case OP_Add: if( sqlite3AddInt64(&iB,iA) ) goto fp_math; break;
case OP_Subtract: if( sqlite3SubInt64(&iB,iA) ) goto fp_math; break;
@@ -1288,6 +1308,7 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
pOut->u.i = iB;
MemSetTypeFlag(pOut, MEM_Int);
}else{
+ bIntint = 0;
fp_math:
rA = sqlite3VdbeRealValue(pIn1);
rB = sqlite3VdbeRealValue(pIn2);
@@ -1319,7 +1340,7 @@ fp_math:
}
pOut->r = rB;
MemSetTypeFlag(pOut, MEM_Real);
- if( (flags & MEM_Real)==0 ){
+ if( (flags & MEM_Real)==0 && !bIntint ){
sqlite3VdbeIntegerAffinity(pOut);
}
#endif
@@ -1737,6 +1758,10 @@ case OP_ToReal: { /* same as TK_TO_REAL, in1 */
**
** If the SQLITE_STOREP2 bit of P5 is set, then do not jump. Instead,
** store a boolean result (either 0, or 1, or NULL) in register P2.
+**
+** If the SQLITE_NULLEQ bit is set in P5, then NULL values are considered
+** equal to one another, provided that they do not have their MEM_Cleared
+** bit set.
*/
/* Opcode: Ne P1 P2 P3 P4 P5
**
@@ -1803,7 +1828,15 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
** or not both operands are null.
*/
assert( pOp->opcode==OP_Eq || pOp->opcode==OP_Ne );
- res = (flags1 & flags3 & MEM_Null)==0;
+ assert( (flags1 & MEM_Cleared)==0 );
+ if( (flags1&MEM_Null)!=0
+ && (flags3&MEM_Null)!=0
+ && (flags3&MEM_Cleared)==0
+ ){
+ res = 0; /* Results are equal */
+ }else{
+ res = 1; /* Results are not equal */
+ }
}else{
/* SQLITE_NULLEQ is clear and at least one operand is NULL,
** then the result is always NULL.
@@ -1862,9 +1895,9 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
** Set the permutation used by the OP_Compare operator to be the array
** of integers in P4.
**
-** The permutation is only valid until the next OP_Permutation, OP_Compare,
-** OP_Halt, or OP_ResultRow. Typically the OP_Permutation should occur
-** immediately prior to the OP_Compare.
+** The permutation is only valid until the next OP_Compare that has
+** the OPFLAG_PERMUTE bit set in P5. Typically the OP_Permutation should
+** occur immediately prior to the OP_Compare.
*/
case OP_Permutation: {
assert( pOp->p4type==P4_INTARRAY );
@@ -1873,12 +1906,17 @@ case OP_Permutation: {
break;
}
-/* Opcode: Compare P1 P2 P3 P4 *
+/* Opcode: Compare P1 P2 P3 P4 P5
**
** Compare two vectors of registers in reg(P1)..reg(P1+P3-1) (call this
** vector "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of
** the comparison for use by the next OP_Jump instruct.
**
+** If P5 has the OPFLAG_PERMUTE bit set, then the order of comparison is
+** determined by the most recent OP_Permutation operator. If the
+** OPFLAG_PERMUTE bit is clear, then register are compared in sequential
+** order.
+**
** P4 is a KeyInfo structure that defines collating sequences and sort
** orders for the comparison. The permutation applies to registers
** only. The KeyInfo elements are used sequentially.
@@ -1897,6 +1935,7 @@ case OP_Compare: {
CollSeq *pColl; /* Collating sequence to use on this term */
int bRev; /* True for DESCENDING sort order */
+ if( (pOp->p5 & OPFLAG_PERMUTE)==0 ) aPermute = 0;
n = pOp->p3;
pKeyInfo = pOp->p4.pKeyInfo;
assert( n>0 );
@@ -2040,8 +2079,6 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
**
** Check if OP_Once flag P1 is set. If so, jump to instruction P2. Otherwise,
** set the flag and fall through to the next instruction.
-**
-** See also: JumpOnce
*/
case OP_Once: { /* jump */
assert( pOp->p1<p->nOnceFlag );
@@ -2212,6 +2249,11 @@ case OP_Column: {
}
}else if( ALWAYS(pC->pseudoTableReg>0) ){
pReg = &aMem[pC->pseudoTableReg];
+ if( pC->multiPseudo ){
+ sqlite3VdbeMemShallowCopy(pDest, pReg+p2, MEM_Ephem);
+ Deephemeralize(pDest);
+ goto op_column_out;
+ }
assert( pReg->flags & MEM_Blob );
assert( memIsValid(pReg) );
payloadSize = pReg->n;
@@ -3270,7 +3312,7 @@ case OP_OpenEphemeral: {
break;
}
-/* Opcode: OpenSorter P1 P2 * P4 *
+/* Opcode: SorterOpen P1 P2 * P4 *
**
** This opcode works like OP_OpenEphemeral except that it opens
** a transient index that is specifically designed to sort large
@@ -3278,6 +3320,7 @@ case OP_OpenEphemeral: {
*/
case OP_SorterOpen: {
VdbeCursor *pCx;
+
#ifndef SQLITE_OMIT_MERGE_SORT
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
if( pCx==0 ) goto no_mem;
@@ -3292,12 +3335,13 @@ case OP_SorterOpen: {
break;
}
-/* Opcode: OpenPseudo P1 P2 P3 * *
+/* Opcode: OpenPseudo P1 P2 P3 * P5
**
** Open a new cursor that points to a fake table that contains a single
** row of data. The content of that one row in the content of memory
-** register P2. In other words, cursor P1 becomes an alias for the
-** MEM_Blob content contained in register P2.
+** register P2 when P5==0. In other words, cursor P1 becomes an alias for the
+** MEM_Blob content contained in register P2. When P5==1, then the
+** row is represented by P3 consecutive registers beginning with P2.
**
** A pseudo-table created by this opcode is used to hold a single
** row output from the sorter so that the row can be decomposed into
@@ -3317,6 +3361,7 @@ case OP_OpenPseudo: {
pCx->pseudoTableReg = pOp->p2;
pCx->isTable = 1;
pCx->isIndex = 0;
+ pCx->multiPseudo = pOp->p5;
break;
}
@@ -4168,6 +4213,7 @@ case OP_SorterCompare: {
*/
case OP_SorterData: {
VdbeCursor *pC;
+
#ifndef SQLITE_OMIT_MERGE_SORT
pOut = &aMem[pOp->p2];
pC = p->apCsr[pOp->p1];
@@ -4280,7 +4326,7 @@ case OP_Rowid: { /* out2-prerelease */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
- assert( pC->pseudoTableReg==0 );
+ assert( pC->pseudoTableReg==0 || pC->nullRow );
if( pC->nullRow ){
pOut->flags = MEM_Null;
break;
@@ -4706,6 +4752,7 @@ case OP_Destroy: { /* out2-prerelease */
int iCnt;
Vdbe *pVdbe;
int iDb;
+
#ifndef SQLITE_OMIT_VIRTUALTABLE
iCnt = 0;
for(pVdbe=db->pVdbe; pVdbe; pVdbe = pVdbe->pNext){
@@ -5495,7 +5542,9 @@ case OP_JournalMode: { /* out2-prerelease */
Pager *pPager; /* Pager associated with pBt */
int eNew; /* New journal mode */
int eOld; /* The old journal mode */
+#ifndef SQLITE_OMIT_WAL
const char *zFilename; /* Name of database file for pPager */
+#endif
eNew = pOp->p3;
assert( eNew==PAGER_JOURNALMODE_DELETE
@@ -6075,7 +6124,10 @@ case OP_Trace: {
char *zTrace;
char *z;
- if( db->xTrace && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 ){
+ if( db->xTrace
+ && !p->doingRerun
+ && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
+ ){
z = sqlite3VdbeExpandSql(p, zTrace);
db->xTrace(db->pTraceArg, z);
sqlite3DbFree(db, z);
diff --git a/lib/libsqlite3/src/vdbe.h b/lib/libsqlite3/src/vdbe.h
index 90a43ce6ee7..fa7b31b7270 100644
--- a/lib/libsqlite3/src/vdbe.h
+++ b/lib/libsqlite3/src/vdbe.h
@@ -188,7 +188,7 @@ VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
int sqlite3VdbeMakeLabel(Vdbe*);
void sqlite3VdbeRunOnlyOnce(Vdbe*);
void sqlite3VdbeDelete(Vdbe*);
-void sqlite3VdbeDeleteObject(sqlite3*,Vdbe*);
+void sqlite3VdbeClearObject(sqlite3*,Vdbe*);
void sqlite3VdbeMakeReady(Vdbe*,Parse*);
int sqlite3VdbeFinalize(Vdbe*);
void sqlite3VdbeResolveLabel(Vdbe*, int);
diff --git a/lib/libsqlite3/src/vdbeInt.h b/lib/libsqlite3/src/vdbeInt.h
index 1f5694a595f..fac0b2f6ed3 100644
--- a/lib/libsqlite3/src/vdbeInt.h
+++ b/lib/libsqlite3/src/vdbeInt.h
@@ -63,6 +63,7 @@ struct VdbeCursor {
Bool isIndex; /* True if an index containing keys only - no data */
Bool isOrdered; /* True if the underlying table is BTREE_UNORDERED */
Bool isSorter; /* True if a new-style sorter */
+ Bool multiPseudo; /* Multi-register pseudo-cursor */
sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
const sqlite3_module *pModule; /* Module for cursor pVtabCursor */
i64 seqCount; /* Sequence counter */
@@ -187,7 +188,9 @@ struct Mem {
#define MEM_RowSet 0x0020 /* Value is a RowSet object */
#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */
#define MEM_Invalid 0x0080 /* Value is undefined */
-#define MEM_TypeMask 0x00ff /* Mask of type bits */
+#define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */
+#define MEM_TypeMask 0x01ff /* Mask of type bits */
+
/* Whenever Mem contains a valid string or blob representation, one of
** the following flags must be set to determine the memory management
@@ -273,6 +276,11 @@ struct Explain {
char zBase[100]; /* Initial space */
};
+/* 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 */
+
/*
** An instance of the virtual machine. This structure contains the complete
** state of the virtual machine.
@@ -314,15 +322,16 @@ struct Vdbe {
int pc; /* The program counter */
int rc; /* Value to return */
u8 errorAction; /* Recovery action to do in case of an error */
- u8 explain; /* True if EXPLAIN present on SQL command */
- u8 changeCntOn; /* True to update the change-counter */
- u8 expired; /* True if the VM needs to be recompiled */
- u8 runOnlyOnce; /* Automatically expire on reset */
u8 minWriteFileFormat; /* Minimum file format for writable database files */
- u8 inVtabMethod; /* See comments above */
- u8 usesStmtJournal; /* True if uses a statement journal */
- u8 readOnly; /* True for read-only statements */
- u8 isPrepareV2; /* True if prepared with prepare_v2() */
+ bft explain:2; /* True if EXPLAIN present on SQL command */
+ bft inVtabMethod:2; /* See comments above */
+ bft changeCntOn:1; /* True to update the change-counter */
+ bft expired:1; /* True if the VM needs to be recompiled */
+ bft runOnlyOnce:1; /* Automatically expire on reset */
+ bft usesStmtJournal:1; /* True if uses a statement journal */
+ bft readOnly:1; /* True for read-only statements */
+ bft isPrepareV2:1; /* True if prepared with prepare_v2() */
+ bft doingRerun:1; /* True if rerunning after an auto-reprepare */
int nChange; /* Number of db changes made since last reset */
yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */
yDbMask lockMask; /* Subset of btreeMask that requires a lock */
diff --git a/lib/libsqlite3/src/vdbeapi.c b/lib/libsqlite3/src/vdbeapi.c
index b9a88a6ab8f..b48826680a3 100644
--- a/lib/libsqlite3/src/vdbeapi.c
+++ b/lib/libsqlite3/src/vdbeapi.c
@@ -478,10 +478,12 @@ int sqlite3_step(sqlite3_stmt *pStmt){
}
db = v->db;
sqlite3_mutex_enter(db->mutex);
+ v->doingRerun = 0;
while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
&& cnt++ < SQLITE_MAX_SCHEMA_RETRY
&& (rc2 = rc = sqlite3Reprepare(v))==SQLITE_OK ){
sqlite3_reset(pStmt);
+ v->doingRerun = 1;
assert( v->expired==0 );
}
if( rc2!=SQLITE_OK && ALWAYS(v->isPrepareV2) && ALWAYS(db->pErr) ){
diff --git a/lib/libsqlite3/src/vdbeaux.c b/lib/libsqlite3/src/vdbeaux.c
index d4f9864b147..3bf8e471482 100644
--- a/lib/libsqlite3/src/vdbeaux.c
+++ b/lib/libsqlite3/src/vdbeaux.c
@@ -53,7 +53,7 @@ Vdbe *sqlite3VdbeCreate(sqlite3 *db){
void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){
assert( isPrepareV2==1 || isPrepareV2==0 );
if( p==0 ) return;
-#ifdef SQLITE_OMIT_TRACE
+#if defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_ENABLE_SQLLOG)
if( !isPrepareV2 ) return;
#endif
assert( p->zSql==0 );
@@ -723,6 +723,7 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
addr = p->nOp - 1;
}
pOp = &p->aOp[addr];
+ assert( pOp->p4type==P4_NOTUSED || pOp->p4type==P4_INT32 );
freeP4(db, pOp->p4type, pOp->p4.p);
pOp->p4.p = 0;
if( n==P4_INT32 ){
@@ -745,10 +746,9 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
u8 *aSortOrder;
memcpy((char*)pKeyInfo, zP4, nByte - nField);
aSortOrder = pKeyInfo->aSortOrder;
- if( aSortOrder ){
- pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField];
- memcpy(pKeyInfo->aSortOrder, aSortOrder, nField);
- }
+ assert( aSortOrder!=0 );
+ pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField];
+ memcpy(pKeyInfo->aSortOrder, aSortOrder, nField);
pOp->p4type = P4_KEYINFO;
}else{
p->db->mallocFailed = 1;
@@ -861,26 +861,23 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
case P4_KEYINFO: {
int i, j;
KeyInfo *pKeyInfo = pOp->p4.pKeyInfo;
+ assert( pKeyInfo->aSortOrder!=0 );
sqlite3_snprintf(nTemp, zTemp, "keyinfo(%d", pKeyInfo->nField);
i = sqlite3Strlen30(zTemp);
for(j=0; j<pKeyInfo->nField; j++){
CollSeq *pColl = pKeyInfo->aColl[j];
- if( pColl ){
- int n = sqlite3Strlen30(pColl->zName);
- if( i+n>nTemp-6 ){
- memcpy(&zTemp[i],",...",4);
- break;
- }
- zTemp[i++] = ',';
- if( pKeyInfo->aSortOrder && pKeyInfo->aSortOrder[j] ){
- zTemp[i++] = '-';
- }
- memcpy(&zTemp[i], pColl->zName,n+1);
- i += n;
- }else if( i+4<nTemp-6 ){
- memcpy(&zTemp[i],",nil",4);
- i += 4;
+ const char *zColl = pColl ? pColl->zName : "nil";
+ int n = sqlite3Strlen30(zColl);
+ if( i+n>nTemp-6 ){
+ memcpy(&zTemp[i],",...",4);
+ break;
}
+ zTemp[i++] = ',';
+ if( pKeyInfo->aSortOrder[j] ){
+ zTemp[i++] = '-';
+ }
+ memcpy(&zTemp[i], zColl, n+1);
+ i += n;
}
zTemp[i++] = ')';
zTemp[i] = 0;
@@ -1770,7 +1767,9 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
if( sqlite3BtreeIsInTrans(pBt) ){
needXcommit = 1;
if( i!=1 ) nTrans++;
+ sqlite3BtreeEnter(pBt);
rc = sqlite3PagerExclusiveLock(sqlite3BtreePager(pBt));
+ sqlite3BtreeLeave(pBt);
}
}
if( rc!=SQLITE_OK ){
@@ -2324,6 +2323,27 @@ int sqlite3VdbeTransferError(Vdbe *p){
return rc;
}
+#ifdef SQLITE_ENABLE_SQLLOG
+/*
+** If an SQLITE_CONFIG_SQLLOG hook is registered and the VM has been run,
+** invoke it.
+*/
+static void vdbeInvokeSqllog(Vdbe *v){
+ if( sqlite3GlobalConfig.xSqllog && v->rc==SQLITE_OK && v->zSql && v->pc>=0 ){
+ char *zExpanded = sqlite3VdbeExpandSql(v, v->zSql);
+ assert( v->db->init.busy==0 );
+ if( zExpanded ){
+ sqlite3GlobalConfig.xSqllog(
+ sqlite3GlobalConfig.pSqllogArg, v->db, zExpanded, 1
+ );
+ sqlite3DbFree(v->db, zExpanded);
+ }
+ }
+}
+#else
+# define vdbeInvokeSqllog(x)
+#endif
+
/*
** Clean up a VDBE after execution but do not delete the VDBE just yet.
** Write any error messages into *pzErrMsg. Return the result code.
@@ -2351,6 +2371,7 @@ int sqlite3VdbeReset(Vdbe *p){
** instructions yet, leave the main database error information unchanged.
*/
if( p->pc>=0 ){
+ vdbeInvokeSqllog(p);
sqlite3VdbeTransferError(p);
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
@@ -2432,12 +2453,14 @@ void sqlite3VdbeDeleteAuxData(VdbeFunc *pVdbeFunc, int mask){
}
/*
-** Free all memory associated with the Vdbe passed as the second argument.
+** Free all memory associated with the Vdbe passed as the second argument,
+** except for object itself, which is preserved.
+**
** The difference between this function and sqlite3VdbeDelete() is that
** VdbeDelete() also unlinks the Vdbe from the list of VMs associated with
-** the database connection.
+** the database connection and frees the object itself.
*/
-void sqlite3VdbeDeleteObject(sqlite3 *db, Vdbe *p){
+void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
SubProgram *pSub, *pNext;
int i;
assert( p->db==0 || p->db==db );
@@ -2455,10 +2478,9 @@ void sqlite3VdbeDeleteObject(sqlite3 *db, Vdbe *p){
sqlite3DbFree(db, p->zSql);
sqlite3DbFree(db, p->pFree);
#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
- sqlite3DbFree(db, p->zExplain);
+ sqlite3_free(p->zExplain);
sqlite3DbFree(db, p->pExplain);
#endif
- sqlite3DbFree(db, p);
}
/*
@@ -2470,6 +2492,7 @@ void sqlite3VdbeDelete(Vdbe *p){
if( NEVER(p==0) ) return;
db = p->db;
assert( sqlite3_mutex_held(db->mutex) );
+ sqlite3VdbeClearObject(db, p);
if( p->pPrev ){
p->pPrev->pNext = p->pNext;
}else{
@@ -2481,7 +2504,7 @@ void sqlite3VdbeDelete(Vdbe *p){
}
p->magic = VDBE_MAGIC_DEAD;
p->db = 0;
- sqlite3VdbeDeleteObject(db, p);
+ sqlite3DbFree(db, p);
}
/*
@@ -2583,9 +2606,6 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
# define MAX_6BYTE ((((i64)0x00008000)<<32)-1)
i64 i = pMem->u.i;
u64 u;
- if( file_format>=4 && (i&1)==i ){
- return 8+(u32)i;
- }
if( i<0 ){
if( i<(-MAX_6BYTE) ) return 6;
/* Previous test prevents: u = -(-9223372036854775808) */
@@ -2593,7 +2613,9 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
}else{
u = i;
}
- if( u<=127 ) return 1;
+ if( u<=127 ){
+ return ((i&1)==i && file_format>=4) ? 8+(u32)u : 1;
+ }
if( u<=32767 ) return 2;
if( u<=8388607 ) return 3;
if( u<=2147483647 ) return 4;
@@ -2878,6 +2900,7 @@ UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(
}
p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))];
+ assert( pKeyInfo->aSortOrder!=0 );
p->pKeyInfo = pKeyInfo;
p->nField = pKeyInfo->nField + 1;
return p;
@@ -2971,6 +2994,7 @@ int sqlite3VdbeRecordCompare(
idx1 = getVarint32(aKey1, szHdr1);
d1 = szHdr1;
nField = pKeyInfo->nField;
+ assert( pKeyInfo->aSortOrder!=0 );
while( idx1<szHdr1 && i<pPKey2->nField ){
u32 serial_type1;
@@ -2990,7 +3014,7 @@ int sqlite3VdbeRecordCompare(
assert( mem1.zMalloc==0 ); /* See comment below */
/* Invert the result if we are using DESC sort order. */
- if( pKeyInfo->aSortOrder && i<nField && pKeyInfo->aSortOrder[i] ){
+ if( i<nField && pKeyInfo->aSortOrder[i] ){
rc = -rc;
}
diff --git a/lib/libsqlite3/src/vdbesort.c b/lib/libsqlite3/src/vdbesort.c
index ba1e9f0f233..d51bbf54a3e 100644
--- a/lib/libsqlite3/src/vdbesort.c
+++ b/lib/libsqlite3/src/vdbesort.c
@@ -195,8 +195,11 @@ static int vdbeSorterIterRead(
int rc; /* sqlite3OsRead() return code */
/* Determine how many bytes of data to read. */
- nRead = (int)(p->iEof - p->iReadOff);
- if( nRead>p->nBuffer ) nRead = p->nBuffer;
+ if( (p->iEof - p->iReadOff) > (i64)p->nBuffer ){
+ nRead = p->nBuffer;
+ }else{
+ nRead = (int)(p->iEof - p->iReadOff);
+ }
assert( nRead>0 );
/* Read data from the file. Return early if an error occurs. */
diff --git a/lib/libsqlite3/src/vtab.c b/lib/libsqlite3/src/vtab.c
index 50d576fc389..958202c31e2 100644
--- a/lib/libsqlite3/src/vtab.c
+++ b/lib/libsqlite3/src/vtab.c
@@ -264,7 +264,7 @@ void sqlite3VtabClear(sqlite3 *db, Table *p){
if( p->azModuleArg ){
int i;
for(i=0; i<p->nModuleArg; i++){
- sqlite3DbFree(db, p->azModuleArg[i]);
+ if( i!=1 ) sqlite3DbFree(db, p->azModuleArg[i]);
}
sqlite3DbFree(db, p->azModuleArg);
}
@@ -324,7 +324,7 @@ void sqlite3VtabBeginParse(
pTable->tabFlags |= TF_Virtual;
pTable->nModuleArg = 0;
addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName));
- addModuleArgument(db, pTable, sqlite3DbStrDup(db, db->aDb[iDb].zName));
+ addModuleArgument(db, pTable, 0);
addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName));
pParse->sNameToken.n = (int)(&pModuleName->z[pModuleName->n] - pName1->z);
@@ -481,6 +481,7 @@ static int vtabCallConstructor(
int nArg = pTab->nModuleArg;
char *zErr = 0;
char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
+ int iDb;
if( !zModuleName ){
return SQLITE_NOMEM;
@@ -494,6 +495,9 @@ static int vtabCallConstructor(
pVTable->db = db;
pVTable->pMod = pMod;
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ pTab->azModuleArg[1] = db->aDb[iDb].zName;
+
/* Invoke the virtual table constructor */
assert( &db->pVtabCtx );
assert( xConstruct );
@@ -528,7 +532,7 @@ static int vtabCallConstructor(
/* If everything went according to plan, link the new VTable structure
** into the linked list headed by pTab->pVTable. Then loop through the
** columns of the table to see if any of them contain the token "hidden".
- ** If so, set the Column.isHidden flag and remove the token from
+ ** If so, set the Column COLFLAG_HIDDEN flag and remove the token from
** the type string. */
pVTable->pNext = pTab->pVTable;
pTab->pVTable = pVTable;
@@ -559,7 +563,7 @@ static int vtabCallConstructor(
assert(zType[i-1]==' ');
zType[i-1] = '\0';
}
- pTab->aCol[iCol].isHidden = 1;
+ pTab->aCol[iCol].colFlags |= COLFLAG_HIDDEN;
}
}
}
diff --git a/lib/libsqlite3/src/wal.c b/lib/libsqlite3/src/wal.c
index cc166ba4303..0d7271bf04f 100644
--- a/lib/libsqlite3/src/wal.c
+++ b/lib/libsqlite3/src/wal.c
@@ -2518,7 +2518,7 @@ int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){
assert( walFramePgno(pWal, iFrame)!=1 );
rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
}
- walCleanupHash(pWal);
+ if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
}
assert( rc==SQLITE_OK );
return rc;
@@ -2828,7 +2828,7 @@ int sqlite3WalFrames(
*/
if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){
if( pWal->padToSectorBoundary ){
- int sectorSize = sqlite3OsSectorSize(pWal->pWalFd);
+ int sectorSize = sqlite3SectorSize(pWal->pWalFd);
w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize;
while( iOffset<w.iSyncPoint ){
rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset);
diff --git a/lib/libsqlite3/src/where.c b/lib/libsqlite3/src/where.c
index 216a47fbe3f..fb3bc5c93cf 100644
--- a/lib/libsqlite3/src/where.c
+++ b/lib/libsqlite3/src/where.c
@@ -23,9 +23,10 @@
** Trace output macros
*/
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
-int sqlite3WhereTrace = 0;
+/***/ int sqlite3WhereTrace = 0;
#endif
-#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+#if defined(SQLITE_DEBUG) \
+ && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE))
# define WHERETRACE(X) if(sqlite3WhereTrace) sqlite3DebugPrintf X
#else
# define WHERETRACE(X)
@@ -256,14 +257,49 @@ struct WhereCost {
#define WHERE_TOP_LIMIT 0x00100000 /* x<EXPR or x<=EXPR constraint */
#define WHERE_BTM_LIMIT 0x00200000 /* x>EXPR or x>=EXPR constraint */
#define WHERE_BOTH_LIMIT 0x00300000 /* Both x>EXPR and x<EXPR */
-#define WHERE_IDX_ONLY 0x00800000 /* Use index only - omit table */
-#define WHERE_ORDERBY 0x01000000 /* Output will appear in correct order */
-#define WHERE_REVERSE 0x02000000 /* Scan in reverse order */
-#define WHERE_UNIQUE 0x04000000 /* Selects no more than one row */
+#define WHERE_IDX_ONLY 0x00400000 /* Use index only - omit table */
+#define WHERE_ORDERED 0x00800000 /* Output will appear in correct order */
+#define WHERE_REVERSE 0x01000000 /* Scan in reverse order */
+#define WHERE_UNIQUE 0x02000000 /* Selects no more than one row */
+#define WHERE_ALL_UNIQUE 0x04000000 /* This and all prior have one row */
#define WHERE_VIRTUALTABLE 0x08000000 /* Use virtual-table processing */
#define WHERE_MULTI_OR 0x10000000 /* OR using multiple indices */
#define WHERE_TEMP_INDEX 0x20000000 /* Uses an ephemeral index */
#define WHERE_DISTINCT 0x40000000 /* Correct order for DISTINCT */
+#define WHERE_COVER_SCAN 0x80000000 /* Full scan of a covering index */
+
+/*
+** This module contains many separate subroutines that work together to
+** find the best indices to use for accessing a particular table in a query.
+** An instance of the following structure holds context information about the
+** index search so that it can be more easily passed between the various
+** routines.
+*/
+typedef struct WhereBestIdx WhereBestIdx;
+struct WhereBestIdx {
+ Parse *pParse; /* Parser context */
+ WhereClause *pWC; /* The WHERE clause */
+ struct SrcList_item *pSrc; /* The FROM clause term to search */
+ Bitmask notReady; /* Mask of cursors not available */
+ Bitmask notValid; /* Cursors not available for any purpose */
+ ExprList *pOrderBy; /* The ORDER BY clause */
+ ExprList *pDistinct; /* The select-list if query is DISTINCT */
+ sqlite3_index_info **ppIdxInfo; /* Index information passed to xBestIndex */
+ int i, n; /* Which loop is being coded; # of loops */
+ WhereLevel *aLevel; /* Info about outer loops */
+ WhereCost cost; /* Lowest cost query plan */
+};
+
+/*
+** Return TRUE if the probe cost is less than the baseline cost
+*/
+static int compareCost(const WhereCost *pProbe, const WhereCost *pBaseline){
+ if( pProbe->rCost<pBaseline->rCost ) return 1;
+ if( pProbe->rCost>pBaseline->rCost ) return 0;
+ if( pProbe->plan.nOBSat>pBaseline->plan.nOBSat ) return 1;
+ if( pProbe->plan.nRow<pBaseline->plan.nRow ) return 1;
+ return 0;
+}
/*
** Initialize a preallocated WhereClause structure.
@@ -367,7 +403,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){
pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]);
}
pTerm = &pWC->a[idx = pWC->nTerm++];
- pTerm->pExpr = p;
+ pTerm->pExpr = sqlite3ExprSkipCollate(p);
pTerm->wtFlags = wtFlags;
pTerm->pWC = pWC;
pTerm->iParent = -1;
@@ -527,23 +563,32 @@ static int allowedOp(int op){
** Commute a comparison operator. Expressions of the form "X op Y"
** are converted into "Y op X".
**
-** If a collation sequence is associated with either the left or right
+** If left/right precendence rules come into play when determining the
+** collating
** side of the comparison, it remains associated with the same side after
** the commutation. So "Y collate NOCASE op X" becomes
-** "X collate NOCASE op Y". This is because any collation sequence on
+** "X op Y". This is because any collation sequence on
** the left hand side of a comparison overrides any collation sequence
-** attached to the right. For the same reason the EP_ExpCollate flag
+** attached to the right. For the same reason the EP_Collate flag
** is not commuted.
*/
static void exprCommute(Parse *pParse, Expr *pExpr){
- u16 expRight = (pExpr->pRight->flags & EP_ExpCollate);
- u16 expLeft = (pExpr->pLeft->flags & EP_ExpCollate);
+ u16 expRight = (pExpr->pRight->flags & EP_Collate);
+ u16 expLeft = (pExpr->pLeft->flags & EP_Collate);
assert( allowedOp(pExpr->op) && pExpr->op!=TK_IN );
- pExpr->pRight->pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight);
- pExpr->pLeft->pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
- SWAP(CollSeq*,pExpr->pRight->pColl,pExpr->pLeft->pColl);
- pExpr->pRight->flags = (pExpr->pRight->flags & ~EP_ExpCollate) | expLeft;
- pExpr->pLeft->flags = (pExpr->pLeft->flags & ~EP_ExpCollate) | expRight;
+ if( expRight==expLeft ){
+ /* Either X and Y both have COLLATE operator or neither do */
+ if( expRight ){
+ /* Both X and Y have COLLATE operators. Make sure X is always
+ ** used by clearing the EP_Collate flag from Y. */
+ pExpr->pRight->flags &= ~EP_Collate;
+ }else if( sqlite3ExprCollSeq(pParse, pExpr->pLeft)!=0 ){
+ /* Neither X nor Y have COLLATE operators, but X has a non-default
+ ** collating sequence. So add the EP_Collate marker on X to cause
+ ** it to be searched first. */
+ pExpr->pLeft->flags |= EP_Collate;
+ }
+ }
SWAP(Expr*,pExpr->pRight,pExpr->pLeft);
if( pExpr->op>=TK_GT ){
assert( TK_LT==TK_GT+2 );
@@ -620,12 +665,12 @@ static WhereTerm *findTerm(
*/
assert(pX->pLeft);
pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
- assert(pColl || pParse->nErr);
+ if( pColl==0 ) pColl = pParse->db->pDfltColl;
for(j=0; pIdx->aiColumn[j]!=iColumn; j++){
if( NEVER(j>=pIdx->nColumn) ) return 0;
}
- if( pColl && sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue;
+ if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue;
}
return pTerm;
}
@@ -1144,6 +1189,7 @@ static void exprAnalyze(
pTerm = &pWC->a[idxTerm];
pMaskSet = pWC->pMaskSet;
pExpr = pTerm->pExpr;
+ assert( pExpr->op!=TK_AS && pExpr->op!=TK_COLLATE );
prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
op = pExpr->op;
if( op==TK_IN ){
@@ -1170,8 +1216,8 @@ static void exprAnalyze(
pTerm->iParent = -1;
pTerm->eOperator = 0;
if( allowedOp(op) && (pTerm->prereqRight & prereqLeft)==0 ){
- Expr *pLeft = pExpr->pLeft;
- Expr *pRight = pExpr->pRight;
+ Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
+ Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
if( pLeft->op==TK_COLUMN ){
pTerm->leftCursor = pLeft->iTable;
pTerm->u.leftColumn = pLeft->iColumn;
@@ -1199,7 +1245,7 @@ static void exprAnalyze(
pNew = pTerm;
}
exprCommute(pParse, pDup);
- pLeft = pDup->pLeft;
+ pLeft = sqlite3ExprSkipCollate(pDup->pLeft);
pNew->leftCursor = pLeft->iTable;
pNew->u.leftColumn = pLeft->iColumn;
testcase( (prereqLeft | extraRight) != prereqLeft );
@@ -1278,7 +1324,7 @@ static void exprAnalyze(
Expr *pNewExpr2;
int idxNew1;
int idxNew2;
- CollSeq *pColl; /* Collating sequence to use */
+ Token sCollSeqName; /* Name of collating sequence */
pLeft = pExpr->x.pList->a[1].pExpr;
pStr2 = sqlite3ExprDup(db, pStr1, 0);
@@ -1300,16 +1346,19 @@ static void exprAnalyze(
}
*pC = c + 1;
}
- pColl = sqlite3FindCollSeq(db, SQLITE_UTF8, noCase ? "NOCASE" : "BINARY",0);
+ sCollSeqName.z = noCase ? "NOCASE" : "BINARY";
+ sCollSeqName.n = 6;
+ pNewExpr1 = sqlite3ExprDup(db, pLeft, 0);
pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
- sqlite3ExprSetColl(sqlite3ExprDup(db,pLeft,0), pColl),
- pStr1, 0);
+ sqlite3ExprAddCollateToken(pParse,pNewExpr1,&sCollSeqName),
+ pStr1, 0);
idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew1==0 );
exprAnalyze(pSrc, pWC, idxNew1);
+ pNewExpr2 = sqlite3ExprDup(db, pLeft, 0);
pNewExpr2 = sqlite3PExpr(pParse, TK_LT,
- sqlite3ExprSetColl(sqlite3ExprDup(db,pLeft,0), pColl),
- pStr2, 0);
+ sqlite3ExprAddCollateToken(pParse,pNewExpr2,&sCollSeqName),
+ pStr2, 0);
idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew2==0 );
exprAnalyze(pSrc, pWC, idxNew2);
@@ -1407,25 +1456,6 @@ static void exprAnalyze(
}
/*
-** Return TRUE if any of the expressions in pList->a[iFirst...] contain
-** a reference to any table other than the iBase table.
-*/
-static int referencesOtherTables(
- ExprList *pList, /* Search expressions in ths list */
- WhereMaskSet *pMaskSet, /* Mapping from tables to bitmaps */
- int iFirst, /* Be searching with the iFirst-th expression */
- int iBase /* Ignore references to this table */
-){
- Bitmask allowed = ~getMask(pMaskSet, iBase);
- while( iFirst<pList->nExpr ){
- if( (exprTableUsage(pMaskSet, pList->a[iFirst++].pExpr)&allowed)!=0 ){
- return 1;
- }
- }
- return 0;
-}
-
-/*
** This function searches the expression list passed as the second argument
** for an expression of type TK_COLUMN that refers to the same column and
** uses the same collation sequence as the iCol'th column of index pIdx.
@@ -1446,12 +1476,12 @@ static int findIndexCol(
const char *zColl = pIdx->azColl[iCol];
for(i=0; i<pList->nExpr; i++){
- Expr *p = pList->a[i].pExpr;
+ Expr *p = sqlite3ExprSkipCollate(pList->a[i].pExpr);
if( p->op==TK_COLUMN
&& p->iColumn==pIdx->aiColumn[iCol]
&& p->iTable==iBase
){
- CollSeq *pColl = sqlite3ExprCollSeq(pParse, p);
+ CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr);
if( ALWAYS(pColl) && 0==sqlite3StrICmp(pColl->zName, zColl) ){
return i;
}
@@ -1484,7 +1514,8 @@ static int isDistinctIndex(
Bitmask mask = 0; /* Mask of unaccounted for pDistinct exprs */
int i; /* Iterator variable */
- if( pIdx->zName==0 || pDistinct==0 || pDistinct->nExpr>=BMS ) return 0;
+ assert( pDistinct!=0 );
+ if( pIdx->zName==0 || pDistinct->nExpr>=BMS ) return 0;
testcase( pDistinct->nExpr==BMS-1 );
/* Loop through all the expressions in the distinct list. If any of them
@@ -1497,7 +1528,7 @@ static int isDistinctIndex(
*/
for(i=0; i<pDistinct->nExpr; i++){
WhereTerm *pTerm;
- Expr *p = pDistinct->a[i].pExpr;
+ Expr *p = sqlite3ExprSkipCollate(pDistinct->a[i].pExpr);
if( p->op!=TK_COLUMN ) return 0;
pTerm = findTerm(pWC, p->iTable, p->iColumn, ~(Bitmask)0, WO_EQ, 0);
if( pTerm ){
@@ -1549,7 +1580,7 @@ static int isDistinctRedundant(
** current SELECT is a correlated sub-query.
*/
for(i=0; i<pDistinct->nExpr; i++){
- Expr *p = pDistinct->a[i].pExpr;
+ Expr *p = sqlite3ExprSkipCollate(pDistinct->a[i].pExpr);
if( p->op==TK_COLUMN && p->iTable==iBase && p->iColumn<0 ) return 1;
}
@@ -1587,165 +1618,6 @@ static int isDistinctRedundant(
}
/*
-** This routine decides if pIdx can be used to satisfy the ORDER BY
-** clause. If it can, it returns 1. If pIdx cannot satisfy the
-** ORDER BY clause, this routine returns 0.
-**
-** pOrderBy is an ORDER BY clause from a SELECT statement. pTab is the
-** left-most table in the FROM clause of that same SELECT statement and
-** the table has a cursor number of "base". pIdx is an index on pTab.
-**
-** nEqCol is the number of columns of pIdx that are used as equality
-** constraints. Any of these columns may be missing from the ORDER BY
-** clause and the match can still be a success.
-**
-** All terms of the ORDER BY that match against the index must be either
-** ASC or DESC. (Terms of the ORDER BY clause past the end of a UNIQUE
-** index do not need to satisfy this constraint.) The *pbRev value is
-** set to 1 if the ORDER BY clause is all DESC and it is set to 0 if
-** the ORDER BY clause is all ASC.
-*/
-static int isSortingIndex(
- Parse *pParse, /* Parsing context */
- WhereMaskSet *pMaskSet, /* Mapping from table cursor numbers to bitmaps */
- Index *pIdx, /* The index we are testing */
- int base, /* Cursor number for the table to be sorted */
- ExprList *pOrderBy, /* The ORDER BY clause */
- int nEqCol, /* Number of index columns with == constraints */
- int wsFlags, /* Index usages flags */
- int *pbRev /* Set to 1 if ORDER BY is DESC */
-){
- int i, j; /* Loop counters */
- int sortOrder = 0; /* XOR of index and ORDER BY sort direction */
- int nTerm; /* Number of ORDER BY terms */
- struct ExprList_item *pTerm; /* A term of the ORDER BY clause */
- sqlite3 *db = pParse->db;
-
- if( !pOrderBy ) return 0;
- if( wsFlags & WHERE_COLUMN_IN ) return 0;
- if( pIdx->bUnordered ) return 0;
-
- nTerm = pOrderBy->nExpr;
- assert( nTerm>0 );
-
- /* Argument pIdx must either point to a 'real' named index structure,
- ** or an index structure allocated on the stack by bestBtreeIndex() to
- ** represent the rowid index that is part of every table. */
- assert( pIdx->zName || (pIdx->nColumn==1 && pIdx->aiColumn[0]==-1) );
-
- /* Match terms of the ORDER BY clause against columns of
- ** the index.
- **
- ** Note that indices have pIdx->nColumn regular columns plus
- ** one additional column containing the rowid. The rowid column
- ** of the index is also allowed to match against the ORDER BY
- ** clause.
- */
- for(i=j=0, pTerm=pOrderBy->a; j<nTerm && i<=pIdx->nColumn; i++){
- Expr *pExpr; /* The expression of the ORDER BY pTerm */
- CollSeq *pColl; /* The collating sequence of pExpr */
- int termSortOrder; /* Sort order for this term */
- int iColumn; /* The i-th column of the index. -1 for rowid */
- int iSortOrder; /* 1 for DESC, 0 for ASC on the i-th index term */
- const char *zColl; /* Name of the collating sequence for i-th index term */
-
- pExpr = pTerm->pExpr;
- if( pExpr->op!=TK_COLUMN || pExpr->iTable!=base ){
- /* Can not use an index sort on anything that is not a column in the
- ** left-most table of the FROM clause */
- break;
- }
- pColl = sqlite3ExprCollSeq(pParse, pExpr);
- if( !pColl ){
- pColl = db->pDfltColl;
- }
- if( pIdx->zName && i<pIdx->nColumn ){
- iColumn = pIdx->aiColumn[i];
- if( iColumn==pIdx->pTable->iPKey ){
- iColumn = -1;
- }
- iSortOrder = pIdx->aSortOrder[i];
- zColl = pIdx->azColl[i];
- }else{
- iColumn = -1;
- iSortOrder = 0;
- zColl = pColl->zName;
- }
- if( pExpr->iColumn!=iColumn || sqlite3StrICmp(pColl->zName, zColl) ){
- /* Term j of the ORDER BY clause does not match column i of the index */
- if( i<nEqCol ){
- /* If an index column that is constrained by == fails to match an
- ** ORDER BY term, that is OK. Just ignore that column of the index
- */
- continue;
- }else if( i==pIdx->nColumn ){
- /* Index column i is the rowid. All other terms match. */
- break;
- }else{
- /* If an index column fails to match and is not constrained by ==
- ** then the index cannot satisfy the ORDER BY constraint.
- */
- return 0;
- }
- }
- assert( pIdx->aSortOrder!=0 || iColumn==-1 );
- assert( pTerm->sortOrder==0 || pTerm->sortOrder==1 );
- assert( iSortOrder==0 || iSortOrder==1 );
- termSortOrder = iSortOrder ^ pTerm->sortOrder;
- if( i>nEqCol ){
- if( termSortOrder!=sortOrder ){
- /* Indices can only be used if all ORDER BY terms past the
- ** equality constraints are all either DESC or ASC. */
- return 0;
- }
- }else{
- sortOrder = termSortOrder;
- }
- j++;
- pTerm++;
- if( iColumn<0 && !referencesOtherTables(pOrderBy, pMaskSet, j, base) ){
- /* If the indexed column is the primary key and everything matches
- ** so far and none of the ORDER BY terms to the right reference other
- ** tables in the join, then we are assured that the index can be used
- ** to sort because the primary key is unique and so none of the other
- ** columns will make any difference
- */
- j = nTerm;
- }
- }
-
- *pbRev = sortOrder!=0;
- if( j>=nTerm ){
- /* All terms of the ORDER BY clause are covered by this index so
- ** this index can be used for sorting. */
- return 1;
- }
- if( pIdx->onError!=OE_None && i==pIdx->nColumn
- && (wsFlags & WHERE_COLUMN_NULL)==0
- && !referencesOtherTables(pOrderBy, pMaskSet, j, base)
- ){
- Column *aCol = pIdx->pTable->aCol;
-
- /* All terms of this index match some prefix of the ORDER BY clause,
- ** the index is UNIQUE, and no terms on the tail of the ORDER BY
- ** refer to other tables in a join. So, assuming that the index entries
- ** visited contain no NULL values, then this index delivers rows in
- ** the required order.
- **
- ** It is not possible for any of the first nEqCol index fields to be
- ** NULL (since the corresponding "=" operator in the WHERE clause would
- ** not be true). So if all remaining index columns have NOT NULL
- ** constaints attached to them, we can be confident that the visited
- ** index entries are free of NULLs. */
- for(i=nEqCol; i<pIdx->nColumn; i++){
- if( aCol[pIdx->aiColumn[i]].notNull==0 ) break;
- }
- return (i==pIdx->nColumn);
- }
- return 0;
-}
-
-/*
** Prepare a crude estimate of the logarithm of the input value.
** The results need not be exact. This is only used for estimating
** the total cost of performing operations with O(logN) or O(NlogN)
@@ -1809,9 +1681,7 @@ static void TRACE_IDX_OUTPUTS(sqlite3_index_info *p){
/*
** Required because bestIndex() is called by bestOrClauseIndex()
*/
-static void bestIndex(
- Parse*, WhereClause*, struct SrcList_item*,
- Bitmask, Bitmask, ExprList*, WhereCost*);
+static void bestIndex(WhereBestIdx*);
/*
** This routine attempts to find an scanning strategy that can be used
@@ -1820,20 +1690,14 @@ static void bestIndex(
** The table associated with FROM clause term pSrc may be either a
** regular B-Tree table or a virtual table.
*/
-static void bestOrClauseIndex(
- Parse *pParse, /* The parsing context */
- WhereClause *pWC, /* The WHERE clause */
- struct SrcList_item *pSrc, /* The FROM clause term to search */
- Bitmask notReady, /* Mask of cursors not available for indexing */
- Bitmask notValid, /* Cursors not available for any purpose */
- ExprList *pOrderBy, /* The ORDER BY clause */
- WhereCost *pCost /* Lowest cost query plan */
-){
+static void bestOrClauseIndex(WhereBestIdx *p){
#ifndef SQLITE_OMIT_OR_OPTIMIZATION
- const int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */
+ WhereClause *pWC = p->pWC; /* The WHERE clause */
+ struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */
+ const int iCur = pSrc->iCursor; /* The cursor of the table */
const Bitmask maskSrc = getMask(pWC->pMaskSet, iCur); /* Bitmask for pSrc */
WhereTerm * const pWCEnd = &pWC->a[pWC->nTerm]; /* End of pWC->a[] */
- WhereTerm *pTerm; /* A single term of the WHERE clause */
+ WhereTerm *pTerm; /* A single term of the WHERE clause */
/* The OR-clause optimization is disallowed if the INDEXED BY or
** NOT INDEXED clauses are used or if the WHERE_AND_ONLY bit is set. */
@@ -1847,7 +1711,7 @@ static void bestOrClauseIndex(
/* Search the WHERE clause terms for a usable WO_OR term. */
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
if( pTerm->eOperator==WO_OR
- && ((pTerm->prereqAll & ~maskSrc) & notReady)==0
+ && ((pTerm->prereqAll & ~maskSrc) & p->notReady)==0
&& (pTerm->u.pOrInfo->indexable & maskSrc)!=0
){
WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc;
@@ -1857,15 +1721,19 @@ static void bestOrClauseIndex(
double rTotal = 0;
double nRow = 0;
Bitmask used = 0;
+ WhereBestIdx sBOI;
+ sBOI = *p;
+ sBOI.pOrderBy = 0;
+ sBOI.pDistinct = 0;
+ sBOI.ppIdxInfo = 0;
for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
- WhereCost sTermCost;
WHERETRACE(("... Multi-index OR testing for term %d of %d....\n",
(pOrTerm - pOrWC->a), (pTerm - pWC->a)
));
if( pOrTerm->eOperator==WO_AND ){
- WhereClause *pAndWC = &pOrTerm->u.pAndInfo->wc;
- bestIndex(pParse, pAndWC, pSrc, notReady, notValid, 0, &sTermCost);
+ sBOI.pWC = &pOrTerm->u.pAndInfo->wc;
+ bestIndex(&sBOI);
}else if( pOrTerm->leftCursor==iCur ){
WhereClause tempWC;
tempWC.pParse = pWC->pParse;
@@ -1875,19 +1743,20 @@ static void bestOrClauseIndex(
tempWC.a = pOrTerm;
tempWC.wctrlFlags = 0;
tempWC.nTerm = 1;
- bestIndex(pParse, &tempWC, pSrc, notReady, notValid, 0, &sTermCost);
+ sBOI.pWC = &tempWC;
+ bestIndex(&sBOI);
}else{
continue;
}
- rTotal += sTermCost.rCost;
- nRow += sTermCost.plan.nRow;
- used |= sTermCost.used;
- if( rTotal>=pCost->rCost ) break;
+ rTotal += sBOI.cost.rCost;
+ nRow += sBOI.cost.plan.nRow;
+ used |= sBOI.cost.used;
+ if( rTotal>=p->cost.rCost ) break;
}
/* If there is an ORDER BY clause, increase the scan cost to account
** for the cost of the sort. */
- if( pOrderBy!=0 ){
+ if( p->pOrderBy!=0 ){
WHERETRACE(("... sorting increases OR cost %.9g to %.9g\n",
rTotal, rTotal+nRow*estLog(nRow)));
rTotal += nRow*estLog(nRow);
@@ -1897,12 +1766,13 @@ static void bestOrClauseIndex(
** less than the current cost stored in pCost, replace the contents
** of pCost. */
WHERETRACE(("... multi-index OR cost=%.9g nrow=%.9g\n", rTotal, nRow));
- if( rTotal<pCost->rCost ){
- pCost->rCost = rTotal;
- pCost->used = used;
- pCost->plan.nRow = nRow;
- pCost->plan.wsFlags = flags;
- pCost->plan.u.pTerm = pTerm;
+ if( rTotal<p->cost.rCost ){
+ p->cost.rCost = rTotal;
+ p->cost.used = used;
+ p->cost.plan.nRow = nRow;
+ p->cost.plan.nOBSat = p->i ? p->aLevel[p->i-1].plan.nOBSat : 0;
+ p->cost.plan.wsFlags = flags;
+ p->cost.plan.u.pTerm = pTerm;
}
}
}
@@ -1939,15 +1809,12 @@ static int termCanDriveIndex(
** is taken into account, then alter the query plan to use the
** transient index.
*/
-static void bestAutomaticIndex(
- Parse *pParse, /* The parsing context */
- WhereClause *pWC, /* The WHERE clause */
- struct SrcList_item *pSrc, /* The FROM clause term to search */
- Bitmask notReady, /* Mask of cursors that are not available */
- WhereCost *pCost /* Lowest cost query plan */
-){
- double nTableRow; /* Rows in the input table */
- double logN; /* log(nTableRow) */
+static void bestAutomaticIndex(WhereBestIdx *p){
+ Parse *pParse = p->pParse; /* The parsing context */
+ WhereClause *pWC = p->pWC; /* The WHERE clause */
+ struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */
+ double nTableRow; /* Rows in the input table */
+ double logN; /* log(nTableRow) */
double costTempIdx; /* per-query cost of the transient index */
WhereTerm *pTerm; /* A single term of the WHERE clause */
WhereTerm *pWCEnd; /* End of pWC->a[] */
@@ -1961,10 +1828,16 @@ static void bestAutomaticIndex(
/* Automatic indices are disabled at run-time */
return;
}
- if( (pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)!=0 ){
+ if( (p->cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0
+ && (p->cost.plan.wsFlags & WHERE_COVER_SCAN)==0
+ ){
/* We already have some kind of index in use for this query. */
return;
}
+ if( pSrc->viaCoroutine ){
+ /* Cannot index a co-routine */
+ return;
+ }
if( pSrc->notIndexed ){
/* The NOT INDEXED clause appears in the SQL. */
return;
@@ -1979,7 +1852,7 @@ static void bestAutomaticIndex(
nTableRow = pTable->nRowEst;
logN = estLog(nTableRow);
costTempIdx = 2*logN*(nTableRow/pParse->nQueryLoop + 1);
- if( costTempIdx>=pCost->rCost ){
+ if( costTempIdx>=p->cost.rCost ){
/* The cost of creating the transient table would be greater than
** doing the full table scan */
return;
@@ -1988,19 +1861,19 @@ static void bestAutomaticIndex(
/* Search for any equality comparison term */
pWCEnd = &pWC->a[pWC->nTerm];
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
- if( termCanDriveIndex(pTerm, pSrc, notReady) ){
+ if( termCanDriveIndex(pTerm, pSrc, p->notReady) ){
WHERETRACE(("auto-index reduces cost from %.1f to %.1f\n",
- pCost->rCost, costTempIdx));
- pCost->rCost = costTempIdx;
- pCost->plan.nRow = logN + 1;
- pCost->plan.wsFlags = WHERE_TEMP_INDEX;
- pCost->used = pTerm->prereqRight;
+ p->cost.rCost, costTempIdx));
+ p->cost.rCost = costTempIdx;
+ p->cost.plan.nRow = logN + 1;
+ p->cost.plan.wsFlags = WHERE_TEMP_INDEX;
+ p->cost.used = pTerm->prereqRight;
break;
}
}
}
#else
-# define bestAutomaticIndex(A,B,C,D,E) /* no-op */
+# define bestAutomaticIndex(A) /* no-op */
#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
@@ -2161,12 +2034,11 @@ static void constructAutomaticIndex(
** responsibility of the caller to eventually release the structure
** by passing the pointer returned by this function to sqlite3_free().
*/
-static sqlite3_index_info *allocateIndexInfo(
- Parse *pParse,
- WhereClause *pWC,
- struct SrcList_item *pSrc,
- ExprList *pOrderBy
-){
+static sqlite3_index_info *allocateIndexInfo(WhereBestIdx *p){
+ Parse *pParse = p->pParse;
+ WhereClause *pWC = p->pWC;
+ struct SrcList_item *pSrc = p->pSrc;
+ ExprList *pOrderBy = p->pOrderBy;
int i, j;
int nTerm;
struct sqlite3_index_constraint *pIdxCons;
@@ -2196,12 +2068,13 @@ static sqlite3_index_info *allocateIndexInfo(
*/
nOrderBy = 0;
if( pOrderBy ){
- for(i=0; i<pOrderBy->nExpr; i++){
+ int n = pOrderBy->nExpr;
+ for(i=0; i<n; i++){
Expr *pExpr = pOrderBy->a[i].pExpr;
if( pExpr->op!=TK_COLUMN || pExpr->iTable!=pSrc->iCursor ) break;
}
- if( i==pOrderBy->nExpr ){
- nOrderBy = pOrderBy->nExpr;
+ if( i==n){
+ nOrderBy = n;
}
}
@@ -2325,16 +2198,10 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
** routine takes care of freeing the sqlite3_index_info structure after
** everybody has finished with it.
*/
-static void bestVirtualIndex(
- Parse *pParse, /* The parsing context */
- WhereClause *pWC, /* The WHERE clause */
- struct SrcList_item *pSrc, /* The FROM clause term to search */
- Bitmask notReady, /* Mask of cursors not available for index */
- Bitmask notValid, /* Cursors not valid for any purpose */
- ExprList *pOrderBy, /* The order by clause */
- WhereCost *pCost, /* Lowest cost query plan */
- sqlite3_index_info **ppIdxInfo /* Index information passed to xBestIndex */
-){
+static void bestVirtualIndex(WhereBestIdx *p){
+ Parse *pParse = p->pParse; /* The parsing context */
+ WhereClause *pWC = p->pWC; /* The WHERE clause */
+ struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */
Table *pTab = pSrc->pTab;
sqlite3_index_info *pIdxInfo;
struct sqlite3_index_constraint *pIdxCons;
@@ -2348,15 +2215,15 @@ static void bestVirtualIndex(
** malloc in allocateIndexInfo() fails and this function returns leaving
** wsFlags in an uninitialized state, the caller may behave unpredictably.
*/
- memset(pCost, 0, sizeof(*pCost));
- pCost->plan.wsFlags = WHERE_VIRTUALTABLE;
+ memset(&p->cost, 0, sizeof(p->cost));
+ p->cost.plan.wsFlags = WHERE_VIRTUALTABLE;
/* If the sqlite3_index_info structure has not been previously
** allocated and initialized, then allocate and initialize it now.
*/
- pIdxInfo = *ppIdxInfo;
+ pIdxInfo = *p->ppIdxInfo;
if( pIdxInfo==0 ){
- *ppIdxInfo = pIdxInfo = allocateIndexInfo(pParse, pWC, pSrc, pOrderBy);
+ *p->ppIdxInfo = pIdxInfo = allocateIndexInfo(p);
}
if( pIdxInfo==0 ){
return;
@@ -2401,7 +2268,7 @@ static void bestVirtualIndex(
for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
j = pIdxCons->iTermOffset;
pTerm = &pWC->a[j];
- pIdxCons->usable = (pTerm->prereqRight&notReady) ? 0 : 1;
+ pIdxCons->usable = (pTerm->prereqRight&p->notReady) ? 0 : 1;
}
memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint);
if( pIdxInfo->needToFreeIdxStr ){
@@ -2414,7 +2281,7 @@ static void bestVirtualIndex(
/* ((double)2) In case of SQLITE_OMIT_FLOATING_POINT... */
pIdxInfo->estimatedCost = SQLITE_BIG_DBL / ((double)2);
nOrderBy = pIdxInfo->nOrderBy;
- if( !pOrderBy ){
+ if( !p->pOrderBy ){
pIdxInfo->nOrderBy = 0;
}
@@ -2425,7 +2292,7 @@ static void bestVirtualIndex(
pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
for(i=0; i<pIdxInfo->nConstraint; i++){
if( pUsage[i].argvIndex>0 ){
- pCost->used |= pWC->a[pIdxCons[i].iTermOffset].prereqRight;
+ p->cost.used |= pWC->a[pIdxCons[i].iTermOffset].prereqRight;
}
}
@@ -2434,7 +2301,7 @@ static void bestVirtualIndex(
** matches the processing for non-virtual tables in bestBtreeIndex().
*/
rCost = pIdxInfo->estimatedCost;
- if( pOrderBy && pIdxInfo->orderByConsumed==0 ){
+ if( p->pOrderBy && pIdxInfo->orderByConsumed==0 ){
rCost += estLog(rCost)*rCost;
}
@@ -2446,21 +2313,24 @@ static void bestVirtualIndex(
** is defined.
*/
if( (SQLITE_BIG_DBL/((double)2))<rCost ){
- pCost->rCost = (SQLITE_BIG_DBL/((double)2));
+ p->cost.rCost = (SQLITE_BIG_DBL/((double)2));
}else{
- pCost->rCost = rCost;
+ p->cost.rCost = rCost;
}
- pCost->plan.u.pVtabIdx = pIdxInfo;
+ p->cost.plan.u.pVtabIdx = pIdxInfo;
if( pIdxInfo->orderByConsumed ){
- pCost->plan.wsFlags |= WHERE_ORDERBY;
+ p->cost.plan.wsFlags |= WHERE_ORDERED;
+ p->cost.plan.nOBSat = nOrderBy;
+ }else{
+ p->cost.plan.nOBSat = p->i ? p->aLevel[p->i-1].plan.nOBSat : 0;
}
- pCost->plan.nEq = 0;
+ p->cost.plan.nEq = 0;
pIdxInfo->nOrderBy = nOrderBy;
/* Try to find a more efficient access pattern by using multiple indexes
** to optimize an OR expression within the WHERE clause.
*/
- bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost);
+ bestOrClauseIndex(p);
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -2548,10 +2418,8 @@ static int whereKeyStats(
pColl = db->pDfltColl;
assert( pColl->enc==SQLITE_UTF8 );
}else{
- pColl = sqlite3GetCollSeq(db, SQLITE_UTF8, 0, *pIdx->azColl);
+ pColl = sqlite3GetCollSeq(pParse, SQLITE_UTF8, 0, *pIdx->azColl);
if( pColl==0 ){
- sqlite3ErrorMsg(pParse, "no such collation sequence: %s",
- *pIdx->azColl);
return SQLITE_ERROR;
}
z = (const u8 *)sqlite3ValueText(pVal, pColl->enc);
@@ -2859,11 +2727,275 @@ static int whereInScanEst(
}
#endif /* defined(SQLITE_ENABLE_STAT3) */
+/*
+** Check to see if column iCol of the table with cursor iTab will appear
+** in sorted order according to the current query plan.
+**
+** Return values:
+**
+** 0 iCol is not ordered
+** 1 iCol has only a single value
+** 2 iCol is in ASC order
+** 3 iCol is in DESC order
+*/
+static int isOrderedColumn(
+ WhereBestIdx *p,
+ int iTab,
+ int iCol
+){
+ int i, j;
+ WhereLevel *pLevel = &p->aLevel[p->i-1];
+ Index *pIdx;
+ u8 sortOrder;
+ for(i=p->i-1; i>=0; i--, pLevel--){
+ if( pLevel->iTabCur!=iTab ) continue;
+ if( (pLevel->plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){
+ return 1;
+ }
+ assert( (pLevel->plan.wsFlags & WHERE_ORDERED)!=0 );
+ if( (pIdx = pLevel->plan.u.pIdx)!=0 ){
+ if( iCol<0 ){
+ sortOrder = 0;
+ testcase( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 );
+ }else{
+ int n = pIdx->nColumn;
+ for(j=0; j<n; j++){
+ if( iCol==pIdx->aiColumn[j] ) break;
+ }
+ if( j>=n ) return 0;
+ sortOrder = pIdx->aSortOrder[j];
+ testcase( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 );
+ }
+ }else{
+ if( iCol!=(-1) ) return 0;
+ sortOrder = 0;
+ testcase( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 );
+ }
+ if( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 ){
+ assert( sortOrder==0 || sortOrder==1 );
+ testcase( sortOrder==1 );
+ sortOrder = 1 - sortOrder;
+ }
+ return sortOrder+2;
+ }
+ return 0;
+}
+
+/*
+** This routine decides if pIdx can be used to satisfy the ORDER BY
+** clause, either in whole or in part. The return value is the
+** cumulative number of terms in the ORDER BY clause that are satisfied
+** by the index pIdx and other indices in outer loops.
+**
+** The table being queried has a cursor number of "base". pIdx is the
+** index that is postulated for use to access the table.
+**
+** The *pbRev value is set to 0 order 1 depending on whether or not
+** pIdx should be run in the forward order or in reverse order.
+*/
+static int isSortingIndex(
+ WhereBestIdx *p, /* Best index search context */
+ Index *pIdx, /* The index we are testing */
+ int base, /* Cursor number for the table to be sorted */
+ int *pbRev /* Set to 1 for reverse-order scan of pIdx */
+){
+ int i; /* Number of pIdx terms used */
+ int j; /* Number of ORDER BY terms satisfied */
+ int sortOrder = 2; /* 0: forward. 1: backward. 2: unknown */
+ int nTerm; /* Number of ORDER BY terms */
+ struct ExprList_item *pOBItem;/* A term of the ORDER BY clause */
+ Table *pTab = pIdx->pTable; /* Table that owns index pIdx */
+ ExprList *pOrderBy; /* The ORDER BY clause */
+ Parse *pParse = p->pParse; /* Parser context */
+ sqlite3 *db = pParse->db; /* Database connection */
+ int nPriorSat; /* ORDER BY terms satisfied by outer loops */
+ int seenRowid = 0; /* True if an ORDER BY rowid term is seen */
+ int uniqueNotNull; /* pIdx is UNIQUE with all terms are NOT NULL */
+
+ if( p->i==0 ){
+ nPriorSat = 0;
+ }else{
+ nPriorSat = p->aLevel[p->i-1].plan.nOBSat;
+ if( (p->aLevel[p->i-1].plan.wsFlags & WHERE_ORDERED)==0 ){
+ /* This loop cannot be ordered unless the next outer loop is
+ ** also ordered */
+ return nPriorSat;
+ }
+ if( OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ){
+ /* Only look at the outer-most loop if the OrderByIdxJoin
+ ** optimization is disabled */
+ return nPriorSat;
+ }
+ }
+ pOrderBy = p->pOrderBy;
+ assert( pOrderBy!=0 );
+ if( pIdx->bUnordered ){
+ /* Hash indices (indicated by the "unordered" tag on sqlite_stat1) cannot
+ ** be used for sorting */
+ return nPriorSat;
+ }
+ nTerm = pOrderBy->nExpr;
+ uniqueNotNull = pIdx->onError!=OE_None;
+ assert( nTerm>0 );
+
+ /* Argument pIdx must either point to a 'real' named index structure,
+ ** or an index structure allocated on the stack by bestBtreeIndex() to
+ ** represent the rowid index that is part of every table. */
+ assert( pIdx->zName || (pIdx->nColumn==1 && pIdx->aiColumn[0]==-1) );
+
+ /* Match terms of the ORDER BY clause against columns of
+ ** the index.
+ **
+ ** Note that indices have pIdx->nColumn regular columns plus
+ ** one additional column containing the rowid. The rowid column
+ ** of the index is also allowed to match against the ORDER BY
+ ** clause.
+ */
+ j = nPriorSat;
+ for(i=0,pOBItem=&pOrderBy->a[j]; j<nTerm && i<=pIdx->nColumn; i++){
+ Expr *pOBExpr; /* The expression of the ORDER BY pOBItem */
+ CollSeq *pColl; /* The collating sequence of pOBExpr */
+ int termSortOrder; /* Sort order for this term */
+ int iColumn; /* The i-th column of the index. -1 for rowid */
+ int iSortOrder; /* 1 for DESC, 0 for ASC on the i-th index term */
+ int isEq; /* Subject to an == or IS NULL constraint */
+ int isMatch; /* ORDER BY term matches the index term */
+ const char *zColl; /* Name of collating sequence for i-th index term */
+ WhereTerm *pConstraint; /* A constraint in the WHERE clause */
+
+ /* If the next term of the ORDER BY clause refers to anything other than
+ ** a column in the "base" table, then this index will not be of any
+ ** further use in handling the ORDER BY. */
+ pOBExpr = sqlite3ExprSkipCollate(pOBItem->pExpr);
+ if( pOBExpr->op!=TK_COLUMN || pOBExpr->iTable!=base ){
+ break;
+ }
+
+ /* Find column number and collating sequence for the next entry
+ ** in the index */
+ if( pIdx->zName && i<pIdx->nColumn ){
+ iColumn = pIdx->aiColumn[i];
+ if( iColumn==pIdx->pTable->iPKey ){
+ iColumn = -1;
+ }
+ iSortOrder = pIdx->aSortOrder[i];
+ zColl = pIdx->azColl[i];
+ assert( zColl!=0 );
+ }else{
+ iColumn = -1;
+ iSortOrder = 0;
+ zColl = 0;
+ }
+
+ /* Check to see if the column number and collating sequence of the
+ ** index match the column number and collating sequence of the ORDER BY
+ ** clause entry. Set isMatch to 1 if they both match. */
+ if( pOBExpr->iColumn==iColumn ){
+ if( zColl ){
+ pColl = sqlite3ExprCollSeq(pParse, pOBItem->pExpr);
+ if( !pColl ) pColl = db->pDfltColl;
+ isMatch = sqlite3StrICmp(pColl->zName, zColl)==0;
+ }else{
+ isMatch = 1;
+ }
+ }else{
+ isMatch = 0;
+ }
+
+ /* termSortOrder is 0 or 1 for whether or not the access loop should
+ ** run forward or backwards (respectively) in order to satisfy this
+ ** term of the ORDER BY clause. */
+ assert( pOBItem->sortOrder==0 || pOBItem->sortOrder==1 );
+ assert( iSortOrder==0 || iSortOrder==1 );
+ termSortOrder = iSortOrder ^ pOBItem->sortOrder;
+
+ /* If X is the column in the index and ORDER BY clause, check to see
+ ** if there are any X= or X IS NULL constraints in the WHERE clause. */
+ pConstraint = findTerm(p->pWC, base, iColumn, p->notReady,
+ WO_EQ|WO_ISNULL|WO_IN, pIdx);
+ if( pConstraint==0 ){
+ isEq = 0;
+ }else if( pConstraint->eOperator==WO_IN ){
+ /* Constraints of the form: "X IN ..." cannot be used with an ORDER BY
+ ** because we do not know in what order the values on the RHS of the IN
+ ** operator will occur. */
+ break;
+ }else if( pConstraint->eOperator==WO_ISNULL ){
+ uniqueNotNull = 0;
+ isEq = 1; /* "X IS NULL" means X has only a single value */
+ }else if( pConstraint->prereqRight==0 ){
+ isEq = 1; /* Constraint "X=constant" means X has only a single value */
+ }else{
+ Expr *pRight = pConstraint->pExpr->pRight;
+ if( pRight->op==TK_COLUMN ){
+ WHERETRACE((" .. isOrderedColumn(tab=%d,col=%d)",
+ pRight->iTable, pRight->iColumn));
+ isEq = isOrderedColumn(p, pRight->iTable, pRight->iColumn);
+ WHERETRACE((" -> isEq=%d\n", isEq));
+
+ /* If the constraint is of the form X=Y where Y is an ordered value
+ ** in an outer loop, then make sure the sort order of Y matches the
+ ** sort order required for X. */
+ if( isMatch && isEq>=2 && isEq!=pOBItem->sortOrder+2 ){
+ testcase( isEq==2 );
+ testcase( isEq==3 );
+ break;
+ }
+ }else{
+ isEq = 0; /* "X=expr" places no ordering constraints on X */
+ }
+ }
+ if( !isMatch ){
+ if( isEq==0 ){
+ break;
+ }else{
+ continue;
+ }
+ }else if( isEq!=1 ){
+ if( sortOrder==2 ){
+ sortOrder = termSortOrder;
+ }else if( termSortOrder!=sortOrder ){
+ break;
+ }
+ }
+ j++;
+ pOBItem++;
+ if( iColumn<0 ){
+ seenRowid = 1;
+ break;
+ }else if( pTab->aCol[iColumn].notNull==0 && isEq!=1 ){
+ testcase( isEq==0 );
+ testcase( isEq==2 );
+ testcase( isEq==3 );
+ uniqueNotNull = 0;
+ }
+ }
+
+ /* If we have not found at least one ORDER BY term that matches the
+ ** index, then show no progress. */
+ if( pOBItem==&pOrderBy->a[nPriorSat] ) return nPriorSat;
+
+ /* Return the necessary scan order back to the caller */
+ *pbRev = sortOrder & 1;
+
+ /* If there was an "ORDER BY rowid" term that matched, or it is only
+ ** possible for a single row from this table to match, then skip over
+ ** any additional ORDER BY terms dealing with this table.
+ */
+ if( seenRowid || (uniqueNotNull && i>=pIdx->nColumn) ){
+ /* Advance j over additional ORDER BY terms associated with base */
+ WhereMaskSet *pMS = p->pWC->pMaskSet;
+ Bitmask m = ~getMask(pMS, base);
+ while( j<nTerm && (exprTableUsage(pMS, pOrderBy->a[j].pExpr)&m)==0 ){
+ j++;
+ }
+ }
+ return j;
+}
/*
** Find the best query plan for accessing a particular table. Write the
-** best query plan and its cost into the WhereCost object supplied as the
-** last parameter.
+** best query plan and its cost into the p->cost.
**
** The lowest cost plan wins. The cost is an estimate of the amount of
** CPU and disk I/O needed to process the requested result.
@@ -2883,21 +3015,15 @@ static int whereInScanEst(
** SQLITE_BIG_DBL. If a plan is found that uses the named index,
** then the cost is calculated in the usual way.
**
-** If a NOT INDEXED clause (pSrc->notIndexed!=0) was attached to the table
+** If a NOT INDEXED clause was attached to the table
** in the SELECT statement, then no indexes are considered. However, the
** selected plan may still take advantage of the built-in rowid primary key
** index.
*/
-static void bestBtreeIndex(
- Parse *pParse, /* The parsing context */
- WhereClause *pWC, /* The WHERE clause */
- struct SrcList_item *pSrc, /* The FROM clause term to search */
- Bitmask notReady, /* Mask of cursors not available for indexing */
- Bitmask notValid, /* Cursors not available for any purpose */
- ExprList *pOrderBy, /* The ORDER BY clause */
- ExprList *pDistinct, /* The select-list if query is DISTINCT */
- WhereCost *pCost /* Lowest cost query plan */
-){
+static void bestBtreeIndex(WhereBestIdx *p){
+ Parse *pParse = p->pParse; /* The parsing context */
+ WhereClause *pWC = p->pWC; /* The WHERE clause */
+ struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */
int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */
Index *pProbe; /* An index we are evaluating */
Index *pIdx; /* Copy of pProbe, or zero for IPK index */
@@ -2906,11 +3032,16 @@ static void bestBtreeIndex(
Index sPk; /* A fake index object for the primary key */
tRowcnt aiRowEstPk[2]; /* The aiRowEst[] value for the sPk index */
int aiColumnPk = -1; /* The aColumn[] value for the sPk index */
- int wsFlagMask; /* Allowed flags in pCost->plan.wsFlag */
+ int wsFlagMask; /* Allowed flags in p->cost.plan.wsFlag */
+ int nPriorSat; /* ORDER BY terms satisfied by outer loops */
+ int nOrderBy; /* Number of ORDER BY terms */
+ char bSortInit; /* Initializer for bSort in inner loop */
+ char bDistInit; /* Initializer for bDist in inner loop */
+
/* Initialize the cost to a worst-case value */
- memset(pCost, 0, sizeof(*pCost));
- pCost->rCost = SQLITE_BIG_DBL;
+ memset(&p->cost, 0, sizeof(p->cost));
+ p->cost.rCost = SQLITE_BIG_DBL;
/* If the pSrc table is the right table of a LEFT JOIN then we may not
** use an index to satisfy IS NULL constraints on that table. This is
@@ -2956,22 +3087,29 @@ static void bestBtreeIndex(
pIdx = 0;
}
+ nOrderBy = p->pOrderBy ? p->pOrderBy->nExpr : 0;
+ if( p->i ){
+ nPriorSat = p->aLevel[p->i-1].plan.nOBSat;
+ bSortInit = nPriorSat<nOrderBy;
+ bDistInit = 0;
+ }else{
+ nPriorSat = 0;
+ bSortInit = nOrderBy>0;
+ bDistInit = p->pDistinct!=0;
+ }
+
/* Loop over all indices looking for the best one to use
*/
for(; pProbe; pIdx=pProbe=pProbe->pNext){
const tRowcnt * const aiRowEst = pProbe->aiRowEst;
- double cost; /* Cost of using pProbe */
- double nRow; /* Estimated number of rows in result set */
+ WhereCost pc; /* Cost of using pProbe */
double log10N = (double)1; /* base-10 logarithm of nRow (inexact) */
- int rev; /* True to scan in reverse order */
- int wsFlags = 0;
- Bitmask used = 0;
/* The following variables are populated based on the properties of
** index being evaluated. They are then used to determine the expected
** cost and number of rows returned.
**
- ** nEq:
+ ** pc.plan.nEq:
** Number of equality terms that can be implemented using the index.
** In other words, the number of initial fields in the index that
** are used in == or IN or NOT NULL constraints of the WHERE clause.
@@ -3014,6 +3152,10 @@ static void bestBtreeIndex(
** external sort (i.e. scanning the index being evaluated will not
** correctly order records).
**
+ ** bDist:
+ ** Boolean. True if there is a DISTINCT clause that will require an
+ ** external btree.
+ **
** bLookup:
** Boolean. True if a table lookup is required for each index entry
** visited. In other words, true if this is not a covering index.
@@ -3029,29 +3171,35 @@ static void bestBtreeIndex(
** SELECT a, b FROM tbl WHERE a = 1;
** SELECT a, b, c FROM tbl WHERE a = 1;
*/
- int nEq; /* Number of == or IN terms matching index */
int bInEst = 0; /* True if "x IN (SELECT...)" seen */
int nInMul = 1; /* Number of distinct equalities to lookup */
double rangeDiv = (double)1; /* Estimated reduction in search space */
int nBound = 0; /* Number of range constraints seen */
- int bSort = !!pOrderBy; /* True if external sort required */
- int bDist = !!pDistinct; /* True if index cannot help with DISTINCT */
- int bLookup = 0; /* True if not a covering index */
+ char bSort = bSortInit; /* True if external sort required */
+ char bDist = bDistInit; /* True if index cannot help with DISTINCT */
+ char bLookup = 0; /* True if not a covering index */
WhereTerm *pTerm; /* A single term of the WHERE clause */
#ifdef SQLITE_ENABLE_STAT3
WhereTerm *pFirstTerm = 0; /* First term matching the index */
#endif
- /* Determine the values of nEq and nInMul */
- for(nEq=0; nEq<pProbe->nColumn; nEq++){
- int j = pProbe->aiColumn[nEq];
- pTerm = findTerm(pWC, iCur, j, notReady, eqTermMask, pIdx);
+ WHERETRACE((
+ " %s(%s):\n",
+ pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk")
+ ));
+ memset(&pc, 0, sizeof(pc));
+ pc.plan.nOBSat = nPriorSat;
+
+ /* Determine the values of pc.plan.nEq and nInMul */
+ for(pc.plan.nEq=0; pc.plan.nEq<pProbe->nColumn; pc.plan.nEq++){
+ int j = pProbe->aiColumn[pc.plan.nEq];
+ pTerm = findTerm(pWC, iCur, j, p->notReady, eqTermMask, pIdx);
if( pTerm==0 ) break;
- wsFlags |= (WHERE_COLUMN_EQ|WHERE_ROWID_EQ);
+ pc.plan.wsFlags |= (WHERE_COLUMN_EQ|WHERE_ROWID_EQ);
testcase( pTerm->pWC!=pWC );
if( pTerm->eOperator & WO_IN ){
Expr *pExpr = pTerm->pExpr;
- wsFlags |= WHERE_COLUMN_IN;
+ pc.plan.wsFlags |= WHERE_COLUMN_IN;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
/* "x IN (SELECT ...)": Assume the SELECT returns 25 rows */
nInMul *= 25;
@@ -3061,12 +3209,12 @@ static void bestBtreeIndex(
nInMul *= pExpr->x.pList->nExpr;
}
}else if( pTerm->eOperator & WO_ISNULL ){
- wsFlags |= WHERE_COLUMN_NULL;
+ pc.plan.wsFlags |= WHERE_COLUMN_NULL;
}
#ifdef SQLITE_ENABLE_STAT3
- if( nEq==0 && pProbe->aSample ) pFirstTerm = pTerm;
+ if( pc.plan.nEq==0 && pProbe->aSample ) pFirstTerm = pTerm;
#endif
- used |= pTerm->prereqRight;
+ pc.used |= pTerm->prereqRight;
}
/* If the index being considered is UNIQUE, and there is an equality
@@ -3075,65 +3223,80 @@ static void bestBtreeIndex(
** indicate this to the caller.
**
** Otherwise, if the search may find more than one row, test to see if
- ** there is a range constraint on indexed column (nEq+1) that can be
+ ** there is a range constraint on indexed column (pc.plan.nEq+1) that can be
** optimized using the index.
*/
- if( nEq==pProbe->nColumn && pProbe->onError!=OE_None ){
- testcase( wsFlags & WHERE_COLUMN_IN );
- testcase( wsFlags & WHERE_COLUMN_NULL );
- if( (wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 ){
- wsFlags |= WHERE_UNIQUE;
+ if( pc.plan.nEq==pProbe->nColumn && pProbe->onError!=OE_None ){
+ testcase( pc.plan.wsFlags & WHERE_COLUMN_IN );
+ testcase( pc.plan.wsFlags & WHERE_COLUMN_NULL );
+ if( (pc.plan.wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 ){
+ pc.plan.wsFlags |= WHERE_UNIQUE;
+ if( p->i==0 || (p->aLevel[p->i-1].plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){
+ pc.plan.wsFlags |= WHERE_ALL_UNIQUE;
+ }
}
}else if( pProbe->bUnordered==0 ){
- int j = (nEq==pProbe->nColumn ? -1 : pProbe->aiColumn[nEq]);
- if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){
- WhereTerm *pTop = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pIdx);
- WhereTerm *pBtm = findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pIdx);
- whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &rangeDiv);
+ int j;
+ j = (pc.plan.nEq==pProbe->nColumn ? -1 : pProbe->aiColumn[pc.plan.nEq]);
+ if( findTerm(pWC, iCur, j, p->notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){
+ WhereTerm *pTop, *pBtm;
+ pTop = findTerm(pWC, iCur, j, p->notReady, WO_LT|WO_LE, pIdx);
+ pBtm = findTerm(pWC, iCur, j, p->notReady, WO_GT|WO_GE, pIdx);
+ whereRangeScanEst(pParse, pProbe, pc.plan.nEq, pBtm, pTop, &rangeDiv);
if( pTop ){
nBound = 1;
- wsFlags |= WHERE_TOP_LIMIT;
- used |= pTop->prereqRight;
+ pc.plan.wsFlags |= WHERE_TOP_LIMIT;
+ pc.used |= pTop->prereqRight;
testcase( pTop->pWC!=pWC );
}
if( pBtm ){
nBound++;
- wsFlags |= WHERE_BTM_LIMIT;
- used |= pBtm->prereqRight;
+ pc.plan.wsFlags |= WHERE_BTM_LIMIT;
+ pc.used |= pBtm->prereqRight;
testcase( pBtm->pWC!=pWC );
}
- wsFlags |= (WHERE_COLUMN_RANGE|WHERE_ROWID_RANGE);
+ pc.plan.wsFlags |= (WHERE_COLUMN_RANGE|WHERE_ROWID_RANGE);
}
}
/* If there is an ORDER BY clause and the index being considered will
** naturally scan rows in the required order, set the appropriate flags
- ** in wsFlags. Otherwise, if there is an ORDER BY clause but the index
- ** will scan rows in a different order, set the bSort variable. */
- if( isSortingIndex(
- pParse, pWC->pMaskSet, pProbe, iCur, pOrderBy, nEq, wsFlags, &rev)
- ){
- bSort = 0;
- wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_ORDERBY;
- wsFlags |= (rev ? WHERE_REVERSE : 0);
+ ** in pc.plan.wsFlags. Otherwise, if there is an ORDER BY clause but
+ ** the index will scan rows in a different order, set the bSort
+ ** variable. */
+ if( bSort && (pSrc->jointype & JT_LEFT)==0 ){
+ 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( nPriorSat<pc.plan.nOBSat || (pc.plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){
+ pc.plan.wsFlags |= WHERE_ORDERED;
+ }
+ if( nOrderBy==pc.plan.nOBSat ){
+ bSort = 0;
+ pc.plan.wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE;
+ }
+ if( bRev & 1 ) pc.plan.wsFlags |= WHERE_REVERSE;
}
/* If there is a DISTINCT qualifier and this index will scan rows in
** order of the DISTINCT expressions, clear bDist and set the appropriate
- ** flags in wsFlags. */
- if( isDistinctIndex(pParse, pWC, pProbe, iCur, pDistinct, nEq)
- && (wsFlags & WHERE_COLUMN_IN)==0
+ ** flags in pc.plan.wsFlags. */
+ if( bDist
+ && isDistinctIndex(pParse, pWC, pProbe, iCur, p->pDistinct, pc.plan.nEq)
+ && (pc.plan.wsFlags & WHERE_COLUMN_IN)==0
){
bDist = 0;
- wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_DISTINCT;
+ pc.plan.wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_DISTINCT;
}
/* If currently calculating the cost of using an index (not the IPK
** index), determine if all required column data may be obtained without
** using the main table (i.e. if the index is a covering
** index for this query). If it is, set the WHERE_IDX_ONLY flag in
- ** wsFlags. Otherwise, set the bLookup variable to true. */
- if( pIdx && wsFlags ){
+ ** pc.plan.wsFlags. Otherwise, set the bLookup variable to true. */
+ if( pIdx ){
Bitmask m = pSrc->colUsed;
int j;
for(j=0; j<pIdx->nColumn; j++){
@@ -3143,7 +3306,7 @@ static void bestBtreeIndex(
}
}
if( m==0 ){
- wsFlags |= WHERE_IDX_ONLY;
+ pc.plan.wsFlags |= WHERE_IDX_ONLY;
}else{
bLookup = 1;
}
@@ -3153,10 +3316,10 @@ static void bestBtreeIndex(
** Estimate the number of rows of output. For an "x IN (SELECT...)"
** constraint, do not let the estimate exceed half the rows in the table.
*/
- nRow = (double)(aiRowEst[nEq] * nInMul);
- if( bInEst && nRow*2>aiRowEst[0] ){
- nRow = aiRowEst[0]/2;
- nInMul = (int)(nRow / aiRowEst[nEq]);
+ pc.plan.nRow = (double)(aiRowEst[pc.plan.nEq] * nInMul);
+ if( bInEst && pc.plan.nRow*2>aiRowEst[0] ){
+ pc.plan.nRow = aiRowEst[0]/2;
+ nInMul = (int)(pc.plan.nRow / aiRowEst[pc.plan.nEq]);
}
#ifdef SQLITE_ENABLE_STAT3
@@ -3166,15 +3329,18 @@ static void bestBtreeIndex(
** to get a better estimate on the number of rows based on
** VALUE and how common that value is according to the histogram.
*/
- if( nRow>(double)1 && nEq==1 && pFirstTerm!=0 && aiRowEst[1]>1 ){
+ if( pc.plan.nRow>(double)1 && pc.plan.nEq==1
+ && pFirstTerm!=0 && aiRowEst[1]>1 ){
assert( (pFirstTerm->eOperator & (WO_EQ|WO_ISNULL|WO_IN))!=0 );
if( pFirstTerm->eOperator & (WO_EQ|WO_ISNULL) ){
testcase( pFirstTerm->eOperator==WO_EQ );
testcase( pFirstTerm->eOperator==WO_ISNULL );
- whereEqualScanEst(pParse, pProbe, pFirstTerm->pExpr->pRight, &nRow);
+ whereEqualScanEst(pParse, pProbe, pFirstTerm->pExpr->pRight,
+ &pc.plan.nRow);
}else if( bInEst==0 ){
assert( pFirstTerm->eOperator==WO_IN );
- whereInScanEst(pParse, pProbe, pFirstTerm->pExpr->x.pList, &nRow);
+ whereInScanEst(pParse, pProbe, pFirstTerm->pExpr->x.pList,
+ &pc.plan.nRow);
}
}
#endif /* SQLITE_ENABLE_STAT3 */
@@ -3182,8 +3348,8 @@ static void bestBtreeIndex(
/* Adjust the number of output rows and downward to reflect rows
** that are excluded by range constraints.
*/
- nRow = nRow/rangeDiv;
- if( nRow<1 ) nRow = 1;
+ pc.plan.nRow = pc.plan.nRow/rangeDiv;
+ if( pc.plan.nRow<1 ) pc.plan.nRow = 1;
/* Experiments run on real SQLite databases show that the time needed
** to do a binary search to locate a row in a table or index is roughly
@@ -3198,7 +3364,18 @@ static void bestBtreeIndex(
** So this computation assumes table records are about twice as big
** as index records
*/
- if( (wsFlags & WHERE_NOT_FULLSCAN)==0 ){
+ if( (pc.plan.wsFlags&~(WHERE_REVERSE|WHERE_ORDERED))==WHERE_IDX_ONLY
+ && (pWC->wctrlFlags & WHERE_ONEPASS_DESIRED)==0
+ && sqlite3GlobalConfig.bUseCis
+ && OptimizationEnabled(pParse->db, SQLITE_CoverIdxScan)
+ ){
+ /* This index is not useful for indexing, but it is a covering index.
+ ** A full-scan of the index might be a little faster than a full-scan
+ ** of the table, so give this case a cost slightly less than a table
+ ** scan. */
+ pc.rCost = aiRowEst[0]*3 + pProbe->nColumn;
+ pc.plan.wsFlags |= WHERE_COVER_SCAN|WHERE_COLUMN_RANGE;
+ }else if( (pc.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){
/* The cost of a full table scan is a number of move operations equal
** to the number of rows in the table.
**
@@ -3208,10 +3385,15 @@ static void bestBtreeIndex(
** decision and one which we expect to revisit in the future. But
** it seems to be working well enough at the moment.
*/
- cost = aiRowEst[0]*4;
+ pc.rCost = aiRowEst[0]*4;
+ pc.plan.wsFlags &= ~WHERE_IDX_ONLY;
+ if( pIdx ){
+ pc.plan.wsFlags &= ~WHERE_ORDERED;
+ pc.plan.nOBSat = nPriorSat;
+ }
}else{
log10N = estLog(aiRowEst[0]);
- cost = nRow;
+ pc.rCost = pc.plan.nRow;
if( pIdx ){
if( bLookup ){
/* For an index lookup followed by a table lookup:
@@ -3219,20 +3401,20 @@ static void bestBtreeIndex(
** + nRow steps through the index
** + nRow table searches to lookup the table entry using the rowid
*/
- cost += (nInMul + nRow)*log10N;
+ pc.rCost += (nInMul + pc.plan.nRow)*log10N;
}else{
/* For a covering index:
** nInMul index searches to find the initial entry
** + nRow steps through the index
*/
- cost += nInMul*log10N;
+ pc.rCost += nInMul*log10N;
}
}else{
/* For a rowid primary key lookup:
** nInMult table searches to find the initial entry for each range
** + nRow steps through the table
*/
- cost += nInMul*log10N;
+ pc.rCost += nInMul*log10N;
}
}
@@ -3243,10 +3425,12 @@ static void bestBtreeIndex(
** difference and select C of 3.0.
*/
if( bSort ){
- cost += nRow*estLog(nRow)*3;
+ double m = estLog(pc.plan.nRow*(nOrderBy - pc.plan.nOBSat)/nOrderBy);
+ m *= (double)(pc.plan.nOBSat ? 2 : 3);
+ pc.rCost += pc.plan.nRow*m;
}
if( bDist ){
- cost += nRow*estLog(nRow)*3;
+ pc.rCost += pc.plan.nRow*estLog(pc.plan.nRow)*3;
}
/**** Cost of using this index has now been computed ****/
@@ -3267,25 +3451,25 @@ static void bestBtreeIndex(
** might be selected even when there exists an optimal index that has
** no such dependency.
*/
- if( nRow>2 && cost<=pCost->rCost ){
+ if( pc.plan.nRow>2 && pc.rCost<=p->cost.rCost ){
int k; /* Loop counter */
- int nSkipEq = nEq; /* Number of == constraints to skip */
+ int nSkipEq = pc.plan.nEq; /* Number of == constraints to skip */
int nSkipRange = nBound; /* Number of < constraints to skip */
Bitmask thisTab; /* Bitmap for pSrc */
thisTab = getMask(pWC->pMaskSet, iCur);
- for(pTerm=pWC->a, k=pWC->nTerm; nRow>2 && k; k--, pTerm++){
+ for(pTerm=pWC->a, k=pWC->nTerm; pc.plan.nRow>2 && k; k--, pTerm++){
if( pTerm->wtFlags & TERM_VIRTUAL ) continue;
- if( (pTerm->prereqAll & notValid)!=thisTab ) continue;
+ if( (pTerm->prereqAll & p->notValid)!=thisTab ) continue;
if( pTerm->eOperator & (WO_EQ|WO_IN|WO_ISNULL) ){
if( nSkipEq ){
- /* Ignore the first nEq equality matches since the index
+ /* Ignore the first pc.plan.nEq equality matches since the index
** has already accounted for these */
nSkipEq--;
}else{
/* Assume each additional equality match reduces the result
** set size by a factor of 10 */
- nRow /= 10;
+ pc.plan.nRow /= 10;
}
}else if( pTerm->eOperator & (WO_LT|WO_LE|WO_GT|WO_GE) ){
if( nSkipRange ){
@@ -3299,37 +3483,33 @@ static void bestBtreeIndex(
** more selective intentionally because of the subjective
** observation that indexed range constraints really are more
** selective in practice, on average. */
- nRow /= 3;
+ pc.plan.nRow /= 3;
}
}else if( pTerm->eOperator!=WO_NOOP ){
/* Any other expression lowers the output row count by half */
- nRow /= 2;
+ pc.plan.nRow /= 2;
}
}
- if( nRow<2 ) nRow = 2;
+ if( pc.plan.nRow<2 ) pc.plan.nRow = 2;
}
WHERETRACE((
- "%s(%s): nEq=%d nInMul=%d rangeDiv=%d bSort=%d bLookup=%d wsFlags=0x%x\n"
- " notReady=0x%llx log10N=%.1f nRow=%.1f cost=%.1f used=0x%llx\n",
- pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk"),
- nEq, nInMul, (int)rangeDiv, bSort, bLookup, wsFlags,
- notReady, log10N, nRow, cost, used
+ " nEq=%d nInMul=%d rangeDiv=%d bSort=%d bLookup=%d wsFlags=0x%08x\n"
+ " notReady=0x%llx log10N=%.1f nRow=%.1f cost=%.1f\n"
+ " used=0x%llx nOBSat=%d\n",
+ pc.plan.nEq, nInMul, (int)rangeDiv, bSort, bLookup, pc.plan.wsFlags,
+ p->notReady, log10N, pc.plan.nRow, pc.rCost, pc.used,
+ pc.plan.nOBSat
));
/* If this index is the best we have seen so far, then record this
- ** index and its cost in the pCost structure.
+ ** index and its cost in the p->cost structure.
*/
- if( (!pIdx || wsFlags)
- && (cost<pCost->rCost || (cost<=pCost->rCost && nRow<pCost->plan.nRow))
- ){
- pCost->rCost = cost;
- pCost->used = used;
- pCost->plan.nRow = nRow;
- pCost->plan.wsFlags = (wsFlags&wsFlagMask);
- pCost->plan.nEq = nEq;
- pCost->plan.u.pIdx = pIdx;
+ if( (!pIdx || pc.plan.wsFlags) && compareCost(&pc, &p->cost) ){
+ p->cost = pc;
+ p->cost.plan.wsFlags &= wsFlagMask;
+ p->cost.plan.u.pIdx = pIdx;
}
/* If there was an INDEXED BY clause, then only that one index is
@@ -3346,25 +3526,23 @@ static void bestBtreeIndex(
** in. This is used for application testing, to help find cases
** where application behaviour depends on the (undefined) order that
** SQLite outputs rows in in the absence of an ORDER BY clause. */
- if( !pOrderBy && pParse->db->flags & SQLITE_ReverseOrder ){
- pCost->plan.wsFlags |= WHERE_REVERSE;
+ if( !p->pOrderBy && pParse->db->flags & SQLITE_ReverseOrder ){
+ p->cost.plan.wsFlags |= WHERE_REVERSE;
}
- assert( pOrderBy || (pCost->plan.wsFlags&WHERE_ORDERBY)==0 );
- assert( pCost->plan.u.pIdx==0 || (pCost->plan.wsFlags&WHERE_ROWID_EQ)==0 );
+ assert( p->pOrderBy || (p->cost.plan.wsFlags&WHERE_ORDERED)==0 );
+ assert( p->cost.plan.u.pIdx==0 || (p->cost.plan.wsFlags&WHERE_ROWID_EQ)==0 );
assert( pSrc->pIndex==0
- || pCost->plan.u.pIdx==0
- || pCost->plan.u.pIdx==pSrc->pIndex
+ || p->cost.plan.u.pIdx==0
+ || p->cost.plan.u.pIdx==pSrc->pIndex
);
- WHERETRACE(("best index is: %s\n",
- ((pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ? "none" :
- pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk")
- ));
+ WHERETRACE((" best index is: %s\n",
+ p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk"));
- bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost);
- bestAutomaticIndex(pParse, pWC, pSrc, notReady, pCost);
- pCost->plan.wsFlags |= eqTermMask;
+ bestOrClauseIndex(p);
+ bestAutomaticIndex(p);
+ p->cost.plan.wsFlags |= eqTermMask;
}
/*
@@ -3372,28 +3550,27 @@ static void bestBtreeIndex(
** best query plan and its cost into the WhereCost object supplied
** as the last parameter. This function may calculate the cost of
** both real and virtual table scans.
+**
+** This function does not take ORDER BY or DISTINCT into account. Nor
+** does it remember the virtual table query plan. All it does is compute
+** the cost while determining if an OR optimization is applicable. The
+** details will be reconsidered later if the optimization is found to be
+** applicable.
*/
-static void bestIndex(
- Parse *pParse, /* The parsing context */
- WhereClause *pWC, /* The WHERE clause */
- struct SrcList_item *pSrc, /* The FROM clause term to search */
- Bitmask notReady, /* Mask of cursors not available for indexing */
- Bitmask notValid, /* Cursors not available for any purpose */
- ExprList *pOrderBy, /* The ORDER BY clause */
- WhereCost *pCost /* Lowest cost query plan */
-){
+static void bestIndex(WhereBestIdx *p){
#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( IsVirtual(pSrc->pTab) ){
- sqlite3_index_info *p = 0;
- bestVirtualIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost,&p);
- if( p->needToFreeIdxStr ){
- sqlite3_free(p->idxStr);
+ if( IsVirtual(p->pSrc->pTab) ){
+ sqlite3_index_info *pIdxInfo = 0;
+ p->ppIdxInfo = &pIdxInfo;
+ bestVirtualIndex(p);
+ if( pIdxInfo->needToFreeIdxStr ){
+ sqlite3_free(pIdxInfo->idxStr);
}
- sqlite3DbFree(pParse->db, p);
+ sqlite3DbFree(p->pParse->db, pIdxInfo);
}else
#endif
{
- bestBtreeIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, 0, pCost);
+ bestBtreeIndex(p);
}
}
@@ -3871,6 +4048,16 @@ static Bitmask codeOneLoopStart(
VdbeComment((v, "init LEFT JOIN no-match flag"));
}
+ /* Special case of a FROM clause subquery implemented as a co-routine */
+ if( pTabItem->viaCoroutine ){
+ int regYield = pTabItem->regReturn;
+ sqlite3VdbeAddOp2(v, OP_Integer, pTabItem->addrFillSub-1, regYield);
+ pLevel->p2 = sqlite3VdbeAddOp1(v, OP_Yield, regYield);
+ VdbeComment((v, "next row of co-routine %s", pTabItem->pTab->zName));
+ sqlite3VdbeAddOp2(v, OP_If, regYield+1, addrBrk);
+ pLevel->op = OP_Goto;
+ }else
+
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( (pLevel->plan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){
/* Case 0: The table is a virtual-table. Use the VFilter and VNext
@@ -4089,7 +4276,7 @@ static Bitmask codeOneLoopStart(
** this requires some special handling.
*/
if( (wctrlFlags&WHERE_ORDERBY_MIN)!=0
- && (pLevel->plan.wsFlags&WHERE_ORDERBY)
+ && (pLevel->plan.wsFlags&WHERE_ORDERED)
&& (pIdx->nColumn>nEq)
){
/* assert( pOrderBy->nExpr==1 ); */
@@ -4252,6 +4439,11 @@ static Bitmask codeOneLoopStart(
pLevel->op = OP_Next;
}
pLevel->p1 = iIdxCur;
+ if( pLevel->plan.wsFlags & WHERE_COVER_SCAN ){
+ pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
+ }else{
+ assert( pLevel->p5==0 );
+ }
}else
#ifndef SQLITE_OMIT_OR_OPTIMIZATION
@@ -4646,42 +4838,46 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
**
** ORDER BY CLAUSE PROCESSING
**
-** *ppOrderBy is a pointer to the ORDER BY clause of a SELECT statement,
+** pOrderBy is a pointer to the ORDER BY clause of a SELECT statement,
** if there is one. If there is no ORDER BY clause or if this routine
-** is called from an UPDATE or DELETE statement, then ppOrderBy is NULL.
+** is called from an UPDATE or DELETE statement, then pOrderBy is NULL.
**
** If an index can be used so that the natural output order of the table
** scan is correct for the ORDER BY clause, then that index is used and
-** *ppOrderBy is set to NULL. This is an optimization that prevents an
-** unnecessary sort of the result set if an index appropriate for the
-** ORDER BY clause already exists.
+** the returned WhereInfo.nOBSat field is set to pOrderBy->nExpr. This
+** is an optimization that prevents an unnecessary sort of the result set
+** if an index appropriate for the ORDER BY clause already exists.
**
** If the where clause loops cannot be arranged to provide the correct
-** output order, then the *ppOrderBy is unchanged.
+** output order, then WhereInfo.nOBSat is 0.
*/
WhereInfo *sqlite3WhereBegin(
Parse *pParse, /* The parser context */
SrcList *pTabList, /* A list of all tables to be scanned */
Expr *pWhere, /* The WHERE clause */
- ExprList **ppOrderBy, /* An ORDER BY clause, or NULL */
+ ExprList *pOrderBy, /* An ORDER BY clause, or NULL */
ExprList *pDistinct, /* The select-list for DISTINCT queries - or NULL */
u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */
int iIdxCur /* If WHERE_ONETABLE_ONLY is set, index cursor number */
){
- int i; /* Loop counter */
int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */
int nTabList; /* Number of elements in pTabList */
WhereInfo *pWInfo; /* Will become the return value of this function */
Vdbe *v = pParse->pVdbe; /* The virtual database engine */
Bitmask notReady; /* Cursors that are not yet positioned */
+ WhereBestIdx sWBI; /* Best index search context */
WhereMaskSet *pMaskSet; /* The expression mask set */
- WhereClause *pWC; /* Decomposition of the WHERE clause */
- struct SrcList_item *pTabItem; /* A single entry from pTabList */
- WhereLevel *pLevel; /* A single level in the pWInfo list */
- int iFrom; /* First unused FROM clause element */
+ WhereLevel *pLevel; /* A single level in pWInfo->a[] */
+ int iFrom; /* First unused FROM clause element */
int andFlags; /* AND-ed combination of all pWC->a[].wtFlags */
+ int ii; /* Loop counter */
sqlite3 *db; /* Database connection */
+
+ /* Variable initialization */
+ memset(&sWBI, 0, sizeof(sWBI));
+ sWBI.pParse = pParse;
+
/* The number of tables in the FROM clause is limited by the number of
** bits in a Bitmask
*/
@@ -4721,22 +4917,23 @@ WhereInfo *sqlite3WhereBegin(
pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList;
pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
- pWInfo->pWC = pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo];
+ pWInfo->pWC = sWBI.pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo];
pWInfo->wctrlFlags = wctrlFlags;
pWInfo->savedNQueryLoop = pParse->nQueryLoop;
- pMaskSet = (WhereMaskSet*)&pWC[1];
+ pMaskSet = (WhereMaskSet*)&sWBI.pWC[1];
+ sWBI.aLevel = pWInfo->a;
/* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via
** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */
- if( db->flags & SQLITE_DistinctOpt ) pDistinct = 0;
+ if( OptimizationDisabled(db, SQLITE_DistinctOpt) ) pDistinct = 0;
/* Split the WHERE clause into separate subexpressions where each
** subexpression is separated by an AND operator.
*/
initMaskSet(pMaskSet);
- whereClauseInit(pWC, pParse, pMaskSet, wctrlFlags);
+ whereClauseInit(sWBI.pWC, pParse, pMaskSet, wctrlFlags);
sqlite3ExprCodeConstants(pParse, pWhere);
- whereSplit(pWC, pWhere, TK_AND); /* IMP: R-15842-53296 */
+ whereSplit(sWBI.pWC, pWhere, TK_AND); /* IMP: R-15842-53296 */
/* Special case: a WHERE clause that is constant. Evaluate the
** expression and either jump over all of the code or fall thru.
@@ -4767,20 +4964,20 @@ WhereInfo *sqlite3WhereBegin(
** equal to pTabList->nSrc but might be shortened to 1 if the
** WHERE_ONETABLE_ONLY flag is set.
*/
- assert( pWC->vmask==0 && pMaskSet->n==0 );
- for(i=0; i<pTabList->nSrc; i++){
- createMask(pMaskSet, pTabList->a[i].iCursor);
+ assert( sWBI.pWC->vmask==0 && pMaskSet->n==0 );
+ for(ii=0; ii<pTabList->nSrc; ii++){
+ createMask(pMaskSet, pTabList->a[ii].iCursor);
#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( ALWAYS(pTabList->a[i].pTab) && IsVirtual(pTabList->a[i].pTab) ){
- pWC->vmask |= ((Bitmask)1 << i);
+ if( ALWAYS(pTabList->a[ii].pTab) && IsVirtual(pTabList->a[ii].pTab) ){
+ sWBI.pWC->vmask |= ((Bitmask)1 << ii);
}
#endif
}
#ifndef NDEBUG
{
Bitmask toTheLeft = 0;
- for(i=0; i<pTabList->nSrc; i++){
- Bitmask m = getMask(pMaskSet, pTabList->a[i].iCursor);
+ for(ii=0; ii<pTabList->nSrc; ii++){
+ Bitmask m = getMask(pMaskSet, pTabList->a[ii].iCursor);
assert( (m-1)==toTheLeft );
toTheLeft |= m;
}
@@ -4792,7 +4989,7 @@ WhereInfo *sqlite3WhereBegin(
** want to analyze these virtual terms, so start analyzing at the end
** and work forward so that the added virtual terms are never processed.
*/
- exprAnalyzeAll(pTabList, pWC);
+ exprAnalyzeAll(pTabList, sWBI.pWC);
if( db->mallocFailed ){
goto whereBeginError;
}
@@ -4801,7 +4998,7 @@ WhereInfo *sqlite3WhereBegin(
** If it is, then set pDistinct to NULL and WhereInfo.eDistinct to
** WHERE_DISTINCT_UNIQUE to tell the caller to ignore the DISTINCT.
*/
- if( pDistinct && isDistinctRedundant(pParse, pTabList, pWC, pDistinct) ){
+ if( pDistinct && isDistinctRedundant(pParse, pTabList, sWBI.pWC, pDistinct) ){
pDistinct = 0;
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
}
@@ -4821,10 +5018,13 @@ WhereInfo *sqlite3WhereBegin(
** This loop also figures out the nesting order of tables in the FROM
** clause.
*/
- notReady = ~(Bitmask)0;
+ sWBI.notValid = ~(Bitmask)0;
+ sWBI.pOrderBy = pOrderBy;
+ sWBI.n = nTabList;
+ sWBI.pDistinct = pDistinct;
andFlags = ~0;
WHERETRACE(("*** Optimizer Start ***\n"));
- for(i=iFrom=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){
+ for(sWBI.i=iFrom=0, pLevel=pWInfo->a; sWBI.i<nTabList; sWBI.i++, pLevel++){
WhereCost bestPlan; /* Most efficient plan seen so far */
Index *pIdx; /* Index for FROM table at pTabItem */
int j; /* For looping over FROM tables */
@@ -4836,7 +5036,7 @@ WhereInfo *sqlite3WhereBegin(
memset(&bestPlan, 0, sizeof(bestPlan));
bestPlan.rCost = SQLITE_BIG_DBL;
- WHERETRACE(("*** Begin search for loop %d ***\n", i));
+ WHERETRACE(("*** Begin search for loop %d ***\n", sWBI.i));
/* Loop through the remaining entries in the FROM clause to find the
** next nested loop. The loop tests all FROM clause entries
@@ -4852,8 +5052,8 @@ WhereInfo *sqlite3WhereBegin(
** by waiting for other tables to run first. This "optimal" test works
** by first assuming that the FROM clause is on the inner loop and finding
** its query plan, then checking to see if that query plan uses any
- ** other FROM clause terms that are notReady. If no notReady terms are
- ** used then the "optimal" query plan works.
+ ** other FROM clause terms that are sWBI.notValid. If no notValid terms
+ ** are used then the "optimal" query plan works.
**
** Note that the WhereCost.nRow parameter for an optimal scan might
** not be as small as it would be if the table really were the innermost
@@ -4884,58 +5084,64 @@ WhereInfo *sqlite3WhereBegin(
nUnconstrained = 0;
notIndexed = 0;
for(isOptimal=(iFrom<nTabList-1); isOptimal>=0 && bestJ<0; isOptimal--){
- Bitmask mask; /* Mask of tables not yet ready */
- for(j=iFrom, pTabItem=&pTabList->a[j]; j<nTabList; j++, pTabItem++){
+ for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; j<nTabList; j++, sWBI.pSrc++){
int doNotReorder; /* True if this table should not be reordered */
- WhereCost sCost; /* Cost information from best[Virtual]Index() */
- ExprList *pOrderBy; /* ORDER BY clause for index to optimize */
- ExprList *pDist; /* DISTINCT clause for index to optimize */
- doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0;
+ doNotReorder = (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0;
if( j!=iFrom && doNotReorder ) break;
- m = getMask(pMaskSet, pTabItem->iCursor);
- if( (m & notReady)==0 ){
+ m = getMask(pMaskSet, sWBI.pSrc->iCursor);
+ if( (m & sWBI.notValid)==0 ){
if( j==iFrom ) iFrom++;
continue;
}
- mask = (isOptimal ? m : notReady);
- pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0);
- pDist = (i==0 ? pDistinct : 0);
- if( pTabItem->pIndex==0 ) nUnconstrained++;
+ sWBI.notReady = (isOptimal ? m : sWBI.notValid);
+ if( sWBI.pSrc->pIndex==0 ) nUnconstrained++;
- WHERETRACE(("=== trying table %d with isOptimal=%d ===\n",
- j, isOptimal));
- assert( pTabItem->pTab );
+ WHERETRACE((" === trying table %d (%s) with isOptimal=%d ===\n",
+ j, sWBI.pSrc->pTab->zName, isOptimal));
+ assert( sWBI.pSrc->pTab );
#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( IsVirtual(pTabItem->pTab) ){
- sqlite3_index_info **pp = &pWInfo->a[j].pIdxInfo;
- bestVirtualIndex(pParse, pWC, pTabItem, mask, notReady, pOrderBy,
- &sCost, pp);
+ if( IsVirtual(sWBI.pSrc->pTab) ){
+ sWBI.ppIdxInfo = &pWInfo->a[j].pIdxInfo;
+ bestVirtualIndex(&sWBI);
}else
#endif
{
- bestBtreeIndex(pParse, pWC, pTabItem, mask, notReady, pOrderBy,
- pDist, &sCost);
+ bestBtreeIndex(&sWBI);
}
- assert( isOptimal || (sCost.used&notReady)==0 );
+ assert( isOptimal || (sWBI.cost.used&sWBI.notValid)==0 );
/* If an INDEXED BY clause is present, then the plan must use that
** index if it uses any index at all */
- assert( pTabItem->pIndex==0
- || (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0
- || sCost.plan.u.pIdx==pTabItem->pIndex );
+ assert( sWBI.pSrc->pIndex==0
+ || (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0
+ || sWBI.cost.plan.u.pIdx==sWBI.pSrc->pIndex );
- if( isOptimal && (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){
+ if( isOptimal && (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){
notIndexed |= m;
}
+ if( isOptimal ){
+ pWInfo->a[j].rOptCost = sWBI.cost.rCost;
+ }else if( iFrom<nTabList-1 ){
+ /* If two or more tables have nearly the same outer loop cost,
+ ** very different inner loop (optimal) cost, we want to choose
+ ** for the outer loop that table which benefits the least from
+ ** being in the inner loop. The following code scales the
+ ** outer loop cost estimate to accomplish that. */
+ WHERETRACE((" scaling cost from %.1f to %.1f\n",
+ sWBI.cost.rCost,
+ sWBI.cost.rCost/pWInfo->a[j].rOptCost));
+ sWBI.cost.rCost /= pWInfo->a[j].rOptCost;
+ }
/* Conditions under which this table becomes the best so far:
**
** (1) The table must not depend on other tables that have not
- ** yet run.
+ ** yet run. (In other words, it must not depend on tables
+ ** in inner loops.)
**
- ** (2) A full-table-scan plan cannot supercede indexed plan unless
- ** the full-table-scan is an "optimal" plan as defined above.
+ ** (2) (This rule was removed on 2012-11-09. The scaling of the
+ ** cost using the optimal scan cost made this rule obsolete.)
**
** (3) All tables have an INDEXED BY clause or this table lacks an
** INDEXED BY clause or this table uses the specific
@@ -4946,43 +5152,39 @@ WhereInfo *sqlite3WhereBegin(
** The NEVER() comes about because rule (2) above prevents
** An indexable full-table-scan from reaching rule (3).
**
- ** (4) The plan cost must be lower than prior plans or else the
- ** cost must be the same and the number of rows must be lower.
+ ** (4) The plan cost must be lower than prior plans, where "cost"
+ ** is defined by the compareCost() function above.
*/
- if( (sCost.used&notReady)==0 /* (1) */
- && (bestJ<0 || (notIndexed&m)!=0 /* (2) */
- || (bestPlan.plan.wsFlags & WHERE_NOT_FULLSCAN)==0
- || (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)
- && (nUnconstrained==0 || pTabItem->pIndex==0 /* (3) */
- || NEVER((sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0))
- && (bestJ<0 || sCost.rCost<bestPlan.rCost /* (4) */
- || (sCost.rCost<=bestPlan.rCost
- && sCost.plan.nRow<bestPlan.plan.nRow))
+ if( (sWBI.cost.used&sWBI.notValid)==0 /* (1) */
+ && (nUnconstrained==0 || sWBI.pSrc->pIndex==0 /* (3) */
+ || NEVER((sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0))
+ && (bestJ<0 || compareCost(&sWBI.cost, &bestPlan)) /* (4) */
){
- WHERETRACE(("=== table %d is best so far"
- " with cost=%g and nRow=%g\n",
- j, sCost.rCost, sCost.plan.nRow));
- bestPlan = sCost;
+ WHERETRACE((" === table %d (%s) is best so far\n"
+ " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=%08x\n",
+ j, sWBI.pSrc->pTab->zName,
+ sWBI.cost.rCost, sWBI.cost.plan.nRow,
+ sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags));
+ bestPlan = sWBI.cost;
bestJ = j;
}
if( doNotReorder ) break;
}
}
assert( bestJ>=0 );
- assert( notReady & getMask(pMaskSet, pTabList->a[bestJ].iCursor) );
- WHERETRACE(("*** Optimizer selects table %d for loop %d"
- " with cost=%g and nRow=%g\n",
- bestJ, pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow));
- /* The ALWAYS() that follows was added to hush up clang scan-build */
- if( (bestPlan.plan.wsFlags & WHERE_ORDERBY)!=0 && ALWAYS(ppOrderBy) ){
- *ppOrderBy = 0;
- }
+ assert( sWBI.notValid & getMask(pMaskSet, pTabList->a[bestJ].iCursor) );
+ WHERETRACE(("*** Optimizer selects table %d (%s) for loop %d with:\n"
+ " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=0x%08x\n",
+ bestJ, pTabList->a[bestJ].pTab->zName,
+ pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow,
+ bestPlan.plan.nOBSat, bestPlan.plan.wsFlags));
if( (bestPlan.plan.wsFlags & WHERE_DISTINCT)!=0 ){
assert( pWInfo->eDistinct==0 );
pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
}
andFlags &= bestPlan.plan.wsFlags;
pLevel->plan = bestPlan.plan;
+ pLevel->iTabCur = pTabList->a[bestJ].iCursor;
testcase( bestPlan.plan.wsFlags & WHERE_INDEXED );
testcase( bestPlan.plan.wsFlags & WHERE_TEMP_INDEX );
if( bestPlan.plan.wsFlags & (WHERE_INDEXED|WHERE_TEMP_INDEX) ){
@@ -4996,7 +5198,7 @@ WhereInfo *sqlite3WhereBegin(
}else{
pLevel->iIdxCur = -1;
}
- notReady &= ~getMask(pMaskSet, pTabList->a[bestJ].iCursor);
+ sWBI.notValid &= ~getMask(pMaskSet, pTabList->a[bestJ].iCursor);
pLevel->iFrom = (u8)bestJ;
if( bestPlan.plan.nRow>=(double)1 ){
pParse->nQueryLoop *= bestPlan.plan.nRow;
@@ -5024,12 +5226,19 @@ WhereInfo *sqlite3WhereBegin(
if( pParse->nErr || db->mallocFailed ){
goto whereBeginError;
}
+ if( nTabList ){
+ pLevel--;
+ pWInfo->nOBSat = pLevel->plan.nOBSat;
+ }else{
+ pWInfo->nOBSat = 0;
+ }
/* If the total query only selects a single row, then the ORDER BY
** clause is irrelevant.
*/
- if( (andFlags & WHERE_UNIQUE)!=0 && ppOrderBy ){
- *ppOrderBy = 0;
+ if( (andFlags & WHERE_UNIQUE)!=0 && pOrderBy ){
+ assert( nTabList==0 || (pLevel->plan.wsFlags & WHERE_ALL_UNIQUE)!=0 );
+ pWInfo->nOBSat = pOrderBy->nExpr;
}
/* If the caller is an UPDATE or DELETE statement that is requesting
@@ -5049,13 +5258,13 @@ WhereInfo *sqlite3WhereBegin(
sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
notReady = ~(Bitmask)0;
pWInfo->nRowOut = (double)1;
- for(i=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){
+ for(ii=0, pLevel=pWInfo->a; ii<nTabList; ii++, pLevel++){
Table *pTab; /* Table to open */
int iDb; /* Index of database containing table/index */
+ struct SrcList_item *pTabItem;
pTabItem = &pTabList->a[pLevel->iFrom];
pTab = pTabItem->pTab;
- pLevel->iTabCur = pTabItem->iCursor;
pWInfo->nRowOut *= pLevel->plan.nRow;
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ){
@@ -5066,6 +5275,8 @@ WhereInfo *sqlite3WhereBegin(
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
int iCur = pTabItem->iCursor;
sqlite3VdbeAddOp4(v, OP_VOpen, iCur, 0, 0, pVTab, P4_VTAB);
+ }else if( IsVirtual(pTab) ){
+ /* noop */
}else
#endif
if( (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0
@@ -5087,7 +5298,7 @@ WhereInfo *sqlite3WhereBegin(
}
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
if( (pLevel->plan.wsFlags & WHERE_TEMP_INDEX)!=0 ){
- constructAutomaticIndex(pParse, pWC, pTabItem, notReady, pLevel);
+ constructAutomaticIndex(pParse, sWBI.pWC, pTabItem, notReady, pLevel);
}else
#endif
if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
@@ -5101,7 +5312,7 @@ WhereInfo *sqlite3WhereBegin(
VdbeComment((v, "%s", pIx->zName));
}
sqlite3CodeVerifySchema(pParse, iDb);
- notReady &= ~getMask(pWC->pMaskSet, pTabItem->iCursor);
+ notReady &= ~getMask(sWBI.pWC->pMaskSet, pTabItem->iCursor);
}
pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
if( db->mallocFailed ) goto whereBeginError;
@@ -5111,10 +5322,10 @@ WhereInfo *sqlite3WhereBegin(
** program.
*/
notReady = ~(Bitmask)0;
- for(i=0; i<nTabList; i++){
- pLevel = &pWInfo->a[i];
- explainOneScan(pParse, pTabList, pLevel, i, pLevel->iFrom, wctrlFlags);
- notReady = codeOneLoopStart(pWInfo, i, wctrlFlags, notReady);
+ for(ii=0; ii<nTabList; ii++){
+ pLevel = &pWInfo->a[ii];
+ explainOneScan(pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags);
+ notReady = codeOneLoopStart(pWInfo, ii, wctrlFlags, notReady);
pWInfo->iContinue = pLevel->addrCont;
}
@@ -5125,16 +5336,20 @@ WhereInfo *sqlite3WhereBegin(
** the index is listed as "{}". If the primary key is used the
** index name is '*'.
*/
- for(i=0; i<nTabList; i++){
+ for(ii=0; ii<nTabList; ii++){
char *z;
int n;
- pLevel = &pWInfo->a[i];
+ int w;
+ struct SrcList_item *pTabItem;
+
+ pLevel = &pWInfo->a[ii];
+ w = pLevel->plan.wsFlags;
pTabItem = &pTabList->a[pLevel->iFrom];
z = pTabItem->zAlias;
if( z==0 ) z = pTabItem->pTab->zName;
n = sqlite3Strlen30(z);
if( n+nQPlan < sizeof(sqlite3_query_plan)-10 ){
- if( pLevel->plan.wsFlags & WHERE_IDX_ONLY ){
+ if( (w & WHERE_IDX_ONLY)!=0 && (w & WHERE_COVER_SCAN)==0 ){
memcpy(&sqlite3_query_plan[nQPlan], "{}", 2);
nQPlan += 2;
}else{
@@ -5143,12 +5358,12 @@ WhereInfo *sqlite3WhereBegin(
}
sqlite3_query_plan[nQPlan++] = ' ';
}
- testcase( pLevel->plan.wsFlags & WHERE_ROWID_EQ );
- testcase( pLevel->plan.wsFlags & WHERE_ROWID_RANGE );
- if( pLevel->plan.wsFlags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
+ testcase( w & WHERE_ROWID_EQ );
+ testcase( w & WHERE_ROWID_RANGE );
+ if( w & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
memcpy(&sqlite3_query_plan[nQPlan], "* ", 2);
nQPlan += 2;
- }else if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
+ }else if( (w & WHERE_INDEXED)!=0 && (w & WHERE_COVER_SCAN)==0 ){
n = sqlite3Strlen30(pLevel->plan.u.pIdx->zName);
if( n+nQPlan < sizeof(sqlite3_query_plan)-2 ){
memcpy(&sqlite3_query_plan[nQPlan], pLevel->plan.u.pIdx->zName, n);