aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/delete.c8
-rw-r--r--src/select.c8
-rw-r--r--src/sqliteInt.h17
-rw-r--r--src/update.c5
-rw-r--r--src/where.c92
5 files changed, 47 insertions, 83 deletions
diff --git a/src/delete.c b/src/delete.c
index 1850ac4a9..4fe8a88ea 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** in order to generate code for DELETE FROM statements.
**
-** $Id: delete.c,v 1.198 2009/03/05 03:48:07 shane Exp $
+** $Id: delete.c,v 1.199 2009/04/24 15:46:22 drh Exp $
*/
#include "sqliteInt.h"
@@ -393,13 +393,15 @@ void sqlite3DeleteFrom(
{
int iRowid = ++pParse->nMem; /* Used for storing rowid values. */
int iRowSet = ++pParse->nMem; /* Register for rowset of rows to delete */
+ int regRowid; /* Actual register containing rowids */
/* Collect rowids of every row to be deleted.
*/
sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0,
- WHERE_FILL_ROWSET, iRowSet);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0,WHERE_DUPLICATES_OK);
if( pWInfo==0 ) goto delete_from_cleanup;
+ regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid, 0);
+ sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, regRowid);
if( db->flags & SQLITE_CountRows ){
sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
}
diff --git a/src/select.c b/src/select.c
index f00f708f0..3c806b187 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.509 2009/04/23 13:22:43 drh Exp $
+** $Id: select.c,v 1.510 2009/04/24 15:46:22 drh Exp $
*/
#include "sqliteInt.h"
@@ -3771,7 +3771,7 @@ int sqlite3Select(
/* This case is for non-aggregate queries
** Begin the database scan
*/
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, 0, 0);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, 0);
if( pWInfo==0 ) goto select_end;
/* If sorting index that was created by a prior OP_OpenEphemeral
@@ -3893,7 +3893,7 @@ int sqlite3Select(
** in the right order to begin with.
*/
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0, 0);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy, 0);
if( pWInfo==0 ) goto select_end;
if( pGroupBy==0 ){
/* The optimizer is able to deliver rows in group by order so
@@ -4151,7 +4151,7 @@ int sqlite3Select(
** of output.
*/
resetAccumulator(pParse, &sAggInfo);
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, flag, 0);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pMinMax, flag);
if( pWInfo==0 ){
sqlite3ExprListDelete(db, pDel);
goto select_end;
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 51729d16c..c3124757b 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.860 2009/04/23 13:22:44 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.861 2009/04/24 15:46:22 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@@ -1742,16 +1742,17 @@ struct WhereLevel {
};
/*
-** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin().
+** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin()
+** and the WhereInfo.wctrlFlags member.
*/
#define WHERE_ORDERBY_NORMAL 0x0000 /* No-op */
#define WHERE_ORDERBY_MIN 0x0001 /* ORDER BY processing for min() func */
#define WHERE_ORDERBY_MAX 0x0002 /* ORDER BY processing for max() func */
#define WHERE_ONEPASS_DESIRED 0x0004 /* Want to do one-pass UPDATE/DELETE */
-#define WHERE_FILL_ROWSET 0x0008 /* Save results in a RowSet object */
-#define WHERE_OMIT_OPEN 0x0010 /* Table cursor are already open */
-#define WHERE_OMIT_CLOSE 0x0020 /* Omit close of table & index cursors */
-#define WHERE_FILL_ROWTEST 0x0040 /* Save results using OP_RowSetTest */
+#define WHERE_DUPLICATES_OK 0x0008 /* Ok to return a row more than once */
+#define WHERE_OMIT_OPEN 0x0010 /* Table cursor are already open */
+#define WHERE_OMIT_CLOSE 0x0020 /* Omit close of table & index cursors */
+#define WHERE_FORCE_TABLE 0x0040 /* Do not use an index-only search */
/*
** The WHERE clause processing routine has two halves. The
@@ -1764,8 +1765,6 @@ struct WhereInfo {
Parse *pParse; /* Parsing and code generating context */
u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE or DELETE */
- int regRowSet; /* Store rowids in this rowset */
- int iRowidHandler; /* Address of OP_RowSet or OP_RowSetTest */
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 */
@@ -2452,7 +2451,7 @@ Expr *sqlite3LimitWhere(Parse *, SrcList *, Expr *, ExprList *, Expr *, Expr *,
#endif
void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
-WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u8, int);
+WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u16);
void sqlite3WhereEnd(WhereInfo*);
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, int);
void sqlite3ExprCodeMove(Parse*, int, int, int);
diff --git a/src/update.c b/src/update.c
index 872e00da5..3d5332413 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.197 2009/04/22 17:15:03 drh Exp $
+** $Id: update.c,v 1.198 2009/04/24 15:46:22 drh Exp $
*/
#include "sqliteInt.h"
@@ -345,8 +345,7 @@ void sqlite3Update(
/* Begin the database scan
*/
sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid);
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0,
- WHERE_ONEPASS_DESIRED, 0);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0, WHERE_ONEPASS_DESIRED);
if( pWInfo==0 ) goto update_cleanup;
okOnePass = pWInfo->okOnePass;
diff --git a/src/where.c b/src/where.c
index 508c634d4..f02689b3e 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.389 2009/04/24 14:51:42 drh Exp $
+** $Id: where.c,v 1.390 2009/04/24 15:46:22 drh Exp $
*/
#include "sqliteInt.h"
@@ -2395,7 +2395,7 @@ static int codeAllEqualityTerms(
static Bitmask codeOneLoopStart(
WhereInfo *pWInfo, /* Complete information about the WHERE clause */
int iLevel, /* Which level of pWInfo->a[] should be coded */
- u8 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */
+ u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */
Bitmask notReady /* Which tables are currently available */
){
int j, k; /* Loop counters */
@@ -2411,21 +2411,6 @@ static Bitmask codeOneLoopStart(
struct SrcList_item *pTabItem; /* FROM clause term being coded */
int addrBrk; /* Jump here to break out of the loop */
int addrCont; /* Jump here to continue with next cycle */
- int regRowSet; /* Write rowids to this RowSet if non-negative */
-
- /* Sometimes, this function is required to generate code to do
- ** something with the rowid of each row scanned. Specifically,
- ** If pWInfo->regRowSet is non-zero, then the rowid must be inserted
- ** into the RowSet object stored in register pWInfo->regRowSet.
- **
- ** Extracting a rowid value from a VDBE cursor is not always a cheap
- ** operation, especially if the rowid is being extracted from an index
- ** cursor. If the rowid value is available as a by-product of the code
- ** generated to create the top of the scan loop, then it can be reused
- ** without extracting it from a cursor. The following two variables are
- ** used to communicate the availability of the rowid value to the C-code
- ** at the end of this function that generates the rowid-handling VDBE code.
- */
int iRowidReg = 0; /* Rowid is stored in this register, if not zero */
int iReleaseReg = 0; /* Temp register to free before returning */
@@ -2437,8 +2422,7 @@ static Bitmask codeOneLoopStart(
iCur = pTabItem->iCursor;
bRev = (pLevel->plan.wsFlags & WHERE_REVERSE)!=0;
omitTable = (pLevel->plan.wsFlags & WHERE_IDX_ONLY)!=0
- && (wctrlFlags & WHERE_FILL_ROWTEST)==0;
- regRowSet = pWInfo->regRowSet;
+ && (wctrlFlags & WHERE_FORCE_TABLE)==0;
/* Create labels for the "break" and "continue" instructions
** for the current loop. Jump to addrBrk to break out of a loop.
@@ -2836,14 +2820,13 @@ static Bitmask codeOneLoopStart(
** B: <after the loop>
**
*/
- const int f = WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE | WHERE_FILL_ROWTEST;
-
WhereClause *pOrWc; /* The OR-clause broken out into subterms */
WhereTerm *pFinal; /* Final subterm within the OR-clause. */
SrcList oneTab; /* Shortened table list */
int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */
- int regRowset = ++pParse->nMem; /* Register for RowSet object */
+ int regRowset; /* Register for RowSet object */
+ int regRowid; /* Register holding rowid */
int iLoopBody = sqlite3VdbeMakeLabel(v); /* Start of loop body */
int iRetInit; /* Address of regReturn init */
int ii;
@@ -2871,7 +2854,11 @@ static Bitmask codeOneLoopStart(
** fall through to the next instruction, just as an OP_Next does if
** called on an uninitialized cursor.
*/
- sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset);
+ if( (wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
+ regRowset = ++pParse->nMem;
+ regRowid = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset);
+ }
iRetInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, regReturn);
for(ii=0; ii<pOrWc->nTerm; ii++){
@@ -2880,20 +2867,18 @@ static Bitmask codeOneLoopStart(
WhereInfo *pSubWInfo; /* Info for single OR-term scan */
/* Loop through table entries that match term pOrTerm. */
- pSubWInfo = sqlite3WhereBegin(
- pParse, &oneTab, pOrTerm->pExpr, 0, f, regRowset);
+ pSubWInfo = sqlite3WhereBegin(pParse, &oneTab, pOrTerm->pExpr, 0,
+ WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE | WHERE_FORCE_TABLE);
if( pSubWInfo ){
- int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
- /* The call to sqlite3WhereBegin has coded an OP_RowSetTest
- ** at instruction iRowSet. Set P2 (the jump target) of this
- ** instruction to jump past the OP_Gosub coded below. This way,
- ** if the rowid is already in the hash-table, the body of the
- ** loop is not executed.
- */
- int iRowSet = pSubWInfo->iRowidHandler;
- assert( iRowSet>0 || pWInfo->pParse->db->mallocFailed );
- sqlite3VdbeChangeP2(v, iRowSet, sqlite3VdbeCurrentAddr(v) + 1);
- sqlite3VdbeChangeP4(v, iRowSet, (char *)iSet, P4_INT32);
+ if( (wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
+ int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
+ int r;
+ r = sqlite3ExprCodeGetColumn(pParse, pTabItem->pTab, -1, iCur,
+ regRowid, 0);
+ sqlite3VdbeAddOp4(v, OP_RowSetTest, regRowset,
+ sqlite3VdbeCurrentAddr(v)+2,
+ r, (char*)iSet, P4_INT32);
+ }
sqlite3VdbeAddOp2(v, OP_Gosub, regReturn, iLoopBody);
/* Finish the loop through table entries that match term pOrTerm. */
@@ -2902,7 +2887,7 @@ static Bitmask codeOneLoopStart(
}
}
sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v));
- sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset);
+ /* sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset); */
sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk);
sqlite3VdbeResolveLabel(v, iLoopBody);
@@ -2965,28 +2950,6 @@ static Bitmask codeOneLoopStart(
pTerm->wtFlags |= TERM_CODED;
}
}
-
- /* Do the special rowid handling now. */
- if( regRowSet ){
- assert( regRowSet>0 );
- if( iRowidReg==0 ){
- /* The rowid was not available as a side-effect of the code
- ** genenerated above. So extract it from the cursor now.
- */
- assert( iReleaseReg==0 );
- iReleaseReg = iRowidReg = sqlite3GetTempReg(pParse);
- sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg);
- }
-
- if( pWInfo->wctrlFlags&WHERE_FILL_ROWSET ){
- sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, iRowidReg);
- VVA_ONLY( pWInfo->iRowidHandler = 0; )
- }else{
- assert( pWInfo->wctrlFlags&WHERE_FILL_ROWTEST );
- pWInfo->iRowidHandler =
- sqlite3VdbeAddOp3(v, OP_RowSetTest, regRowSet, 0, iRowidReg);
- }
- }
sqlite3ReleaseTempReg(pParse, iReleaseReg);
return notReady;
@@ -3120,8 +3083,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 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */
- int regRowSet /* Register hold RowSet if WHERE_FILL_ROWSET is set */
+ u16 wctrlFlags /* One of the WHERE_* flags defined in sqliteInt.h */
){
int i; /* Loop counter */
int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */
@@ -3170,11 +3132,9 @@ WhereInfo *sqlite3WhereBegin(
pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList;
pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
- pWInfo->regRowSet = regRowSet;
pWInfo->pWC = pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo];
pWInfo->wctrlFlags = wctrlFlags;
pMaskSet = (WhereMaskSet*)&pWC[1];
- assert( regRowSet==0 || (wctrlFlags&(WHERE_FILL_ROWSET|WHERE_FILL_ROWTEST)) );
/* Split the WHERE clause into separate subexpressions where each
** subexpression is separated by an AND operator.
@@ -3534,7 +3494,11 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
if( pLevel->iIdxCur>=0 ){
sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iIdxCur);
}
- sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrFirst);
+ if( pLevel->op==OP_Return ){
+ sqlite3VdbeAddOp2(v, OP_Gosub, pLevel->p1, pLevel->addrFirst);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrFirst);
+ }
sqlite3VdbeJumpHere(v, addr);
}
}