-C Fix\sa\sNULL\spointer\sdereference\sfollowing\san\sOOM\serror\sin\sthe\scolumn\sname\nresolver.\s(CVS\s6685)
-D 2009-05-28T14:34:50
+C Remove\sreferences\sto\sdeleted\sfunction\ssqlite3ExprRegister().\s\sChanges\sto\nthe\sexpr.c\ssource\smodule\sto\spromote\sbetter\stesting.\s(CVS\s6686)
+D 2009-05-28T21:04:38
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in 583e87706abc3026960ed759aff6371faf84c211
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
F src/btree.c 41bee6e4699e61f9d33beabfcf13caba4467c20a
F src/btree.h 3748683b382bc3022f23840c0a35d3231b24fc6e
F src/btreeInt.h df64030d632f8c8ac217ed52e8b6b3eacacb33a5
-F src/build.c 567574f5756e9e462cf50c5da1895dc43672bafe
+F src/build.c dedb5bcbd8261c182e831b4784a596c000c72958
F src/callback.c 57359fa93de47c341b6b8ee504a88ff276397686
F src/complete.c 5ad5c6cd4548211867c204c41a126d73a9fbcea0
F src/date.c ab5f7137656652a48434d64f96bdcdc823bb23b3
F src/delete.c cb791855c7948cecc96def9d97989879ca26f257
-F src/expr.c 2f8b6e5c3c867fa421189ad5692b1ff60ecc59c4
+F src/expr.c 9d25d7229719334dc87909f8094b10d033b994f1
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
F src/func.c 9d7b47729c337c5e4b78d795922ed34eec4aef67
F src/global.c 448419c44ce0701104c2121b0e06919b44514c0c
F src/shell.c 7eacd0bdaa887931f5ff205c9defc3e8df95a2dd
F src/sqlite.h.in 79210c4d8905cfb4b038486dde5f36fabb796a86
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
-F src/sqliteInt.h 97f9125229c14cd3afa6c4fed4b419a1899be476
+F src/sqliteInt.h 39fb1a85a71f9a86817ccc55b308335b4b43012a
F src/sqliteLimit.h ffe93f5a0c4e7bd13e70cd7bf84cfb5c3465f45d
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
F src/table.c cc86ad3d6ad54df7c63a3e807b5783c90411a08d
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
-P 376ecf0d87e4a2329f5861401f83ed9ceb35d528
-R bbce5972206d6f118dd6353677bfd682
+P 3b46142532934d17aa136c2e56e58e7828df0f54
+R 6a3a4185326252490b36e399fe92cbcc
U drh
-Z f90523b52af270223148e00c0be5042d
+Z 2830ef720e4e0990284e68ba861f067a
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
-** $Id: expr.c,v 1.438 2009/05/28 01:00:55 drh Exp $
+** $Id: expr.c,v 1.439 2009/05/28 21:04:38 drh Exp $
*/
#include "sqliteInt.h"
case TK_COLUMN:
case TK_AGG_FUNCTION:
case TK_AGG_COLUMN:
-#ifndef SQLITE_OMIT_SUBQUERY
- case TK_SELECT:
- case TK_EXISTS:
- testcase( pExpr->op==TK_SELECT );
- testcase( pExpr->op==TK_EXISTS );
-#endif
testcase( pExpr->op==TK_ID );
testcase( pExpr->op==TK_COLUMN );
testcase( pExpr->op==TK_AGG_FUNCTION );
pWalker->u.i = 0;
return WRC_Abort;
default:
+ testcase( pExpr->op==TK_SELECT ); /* selectNodeIsConstant will disallow */
+ testcase( pExpr->op==TK_EXISTS ); /* selectNodeIsConstant will disallow */
return WRC_Continue;
}
}
}
/*
-** Return true if the IN operator optimization is enabled and
-** the SELECT statement p exists and is of the
-** simple form:
+** Return true if we are able to the IN operator optimization on a
+** query of the form
**
-** SELECT <column> FROM <table>
+** x IN (SELECT ...)
+**
+** Where the SELECT... clause is as specified by the parameter to this
+** routine.
**
-** If this is the case, it may be possible to use an existing table
-** or index instead of generating an epheremal table.
+** The Select object passed in has already been preprocessed and no
+** errors have been found.
*/
#ifndef SQLITE_OMIT_SUBQUERY
static int isCandidateForInOpt(Select *p){
if( p==0 ) return 0; /* right-hand side of IN is SELECT */
if( p->pPrior ) return 0; /* Not a compound SELECT */
if( p->selFlags & (SF_Distinct|SF_Aggregate) ){
- return 0; /* No DISTINCT keyword and no aggregate functions */
+ testcase( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
+ testcase( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate );
+ return 0; /* No DISTINCT keyword and no aggregate functions */
}
- if( p->pGroupBy ) return 0; /* Has no GROUP BY clause */
+ assert( p->pGroupBy==0 ); /* Has no GROUP BY clause */
if( p->pLimit ) return 0; /* Has no LIMIT clause */
- if( p->pOffset ) return 0;
+ assert( p->pOffset==0 ); /* No LIMIT means no OFFSET */
if( p->pWhere ) return 0; /* Has no WHERE clause */
pSrc = p->pSrc;
assert( pSrc!=0 );
if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */
- if( pSrc->a[0].pSelect ) return 0; /* FROM clause is not a subquery */
+ if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */
pTab = pSrc->a[0].pTab;
- if( pTab==0 ) return 0;
- if( pTab->pSelect ) return 0; /* FROM clause is not a view */
+ if( NEVER(pTab==0) ) return 0;
+ assert( pTab->pSelect==0 ); /* FROM clause is not a view */
if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */
pEList = p->pEList;
if( pEList->nExpr!=1 ) return 0; /* One column in the result set */
** either to test for membership of the (...) set or to iterate through
** its members, skipping duplicates.
**
-** The cursor opened on the structure (database table, database index
+** The index of the cursor opened on the b-tree (database table, database index
** or ephermal table) is stored in pX->iTable before this function returns.
-** The returned value indicates the structure type, as follows:
+** The returned value of this function indicates the b-tree type, as follows:
**
** IN_INDEX_ROWID - The cursor was opened on a database table.
** IN_INDEX_INDEX - The cursor was opened on a database index.
** IN_INDEX_EPH - The cursor was opened on a specially created and
** populated epheremal table.
**
-** An existing structure may only be used if the SELECT is of the simple
+** An existing b-tree may only be used if the SELECT is of the simple
** form:
**
** SELECT <column> FROM <table>
**
-** If prNotFound parameter is 0, then the structure will be used to iterate
+** If the prNotFound parameter is 0, then the b-tree will be used to iterate
** through the set members, skipping any duplicates. In this case an
** epheremal table must be used unless the selected <column> is guaranteed
** to be unique - either because it is an INTEGER PRIMARY KEY or it
-** is unique by virtue of a constraint or implicit index.
+** has a UNIQUE constraint or UNIQUE index.
**
-** If the prNotFound parameter is not 0, then the structure will be used
+** If the prNotFound parameter is not 0, then the b-tree will be used
** for fast set membership tests. In this case an epheremal table must
** be used unless <column> is an INTEGER PRIMARY KEY or an index can
** be found with <column> as its left-most column.
**
-** When the structure is being used for set membership tests, the user
+** When the b-tree is being used for membership tests, the calling function
** needs to know whether or not the structure contains an SQL NULL
** value in order to correctly evaluate expressions like "X IN (Y, Z)".
-** If there is a chance that the structure may contain a NULL value at
+** If there is a chance that the b-tree might contain a NULL value at
** runtime, then a register is allocated and the register number written
-** to *prNotFound. If there is no chance that the structure contains a
+** to *prNotFound. If there is no chance that the b-tree contains a
** NULL value, then *prNotFound is left unchanged.
**
** If a register is allocated and its location stored in *prNotFound, then
-** its initial value is NULL. If the structure does not remain constant
-** for the duration of the query (i.e. the set is a correlated sub-select),
-** the value of the allocated register is reset to NULL each time the
-** structure is repopulated. This allows the caller to use vdbe code
-** equivalent to the following:
+** its initial value is NULL. If the b-tree does not remain constant
+** for the duration of the query (i.e. the SELECT that generates the b-tree
+** is a correlated subquery) then the value of the allocated register is
+** reset to NULL each time the b-tree is repopulated. This allows the
+** caller to use vdbe code equivalent to the following:
**
** if( register==NULL ){
** has_null = <test if data structure contains null>
*/
#ifndef SQLITE_OMIT_SUBQUERY
int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
- Select *p;
- int eType = 0;
- int iTab = pParse->nTab++;
- int mustBeUnique = !prNotFound;
-
- /* The follwing if(...) expression is true if the SELECT is of the
- ** simple form:
- **
- ** SELECT <column> FROM <table>
- **
- ** If this is the case, it may be possible to use an existing table
- ** or index instead of generating an epheremal table.
+ Select *p; /* SELECT to the right of IN operator */
+ int eType = 0; /* Type of RHS table. IN_INDEX_* */
+ int iTab = pParse->nTab++; /* Cursor of the RHS table */
+ int mustBeUnique = (prNotFound==0); /* True if RHS must be unique */
+
+ /* Check to see if an existing table or index can be used to
+ ** satisfy the query. This is preferable to generating a new
+ ** ephemeral table.
*/
p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
- if( isCandidateForInOpt(p) ){
+ if( pParse->nErr==0 && isCandidateForInOpt(p) ){
sqlite3 *db = pParse->db; /* Database connection */
Expr *pExpr = p->pEList->a[0].pExpr; /* Expression <column> */
int iCol = pExpr->iColumn; /* Index of column <column> */
}else{
Index *pIdx; /* Iterator variable */
- /* The collation sequence used by the comparison. If an index is to
+ /* The collation sequence used by the comparison. If an index is to
** be used in place of a temp-table, it must be ordered according
** to this collation sequence. */
CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pExpr);
for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){
if( (pIdx->aiColumn[0]==iCol)
- && (pReq==sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0))
+ && sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq
&& (!mustBeUnique || (pIdx->nColumn==1 && pIdx->onError!=OE_None))
){
int iMem = ++pParse->nMem;
}
if( eType==0 ){
+ /* Could not found an existing able or index to use as the RHS b-tree.
+ ** We will have to generate an ephemeral table to do the job.
+ */
int rMayHaveNull = 0;
eType = IN_INDEX_EPH;
if( prNotFound ){