aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/select.c20
-rw-r--r--src/sqliteInt.h15
-rw-r--r--src/update.c22
-rw-r--r--src/where.c26
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 ){