aboutsummaryrefslogtreecommitdiff
path: root/src/wherecode.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/wherecode.c')
-rw-r--r--src/wherecode.c76
1 files changed, 63 insertions, 13 deletions
diff --git a/src/wherecode.c b/src/wherecode.c
index 9d53a20a6..f5f45da39 100644
--- a/src/wherecode.c
+++ b/src/wherecode.c
@@ -76,7 +76,7 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){
for(i=0; i<nEq; i++){
const char *z = explainIndexColumnName(pIndex, i);
if( i ) sqlite3StrAccumAppend(pStr, " AND ", 5);
- sqlite3XPrintf(pStr, 0, i>=nSkip ? "%s=?" : "ANY(%s)", z);
+ sqlite3XPrintf(pStr, i>=nSkip ? "%s=?" : "ANY(%s)", z);
}
j = i;
@@ -135,13 +135,13 @@ int sqlite3WhereExplainOneScan(
sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN");
if( pItem->pSelect ){
- sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId);
+ sqlite3XPrintf(&str, " SUBQUERY %d", pItem->iSelectId);
}else{
- sqlite3XPrintf(&str, 0, " TABLE %s", pItem->zName);
+ sqlite3XPrintf(&str, " TABLE %s", pItem->zName);
}
if( pItem->zAlias ){
- sqlite3XPrintf(&str, 0, " AS %s", pItem->zAlias);
+ sqlite3XPrintf(&str, " AS %s", pItem->zAlias);
}
if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){
const char *zFmt = 0;
@@ -165,7 +165,7 @@ int sqlite3WhereExplainOneScan(
}
if( zFmt ){
sqlite3StrAccumAppend(&str, " USING ", 7);
- sqlite3XPrintf(&str, 0, zFmt, pIdx->zName);
+ sqlite3XPrintf(&str, zFmt, pIdx->zName);
explainIndexRange(&str, pLoop);
}
}else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){
@@ -180,17 +180,17 @@ int sqlite3WhereExplainOneScan(
assert( flags&WHERE_TOP_LIMIT);
zRangeOp = "<";
}
- sqlite3XPrintf(&str, 0, " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp);
+ sqlite3XPrintf(&str, " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp);
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
- sqlite3XPrintf(&str, 0, " VIRTUAL TABLE INDEX %d:%s",
+ sqlite3XPrintf(&str, " VIRTUAL TABLE INDEX %d:%s",
pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
}
#endif
#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS
if( pLoop->nOut>=10 ){
- sqlite3XPrintf(&str, 0, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut));
+ sqlite3XPrintf(&str, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut));
}else{
sqlite3StrAccumAppend(&str, " (~1 row)", 9);
}
@@ -747,6 +747,54 @@ static void codeCursorHint(
#endif /* SQLITE_ENABLE_CURSOR_HINTS */
/*
+** Cursor iCur is open on an intkey b-tree (a table). Register iRowid contains
+** a rowid value just read from cursor iIdxCur, open on index pIdx. This
+** function generates code to do a deferred seek of cursor iCur to the
+** rowid stored in register iRowid.
+**
+** Normally, this is just:
+**
+** OP_Seek $iCur $iRowid
+**
+** However, if the scan currently being coded is a branch of an OR-loop and
+** the statement currently being coded is a SELECT, then P3 of the OP_Seek
+** is set to iIdxCur and P4 is set to point to an array of integers
+** containing one entry for each column of the table cursor iCur is open
+** on. For each table column, if the column is the i'th column of the
+** index, then the corresponding array entry is set to (i+1). If the column
+** does not appear in the index at all, the array entry is set to 0.
+*/
+static void codeDeferredSeek(
+ WhereInfo *pWInfo, /* Where clause context */
+ Index *pIdx, /* Index scan is using */
+ int iCur, /* Cursor for IPK b-tree */
+ int iIdxCur /* Index cursor */
+){
+ Parse *pParse = pWInfo->pParse; /* Parse context */
+ Vdbe *v = pParse->pVdbe; /* Vdbe to generate code within */
+
+ assert( iIdxCur>0 );
+ assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 );
+
+ sqlite3VdbeAddOp3(v, OP_Seek, iIdxCur, 0, iCur);
+ if( (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)
+ && DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask)
+ ){
+ int i;
+ Table *pTab = pIdx->pTable;
+ int *ai = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*(pTab->nCol+1));
+ if( ai ){
+ ai[0] = pTab->nCol;
+ for(i=0; i<pIdx->nColumn-1; i++){
+ assert( pIdx->aiColumn[i]<pTab->nCol );
+ if( pIdx->aiColumn[i]>=0 ) ai[pIdx->aiColumn[i]+1] = i+1;
+ }
+ sqlite3VdbeChangeP4(v, -1, (char*)ai, P4_INTARRAY);
+ }
+ }
+}
+
+/*
** Generate code for the start of the iLevel-th loop in the WHERE clause
** implementation described by pWInfo.
*/
@@ -1225,14 +1273,14 @@ Bitmask sqlite3WhereCodeOneLoopStart(
if( omitTable ){
/* pIdx is a covering index. No need to access the main table. */
}else if( HasRowid(pIdx->pTable) ){
- iRowidReg = ++pParse->nMem;
- sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
- sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
if( pWInfo->eOnePass!=ONEPASS_OFF ){
+ iRowidReg = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
+ sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg);
VdbeCoverage(v);
}else{
- sqlite3VdbeAddOp2(v, OP_Seek, iCur, iRowidReg); /* Deferred seek */
+ codeDeferredSeek(pWInfo, pIdx, iCur, iIdxCur);
}
}else if( iCur!=iIdxCur ){
Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
@@ -1401,7 +1449,9 @@ Bitmask sqlite3WhereCodeOneLoopStart(
Expr *pExpr = pWC->a[iTerm].pExpr;
if( &pWC->a[iTerm] == pTerm ) continue;
if( ExprHasProperty(pExpr, EP_FromJoin) ) continue;
- if( (pWC->a[iTerm].wtFlags & TERM_VIRTUAL)!=0 ) continue;
+ testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL );
+ testcase( pWC->a[iTerm].wtFlags & TERM_CODED );
+ if( (pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_CODED))!=0 ) continue;
if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue;
testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO );
pExpr = sqlite3ExprDup(db, pExpr, 0);