diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/select.c | 20 | ||||
-rw-r--r-- | src/sqliteInt.h | 15 | ||||
-rw-r--r-- | src/update.c | 22 | ||||
-rw-r--r-- | src/where.c | 26 |
4 files changed, 55 insertions, 28 deletions
diff --git a/src/select.c b/src/select.c index c7600e887..89fe2e13e 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.425 2008/04/01 05:07:15 drh Exp $ +** $Id: select.c,v 1.426 2008/04/10 13:33:18 drh Exp $ */ #include "sqliteInt.h" @@ -2677,7 +2677,7 @@ static int flattenSubquery( /* ** Analyze the SELECT statement passed as an argument to see if it -** is a min() or max() query. Return ORDERBY_MIN or ORDERBY_MAX if +** is a min() or max() query. Return WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX if ** it is, or 0 otherwise. At present, a query is considered to be ** a min()/max() query if: ** @@ -2690,18 +2690,18 @@ static int minMaxQuery(Parse *pParse, Select *p){ Expr *pExpr; ExprList *pEList = p->pEList; - if( pEList->nExpr!=1 ) return ORDERBY_NORMAL; + if( pEList->nExpr!=1 ) return WHERE_ORDERBY_NORMAL; pExpr = pEList->a[0].pExpr; pEList = pExpr->pList; if( pExpr->op!=TK_AGG_FUNCTION || pEList==0 || pEList->nExpr!=1 ) return 0; - if( pEList->a[0].pExpr->op!=TK_AGG_COLUMN ) return ORDERBY_NORMAL; - if( pExpr->token.n!=3 ) return ORDERBY_NORMAL; + if( pEList->a[0].pExpr->op!=TK_AGG_COLUMN ) return WHERE_ORDERBY_NORMAL; + if( pExpr->token.n!=3 ) return WHERE_ORDERBY_NORMAL; if( sqlite3StrNICmp((char*)pExpr->token.z,"min",3)==0 ){ - return ORDERBY_MIN; + return WHERE_ORDERBY_MIN; }else if( sqlite3StrNICmp((char*)pExpr->token.z,"max",3)==0 ){ - return ORDERBY_MAX; + return WHERE_ORDERBY_MAX; } - return ORDERBY_NORMAL; + return WHERE_ORDERBY_NORMAL; } /* @@ -3559,7 +3559,7 @@ int sqlite3Select( if( flag ){ pDel = pMinMax = sqlite3ExprListDup(db, p->pEList->a[0].pExpr->pList); if( pMinMax && !db->mallocFailed ){ - pMinMax->a[0].sortOrder = ((flag==ORDERBY_MIN)?0:1); + pMinMax->a[0].sortOrder = ((flag==WHERE_ORDERBY_MIN)?0:1); pMinMax->a[0].pExpr->op = TK_COLUMN; } } @@ -3577,7 +3577,7 @@ int sqlite3Select( updateAccumulator(pParse, &sAggInfo); if( !pMinMax && flag ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, pWInfo->iBreak); - VdbeComment((v, "%s() by index", (flag==ORDERBY_MIN?"min":"max"))); + VdbeComment((v, "%s() by index", (flag==WHERE_ORDERBY_MIN?"min":"max"))); } sqlite3WhereEnd(pWInfo); finalizeAggFunctions(pParse, &sAggInfo); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index e124031eb..cd831f07d 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.689 2008/04/05 18:41:43 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.690 2008/04/10 13:33:18 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1311,9 +1311,13 @@ struct WhereLevel { sqlite3_index_info *pIdxInfo; /* Index info for n-th source table */ }; -#define ORDERBY_NORMAL 0 -#define ORDERBY_MIN 1 -#define ORDERBY_MAX 2 +/* +** Flags appropriate for the wflags parameter of sqlite3WhereBegin(). +*/ +#define WHERE_ORDERBY_NORMAL 0 /* No-op */ +#define WHERE_ORDERBY_MIN 1 /* ORDER BY processing for min() func */ +#define WHERE_ORDERBY_MAX 2 /* ORDER BY processing for max() func */ +#define WHERE_ONEPASS_DESIRED 4 /* Want to do one-pass UPDATE/DELETE */ /* ** The WHERE clause processing routine has two halves. The @@ -1323,7 +1327,8 @@ struct WhereLevel { ** into the second half to give some continuity. */ struct WhereInfo { - Parse *pParse; + Parse *pParse; /* Parsing and code generating context */ + u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE or DELETE */ SrcList *pTabList; /* List of tables in the join */ int iTop; /* The very beginning of the WHERE loop */ int iContinue; /* Jump here to continue with next record */ diff --git a/src/update.c b/src/update.c index a22d901e9..0d8e61ab6 100644 --- a/src/update.c +++ b/src/update.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** -** $Id: update.c,v 1.175 2008/04/01 05:07:15 drh Exp $ +** $Id: update.c,v 1.176 2008/04/10 13:33:18 drh Exp $ */ #include "sqliteInt.h" @@ -103,6 +103,7 @@ void sqlite3Update( NameContext sNC; /* The name-context to resolve expressions in */ int iDb; /* Database containing the table being updated */ int j1; /* Addresses of jump instructions */ + int okOnePass; /* True for one-pass algorithm without the FIFO */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* Trying to update a view */ @@ -341,13 +342,16 @@ void sqlite3Update( /* Begin the database scan */ - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0); + sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, + WHERE_ONEPASS_DESIRED); if( pWInfo==0 ) goto update_cleanup; + okOnePass = pWInfo->okOnePass; /* Remember the rowid of every item to be updated. */ - sqlite3VdbeAddOp2(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid,iCur,regOldRowid); - sqlite3VdbeAddOp2(v, OP_FifoWrite, regOldRowid, 0); + sqlite3VdbeAddOp2(v, IsVirtual(pTab)?OP_VRowid:OP_Rowid, iCur, regOldRowid); + if( !okOnePass ) sqlite3VdbeAddOp2(v, OP_FifoWrite, regOldRowid, 0); /* End the database scan loop. */ @@ -367,7 +371,7 @@ void sqlite3Update( ** action, then we need to open all indices because we might need ** to be deleting some records. */ - sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite); + if( !okOnePass ) sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite); if( onError==OE_Replace ){ openAll = 1; }else{ @@ -395,7 +399,13 @@ void sqlite3Update( } /* Top of the update loop */ - addr = sqlite3VdbeAddOp2(v, OP_FifoRead, regOldRowid, 0); + if( okOnePass ){ + int a1 = sqlite3VdbeAddOp1(v, OP_NotNull, regOldRowid); + addr = sqlite3VdbeAddOp0(v, OP_Goto); + sqlite3VdbeJumpHere(v, a1); + }else{ + addr = sqlite3VdbeAddOp2(v, OP_FifoRead, regOldRowid, 0); + } if( triggers_exist ){ int regRowid; diff --git a/src/where.c b/src/where.c index e70b0057c..4bdb26929 100644 --- a/src/where.c +++ b/src/where.c @@ -16,7 +16,7 @@ ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". ** -** $Id: where.c,v 1.297 2008/04/01 05:07:15 drh Exp $ +** $Id: where.c,v 1.298 2008/04/10 13:33:18 drh Exp $ */ #include "sqliteInt.h" @@ -2002,7 +2002,7 @@ WhereInfo *sqlite3WhereBegin( SrcList *pTabList, /* A list of all tables to be scanned */ Expr *pWhere, /* The WHERE clause */ ExprList **ppOrderBy, /* An ORDER BY clause, or NULL */ - u8 obflag /* One of ORDERBY_MIN, ORDERBY_MAX or ORDERBY_NORMAL */ + u8 wflags /* One of the WHERE_* flags defined in sqliteInt.h */ ){ int i; /* Loop counter */ WhereInfo *pWInfo; /* Will become the return value of this function */ @@ -2210,6 +2210,17 @@ WhereInfo *sqlite3WhereBegin( *ppOrderBy = 0; } + /* If the caller is an UPDATE or DELETE statement that is requesting + ** to use a one-pass algorithm, determine if this is appropriate. + ** The one-pass algorithm only works if the WHERE clause constraints + ** the statement to update a single row. + */ + assert( (wflags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 ); + if( (wflags & WHERE_ONEPASS_DESIRED)!=0 && (andFlags & WHERE_UNIQUE)!=0 ){ + pWInfo->okOnePass = 1; + pWInfo->a[0].flags &= ~WHERE_IDX_ONLY; + } + /* Open all tables in the pTabList and any indices selected for ** searching those tables. */ @@ -2258,8 +2269,9 @@ WhereInfo *sqlite3WhereBegin( }else #endif if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){ - sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, OP_OpenRead); - if( pTab->nCol<(sizeof(Bitmask)*8) ){ + int op = pWInfo->okOnePass ? OP_OpenWrite : OP_OpenRead; + sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op); + if( !pWInfo->okOnePass && pTab->nCol<(sizeof(Bitmask)*8) ){ Bitmask b = pTabItem->colUsed; int n = 0; for(; b; b=b>>1, n++){} @@ -2496,7 +2508,7 @@ WhereInfo *sqlite3WhereBegin( ** the first one after the nEq equality constraints in the index, ** this requires some special handling. */ - if( (obflag==ORDERBY_MIN) + if( (wflags&WHERE_ORDERBY_MIN)!=0 && (pLevel->flags&WHERE_ORDERBY) && (pIdx->nColumn>nEq) && (pOrderBy->a[0].pExpr->iColumn==pIdx->aiColumn[nEq]) @@ -2635,7 +2647,7 @@ WhereInfo *sqlite3WhereBegin( regBase = codeAllEqualityTerms(pParse, pLevel, &wc, notReady, 1); nxt = pLevel->nxt; - if( (obflag==ORDERBY_MIN) + if( (wflags&WHERE_ORDERBY_MIN)!=0 && (pLevel->flags&WHERE_ORDERBY) && (pIdx->nColumn>nEq) && (pOrderBy->a[0].pExpr->iColumn==pIdx->aiColumn[nEq]) @@ -2853,7 +2865,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ Table *pTab = pTabItem->pTab; assert( pTab!=0 ); if( pTab->isEphem || pTab->pSelect ) continue; - if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){ + if( !pWInfo->okOnePass && (pLevel->flags & WHERE_IDX_ONLY)==0 ){ sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor); } if( pLevel->pIdx!=0 ){ |