diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/delete.c | 8 | ||||
-rw-r--r-- | src/select.c | 8 | ||||
-rw-r--r-- | src/sqliteInt.h | 17 | ||||
-rw-r--r-- | src/update.c | 5 | ||||
-rw-r--r-- | src/where.c | 92 |
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); } } |