diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/analyze.c | 33 | ||||
-rw-r--r-- | src/build.c | 59 | ||||
-rw-r--r-- | src/delete.c | 35 | ||||
-rw-r--r-- | src/expr.c | 94 | ||||
-rw-r--r-- | src/insert.c | 25 | ||||
-rw-r--r-- | src/loadext.c | 29 | ||||
-rw-r--r-- | src/main.c | 3 | ||||
-rw-r--r-- | src/os_win.c | 84 | ||||
-rw-r--r-- | src/parse.y | 4 | ||||
-rw-r--r-- | src/pragma.c | 58 | ||||
-rw-r--r-- | src/prepare.c | 6 | ||||
-rw-r--r-- | src/resolve.c | 113 | ||||
-rw-r--r-- | src/select.c | 4 | ||||
-rw-r--r-- | src/shell.c | 23 | ||||
-rw-r--r-- | src/sqlite.h.in | 91 | ||||
-rw-r--r-- | src/sqliteInt.h | 43 | ||||
-rw-r--r-- | src/test_autoext.c | 54 | ||||
-rw-r--r-- | src/test_vfs.c | 1 | ||||
-rw-r--r-- | src/update.c | 2 | ||||
-rw-r--r-- | src/vdbe.c | 38 | ||||
-rw-r--r-- | src/vdbe.h | 5 | ||||
-rw-r--r-- | src/vdbeInt.h | 37 | ||||
-rw-r--r-- | src/vdbeapi.c | 43 | ||||
-rw-r--r-- | src/vdbeaux.c | 59 | ||||
-rw-r--r-- | src/vtab.c | 4 | ||||
-rw-r--r-- | src/where.c | 244 |
26 files changed, 795 insertions, 396 deletions
diff --git a/src/analyze.c b/src/analyze.c index 78bbf28b4..d25a9b196 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -441,6 +441,7 @@ static void analyzeOneTable( int endOfLoop; /* The end of the loop */ int jZeroRows = -1; /* Jump from here if number of rows is zero */ int iDb; /* Index of database containing pTab */ + u8 needTableCnt = 1; /* True to count the table */ int regTabname = iMem++; /* Register containing table name */ int regIdxname = iMem++; /* Register containing index name */ int regStat1 = iMem++; /* The stat column of sqlite_stat1 */ @@ -500,6 +501,7 @@ static void analyzeOneTable( int *aChngAddr; /* Array of jump instruction addresses */ if( pOnlyIdx && pOnlyIdx!=pIdx ) continue; + if( pIdx->pPartIdxWhere==0 ) needTableCnt = 0; VdbeNoopComment((v, "Begin analysis of %s", pIdx->zName)); nCol = pIdx->nColumn; aChngAddr = sqlite3DbMallocRaw(db, sizeof(int)*nCol); @@ -659,9 +661,7 @@ static void analyzeOneTable( ** is never possible. */ sqlite3VdbeAddOp2(v, OP_SCopy, iMem, regStat1); - if( jZeroRows<0 ){ - jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, iMem); - } + jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, iMem); for(i=0; i<nCol; i++){ sqlite3VdbeAddOp4(v, OP_String8, 0, regTemp, 0, " ", 0); sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regStat1, regStat1); @@ -671,32 +671,31 @@ static void analyzeOneTable( sqlite3VdbeAddOp1(v, OP_ToInt, regTemp); sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regStat1, regStat1); } + if( pIdx->pPartIdxWhere!=0 ) sqlite3VdbeJumpHere(v, jZeroRows); sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regNewRowid); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); + if( pIdx->pPartIdxWhere==0 ) sqlite3VdbeJumpHere(v, jZeroRows); } - /* If the table has no indices, create a single sqlite_stat1 entry - ** containing NULL as the index name and the row count as the content. + /* Create a single sqlite_stat1 entry containing NULL as the index + ** name and the row count as the content. */ - if( pTab->pIndex==0 ){ + if( pOnlyIdx==0 && needTableCnt ){ sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pTab->tnum, iDb); VdbeComment((v, "%s", pTab->zName)); sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat1); sqlite3VdbeAddOp1(v, OP_Close, iIdxCur); jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, regStat1); - }else{ + sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname); + sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0); + sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); + sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regNewRowid); + sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3VdbeJumpHere(v, jZeroRows); - jZeroRows = sqlite3VdbeAddOp0(v, OP_Goto); } - sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname); - sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0); - sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); - sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regNewRowid); - sqlite3VdbeChangeP5(v, OPFLAG_APPEND); if( pParse->nMem<regRec ) pParse->nMem = regRec; - sqlite3VdbeJumpHere(v, jZeroRows); } @@ -879,8 +878,10 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){ v = v*10 + c - '0'; z++; } - if( i==0 ) pTable->nRowEst = v; - if( pIndex==0 ) break; + if( i==0 && (pIndex==0 || pIndex->pPartIdxWhere==0) ){ + if( v>0 ) pTable->nRowEst = v; + if( pIndex==0 ) break; + } pIndex->aiRowEst[i] = v; if( *z==' ' ) z++; if( strcmp(z, "unordered")==0 ){ diff --git a/src/build.c b/src/build.c index 0a3922c95..06ecf6570 100644 --- a/src/build.c +++ b/src/build.c @@ -382,6 +382,7 @@ static void freeIndex(sqlite3 *db, Index *p){ #ifndef SQLITE_OMIT_ANALYZE sqlite3DeleteIndexSamples(db, p); #endif + sqlite3ExprDelete(db, p->pPartIdxWhere); sqlite3DbFree(db, p->zColAff); sqlite3DbFree(db, p); } @@ -1225,7 +1226,8 @@ void sqlite3AddPrimaryKey( #endif }else{ Index *p; - p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0); + p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, + 0, sortOrder, 0); if( p ){ p->autoIndex = 2; } @@ -1520,26 +1522,7 @@ void sqlite3EndTable( /* Resolve names in all CHECK constraint expressions. */ if( p->pCheck ){ - SrcList sSrc; /* Fake SrcList for pParse->pNewTable */ - NameContext sNC; /* Name context for pParse->pNewTable */ - ExprList *pList; /* List of all CHECK constraints */ - int i; /* Loop counter */ - - memset(&sNC, 0, sizeof(sNC)); - memset(&sSrc, 0, sizeof(sSrc)); - sSrc.nSrc = 1; - sSrc.a[0].zName = p->zName; - sSrc.a[0].pTab = p; - sSrc.a[0].iCursor = -1; - sNC.pParse = pParse; - sNC.pSrcList = &sSrc; - sNC.ncFlags = NC_IsCheck; - pList = p->pCheck; - for(i=0; i<pList->nExpr; i++){ - if( sqlite3ResolveExprNames(&sNC, pList->a[i].pExpr) ){ - return; - } - } + sqlite3ResolveSelfReference(pParse, p, NC_IsCheck, 0, p->pCheck); } #endif /* !defined(SQLITE_OMIT_CHECK) */ @@ -2391,6 +2374,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ int addr1; /* Address of top of loop */ int addr2; /* Address to jump to for next iteration */ int tnum; /* Root page of index */ + int iPartIdxLabel; /* Jump to this label to skip a row */ Vdbe *v; /* Generate code into this virtual machine */ KeyInfo *pKey; /* KeyInfo for index */ int regRecord; /* Register holding assemblied index record */ @@ -2430,8 +2414,9 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); regRecord = sqlite3GetTempReg(pParse); - sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 1); + sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 1, &iPartIdxLabel); sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord); + sqlite3VdbeResolveLabel(v, iPartIdxLabel); sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); sqlite3VdbeJumpHere(v, addr1); addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); @@ -2482,7 +2467,7 @@ Index *sqlite3CreateIndex( ExprList *pList, /* A list of columns to be indexed */ int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ Token *pStart, /* The CREATE token that begins this statement */ - Token *pEnd, /* The ")" that closes the CREATE INDEX statement */ + Expr *pPIWhere, /* WHERE clause for partial indices */ int sortOrder, /* Sort order of primary key when pList==NULL */ int ifNotExist /* Omit error if index already exists */ ){ @@ -2504,7 +2489,6 @@ Index *sqlite3CreateIndex( int nExtra = 0; char *zExtra; - assert( pStart==0 || pEnd!=0 ); /* pEnd must be non-NULL if pStart is */ assert( pParse->nErr==0 ); /* Never called with prior errors */ if( db->mallocFailed || IN_DECLARE_VTAB ){ goto exit_create_index; @@ -2550,7 +2534,12 @@ Index *sqlite3CreateIndex( 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 ); + if( iDb==1 && db->aDb[iDb].pSchema!=pTab->pSchema ){ + sqlite3ErrorMsg(pParse, + "cannot create a TEMP index on non-TEMP table \"%s\"", + pTab->zName); + goto exit_create_index; + } }else{ assert( pName==0 ); assert( pStart==0 ); @@ -2699,6 +2688,11 @@ Index *sqlite3CreateIndex( pIndex->uniqNotNull = onError==OE_Abort; pIndex->autoIndex = (u8)(pName==0); pIndex->pSchema = db->aDb[iDb].pSchema; + if( pPIWhere ){ + sqlite3ResolveSelfReference(pParse, pTab, NC_PartIdx, pPIWhere, 0); + pIndex->pPartIdxWhere = pPIWhere; + pPIWhere = 0; + } assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); /* Check to see if we should honor DESC requests on index columns @@ -2854,7 +2848,7 @@ Index *sqlite3CreateIndex( ** has just been created, it contains no data and the index initialization ** step can be skipped. */ - else{ /* if( db->init.busy==0 ) */ + else if( pParse->nErr==0 ){ Vdbe *v; char *zStmt; int iMem = ++pParse->nMem; @@ -2872,12 +2866,11 @@ Index *sqlite3CreateIndex( ** the zStmt variable */ if( pStart ){ - assert( pEnd!=0 ); + int n = (pParse->sLastToken.z - pName->z) + pParse->sLastToken.n; + if( pName->z[n-1]==';' ) n--; /* A named index with an explicit CREATE INDEX statement */ zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s", - onError==OE_None ? "" : " UNIQUE", - (int)(pEnd->z - pName->z) + 1, - pName->z); + onError==OE_None ? "" : " UNIQUE", n, pName->z); }else{ /* An automatic index created by a PRIMARY KEY or UNIQUE constraint */ /* zStmt = sqlite3MPrintf(""); */ @@ -2933,10 +2926,8 @@ Index *sqlite3CreateIndex( /* Clean up before exiting */ exit_create_index: - if( pIndex ){ - sqlite3DbFree(db, pIndex->zColAff); - sqlite3DbFree(db, pIndex); - } + if( pIndex ) freeIndex(db, pIndex); + sqlite3ExprDelete(db, pPIWhere); sqlite3ExprListDelete(db, pList); sqlite3SrcListDelete(db, pTblName); sqlite3DbFree(db, zName); diff --git a/src/delete.c b/src/delete.c index 0bd9496d6..99891e737 100644 --- a/src/delete.c +++ b/src/delete.c @@ -603,11 +603,14 @@ void sqlite3GenerateRowIndexDelete( int i; Index *pIdx; int r1; + int iPartIdxLabel; + Vdbe *v = pParse->pVdbe; for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ if( aRegIdx!=0 && aRegIdx[i-1]==0 ) continue; - r1 = sqlite3GenerateIndexKey(pParse, pIdx, iCur, 0, 0); - sqlite3VdbeAddOp3(pParse->pVdbe, OP_IdxDelete, iCur+i, r1,pIdx->nColumn+1); + r1 = sqlite3GenerateIndexKey(pParse, pIdx, iCur, 0, 0, &iPartIdxLabel); + sqlite3VdbeAddOp3(v, OP_IdxDelete, iCur+i, r1, pIdx->nColumn+1); + sqlite3VdbeResolveLabel(v, iPartIdxLabel); } } @@ -621,13 +624,21 @@ void sqlite3GenerateRowIndexDelete( ** registers that holds the elements of the index key. The ** block of registers has already been deallocated by the time ** this routine returns. +** +** If *piPartIdxLabel is not NULL, fill it in with a label and jump +** to that label if pIdx is a partial index that should be skipped. +** A partial index should be skipped if its WHERE clause evaluates +** to false or null. If pIdx is not a partial index, *piPartIdxLabel +** will be set to zero which is an empty label that is ignored by +** sqlite3VdbeResolveLabel(). */ int sqlite3GenerateIndexKey( - Parse *pParse, /* Parsing context */ - Index *pIdx, /* The index for which to generate a key */ - int iCur, /* Cursor number for the pIdx->pTable table */ - int regOut, /* Write the new index key to this register */ - int doMakeRec /* Run the OP_MakeRecord instruction if true */ + Parse *pParse, /* Parsing context */ + Index *pIdx, /* The index for which to generate a key */ + int iCur, /* Cursor number for the pIdx->pTable table */ + int regOut, /* Write the new index key to this register */ + int doMakeRec, /* Run the OP_MakeRecord instruction if true */ + int *piPartIdxLabel /* OUT: Jump to this label to skip partial index */ ){ Vdbe *v = pParse->pVdbe; int j; @@ -635,6 +646,16 @@ int sqlite3GenerateIndexKey( int regBase; int nCol; + if( piPartIdxLabel ){ + if( pIdx->pPartIdxWhere ){ + *piPartIdxLabel = sqlite3VdbeMakeLabel(v); + pParse->iPartIdxTab = iCur; + sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, + SQLITE_JUMPIFNULL); + }else{ + *piPartIdxLabel = 0; + } + } nCol = pIdx->nColumn; regBase = sqlite3GetTempRange(pParse, nCol+1); sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regBase+nCol); diff --git a/src/expr.c b/src/expr.c index 2c0419aa2..e7ac855f7 100644 --- a/src/expr.c +++ b/src/expr.c @@ -2362,15 +2362,20 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ /* Otherwise, fall thru into the TK_COLUMN case */ } case TK_COLUMN: { - if( pExpr->iTable<0 ){ - /* This only happens when coding check constraints */ - assert( pParse->ckBase>0 ); - inReg = pExpr->iColumn + pParse->ckBase; - }else{ - inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab, - pExpr->iColumn, pExpr->iTable, target, - pExpr->op2); + int iTab = pExpr->iTable; + if( iTab<0 ){ + if( pParse->ckBase>0 ){ + /* Generating CHECK constraints or inserting into partial index */ + inReg = pExpr->iColumn + pParse->ckBase; + break; + }else{ + /* Deleting from a partial index */ + iTab = pParse->iPartIdxTab; + } } + inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab, + pExpr->iColumn, iTab, target, + pExpr->op2); break; } case TK_INTEGER: { @@ -3793,6 +3798,12 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ ** by a COLLATE operator at the top level. Return 2 if there are differences ** other than the top-level COLLATE operator. ** +** If any subelement of pB has Expr.iTable==(-1) then it is allowed +** to compare equal to an equivalent element in pA with Expr.iTable==iTab. +** +** The pA side might be using TK_REGISTER. If that is the case and pB is +** not using TK_REGISTER but is otherwise equivalent, then still return 0. +** ** Sometimes this routine will return 2 even if the two expressions ** really are equivalent. If we cannot prove that the expressions are ** identical, we return 2 just to be safe. So if this routine @@ -3803,7 +3814,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ ** just might result in some slightly slower code. But returning ** an incorrect 0 or 1 could lead to a malfunction. */ -int sqlite3ExprCompare(Expr *pA, Expr *pB){ +int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){ if( pA==0||pB==0 ){ return pB==pA ? 0 : 2; } @@ -3813,19 +3824,22 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){ return 2; } if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2; - if( pA->op!=pB->op ){ - if( pA->op==TK_COLLATE && sqlite3ExprCompare(pA->pLeft, pB)<2 ){ + if( pA->op!=pB->op && (pA->op!=TK_REGISTER || pA->op2!=pB->op) ){ + if( pA->op==TK_COLLATE && sqlite3ExprCompare(pA->pLeft, pB, iTab)<2 ){ return 1; } - if( pB->op==TK_COLLATE && sqlite3ExprCompare(pA, pB->pLeft)<2 ){ + if( pB->op==TK_COLLATE && sqlite3ExprCompare(pA, pB->pLeft, iTab)<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; - if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 2; + if( sqlite3ExprCompare(pA->pLeft, pB->pLeft, iTab) ) return 2; + if( sqlite3ExprCompare(pA->pRight, pB->pRight, iTab) ) return 2; + if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2; + if( pA->iColumn!=pB->iColumn ) return 2; + if( pA->iTable!=pB->iTable + && pA->op!=TK_REGISTER + && (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2; if( ExprHasProperty(pA, EP_IntValue) ){ if( !ExprHasProperty(pB, EP_IntValue) || pA->u.iValue!=pB->u.iValue ){ return 2; @@ -3843,6 +3857,9 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){ ** Compare two ExprList objects. Return 0 if they are identical and ** non-zero if they differ in any way. ** +** If any subelement of pB has Expr.iTable==(-1) then it is allowed +** to compare equal to an equivalent element in pA with Expr.iTable==iTab. +** ** This routine might return non-zero for equivalent ExprLists. The ** only consequence will be disabled optimizations. But this routine ** must never return 0 if the two ExprList objects are different, or @@ -3851,7 +3868,7 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){ ** Two NULL pointers are considered to be the same. But a NULL pointer ** always differs from a non-NULL pointer. */ -int sqlite3ExprListCompare(ExprList *pA, ExprList *pB){ +int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){ int i; if( pA==0 && pB==0 ) return 0; if( pA==0 || pB==0 ) return 1; @@ -3860,7 +3877,46 @@ int sqlite3ExprListCompare(ExprList *pA, ExprList *pB){ Expr *pExprA = pA->a[i].pExpr; Expr *pExprB = pB->a[i].pExpr; if( pA->a[i].sortOrder!=pB->a[i].sortOrder ) return 1; - if( sqlite3ExprCompare(pExprA, pExprB) ) return 1; + if( sqlite3ExprCompare(pExprA, pExprB, iTab) ) return 1; + } + return 0; +} + +/* +** Return true if we can prove the pE2 will always be true if pE1 is +** true. Return false if we cannot complete the proof or if pE2 might +** be false. Examples: +** +** pE1: x==5 pE2: x==5 Result: true +** pE1: x>0 pE2: x==5 Result: false +** pE1: x=21 pE2: x=21 OR y=43 Result: true +** pE1: x!=123 pE2: x IS NOT NULL Result: true +** pE1: x!=?1 pE2: x IS NOT NULL Result: true +** pE1: x IS NULL pE2: x IS NOT NULL Result: false +** pE1: x IS ?2 pE2: x IS NOT NULL Reuslt: false +** +** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has +** Expr.iTable<0 then assume a table number given by iTab. +** +** When in doubt, return false. Returning true might give a performance +** improvement. Returning false might cause a performance reduction, but +** it will always give the correct answer and is hence always safe. +*/ +int sqlite3ExprImpliesExpr(Expr *pE1, Expr *pE2, int iTab){ + if( sqlite3ExprCompare(pE1, pE2, iTab)==0 ){ + return 1; + } + if( pE2->op==TK_OR + && (sqlite3ExprImpliesExpr(pE1, pE2->pLeft, iTab) + || sqlite3ExprImpliesExpr(pE1, pE2->pRight, iTab) ) + ){ + return 1; + } + if( pE2->op==TK_NOTNULL + && sqlite3ExprCompare(pE1->pLeft, pE2->pLeft, iTab)==0 + && (pE1->op!=TK_ISNULL && pE1->op!=TK_IS) + ){ + return 1; } return 0; } @@ -4045,7 +4101,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ */ struct AggInfo_func *pItem = pAggInfo->aFunc; for(i=0; i<pAggInfo->nFunc; i++, pItem++){ - if( sqlite3ExprCompare(pItem->pExpr, pExpr)==0 ){ + if( sqlite3ExprCompare(pItem->pExpr, pExpr, -1)==0 ){ break; } } diff --git a/src/insert.c b/src/insert.c index 140b43600..b64a3a1af 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1389,9 +1389,19 @@ void sqlite3GenerateConstraintChecks( for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){ int regIdx; int regR; + int addrSkipRow = 0; if( aRegIdx[iCur]==0 ) continue; /* Skip unused indices */ + if( pIdx->pPartIdxWhere ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[iCur]); + addrSkipRow = sqlite3VdbeMakeLabel(v); + pParse->ckBase = regData; + sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrSkipRow, + SQLITE_JUMPIFNULL); + pParse->ckBase = 0; + } + /* Create a key for accessing the index entry */ regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn+1); for(i=0; i<pIdx->nColumn; i++){ @@ -1411,6 +1421,7 @@ void sqlite3GenerateConstraintChecks( onError = pIdx->onError; if( onError==OE_None ){ sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1); + sqlite3VdbeResolveLabel(v, addrSkipRow); continue; /* pIdx is not a UNIQUE index */ } if( overrideError!=OE_Default ){ @@ -1480,6 +1491,7 @@ void sqlite3GenerateConstraintChecks( } } sqlite3VdbeJumpHere(v, j3); + sqlite3VdbeResolveLabel(v, addrSkipRow); sqlite3ReleaseTempReg(pParse, regR); } @@ -1509,7 +1521,6 @@ void sqlite3CompleteInsertion( ){ int i; Vdbe *v; - int nIdx; Index *pIdx; u8 pik_flags; int regData; @@ -1518,9 +1529,11 @@ void sqlite3CompleteInsertion( v = sqlite3GetVdbe(pParse); assert( v!=0 ); assert( pTab->pSelect==0 ); /* This table is not a VIEW */ - for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){} - for(i=nIdx-1; i>=0; i--){ + for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ if( aRegIdx[i]==0 ) continue; + if( pIdx->pPartIdxWhere ){ + sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2); + } sqlite3VdbeAddOp2(v, OP_IdxInsert, baseCur+i+1, aRegIdx[i]); if( useSeekResult ){ sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); @@ -1622,6 +1635,7 @@ static int xferCompatibleCollation(const char *z1, const char *z2){ ** * The same DESC and ASC markings occurs on all columns ** * The same onError processing (OE_Abort, OE_Ignore, etc) ** * The same collating sequence on each column +** * The index has the exact same WHERE clause */ static int xferCompatibleIndex(Index *pDest, Index *pSrc){ int i; @@ -1644,6 +1658,9 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){ return 0; /* Different collating sequences */ } } + if( sqlite3ExprCompare(pSrc->pPartIdxWhere, pDest->pPartIdxWhere, -1) ){ + return 0; /* Different WHERE clauses */ + } /* If no test above fails then the indices must be compatible */ return 1; @@ -1799,7 +1816,7 @@ static int xferOptimization( } } #ifndef SQLITE_OMIT_CHECK - if( pDest->pCheck && sqlite3ExprListCompare(pSrc->pCheck, pDest->pCheck) ){ + if( pDest->pCheck && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) ){ return 0; /* Tables have different CHECK constraints. Ticket #2252 */ } #endif diff --git a/src/loadext.c b/src/loadext.c index cdcf6a93b..828e865b6 100644 --- a/src/loadext.c +++ b/src/loadext.c @@ -669,6 +669,35 @@ int sqlite3_auto_extension(void (*xInit)(void)){ } /* +** Cancel a prior call to sqlite3_auto_extension. Remove xInit from the +** set of routines that is invoked for each new database connection, if it +** is currently on the list. If xInit is not on the list, then this +** routine is a no-op. +** +** Return 1 if xInit was found on the list and removed. Return 0 if xInit +** was not on the list. +*/ +int sqlite3_cancel_auto_extension(void (*xInit)(void)){ +#if SQLITE_THREADSAFE + sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); +#endif + int i; + int n = 0; + wsdAutoextInit; + sqlite3_mutex_enter(mutex); + for(i=wsdAutoext.nExt-1; i>=0; i--){ + if( wsdAutoext.aExt[i]==xInit ){ + wsdAutoext.nExt--; + wsdAutoext.aExt[i] = wsdAutoext.aExt[wsdAutoext.nExt]; + n++; + break; + } + } + sqlite3_mutex_leave(mutex); + return n; +} + +/* ** Reset the automatic extension loading mechanism. */ void sqlite3_reset_auto_extension(void){ diff --git a/src/main.c b/src/main.c index 263921aba..c4ba03849 100644 --- a/src/main.c +++ b/src/main.c @@ -1100,6 +1100,7 @@ const char *sqlite3ErrName(int rc){ case SQLITE_IOERR_SEEK: zName = "SQLITE_IOERR_SEEK"; break; case SQLITE_IOERR_DELETE_NOENT: zName = "SQLITE_IOERR_DELETE_NOENT";break; case SQLITE_IOERR_MMAP: zName = "SQLITE_IOERR_MMAP"; break; + case SQLITE_IOERR_GETTEMPPATH: zName = "SQLITE_IOERR_GETTEMPPATH"; break; case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break; case SQLITE_CORRUPT_VTAB: zName = "SQLITE_CORRUPT_VTAB"; break; case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break; @@ -2476,7 +2477,7 @@ static int openDatabase( db->szMmap = sqlite3GlobalConfig.szMmap; db->nextPagesize = 0; db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger -#if !defined(SQLITE_DEAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX +#if !defined(SQLITE_DEFAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX | SQLITE_AutoIndex #endif #if SQLITE_DEFAULT_FILE_FORMAT<4 diff --git a/src/os_win.c b/src/os_win.c index bdf025aa4..10c431644 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -17,6 +17,7 @@ #ifdef __CYGWIN__ # include <sys/cygwin.h> +# include <errno.h> #endif /* @@ -230,6 +231,7 @@ struct winFile { # define SQLITE_WIN32_HEAP_FLAGS (0) #endif + /* ** The winMemData structure stores information required by the Win32-specific ** sqlite3_mem_methods implementation. @@ -3694,10 +3696,10 @@ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){ return SQLITE_OK; } assert( (nMap % winSysInfo.dwPageSize)==0 ); + assert( sizeof(SIZE_T)==sizeof(sqlite3_int64) || nMap<=0xffffffff ); #if SQLITE_OS_WINRT - pNew = osMapViewOfFileFromApp(pFd->hMap, flags, 0, nMap); + pNew = osMapViewOfFileFromApp(pFd->hMap, flags, 0, (SIZE_T)nMap); #else - assert( sizeof(SIZE_T)==sizeof(sqlite3_int64) || nMap<=0xffffffff ); pNew = osMapViewOfFile(pFd->hMap, flags, 0, 0, (SIZE_T)nMap); #endif if( pNew==NULL ){ @@ -3867,6 +3869,15 @@ static void *convertUtf8Filename(const char *zFilename){ } /* +** Maximum pathname length (in bytes) for windows. The MAX_PATH macro is +** in characters, so we allocate 3 bytes per character assuming worst-case +** 3-bytes-per-character UTF8. +*/ +#ifndef SQLITE_WIN32_MAX_PATH +# define SQLITE_WIN32_MAX_PATH (MAX_PATH*3) +#endif + +/* ** Create a temporary file name in zBuf. zBuf must be big enough to ** hold at pVfs->mxPathname characters. */ @@ -3877,7 +3888,7 @@ static int getTempname(int nBuf, char *zBuf){ "0123456789"; size_t i, j; int nTempPath; - char zTempPath[MAX_PATH+2]; + char zTempPath[SQLITE_WIN32_MAX_PATH+2]; /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this @@ -3885,19 +3896,21 @@ static int getTempname(int nBuf, char *zBuf){ */ SimulateIOError( return SQLITE_IOERR ); - memset(zTempPath, 0, MAX_PATH+2); - if( sqlite3_temp_directory ){ - sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory); + sqlite3_snprintf(SQLITE_WIN32_MAX_PATH-30, zTempPath, "%s", + sqlite3_temp_directory); } #if !SQLITE_OS_WINRT else if( isNT() ){ char *zMulti; WCHAR zWidePath[MAX_PATH]; - osGetTempPathW(MAX_PATH-30, zWidePath); + if( osGetTempPathW(MAX_PATH-30, zWidePath)==0 ){ + OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_GETTEMPPATH\n")); + return SQLITE_IOERR_GETTEMPPATH; + } zMulti = unicodeToUtf8(zWidePath); if( zMulti ){ - sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zMulti); + sqlite3_snprintf(SQLITE_WIN32_MAX_PATH-30, zTempPath, "%s", zMulti); sqlite3_free(zMulti); }else{ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); @@ -3907,19 +3920,38 @@ static int getTempname(int nBuf, char *zBuf){ #ifdef SQLITE_WIN32_HAS_ANSI else{ char *zUtf8; - char zMbcsPath[MAX_PATH]; - osGetTempPathA(MAX_PATH-30, zMbcsPath); + char zMbcsPath[SQLITE_WIN32_MAX_PATH]; + if( osGetTempPathA(SQLITE_WIN32_MAX_PATH-30, zMbcsPath)==0 ){ + OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_GETTEMPPATH\n")); + return SQLITE_IOERR_GETTEMPPATH; + } zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath); if( zUtf8 ){ - sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zUtf8); + sqlite3_snprintf(SQLITE_WIN32_MAX_PATH-30, zTempPath, "%s", zUtf8); sqlite3_free(zUtf8); }else{ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); return SQLITE_IOERR_NOMEM; } } -#endif -#endif +#else + else{ + /* + ** Compiled without ANSI support and the current operating system + ** is not Windows NT; therefore, just zero the temporary buffer. + */ + memset(zTempPath, 0, SQLITE_WIN32_MAX_PATH+2); + } +#endif /* SQLITE_WIN32_HAS_ANSI */ +#else + else{ + /* + ** Compiled for WinRT and the sqlite3_temp_directory is not set; + ** therefore, just zero the temporary buffer. + */ + memset(zTempPath, 0, SQLITE_WIN32_MAX_PATH+2); + } +#endif /* !SQLITE_OS_WINRT */ /* Check that the output buffer is large enough for the temporary file ** name. If it is not, return SQLITE_ERROR. @@ -4005,7 +4037,7 @@ static int winOpen( /* If argument zPath is a NULL pointer, this function is required to open ** a temporary file. Use this buffer to store the file name in. */ - char zTmpname[MAX_PATH+2]; /* Buffer used to create temp filename */ + char zTmpname[SQLITE_WIN32_MAX_PATH+2]; /* Buffer used to create temp filename */ int rc = SQLITE_OK; /* Function Return Code */ #if !defined(NDEBUG) || SQLITE_OS_WINCE @@ -4071,8 +4103,7 @@ static int winOpen( */ if( !zUtf8Name ){ assert(isDelete && !isOpenJournal); - memset(zTmpname, 0, MAX_PATH+2); - rc = getTempname(MAX_PATH+2, zTmpname); + rc = getTempname(SQLITE_WIN32_MAX_PATH+2, zTmpname); if( rc!=SQLITE_OK ){ OSTRACE(("OPEN name=%s, rc=%s", zUtf8Name, sqlite3ErrName(rc))); return rc; @@ -4503,7 +4534,7 @@ static int winFullPathname( #if defined(__CYGWIN__) SimulateIOError( return SQLITE_ERROR ); UNUSED_PARAMETER(nFull); - assert( pVfs->mxPathname>=MAX_PATH ); + assert( pVfs->mxPathname>=SQLITE_WIN32_MAX_PATH ); assert( nFull>=pVfs->mxPathname ); if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ /* @@ -4512,14 +4543,21 @@ static int winFullPathname( ** for converting the relative path name to an absolute ** one by prepending the data directory and a slash. */ - char zOut[MAX_PATH+1]; - memset(zOut, 0, MAX_PATH+1); - cygwin_conv_path(CCP_POSIX_TO_WIN_A|CCP_RELATIVE, zRelative, zOut, - MAX_PATH+1); + char zOut[SQLITE_WIN32_MAX_PATH+1]; + if( cygwin_conv_path(CCP_POSIX_TO_WIN_A|CCP_RELATIVE, zRelative, zOut, + SQLITE_WIN32_MAX_PATH+1)<0 ){ + winLogError(SQLITE_CANTOPEN_FULLPATH, (DWORD)errno, "cygwin_conv_path", + zRelative); + return SQLITE_CANTOPEN_FULLPATH; + } sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s\\%s", sqlite3_data_directory, zOut); }else{ - cygwin_conv_path(CCP_POSIX_TO_WIN_A, zRelative, zFull, nFull); + if( cygwin_conv_path(CCP_POSIX_TO_WIN_A, zRelative, zFull, nFull)<0 ){ + winLogError(SQLITE_CANTOPEN_FULLPATH, (DWORD)errno, "cygwin_conv_path", + zRelative); + return SQLITE_CANTOPEN_FULLPATH; + } } return SQLITE_OK; #endif @@ -4861,7 +4899,7 @@ int sqlite3_os_init(void){ static sqlite3_vfs winVfs = { 3, /* iVersion */ sizeof(winFile), /* szOsFile */ - MAX_PATH, /* mxPathname */ + SQLITE_WIN32_MAX_PATH, /* mxPathname */ 0, /* pNext */ "win32", /* zName */ 0, /* pAppData */ diff --git a/src/parse.y b/src/parse.y index d707ee0a8..139040339 100644 --- a/src/parse.y +++ b/src/parse.y @@ -1125,10 +1125,10 @@ nexprlist(A) ::= expr(Y). ///////////////////////////// The CREATE INDEX command /////////////////////// // cmd ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D) - ON nm(Y) LP idxlist(Z) RP(E). { + ON nm(Y) LP idxlist(Z) RP where_opt(W). { sqlite3CreateIndex(pParse, &X, &D, sqlite3SrcListAppend(pParse->db,0,&Y,0), Z, U, - &S, &E, SQLITE_SO_ASC, NE); + &S, W, SQLITE_SO_ASC, NE); } %type uniqueflag {int} diff --git a/src/pragma.c b/src/pragma.c index 9bbbfa8aa..f152220d4 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1400,9 +1400,7 @@ void sqlite3Pragma( } /* Make sure sufficient number of registers have been allocated */ - if( pParse->nMem < cnt+4 ){ - pParse->nMem = cnt+4; - } + pParse->nMem = MAX( pParse->nMem, cnt+7 ); /* Do the b-tree integrity checks */ sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1); @@ -1427,12 +1425,15 @@ void sqlite3Pragma( addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Stop if out of errors */ sqlite3VdbeAddOp2(v, OP_Halt, 0, 0); sqlite3VdbeJumpHere(v, addr); + sqlite3ExprCacheClear(pParse); sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead); - sqlite3VdbeAddOp2(v, OP_Integer, 0, 2); /* reg(2) will count entries */ - loopTop = sqlite3VdbeAddOp2(v, OP_Rewind, 1, 0); - sqlite3VdbeAddOp2(v, OP_AddImm, 2, 1); /* increment entry count */ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ - int jmp2; + sqlite3VdbeAddOp2(v, OP_Integer, 0, 7+j); /* index entries counter */ + } + pParse->nMem = MAX(pParse->nMem, 7+j); + loopTop = sqlite3VdbeAddOp2(v, OP_Rewind, 1, 0) + 1; + for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ + int jmp2, jmp3; int r1; static const VdbeOpList idxErr[] = { { OP_AddImm, 1, -1, 0}, @@ -1447,7 +1448,8 @@ void sqlite3Pragma( { OP_IfPos, 1, 0, 0}, /* 9 */ { OP_Halt, 0, 0, 0}, }; - r1 = sqlite3GenerateIndexKey(pParse, pIdx, 1, 3, 0); + r1 = sqlite3GenerateIndexKey(pParse, pIdx, 1, 3, 0, &jmp3); + sqlite3VdbeAddOp2(v, OP_AddImm, 7+j, 1); /* increment entry count */ jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, j+2, 0, r1, pIdx->nColumn+1); addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr); sqlite3VdbeChangeP4(v, addr+1, "rowid ", P4_STATIC); @@ -1455,35 +1457,25 @@ void sqlite3Pragma( sqlite3VdbeChangeP4(v, addr+4, pIdx->zName, P4_TRANSIENT); sqlite3VdbeJumpHere(v, addr+9); sqlite3VdbeJumpHere(v, jmp2); + sqlite3VdbeResolveLabel(v, jmp3); } - sqlite3VdbeAddOp2(v, OP_Next, 1, loopTop+1); - sqlite3VdbeJumpHere(v, loopTop); + sqlite3VdbeAddOp2(v, OP_Next, 1, loopTop); + sqlite3VdbeJumpHere(v, loopTop-1); +#ifndef SQLITE_OMIT_BTREECOUNT + sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, + "wrong # of entries in index ", P4_STATIC); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ - static const VdbeOpList cntIdx[] = { - { OP_Integer, 0, 3, 0}, - { OP_Rewind, 0, 0, 0}, /* 1 */ - { OP_AddImm, 3, 1, 0}, - { OP_Next, 0, 0, 0}, /* 3 */ - { OP_Eq, 2, 0, 3}, /* 4 */ - { OP_AddImm, 1, -1, 0}, - { OP_String8, 0, 2, 0}, /* 6 */ - { OP_String8, 0, 3, 0}, /* 7 */ - { OP_Concat, 3, 2, 2}, - { OP_ResultRow, 2, 1, 0}, - }; - addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); + addr = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr+2); sqlite3VdbeAddOp2(v, OP_Halt, 0, 0); - sqlite3VdbeJumpHere(v, addr); - addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx); - sqlite3VdbeChangeP1(v, addr+1, j+2); - sqlite3VdbeChangeP2(v, addr+1, addr+4); - sqlite3VdbeChangeP1(v, addr+3, j+2); - sqlite3VdbeChangeP2(v, addr+3, addr+2); - sqlite3VdbeJumpHere(v, addr+4); - sqlite3VdbeChangeP4(v, addr+6, - "wrong # of entries in index ", P4_STATIC); - sqlite3VdbeChangeP4(v, addr+7, pIdx->zName, P4_TRANSIENT); + sqlite3VdbeAddOp2(v, OP_Count, j+2, 3); + sqlite3VdbeAddOp3(v, OP_Eq, 7+j, addr+8, 3); + sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pIdx->zName, P4_TRANSIENT); + sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7); + sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1); } +#endif /* SQLITE_OMIT_BTREECOUNT */ } } addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode); diff --git a/src/prepare.c b/src/prepare.c index 28145aa4e..cfc9c3485 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -810,6 +810,12 @@ static int sqlite3Prepare16( if( !sqlite3SafetyCheckOk(db) ){ return SQLITE_MISUSE_BKPT; } + if( nBytes>=0 ){ + int sz; + const char *z = (const char*)zSql; + for(sz=0; sz<nBytes && (z[sz]!=0 || z[sz+1]!=0); sz += 2){} + nBytes = sz; + } sqlite3_mutex_enter(db->mutex); zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE); if( zSql8 ){ diff --git a/src/resolve.c b/src/resolve.c index 91efcaa1a..a194a2655 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -240,11 +240,20 @@ static int lookupName( ** resulting in an appropriate error message toward the end of this routine */ if( zDb ){ - for(i=0; i<db->nDb; i++){ - assert( db->aDb[i].zName ); - if( sqlite3StrICmp(db->aDb[i].zName,zDb)==0 ){ - pSchema = db->aDb[i].pSchema; - break; + testcase( pNC->ncFlags & NC_PartIdx ); + testcase( pNC->ncFlags & NC_IsCheck ); + if( (pNC->ncFlags & (NC_PartIdx|NC_IsCheck))!=0 ){ + /* Silently ignore database qualifiers inside CHECK constraints and partial + ** indices. Do not raise errors because that might break legacy and + ** because it does not hurt anything to just ignore the database name. */ + zDb = 0; + }else{ + for(i=0; i<db->nDb; i++){ + assert( db->aDb[i].zName ); + if( sqlite3StrICmp(db->aDb[i].zName,zDb)==0 ){ + pSchema = db->aDb[i].pSchema; + break; + } } } } @@ -523,6 +532,39 @@ Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){ } /* +** Report an error that an expression is not valid for a partial index WHERE +** clause. +*/ +static void notValidPartIdxWhere( + Parse *pParse, /* Leave error message here */ + NameContext *pNC, /* The name context */ + const char *zMsg /* Type of error */ +){ + if( (pNC->ncFlags & NC_PartIdx)!=0 ){ + sqlite3ErrorMsg(pParse, "%s prohibited in partial index WHERE clauses", + zMsg); + } +} + +#ifndef SQLITE_OMIT_CHECK +/* +** Report an error that an expression is not valid for a CHECK constraint. +*/ +static void notValidCheckConstraint( + Parse *pParse, /* Leave error message here */ + NameContext *pNC, /* The name context */ + const char *zMsg /* Type of error */ +){ + if( (pNC->ncFlags & NC_IsCheck)!=0 ){ + sqlite3ErrorMsg(pParse,"%s prohibited in CHECK constraints", zMsg); + } +} +#else +# define notValidCheckConstraint(P,N,M) +#endif + + +/* ** This routine is callback for sqlite3WalkExpr(). ** ** Resolve symbolic names into TK_COLUMN operators for the current @@ -621,6 +663,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_CONST_FUNC ); assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + notValidPartIdxWhere(pParse, pNC, "functions"); zId = pExpr->u.zToken; nId = sqlite3Strlen30(zId); pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0); @@ -686,11 +729,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_IN ); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ int nRef = pNC->nRef; -#ifndef SQLITE_OMIT_CHECK - if( (pNC->ncFlags & NC_IsCheck)!=0 ){ - sqlite3ErrorMsg(pParse,"subqueries prohibited in CHECK constraints"); - } -#endif + notValidCheckConstraint(pParse, pNC, "subqueries"); + notValidPartIdxWhere(pParse, pNC, "subqueries"); sqlite3WalkSelect(pWalker, pExpr->x.pSelect); assert( pNC->nRef>=nRef ); if( nRef!=pNC->nRef ){ @@ -699,14 +739,11 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ } break; } -#ifndef SQLITE_OMIT_CHECK case TK_VARIABLE: { - if( (pNC->ncFlags & NC_IsCheck)!=0 ){ - sqlite3ErrorMsg(pParse,"parameters prohibited in CHECK constraints"); - } + notValidCheckConstraint(pParse, pNC, "parameters"); + notValidPartIdxWhere(pParse, pNC, "parameters"); break; } -#endif } return (pParse->nErr || pParse->db->mallocFailed) ? WRC_Abort : WRC_Continue; } @@ -797,7 +834,7 @@ static int resolveOrderByTermToExprList( ** result-set entry. */ for(i=0; i<pEList->nExpr; i++){ - if( sqlite3ExprCompare(pEList->a[i].pExpr, pE)<2 ){ + if( sqlite3ExprCompare(pEList->a[i].pExpr, pE, -1)<2 ){ return i+1; } } @@ -1025,7 +1062,7 @@ static int resolveOrderGroupBy( return 1; } for(j=0; j<pSelect->pEList->nExpr; j++){ - if( sqlite3ExprCompare(pE, pSelect->pEList->a[j].pExpr)==0 ){ + if( sqlite3ExprCompare(pE, pSelect->pEList->a[j].pExpr, -1)==0 ){ pItem->iOrderByCol = j+1; } } @@ -1331,3 +1368,45 @@ void sqlite3ResolveSelectNames( w.u.pNC = pOuterNC; sqlite3WalkSelect(&w, p); } + +/* +** Resolve names in expressions that can only reference a single table: +** +** * CHECK constraints +** * WHERE clauses on partial indices +** +** The Expr.iTable value for Expr.op==TK_COLUMN nodes of the expression +** is set to -1 and the Expr.iColumn value is set to the column number. +** +** Any errors cause an error message to be set in pParse. +*/ +void sqlite3ResolveSelfReference( + Parse *pParse, /* Parsing context */ + Table *pTab, /* The table being referenced */ + int type, /* NC_IsCheck or NC_PartIdx */ + Expr *pExpr, /* Expression to resolve. May be NULL. */ + ExprList *pList /* Expression list to resolve. May be NUL. */ +){ + SrcList sSrc; /* Fake SrcList for pParse->pNewTable */ + NameContext sNC; /* Name context for pParse->pNewTable */ + int i; /* Loop counter */ + + assert( type==NC_IsCheck || type==NC_PartIdx ); + memset(&sNC, 0, sizeof(sNC)); + memset(&sSrc, 0, sizeof(sSrc)); + sSrc.nSrc = 1; + sSrc.a[0].zName = pTab->zName; + sSrc.a[0].pTab = pTab; + sSrc.a[0].iCursor = -1; + sNC.pParse = pParse; + sNC.pSrcList = &sSrc; + sNC.ncFlags = type; + if( sqlite3ResolveExprNames(&sNC, pExpr) ) return; + if( pList ){ + for(i=0; i<pList->nExpr; i++){ + if( sqlite3ResolveExprNames(&sNC, pList->a[i].pExpr) ){ + return; + } + } + } +} diff --git a/src/select.c b/src/select.c index fa35f4587..014feca8f 100644 --- a/src/select.c +++ b/src/select.c @@ -4177,7 +4177,7 @@ int sqlite3Select( ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER ** to disable this optimization for testing purposes. */ - if( sqlite3ExprListCompare(p->pGroupBy, pOrderBy)==0 + if( sqlite3ExprListCompare(p->pGroupBy, pOrderBy, -1)==0 && OptimizationEnabled(db, SQLITE_GroupByOrder) ){ pOrderBy = 0; } @@ -4198,7 +4198,7 @@ int sqlite3Select( ** BY and DISTINCT, and an index or separate temp-table for the other. */ if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct - && sqlite3ExprListCompare(pOrderBy, p->pEList)==0 + && sqlite3ExprListCompare(pOrderBy, p->pEList, -1)==0 ){ p->selFlags &= ~SF_Distinct; p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0); diff --git a/src/shell.c b/src/shell.c index 79548fa1e..7b8a8ad7f 100644 --- a/src/shell.c +++ b/src/shell.c @@ -65,7 +65,7 @@ #define isatty(h) _isatty(h) #define access(f,m) _access((f),(m)) #undef popen -#define popen(a,b) _popen((a),(b)) +#define popen _popen #undef pclose #define pclose _pclose #else @@ -74,6 +74,11 @@ extern int isatty(int); #endif +/* popen and pclose are not C89 functions and so are sometimes omitted from +** the <stdio.h> header */ +FILE *popen(const char*,const char*); +int pclose(FILE*); + #if defined(_WIN32_WCE) /* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty() * thus we always assume that we have a console. That can be @@ -1721,7 +1726,6 @@ static char *csv_read_one_field(CSVReader *p){ || (c==EOF && pc==cQuote) ){ do{ p->n--; }while( p->z[p->n]!=cQuote ); - p->z[p->n] = 0; p->cTerm = c; break; } @@ -1732,7 +1736,6 @@ static char *csv_read_one_field(CSVReader *p){ if( c==EOF ){ fprintf(stderr, "%s:%d: unterminated %c-quoted field\n", p->zFile, startLine, cQuote); - p->z[p->n] = 0; p->cTerm = EOF; break; } @@ -1748,9 +1751,9 @@ static char *csv_read_one_field(CSVReader *p){ p->nLine++; if( p->n>1 && p->z[p->n-1]=='\r' ) p->n--; } - p->z[p->n] = 0; p->cTerm = c; } + if( p->z ) p->z[p->n] = 0; return p->z; } @@ -1799,7 +1802,6 @@ static int do_meta_command(char *zLine, struct callback_data *p){ if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 ){ const char *zDestFile = 0; const char *zDb = 0; - const char *zKey = 0; sqlite3 *pDest; sqlite3_backup *pBackup; int j; @@ -1807,9 +1809,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ const char *z = azArg[j]; if( z[0]=='-' ){ while( z[0]=='-' ) z++; - if( strcmp(z,"key")==0 && j<nArg-1 ){ - zKey = azArg[++j]; - }else + /* No options to process at this time */ { fprintf(stderr, "unknown option: %s\n", azArg[j]); return 1; @@ -1835,11 +1835,6 @@ static int do_meta_command(char *zLine, struct callback_data *p){ sqlite3_close(pDest); return 1; } -#ifdef SQLITE_HAS_CODEC - sqlite3_key(pDest, zKey, (int)strlen(zKey)); -#else - (void)zKey; -#endif open_db(p); pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb); if( pBackup==0 ){ @@ -2669,7 +2664,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ /* sqlite3_test_control(int, uint) */ case SQLITE_TESTCTRL_PENDING_BYTE: if( nArg==3 ){ - unsigned int opt = (unsigned int)integerValue(azArg[2]); + unsigned int opt = (unsigned int)integerValue(azArg[2]); rc = sqlite3_test_control(testctrl, opt); fprintf(p->out, "%d (0x%08x)\n", rc, rc); } else { diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 6e51fadc7..551a11857 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -473,6 +473,7 @@ int sqlite3_exec( #define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) #define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8)) #define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8)) +#define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) @@ -2554,9 +2555,10 @@ SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*, ** interface is to keep a GUI updated during a large query. ** ** ^The parameter P is passed through as the only parameter to the -** callback function X. ^The parameter N is the number of +** callback function X. ^The parameter N is the approximate number of ** [virtual machine instructions] that are evaluated between successive -** invocations of the callback X. +** invocations of the callback X. ^If N is less than one then the progress +** handler is disabled. ** ** ^Only a single progress handler may be defined at one time per ** [database connection]; setting a new progress handler cancels the @@ -4176,41 +4178,49 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*); /* ** CAPI3REF: Function Auxiliary Data ** -** The following two functions may be used by scalar SQL functions to +** These functions may be used by (non-aggregate) SQL functions to ** associate metadata with argument values. If the same value is passed to ** multiple invocations of the same SQL function during query execution, under -** some circumstances the associated metadata may be preserved. This may -** be used, for example, to add a regular-expression matching scalar -** function. The compiled version of the regular expression is stored as -** metadata associated with the SQL value passed as the regular expression -** pattern. The compiled regular expression can be reused on multiple -** invocations of the same function so that the original pattern string -** does not need to be recompiled on each invocation. +** some circumstances the associated metadata may be preserved. An example +** of where this might be useful is in a regular-expression matching +** function. The compiled version of the regular expression can be stored as +** metadata associated with the pattern string. +** Then as long as the pattern string remains the same, +** the compiled regular expression can be reused on multiple +** invocations of the same function. ** ** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata ** associated by the sqlite3_set_auxdata() function with the Nth argument -** value to the application-defined function. ^If no metadata has been ever -** been set for the Nth argument of the function, or if the corresponding -** function parameter has changed since the meta-data was set, -** then sqlite3_get_auxdata() returns a NULL pointer. -** -** ^The sqlite3_set_auxdata() interface saves the metadata -** pointed to by its 3rd parameter as the metadata for the N-th -** argument of the application-defined function. Subsequent -** calls to sqlite3_get_auxdata() might return this data, if it has -** not been destroyed. -** ^If it is not NULL, SQLite will invoke the destructor -** function given by the 4th parameter to sqlite3_set_auxdata() on -** the metadata when the corresponding function parameter changes -** or when the SQL statement completes, whichever comes first. -** -** SQLite is free to call the destructor and drop metadata on any -** parameter of any function at any time. ^The only guarantee is that -** the destructor will be called before the metadata is dropped. +** value to the application-defined function. ^If there is no metadata +** associated with the function argument, this sqlite3_get_auxdata() interface +** returns a NULL pointer. +** +** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th +** argument of the application-defined function. ^Subsequent +** calls to sqlite3_get_auxdata(C,N) return P from the most recent +** sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or +** NULL if the metadata has been discarded. +** ^After each call to sqlite3_set_auxdata(C,N,P,X) where X is not NULL, +** SQLite will invoke the destructor function X with parameter P exactly +** once, when the metadata is discarded. +** SQLite is free to discard the metadata at any time, including: <ul> +** <li> when the corresponding function parameter changes, or +** <li> when [sqlite3_reset()] or [sqlite3_finalize()] is called for the +** SQL statement, or +** <li> when sqlite3_set_auxdata() is invoked again on the same parameter, or +** <li> during the original sqlite3_set_auxdata() call when a memory +** allocation error occurs. </ul>)^ +** +** Note the last bullet in particular. The destructor X in +** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the +** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata() +** should be called near the end of the function implementation and the +** function implementation should not make any use of P after +** sqlite3_set_auxdata() has been called. ** ** ^(In practice, metadata is preserved between function calls for -** expressions that are constant at compile time. This includes literal -** values and [parameters].)^ +** function parameters that are compile-time constants, including literal +** values and [parameters] and expressions composed from the same.)^ ** ** These routines must be called from the same thread in which ** the SQL function is running. @@ -5123,11 +5133,24 @@ int sqlite3_enable_load_extension(sqlite3 *db, int onoff); ** on the list of automatic extensions is a harmless no-op. ^No entry point ** will be called more than once for each database connection that is opened. ** -** See also: [sqlite3_reset_auto_extension()]. +** See also: [sqlite3_reset_auto_extension()] +** and [sqlite3_cancel_auto_extension()] */ int sqlite3_auto_extension(void (*xEntryPoint)(void)); /* +** CAPI3REF: Cancel Automatic Extension Loading +** +** ^The [sqlite3_cancel_auto_extension(X)] interface unregisters the +** initialization routine X that was registered using a prior call to +** [sqlite3_auto_extension(X)]. ^The [sqlite3_cancel_auto_extension(X)] +** routine returns 1 if initialization routine X was successfully +** unregistered and it returns 0 if X was not on the list of initialization +** routines. +*/ +int sqlite3_cancel_auto_extension(void (*xEntryPoint)(void)); + +/* ** CAPI3REF: Reset Automatic Extension Loading ** ** ^This interface disables all automatic extensions previously @@ -6241,9 +6264,9 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); ** </dd> ** ** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(<dt>SQLITE_DBSTATUS_DEFERRED_FKS</dt> -** <dd>This parameter returns the zero for the current value if and only if -** there all foreign key constraints (deferred or immediate) have been -** resolved. The highwater mark is always 0. +** <dd>This parameter returns zero for the current value if and only if +** all foreign key constraints (deferred or immediate) have been +** resolved.)^ ^The highwater mark is always 0. ** </dd> ** </dl> */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 86d0804fa..d6b4dd492 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -161,9 +161,6 @@ ** will cause HeapValidate to be called. If heap validation should fail, an ** assertion will be triggered. ** -** (Historical note: There used to be several other options, but we've -** pared it down to just these three.) -** ** If none of the above are defined, then set SQLITE_SYSTEM_MALLOC as ** the default. */ @@ -202,19 +199,12 @@ #endif /* -** The TCL headers are only needed when compiling the TCL bindings. -*/ -#if defined(SQLITE_TCL) || defined(TCLSH) -# include <tcl.h> -#endif - -/* ** NDEBUG and SQLITE_DEBUG are opposites. It should always be true that ** defined(NDEBUG)==!defined(SQLITE_DEBUG). If this is not currently true, ** make it true by defining or undefining NDEBUG. ** -** Setting NDEBUG makes the code smaller and run faster by disabling the -** number assert() statements in the code. So we want the default action +** Setting NDEBUG makes the code smaller and faster by disabling the +** assert() statements in the code. So we want the default action ** to be for NDEBUG to be set and NDEBUG to be undefined only if SQLITE_DEBUG ** is set. Thus NDEBUG becomes an opt-in rather than an opt-out ** feature. @@ -284,7 +274,7 @@ ** In other words, ALWAYS and NEVER are added for defensive code. ** ** When doing coverage testing ALWAYS and NEVER are hard-coded to -** be true and false so that the unreachable code then specify will +** be true and false so that the unreachable code they specify will ** not be counted as untested code. */ #if defined(SQLITE_COVERAGE_TEST) @@ -308,16 +298,12 @@ /* ** The macro unlikely() is a hint that surrounds a boolean ** expression that is usually false. Macro likely() surrounds -** a boolean expression that is usually true. GCC is able to -** use these hints to generate better code, sometimes. +** a boolean expression that is usually true. These hints could, +** in theory, be used by the compiler to generate better code, but +** currently they are just comments for human readers. */ -#if defined(__GNUC__) && 0 -# define likely(X) __builtin_expect((X),1) -# define unlikely(X) __builtin_expect((X),0) -#else -# define likely(X) !!(X) -# define unlikely(X) !!(X) -#endif +#define likely(X) (X) +#define unlikely(X) (X) #include "sqlite3.h" #include "hash.h" @@ -1560,6 +1546,7 @@ struct Index { Schema *pSchema; /* Schema containing this index */ u8 *aSortOrder; /* for each column: True==DESC, False==ASC */ char **azColl; /* Array of collation sequence names for index */ + Expr *pPartIdxWhere; /* WHERE clause for partial indices */ int tnum; /* DB Page containing root of this index */ u16 nColumn; /* Number of columns in table used by this index */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ @@ -2040,6 +2027,7 @@ struct NameContext { #define NC_InAggFunc 0x08 /* True if analyzing arguments to an agg func */ #define NC_AsMaybe 0x10 /* Resolve to AS terms of the result set only ** if no other resolution is available */ +#define NC_PartIdx 0x20 /* True if resolving a partial index WHERE */ /* ** An instance of the following structure contains all information @@ -2224,6 +2212,7 @@ struct Parse { int nSet; /* Number of sets used so far */ int nOnce; /* Number of OP_Once instructions so far */ int ckBase; /* Base register of data during check constraints */ + int iPartIdxTab; /* Table corresponding to a partial index */ int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */ int iCacheCnt; /* Counter used to generate aColCache[].lru values */ struct yColCache { @@ -2809,7 +2798,7 @@ void sqlite3SrcListAssignCursors(Parse*, SrcList*); void sqlite3IdListDelete(sqlite3*, IdList*); void sqlite3SrcListDelete(sqlite3*, SrcList*); Index *sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, - Token*, int, int); + Expr*, int, int); void sqlite3DropIndex(Parse*, SrcList*, int); int sqlite3Select(Parse*, Select*, SelectDest*); Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, @@ -2857,8 +2846,9 @@ void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*); void sqlite3Vacuum(Parse*); int sqlite3RunVacuum(char**, sqlite3*); char *sqlite3NameFromToken(sqlite3*, Token*); -int sqlite3ExprCompare(Expr*, Expr*); -int sqlite3ExprListCompare(ExprList*, ExprList*); +int sqlite3ExprCompare(Expr*, Expr*, int); +int sqlite3ExprListCompare(ExprList*, ExprList*, int); +int sqlite3ExprImpliesExpr(Expr*, Expr*, int); void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); int sqlite3FunctionUsesThisSrc(Expr*, SrcList*); @@ -2885,7 +2875,7 @@ int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); int sqlite3IsRowid(const char*); void sqlite3GenerateRowDelete(Parse*, Table*, int, int, int, Trigger *, int); void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int*); -int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int); +int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*); void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int, int*,int,int,int,int,int*); void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*, int, int, int); @@ -3088,6 +3078,7 @@ void sqlite3SelectPrep(Parse*, Select*, NameContext*); int sqlite3MatchSpanName(const char*, const char*, const char*, const char*); int sqlite3ResolveExprNames(NameContext*, Expr*); void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*); +void sqlite3ResolveSelfReference(Parse*,Table*,int,Expr*,ExprList*); int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*); void sqlite3ColumnDefault(Vdbe *, Table *, int, int); void sqlite3AlterFinishAddColumn(Parse *, Token *); diff --git a/src/test_autoext.c b/src/test_autoext.c index b5013f317..4a5a5caa0 100644 --- a/src/test_autoext.c +++ b/src/test_autoext.c @@ -99,6 +99,22 @@ static int autoExtSqrObjCmd( } /* +** tclcmd: sqlite3_cancel_auto_extension_sqr +** +** Unregister the "sqr" extension. +*/ +static int cancelAutoExtSqrObjCmd( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + int rc = sqlite3_cancel_auto_extension((void*)sqr_init); + Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); + return SQLITE_OK; +} + +/* ** tclcmd: sqlite3_auto_extension_cube ** ** Register the "cube" extension to be loaded automatically. @@ -115,6 +131,22 @@ static int autoExtCubeObjCmd( } /* +** tclcmd: sqlite3_cancel_auto_extension_cube +** +** Unregister the "cube" extension. +*/ +static int cancelAutoExtCubeObjCmd( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + int rc = sqlite3_cancel_auto_extension((void*)cube_init); + Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); + return SQLITE_OK; +} + +/* ** tclcmd: sqlite3_auto_extension_broken ** ** Register the broken extension to be loaded automatically. @@ -130,6 +162,22 @@ static int autoExtBrokenObjCmd( return SQLITE_OK; } +/* +** tclcmd: sqlite3_cancel_auto_extension_broken +** +** Unregister the broken extension. +*/ +static int cancelAutoExtBrokenObjCmd( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + int rc = sqlite3_cancel_auto_extension((void*)broken_init); + Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); + return SQLITE_OK; +} + #endif /* SQLITE_OMIT_LOAD_EXTENSION */ @@ -161,6 +209,12 @@ int Sqlitetest_autoext_Init(Tcl_Interp *interp){ Tcl_CreateObjCommand(interp, "sqlite3_auto_extension_broken", autoExtBrokenObjCmd, 0, 0); #endif + Tcl_CreateObjCommand(interp, "sqlite3_cancel_auto_extension_sqr", + cancelAutoExtSqrObjCmd, 0, 0); + Tcl_CreateObjCommand(interp, "sqlite3_cancel_auto_extension_cube", + cancelAutoExtCubeObjCmd, 0, 0); + Tcl_CreateObjCommand(interp, "sqlite3_cancel_auto_extension_broken", + cancelAutoExtBrokenObjCmd, 0, 0); Tcl_CreateObjCommand(interp, "sqlite3_reset_auto_extension", resetAutoExtObjCmd, 0, 0); return TCL_OK; diff --git a/src/test_vfs.c b/src/test_vfs.c index 8b6b530bb..613b0fce7 100644 --- a/src/test_vfs.c +++ b/src/test_vfs.c @@ -28,6 +28,7 @@ #include "sqlite3.h" #include "sqliteInt.h" +#include <tcl.h> typedef struct Testvfs Testvfs; typedef struct TestvfsShm TestvfsShm; diff --git a/src/update.c b/src/update.c index 7511c7916..b65bd0187 100644 --- a/src/update.c +++ b/src/update.c @@ -246,7 +246,7 @@ void sqlite3Update( } for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int reg; - if( hasFK || chngRowid ){ + if( hasFK || chngRowid || pIdx->pPartIdxWhere ){ reg = ++pParse->nMem; }else{ reg = 0; diff --git a/src/vdbe.c b/src/vdbe.c index c354d3e27..2c9edf897 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -565,7 +565,7 @@ int sqlite3VdbeExec( int iCompare = 0; /* Result of last OP_Compare operation */ unsigned nVmStep = 0; /* Number of virtual machine steps */ #ifndef SQLITE_OMIT_PROGRESS_CALLBACK - unsigned nProgressOps = 0; /* nVmStep at last progress callback. */ + unsigned nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */ #endif Mem *aMem = p->aMem; /* Copy of p->aMem */ Mem *pIn1 = 0; /* 1st input operand */ @@ -595,6 +595,17 @@ int sqlite3VdbeExec( db->busyHandler.nBusy = 0; CHECK_FOR_INTERRUPT; sqlite3VdbeIOTraceSql(p); +#ifndef SQLITE_OMIT_PROGRESS_CALLBACK + if( db->xProgress ){ + assert( 0 < db->nProgressOps ); + nProgressLimit = (unsigned)p->aCounter[SQLITE_STMTSTATUS_VM_STEP-1]; + if( nProgressLimit==0 ){ + nProgressLimit = db->nProgressOps; + }else{ + nProgressLimit %= (unsigned)db->nProgressOps; + } + } +#endif #ifdef SQLITE_DEBUG sqlite3BeginBenignMalloc(); if( p->pc==0 && (p->db->flags & SQLITE_VdbeListing)!=0 ){ @@ -755,14 +766,16 @@ check_for_interrupt: ** If the progress callback returns non-zero, exit the virtual machine with ** a return code SQLITE_ABORT. */ - if( db->xProgress!=0 && (nVmStep - nProgressOps)>=db->nProgressOps ){ + if( db->xProgress!=0 && nVmStep>=nProgressLimit ){ int prc; prc = db->xProgress(db->pProgressArg); if( prc!=0 ){ rc = SQLITE_INTERRUPT; goto vdbe_error_halt; } - nProgressOps = nVmStep; + if( db->xProgress!=0 ){ + nProgressLimit = nVmStep + db->nProgressOps - (nVmStep%db->nProgressOps); + } } #endif @@ -1430,19 +1443,14 @@ case OP_Function: { REGISTER_TRACE(pOp->p2+i, pArg); } - assert( pOp->p4type==P4_FUNCDEF || pOp->p4type==P4_VDBEFUNC ); - if( pOp->p4type==P4_FUNCDEF ){ - ctx.pFunc = pOp->p4.pFunc; - ctx.pVdbeFunc = 0; - }else{ - ctx.pVdbeFunc = (VdbeFunc*)pOp->p4.pVdbeFunc; - ctx.pFunc = ctx.pVdbeFunc->pFunc; - } - + assert( pOp->p4type==P4_FUNCDEF ); + ctx.pFunc = pOp->p4.pFunc; ctx.s.flags = MEM_Null; ctx.s.db = db; ctx.s.xDel = 0; ctx.s.zMalloc = 0; + ctx.iOp = pc; + ctx.pVdbe = p; /* The output cell may already have a buffer allocated. Move ** the pointer to ctx.s so in case the user-function can use @@ -1465,11 +1473,7 @@ case OP_Function: { /* If any auxiliary data functions have been called by this user function, ** immediately call the destructor for any non-static values. */ - if( ctx.pVdbeFunc ){ - sqlite3VdbeDeleteAuxData(ctx.pVdbeFunc, pOp->p1); - pOp->p4.pVdbeFunc = ctx.pVdbeFunc; - pOp->p4type = P4_VDBEFUNC; - } + sqlite3VdbeDeleteAuxData(p, pc, pOp->p1); if( db->mallocFailed ){ /* Even though a malloc() has failed, the implementation of the diff --git a/src/vdbe.h b/src/vdbe.h index 50ab1d30e..e1db15fe2 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -30,7 +30,6 @@ typedef struct Vdbe Vdbe; ** The names of the following types declared in vdbeInt.h are required ** for the VdbeOp definition. */ -typedef struct VdbeFunc VdbeFunc; typedef struct Mem Mem; typedef struct SubProgram SubProgram; @@ -54,7 +53,6 @@ struct VdbeOp { i64 *pI64; /* Used when p4type is P4_INT64 */ double *pReal; /* Used when p4type is P4_REAL */ FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */ - VdbeFunc *pVdbeFunc; /* Used when p4type is P4_VDBEFUNC */ CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */ Mem *pMem; /* Used when p4type is P4_MEM */ VTable *pVtab; /* Used when p4type is P4_VTAB */ @@ -109,7 +107,6 @@ typedef struct VdbeOpList VdbeOpList; #define P4_COLLSEQ (-4) /* P4 is a pointer to a CollSeq structure */ #define P4_FUNCDEF (-5) /* P4 is a pointer to a FuncDef structure */ #define P4_KEYINFO (-6) /* P4 is a pointer to a KeyInfo structure */ -#define P4_VDBEFUNC (-7) /* P4 is a pointer to a VdbeFunc structure */ #define P4_MEM (-8) /* P4 is a pointer to a Mem* structure */ #define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */ #define P4_VTAB (-10) /* P4 is a pointer to an sqlite3_vtab structure */ @@ -209,7 +206,7 @@ sqlite3 *sqlite3VdbeDb(Vdbe*); void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, int); void sqlite3VdbeSwap(Vdbe*,Vdbe*); VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*); -sqlite3_value *sqlite3VdbeGetValue(Vdbe*, int, u8); +sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe*, int, u8); void sqlite3VdbeSetVarmask(Vdbe*, int); #ifndef SQLITE_OMIT_TRACE char *sqlite3VdbeExpandSql(Vdbe*, const char*); diff --git a/src/vdbeInt.h b/src/vdbeInt.h index dee4ca68d..adaff773e 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -44,6 +44,9 @@ typedef struct VdbeSorter VdbeSorter; /* Opaque type used by the explainer */ typedef struct Explain Explain; +/* Elements of the linked list at Vdbe.pAuxData */ +typedef struct AuxData AuxData; + /* ** A cursor is a pointer into a single BTree within a database file. ** The cursor can seek to a BTree entry with a particular key, or @@ -230,23 +233,19 @@ struct Mem { #define memIsValid(M) ((M)->flags & MEM_Invalid)==0 #endif - -/* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains -** additional information about auxiliary information bound to arguments -** of the function. This is used to implement the sqlite3_get_auxdata() -** and sqlite3_set_auxdata() APIs. The "auxdata" is some auxiliary data -** that can be associated with a constant argument to a function. This -** allows functions such as "regexp" to compile their constant regular -** expression argument once and reused the compiled code for multiple -** invocations. +/* +** Each auxilliary data pointer stored by a user defined function +** implementation calling sqlite3_set_auxdata() is stored in an instance +** of this structure. All such structures associated with a single VM +** are stored in a linked list headed at Vdbe.pAuxData. All are destroyed +** when the VM is halted (if not before). */ -struct VdbeFunc { - FuncDef *pFunc; /* The definition of the function */ - int nAux; /* Number of entries allocated for apAux[] */ - struct AuxData { - void *pAux; /* Aux data for the i-th argument */ - void (*xDelete)(void *); /* Destructor for the aux data */ - } apAux[1]; /* One slot for each function argument */ +struct AuxData { + int iOp; /* Instruction number of OP_Function opcode */ + int iArg; /* Index of function argument. */ + void *pAux; /* Aux data pointer */ + void (*xDelete)(void *); /* Destructor for the aux data */ + AuxData *pNext; /* Next element in list */ }; /* @@ -264,12 +263,13 @@ struct VdbeFunc { */ struct sqlite3_context { FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */ - VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */ Mem s; /* The return value is stored here */ Mem *pMem; /* Memory cell used to store aggregate context */ CollSeq *pColl; /* Collating sequence */ int isError; /* Error code returned by the function. */ int skipFlag; /* Skip skip accumulator loading if true */ + int iOp; /* Instruction number of OP_Function */ + Vdbe *pVdbe; /* The VM that owns this context */ }; /* @@ -368,6 +368,7 @@ struct Vdbe { SubProgram *pProgram; /* Linked list of all sub-programs used by VM */ int nOnceFlag; /* Size of array aOnceFlag[] */ u8 *aOnceFlag; /* Flags for OP_Once */ + AuxData *pAuxData; /* Linked list of auxdata allocations */ }; /* @@ -410,7 +411,7 @@ u32 sqlite3VdbeSerialTypeLen(u32); u32 sqlite3VdbeSerialType(Mem*, int); u32 sqlite3VdbeSerialPut(unsigned char*, int, Mem*, int); u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); -void sqlite3VdbeDeleteAuxData(VdbeFunc*, int); +void sqlite3VdbeDeleteAuxData(Vdbe*, int, int); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); int sqlite3VdbeIdxKeyCompare(VdbeCursor*,UnpackedRecord*,int*); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 854396a37..7e3ae843f 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -584,14 +584,14 @@ void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){ ** the user-function defined by pCtx. */ void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){ - VdbeFunc *pVdbeFunc; + AuxData *pAuxData; assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); - pVdbeFunc = pCtx->pVdbeFunc; - if( !pVdbeFunc || iArg>=pVdbeFunc->nAux || iArg<0 ){ - return 0; + for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){ + if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break; } - return pVdbeFunc->apAux[iArg].pAux; + + return (pAuxData ? pAuxData->pAux : 0); } /* @@ -605,29 +605,26 @@ void sqlite3_set_auxdata( void *pAux, void (*xDelete)(void*) ){ - struct AuxData *pAuxData; - VdbeFunc *pVdbeFunc; - if( iArg<0 ) goto failed; + AuxData *pAuxData; + Vdbe *pVdbe = pCtx->pVdbe; assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); - pVdbeFunc = pCtx->pVdbeFunc; - if( !pVdbeFunc || pVdbeFunc->nAux<=iArg ){ - int nAux = (pVdbeFunc ? pVdbeFunc->nAux : 0); - int nMalloc = sizeof(VdbeFunc) + sizeof(struct AuxData)*iArg; - pVdbeFunc = sqlite3DbRealloc(pCtx->s.db, pVdbeFunc, nMalloc); - if( !pVdbeFunc ){ - goto failed; - } - pCtx->pVdbeFunc = pVdbeFunc; - memset(&pVdbeFunc->apAux[nAux], 0, sizeof(struct AuxData)*(iArg+1-nAux)); - pVdbeFunc->nAux = iArg+1; - pVdbeFunc->pFunc = pCtx->pFunc; - } + if( iArg<0 ) goto failed; - pAuxData = &pVdbeFunc->apAux[iArg]; - if( pAuxData->pAux && pAuxData->xDelete ){ + for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){ + if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break; + } + if( pAuxData==0 ){ + pAuxData = sqlite3DbMallocZero(pVdbe->db, sizeof(AuxData)); + if( !pAuxData ) goto failed; + pAuxData->iOp = pCtx->iOp; + pAuxData->iArg = iArg; + pAuxData->pNext = pVdbe->pAuxData; + pVdbe->pAuxData = pAuxData; + }else if( pAuxData->xDelete ){ pAuxData->xDelete(pAuxData->pAux); } + pAuxData->pAux = pAux; pAuxData->xDelete = xDelete; return; diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 654230dfa..3235e1428 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -251,8 +251,8 @@ int sqlite3VdbeMakeLabel(Vdbe *p){ void sqlite3VdbeResolveLabel(Vdbe *p, int x){ int j = -1-x; assert( p->magic==VDBE_MAGIC_INIT ); - assert( j>=0 && j<p->nLabel ); - if( p->aLabel ){ + assert( j<p->nLabel ); + if( j>=0 && p->aLabel ){ p->aLabel[j] = p->nOp; } } @@ -576,8 +576,7 @@ void sqlite3VdbeChangeP5(Vdbe *p, u8 val){ ** the address of the next instruction to be coded. */ void sqlite3VdbeJumpHere(Vdbe *p, int addr){ - assert( addr>=0 || p->db->mallocFailed ); - if( addr>=0 ) sqlite3VdbeChangeP2(p, addr, p->nOp); + if( ALWAYS(addr>=0) ) sqlite3VdbeChangeP2(p, addr, p->nOp); } @@ -613,13 +612,6 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){ if( db->pnBytesFreed==0 ) sqlite3_free(p4); break; } - case P4_VDBEFUNC: { - VdbeFunc *pVdbeFunc = (VdbeFunc *)p4; - freeEphemeralFunction(db, pVdbeFunc->pFunc); - if( db->pnBytesFreed==0 ) sqlite3VdbeDeleteAuxData(pVdbeFunc, 0); - sqlite3DbFree(db, pVdbeFunc); - break; - } case P4_FUNCDEF: { freeEphemeralFunction(db, (FuncDef*)p4); break; @@ -1649,6 +1641,10 @@ static void closeAllCursors(Vdbe *p){ p->pDelFrame = pDel->pParent; sqlite3VdbeFrameDelete(pDel); } + + /* Delete any auxdata allocations made by the VM */ + sqlite3VdbeDeleteAuxData(p, -1, 0); + assert( p->pAuxData==0 ); } /* @@ -2447,20 +2443,35 @@ int sqlite3VdbeFinalize(Vdbe *p){ } /* -** Call the destructor for each auxdata entry in pVdbeFunc for which -** the corresponding bit in mask is clear. Auxdata entries beyond 31 -** are always destroyed. To destroy all auxdata entries, call this -** routine with mask==0. +** If parameter iOp is less than zero, then invoke the destructor for +** all auxiliary data pointers currently cached by the VM passed as +** the first argument. +** +** Or, if iOp is greater than or equal to zero, then the destructor is +** only invoked for those auxiliary data pointers created by the user +** function invoked by the OP_Function opcode at instruction iOp of +** VM pVdbe, and only then if: +** +** * the associated function parameter is the 32nd or later (counting +** from left to right), or +** +** * the corresponding bit in argument mask is clear (where the first +** function parameter corrsponds to bit 0 etc.). */ -void sqlite3VdbeDeleteAuxData(VdbeFunc *pVdbeFunc, int mask){ - int i; - for(i=0; i<pVdbeFunc->nAux; i++){ - struct AuxData *pAux = &pVdbeFunc->apAux[i]; - if( (i>31 || !(mask&(((u32)1)<<i))) && pAux->pAux ){ +void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){ + AuxData **pp = &pVdbe->pAuxData; + while( *pp ){ + AuxData *pAux = *pp; + if( (iOp<0) + || (pAux->iOp==iOp && (pAux->iArg>31 || !(mask & ((u32)1<<pAux->iArg)))) + ){ if( pAux->xDelete ){ pAux->xDelete(pAux->pAux); } - pAux->pAux = 0; + *pp = pAux->pNext; + sqlite3DbFree(pVdbe->db, pAux); + }else{ + pp= &pAux->pNext; } } } @@ -2980,7 +2991,7 @@ int sqlite3VdbeRecordCompare( int nKey1, const void *pKey1, /* Left key */ UnpackedRecord *pPKey2 /* Right key */ ){ - int d1; /* Offset into aKey[] of next data element */ + u32 d1; /* Offset into aKey[] of next data element */ u32 idx1; /* Offset into aKey[] of next header element */ u32 szHdr1; /* Number of bytes in header */ int i = 0; @@ -3014,7 +3025,7 @@ int sqlite3VdbeRecordCompare( /* Read the serial types for the next element in each key. */ idx1 += getVarint32( aKey1+idx1, serial_type1 ); - if( d1>=nKey1 && sqlite3VdbeSerialTypeLen(serial_type1)>0 ) break; + if( d1+sqlite3VdbeSerialTypeLen(serial_type1)>(u32)nKey1 ) break; /* Extract the values to be compared. */ @@ -3243,7 +3254,7 @@ sqlite3 *sqlite3VdbeDb(Vdbe *v){ ** ** The returned value must be freed by the caller using sqlite3ValueFree(). */ -sqlite3_value *sqlite3VdbeGetValue(Vdbe *v, int iVar, u8 aff){ +sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff){ assert( iVar>0 ); if( v ){ Mem *pMem = &v->aVar[iVar-1]; diff --git a/src/vtab.c b/src/vtab.c index 958202c31..a7fd17a35 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -825,8 +825,8 @@ int sqlite3VtabSync(sqlite3 *db, char **pzErrmsg){ if( pVtab && (x = pVtab->pModule->xSync)!=0 ){ rc = x(pVtab); sqlite3DbFree(db, *pzErrmsg); - *pzErrmsg = sqlite3DbStrDup(db, pVtab->zErrMsg); - sqlite3_free(pVtab->zErrMsg); + *pzErrmsg = pVtab->zErrMsg; + pVtab->zErrMsg = 0; } } db->aVTrans = aVTrans; diff --git a/src/where.c b/src/where.c index e18e88623..02193785b 100644 --- a/src/where.c +++ b/src/where.c @@ -45,6 +45,8 @@ typedef struct WherePath WherePath; typedef struct WhereTerm WhereTerm; typedef struct WhereLoopBuilder WhereLoopBuilder; typedef struct WhereScan WhereScan; +typedef struct WhereOrCost WhereOrCost; +typedef struct WhereOrSet WhereOrSet; /* ** Cost X is tracked as 10*log2(X) stored in a 16-bit integer. The @@ -152,6 +154,27 @@ struct WhereLoop { WhereTerm *aLTermSpace[4]; /* Initial aLTerm[] space */ }; +/* This object holds the prerequisites and the cost of running a +** subquery on one operand of an OR operator in the WHERE clause. +** See WhereOrSet for additional information +*/ +struct WhereOrCost { + Bitmask prereq; /* Prerequisites */ + WhereCost rRun; /* Cost of running this subquery */ + WhereCost nOut; /* Number of outputs for this subquery */ +}; + +/* The WhereOrSet object holds a set of possible WhereOrCosts that +** correspond to the subquery(s) of OR-clause processing. At most +** favorable N_OR_COST elements are retained. +*/ +#define N_OR_COST 3 +struct WhereOrSet { + u16 n; /* Number of valid a[] entries */ + WhereOrCost a[N_OR_COST]; /* Set of best costs */ +}; + + /* Forward declaration of methods */ static int whereLoopResize(sqlite3*, WhereLoop*, int); @@ -366,7 +389,7 @@ struct WhereLoopBuilder { WhereClause *pWC; /* WHERE clause terms */ ExprList *pOrderBy; /* ORDER BY clause */ WhereLoop *pNew; /* Template WhereLoop */ - WhereLoop *pBest; /* If non-NULL, store single best loop here */ + WhereOrSet *pOrSet; /* Record best loops here, if not NULL */ }; /* @@ -510,6 +533,54 @@ int sqlite3WhereOkOnePass(WhereInfo *pWInfo){ } /* +** Move the content of pSrc into pDest +*/ +static void whereOrMove(WhereOrSet *pDest, WhereOrSet *pSrc){ + pDest->n = pSrc->n; + memcpy(pDest->a, pSrc->a, pDest->n*sizeof(pDest->a[0])); +} + +/* +** Try to insert a new prerequisite/cost entry into the WhereOrSet pSet. +** +** The new entry might overwrite an existing entry, or it might be +** appended, or it might be discarded. Do whatever is the right thing +** so that pSet keeps the N_OR_COST best entries seen so far. +*/ +static int whereOrInsert( + WhereOrSet *pSet, /* The WhereOrSet to be updated */ + Bitmask prereq, /* Prerequisites of the new entry */ + WhereCost rRun, /* Run-cost of the new entry */ + WhereCost nOut /* Number of outputs for the new entry */ +){ + u16 i; + WhereOrCost *p; + for(i=pSet->n, p=pSet->a; i>0; i--, p++){ + if( rRun<=p->rRun && (prereq & p->prereq)==prereq ){ + goto whereOrInsert_done; + } + if( p->rRun<=rRun && (p->prereq & prereq)==p->prereq ){ + return 0; + } + } + if( pSet->n<N_OR_COST ){ + p = &pSet->a[pSet->n++]; + p->nOut = nOut; + }else{ + p = pSet->a; + for(i=1; i<pSet->n; i++){ + if( p->rRun>pSet->a[i].rRun ) p = pSet->a + i; + } + if( p->rRun<=rRun ) return 0; + } +whereOrInsert_done: + p->prereq = prereq; + p->rRun = rRun; + if( p->nOut>nOut ) p->nOut = nOut; + return 1; +} + +/* ** Initialize a preallocated WhereClause structure. */ static void whereClauseInit( @@ -1057,7 +1128,7 @@ static int isLikeOrGlob( if( op==TK_VARIABLE ){ Vdbe *pReprepare = pParse->pReprepare; int iCol = pRight->iColumn; - pVal = sqlite3VdbeGetValue(pReprepare, iCol, SQLITE_AFF_NONE); + pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_NONE); if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){ z = (char *)sqlite3_value_text(pVal); } @@ -2164,7 +2235,7 @@ static void constructAutomaticIndex( /* Fill the automatic index with content */ addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); regRecord = sqlite3GetTempReg(pParse); - sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 1); + sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 1, 0); sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); @@ -2521,7 +2592,7 @@ static int valueFromExpr( ){ int iVar = pExpr->iColumn; sqlite3VdbeSetVarmask(pParse->pVdbe, iVar); - *pp = sqlite3VdbeGetValue(pParse->pReprepare, iVar, aff); + *pp = sqlite3VdbeGetBoundValue(pParse->pReprepare, iVar, aff); return SQLITE_OK; } return sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, aff, pp); @@ -3179,6 +3250,7 @@ static Bitmask codeOneLoopStart( WhereClause *pWC; /* Decomposition of the entire WHERE clause */ WhereTerm *pTerm; /* A WHERE clause term */ Parse *pParse; /* Parsing context */ + sqlite3 *db; /* Database connection */ Vdbe *v; /* The prepared stmt under constructions */ struct SrcList_item *pTabItem; /* FROM clause term being coded */ int addrBrk; /* Jump here to break out of the loop */ @@ -3190,6 +3262,7 @@ static Bitmask codeOneLoopStart( pParse = pWInfo->pParse; v = pParse->pVdbe; pWC = &pWInfo->sWC; + db = pParse->db; pLevel = &pWInfo->a[iLevel]; pLoop = pLevel->pWLoop; pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; @@ -3480,7 +3553,7 @@ static Bitmask codeOneLoopStart( ** starting at regBase. */ regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff); - zEndAff = sqlite3DbStrDup(pParse->db, zStartAff); + zEndAff = sqlite3DbStrDup(db, zStartAff); addrNxt = pLevel->addrNxt; /* If we are doing a reverse order scan on an ascending index, or @@ -3565,8 +3638,8 @@ static Bitmask codeOneLoopStart( nConstraint++; testcase( pRangeEnd->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */ } - sqlite3DbFree(pParse->db, zStartAff); - sqlite3DbFree(pParse->db, zEndAff); + sqlite3DbFree(db, zStartAff); + sqlite3DbFree(db, zEndAff); /* Top of the loop body */ pLevel->p2 = sqlite3VdbeCurrentAddr(v); @@ -3693,7 +3766,7 @@ static Bitmask codeOneLoopStart( int nNotReady; /* The number of notReady tables */ struct SrcList_item *origSrc; /* Original list of tables */ nNotReady = pWInfo->nLevel - iLevel - 1; - pOrTab = sqlite3StackAllocRaw(pParse->db, + pOrTab = sqlite3StackAllocRaw(db, sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0])); if( pOrTab==0 ) return notReady; pOrTab->nAlloc = (u8)(nNotReady + 1); @@ -3743,11 +3816,12 @@ static Bitmask codeOneLoopStart( int iTerm; for(iTerm=0; iTerm<pWC->nTerm; iTerm++){ 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|TERM_ORINFO) ) continue; + if( pWC->a[iTerm].wtFlags & (TERM_ORINFO) ) continue; if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue; - pExpr = sqlite3ExprDup(pParse->db, pExpr, 0); - pAndExpr = sqlite3ExprAnd(pParse->db, pAndExpr, pExpr); + pExpr = sqlite3ExprDup(db, pExpr, 0); + pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr); } if( pAndExpr ){ pAndExpr = sqlite3PExpr(pParse, TK_AND, 0, pAndExpr, 0); @@ -3767,7 +3841,7 @@ static Bitmask codeOneLoopStart( pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY | WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY, iCovCur); - assert( pSubWInfo || pParse->nErr || pParse->db->mallocFailed ); + assert( pSubWInfo || pParse->nErr || db->mallocFailed ); if( pSubWInfo ){ WhereLoop *pSubLoop; explainOneScan( @@ -3822,13 +3896,13 @@ static Bitmask codeOneLoopStart( if( pCov ) pLevel->iIdxCur = iCovCur; if( pAndExpr ){ pAndExpr->pLeft = 0; - sqlite3ExprDelete(pParse->db, pAndExpr); + sqlite3ExprDelete(db, pAndExpr); } sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v)); sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk); sqlite3VdbeResolveLabel(v, iLoopBody); - if( pWInfo->nLevel>1 ) sqlite3StackFree(pParse->db, pOrTab); + if( pWInfo->nLevel>1 ) sqlite3StackFree(db, pOrTab); if( !untestedTerms ) disableTerm(pLevel, pTerm); }else #endif /* SQLITE_OMIT_OR_OPTIMIZATION */ @@ -3883,9 +3957,8 @@ static Bitmask codeOneLoopStart( ** the implied "t1.a=123" constraint. */ for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ - Expr *pE; + Expr *pE, *pEAlt; WhereTerm *pAlt; - Expr sEq; if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( pTerm->eOperator!=(WO_EQUIV|WO_EQ) ) continue; if( pTerm->leftCursor!=iCur ) continue; @@ -3899,9 +3972,13 @@ static Bitmask codeOneLoopStart( testcase( pAlt->eOperator & WO_EQ ); testcase( pAlt->eOperator & WO_IN ); VdbeNoopComment((v, "begin transitive constraint")); - sEq = *pAlt->pExpr; - sEq.pLeft = pE->pLeft; - sqlite3ExprIfFalse(pParse, &sEq, addrCont, SQLITE_JUMPIFNULL); + pEAlt = sqlite3StackAllocRaw(db, sizeof(*pEAlt)); + if( pEAlt ){ + *pEAlt = *pAlt->pExpr; + pEAlt->pLeft = pE->pLeft; + sqlite3ExprIfFalse(pParse, pEAlt, addrCont, SQLITE_JUMPIFNULL); + sqlite3StackFree(db, pEAlt); + } } /* For a LEFT OUTER JOIN, generate code that will record the fact that @@ -4072,12 +4149,12 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ ** fewer dependencies than the template. Otherwise a new WhereLoop is ** added based on the template. ** -** If pBuilder->pBest is not NULL then we only care about the very -** best template and that template should be stored in pBuilder->pBest. -** If pBuilder->pBest is NULL then a list of the best templates are stored -** in pBuilder->pWInfo->pLoops. +** If pBuilder->pOrSet is not NULL then we only care about only the +** prerequisites and rRun and nOut costs of the N best loops. That +** information is gathered in the pBuilder->pOrSet object. This special +** processing mode is used only for OR clause processing. ** -** When accumulating multiple loops (when pBuilder->pBest is NULL) we +** When accumulating multiple loops (when pBuilder->pOrSet is NULL) we ** still might overwrite similar loops with the new template if the ** template is better. Loops may be overwritten if the following ** conditions are met: @@ -4094,30 +4171,22 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ WhereInfo *pWInfo = pBuilder->pWInfo; sqlite3 *db = pWInfo->pParse->db; - /* If pBuilder->pBest is defined, then only keep track of the single - ** best WhereLoop. pBuilder->pBest->maskSelf==0 indicates that no - ** prior WhereLoops have been evaluated and that the current pTemplate - ** is therefore the first and hence the best and should be retained. + /* If pBuilder->pOrSet is defined, then only keep track of the costs + ** and prereqs. */ - if( (p = pBuilder->pBest)!=0 ){ - if( p->maskSelf!=0 ){ - WhereCost rCost = whereCostAdd(p->rRun,p->rSetup); - WhereCost rTemplate = whereCostAdd(pTemplate->rRun,pTemplate->rSetup); - if( rCost < rTemplate ){ - testcase( rCost==rTemplate-1 ); - goto whereLoopInsert_noop; - } - if( rCost==rTemplate && (p->prereq & pTemplate->prereq)==p->prereq ){ - goto whereLoopInsert_noop; - } - } + if( pBuilder->pOrSet!=0 ){ +#if WHERETRACE_ENABLED + u16 n = pBuilder->pOrSet->n; + int x = +#endif + whereOrInsert(pBuilder->pOrSet, pTemplate->prereq, pTemplate->rRun, + pTemplate->nOut); #if WHERETRACE_ENABLED if( sqlite3WhereTrace & 0x8 ){ - sqlite3DebugPrintf(p->maskSelf==0 ? "ins-init: " : "ins-best: "); + sqlite3DebugPrintf(x?" or-%d: ":" or-X: ", n); whereLoopPrint(pTemplate, pWInfo->pTabList); } #endif - whereLoopXfer(db, p, pTemplate); return SQLITE_OK; } @@ -4211,7 +4280,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ whereLoopInsert_noop: #if WHERETRACE_ENABLED if( sqlite3WhereTrace & 0x8 ){ - sqlite3DebugPrintf(pBuilder->pBest ? "ins-skip: " : "ins-noop: "); + sqlite3DebugPrintf("ins-noop: "); whereLoopPrint(pTemplate, pWInfo->pTabList); } #endif @@ -4362,7 +4431,8 @@ static int whereLoopAddBtreeIndex( && !ExprHasProperty(pTerm->pExpr, EP_xIsSelect) ){ rc = whereInScanEst(pParse, pProbe, pTerm->pExpr->x.pList, &nOut); } - if( rc==SQLITE_OK ) pNew->nOut = whereCost(nOut); + assert( nOut==0 || rc==SQLITE_OK ); + if( nOut ) pNew->nOut = whereCost(nOut); } #endif if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){ @@ -4434,6 +4504,17 @@ static Bitmask columnsInIndex(Index *pIdx){ return m; } +/* Check to see if a partial index with pPartIndexWhere can be used +** in the current query. Return true if it can be and false if not. +*/ +static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){ + int i; + WhereTerm *pTerm; + for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){ + if( sqlite3ExprImpliesExpr(pTerm->pExpr, pWhere, iTab) ) return 1; + } + return 0; +} /* ** Add all WhereLoop objects for a single table of the join where the table @@ -4457,11 +4538,13 @@ static int whereLoopAddBtree( int b; /* A boolean value */ WhereCost rSize; /* number of rows in the table */ WhereCost rLogSize; /* Logarithm of the number of rows in the table */ + WhereClause *pWC; /* The parsed WHERE clause */ pNew = pBuilder->pNew; pWInfo = pBuilder->pWInfo; pTabList = pWInfo->pTabList; pSrc = pTabList->a + pNew->iTab; + pWC = pBuilder->pWC; assert( !IsVirtual(pSrc->pTab) ); if( pSrc->pIndex ){ @@ -4493,7 +4576,7 @@ static int whereLoopAddBtree( rLogSize = estLog(rSize); /* Automatic indexes */ - if( !pBuilder->pBest + if( !pBuilder->pOrSet && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 && pSrc->pIndex==0 && !pSrc->viaCoroutine @@ -4501,7 +4584,6 @@ static int whereLoopAddBtree( && !pSrc->isCorrelated ){ /* Generate auto-index WhereLoops */ - WhereClause *pWC = pBuilder->pWC; WhereTerm *pTerm; WhereTerm *pWCEnd = pWC->a + pWC->nTerm; for(pTerm=pWC->a; rc==SQLITE_OK && pTerm<pWCEnd; pTerm++){ @@ -4531,6 +4613,10 @@ static int whereLoopAddBtree( /* Loop over all indices */ for(; rc==SQLITE_OK && pProbe; pProbe=pProbe->pNext, iSortIdx++){ + if( pProbe->pPartIdxWhere!=0 + && !whereUsablePartialIndex(pNew->iTab, pWC, pProbe->pPartIdxWhere) ){ + continue; /* Partial index inappropriate for this query */ + } pNew->u.btree.nEq = 0; pNew->nLTerm = 0; pNew->iSortIdx = 0; @@ -4779,7 +4865,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ int iCur; WhereClause tempWC; WhereLoopBuilder sSubBuild; - WhereLoop sBest; + WhereOrSet sSum, sCur, sPrev; struct SrcList_item *pItem; pWC = pBuilder->pWC; @@ -4794,16 +4880,14 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc; WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm]; WhereTerm *pOrTerm; - WhereCost rTotal = 0; - WhereCost nRow = 0; - Bitmask prereq = mExtra; + int once = 1; + int i, j; - whereLoopInit(&sBest); pItem = pWInfo->pTabList->a + pNew->iTab; iCur = pItem->iCursor; sSubBuild = *pBuilder; sSubBuild.pOrderBy = 0; - sSubBuild.pBest = &sBest; + sSubBuild.pOrSet = &sCur; for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){ if( (pOrTerm->eOperator & WO_AND)!=0 ){ @@ -4818,39 +4902,48 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ }else{ continue; } - sBest.maskSelf = 0; - sBest.rSetup = 0; - sBest.rRun = 0; + sCur.n = 0; #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ rc = whereLoopAddVirtual(&sSubBuild); + for(i=0; i<sCur.n; i++) sCur.a[i].prereq |= mExtra; }else #endif { rc = whereLoopAddBtree(&sSubBuild, mExtra); } - /* sBest.maskSelf is always zero if an error occurs */ - assert( rc==SQLITE_OK || sBest.maskSelf==0 ); - if( sBest.maskSelf==0 ) break; - assert( sBest.rSetup==0 ); - rTotal = whereCostAdd(rTotal, sBest.rRun); - nRow = whereCostAdd(nRow, sBest.nOut); - prereq |= sBest.prereq; + assert( rc==SQLITE_OK || sCur.n==0 ); + if( sCur.n==0 ){ + sSum.n = 0; + break; + }else if( once ){ + whereOrMove(&sSum, &sCur); + once = 0; + }else{ + whereOrMove(&sPrev, &sSum); + sSum.n = 0; + for(i=0; i<sPrev.n; i++){ + for(j=0; j<sCur.n; j++){ + whereOrInsert(&sSum, sPrev.a[i].prereq | sCur.a[j].prereq, + whereCostAdd(sPrev.a[i].rRun, sCur.a[j].rRun), + whereCostAdd(sPrev.a[i].nOut, sCur.a[j].nOut)); + } + } + } } - assert( pNew->nLSlot>=1 ); - if( sBest.maskSelf ){ - pNew->nLTerm = 1; - pNew->aLTerm[0] = pTerm; - pNew->wsFlags = WHERE_MULTI_OR; - pNew->rSetup = 0; + pNew->nLTerm = 1; + pNew->aLTerm[0] = pTerm; + pNew->wsFlags = WHERE_MULTI_OR; + pNew->rSetup = 0; + pNew->iSortIdx = 0; + memset(&pNew->u, 0, sizeof(pNew->u)); + for(i=0; rc==SQLITE_OK && i<sSum.n; i++){ /* TUNING: Multiple by 3.5 for the secondary table lookup */ - pNew->rRun = rTotal + 18; assert( 18==whereCost(7)-whereCost(2) ); - pNew->nOut = nRow; - pNew->prereq = prereq; - memset(&pNew->u, 0, sizeof(pNew->u)); + pNew->rRun = sSum.a[i].rRun + 18; + pNew->nOut = sSum.a[i].nOut; + pNew->prereq = sSum.a[i].prereq; rc = whereLoopInsert(pBuilder, pNew); } - whereLoopClear(pWInfo->pParse->db, &sBest); } } return rc; @@ -5464,7 +5557,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ pLoop->rRun = 33; /* 33==whereCost(10) */ }else{ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->onError==OE_None ) continue; + if( pIdx->onError==OE_None || pIdx->pPartIdxWhere!=0 ) continue; for(j=0; j<pIdx->nColumn; j++){ pTerm = findTerm(pWC, iCur, pIdx->aiColumn[j], 0, WO_EQ, pIdx); if( pTerm==0 ) break; @@ -5657,7 +5750,8 @@ WhereInfo *sqlite3WhereBegin( pMaskSet = &pWInfo->sMaskSet; sWLB.pWInfo = pWInfo; sWLB.pWC = &pWInfo->sWC; - sWLB.pNew = (WhereLoop*)&pWInfo->a[nTabList]; + sWLB.pNew = (WhereLoop*)(((char*)pWInfo)+nByteWInfo); + assert( EIGHT_BYTE_ALIGNMENT(sWLB.pNew) ); whereLoopInit(sWLB.pNew); #ifdef SQLITE_DEBUG sWLB.pNew->cId = '*'; |