From: drh Date: Thu, 20 Jan 2005 13:36:19 +0000 (+0000) Subject: Added the SQLITE_OMIT_SUBQUERY compile-time option and the EXISTS operator. X-Git-Tag: version-3.6.10~3907 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=51522cd34ad239170a78369bcbd3c372fb0abec9;p=thirdparty%2Fsqlite.git Added the SQLITE_OMIT_SUBQUERY compile-time option and the EXISTS operator. Regression tests are currently failing with an assertion fault. (CVS 2245) FossilOrigin-Name: d30fdf0f2c24cb74b48fab9b83fba4e4b2fe878a --- diff --git a/manifest b/manifest index a52e6f6c62..e7853ffe1f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sa\sfew\smore\slines\sof\scode\swhen\sSQLITE_OMIT_**\smacros\sare\sdefined.\s(CVS\s2244) -D 2005-01-20T13:03:10 +C Added\sthe\sSQLITE_OMIT_SUBQUERY\scompile-time\soption\sand\sthe\sEXISTS\soperator.\nRegression\stests\sare\scurrently\sfailing\swith\san\sassertion\sfault.\s(CVS\s2245) +D 2005-01-20T13:36:20 F Makefile.in ffd81f5e926d40b457071b4de8d7c1fa18f39b5a F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1 @@ -36,7 +36,7 @@ F src/cursor.c de73c00aefc4747ad59b5105cf38bbff0667922e F src/date.c f3d1f5cd1503dabf426a198f3ebef5afbc122a7f F src/delete.c b3accca9c38d9a67dbd724f67b04151a13735ebd F src/experimental.c 8cc66b2be6a011055d75ef19ed2584bcfbb585ad -F src/expr.c 09022cbd4fbdff66fbab0f04d010d413cb06b493 +F src/expr.c 12b37893ab7e3a41d1d9e9a4931eeb3690951d1f F src/func.c dc188d862d7276ea897655b248e2cb17022686e3 F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5 F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 @@ -54,14 +54,14 @@ F src/os_win.c 3c0b0a3bc33318cf555a1cd130232ad1b9a5a711 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b F src/pager.c 05d23abbcfa3133f716a99589e53883c10551b1f F src/pager.h 9eba8c53dd91eae7f3f90743b2ee242da02a9862 -F src/parse.y 276efb30de5d8582bda9b6a98b17aac6875ab3e9 +F src/parse.y 301d07db056f5125806e84994b5f41a8355d28ad F src/pragma.c 8ab313986673aa4c45e8693d8aabb9b95ee7b14a F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 -F src/select.c 1686f2503c9c7f9de4d564944584015b71c50ac3 +F src/select.c 8a4a38310c5168d1f6e1759494e57cf838d6d37c F src/shell.c 591364a0e9ca4ce53873e21e0294476c0c2b4770 F src/sqlite.h.in 8249b697d71ef6d7f7f752ba4ca04058e9e8b5ff -F src/sqliteInt.h c1acfbeb8b84444e5b86dfce19ff42b5854f6478 +F src/sqliteInt.h 9a582fcb8333b5a30706250282d9697654305dbc F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9 F src/tclsqlite.c fd27457b228118be96524dae285146c76efe032b F src/test1.c 59fc0f0c35cb3bccdf166f36a1a5f9ffb0b951e7 @@ -214,7 +214,7 @@ F tool/lempar.c 1e61d2b6cb9d8affa264a13336bc0c088498caa4 F tool/memleak.awk 4e7690a51bf3ed757e611273d43fe3f65b510133 F tool/memleak2.awk 9cc20c8e8f3c675efac71ea0721ee6874a1566e8 F tool/memleak3.tcl b8eb053190e95a55dc188896afb972e8108822d6 -F tool/mkkeywordhash.c 408dccad57ed50dc67a9a1ee7fd258e0f0a07bd2 +F tool/mkkeywordhash.c db33613e94e9ed3fb0838e2c3ca4415c5fd7ec0e F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e x F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c F tool/report1.txt 9eae07f26a8fc53889b45fc833a66a33daa22816 @@ -270,7 +270,7 @@ F www/tclsqlite.tcl e73f8f8e5f20e8277619433f7970060ab01088fc F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 F www/whentouse.tcl c3b50d3ac31c54be2a1af9b488a89d22f1e6e746 -P 5b1a9bf6aa5a5c466b88f649e322e81b8466851f -R db2528b7bd532f73e60abad289bd81fd -U danielk1977 -Z b2590dd052208a3aa6c3782df4f94dd4 +P 417bbba93ad7ed5c03d9db6afc12e170155bd152 +R 0a5b2b3342f1338802ba7063dbaea636 +U drh +Z 9bd559beb0f6f23bafe4d9cc37e5f07d diff --git a/manifest.uuid b/manifest.uuid index d1c6a0719b..12ebe43388 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -417bbba93ad7ed5c03d9db6afc12e170155bd152 \ No newline at end of file +d30fdf0f2c24cb74b48fab9b83fba4e4b2fe878a \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 8d9d9f47ea..514566aaa1 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.184 2005/01/20 13:03:10 danielk1977 Exp $ +** $Id: expr.c,v 1.185 2005/01/20 13:36:20 drh Exp $ */ #include "sqliteInt.h" #include @@ -1176,6 +1176,7 @@ struct QueryCoder { ** sqlite3ExprCodeSubquery(). See comments on those routines for ** additional information. */ +#ifndef SQLITE_OMIT_SUBQUERY static int codeSubqueryStep(void *pArg, Expr *pExpr){ QueryCoder *pCoder = (QueryCoder*)pArg; Parse *pParse = pCoder->pParse; @@ -1263,6 +1264,7 @@ static int codeSubqueryStep(void *pArg, Expr *pExpr){ return 1; } + case TK_EXISTS: case TK_SELECT: { /* This has to be a scalar SELECT. Generate code to put the ** value of this select in a memory cell and record the number @@ -1272,6 +1274,8 @@ static int codeSubqueryStep(void *pArg, Expr *pExpr){ int nRef; Vdbe *v; int addr; + int sop; + Select *pSel; pNC = pCoder->pNC; if( pNC ) nRef = pNC->nRef; @@ -1279,7 +1283,17 @@ static int codeSubqueryStep(void *pArg, Expr *pExpr){ v = sqlite3GetVdbe(pParse); addr = sqlite3VdbeAddOp(v, OP_Goto, 0, 0); pExpr->iColumn = pParse->nMem++; - sqlite3Select(pParse, pExpr->pSelect, SRT_Mem,pExpr->iColumn,0,0,0,0,pNC); + pSel = pExpr->pSelect; + if( pExpr->op==TK_SELECT ){ + sop = SRT_Mem; + }else{ + static const Token one = { "1", 0, 1 }; + sop = SRT_Exists; + sqlite3ExprListDelete(pSel->pEList); + pSel->pEList = sqlite3ExprListAppend(0, + sqlite3Expr(TK_INTEGER, 0, 0, &one), 0); + } + sqlite3Select(pParse, pSel, sop, pExpr->iColumn, 0, 0, 0, 0, pNC); if( pNC && pNC->nRef>nRef ){ /* Subquery value changes. Evaluate at each use */ pExpr->iTable = addr+1; @@ -1295,6 +1309,7 @@ static int codeSubqueryStep(void *pArg, Expr *pExpr){ } return 0; } +#endif /* SQLITE_OMIT_SUBQUERY */ /* ** Generate code to evaluate subqueries and IN operators contained @@ -1305,10 +1320,12 @@ static int sqlite3ExprCodeSubquery( NameContext *pNC, /* First enclosing namespace. Often NULL */ Expr *pExpr /* Subquery to be coded */ ){ +#ifndef SQLITE_OMIT_SUBQUERY QueryCoder sCoder; sCoder.pParse = pParse; sCoder.pNC = pNC; walkExprTree(pExpr, codeSubqueryStep, &sCoder); +#endif return 0; } diff --git a/src/parse.y b/src/parse.y index 197fce69a8..f5acf880e9 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,7 +14,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.160 2005/01/20 02:14:31 drh Exp $ +** @(#) $Id: parse.y,v 1.161 2005/01/20 13:36:20 drh Exp $ */ %token_prefix TK_ %token_type {Token} @@ -418,31 +418,33 @@ seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). { else { sqlite3IdListDelete(U); } } } -seltablist(A) ::= stl_prefix(X) LP seltablist_paren(S) RP - as(Z) on_opt(N) using_opt(U). { - A = sqlite3SrcListAppend(X,0,0); - A->a[A->nSrc-1].pSelect = S; - if( Z.n ) sqlite3SrcListAddAlias(A,&Z); - if( N ){ - if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pOn = N; } - else { sqlite3ExprDelete(N); } +%ifndef SQLITE_OMIT_SUBQUERY + seltablist(A) ::= stl_prefix(X) LP seltablist_paren(S) RP + as(Z) on_opt(N) using_opt(U). { + A = sqlite3SrcListAppend(X,0,0); + A->a[A->nSrc-1].pSelect = S; + if( Z.n ) sqlite3SrcListAddAlias(A,&Z); + if( N ){ + if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pOn = N; } + else { sqlite3ExprDelete(N); } + } + if( U ){ + if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pUsing = U; } + else { sqlite3IdListDelete(U); } + } } - if( U ){ - if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pUsing = U; } - else { sqlite3IdListDelete(U); } + + // A seltablist_paren nonterminal represents anything in a FROM that + // is contained inside parentheses. This can be either a subquery or + // a grouping of table and subqueries. + // + %type seltablist_paren {Select*} + %destructor seltablist_paren {sqlite3SelectDelete($$);} + seltablist_paren(A) ::= select(S). {A = S;} + seltablist_paren(A) ::= seltablist(F). { + A = sqlite3SelectNew(0,F,0,0,0,0,0,-1,0); } -} - -// A seltablist_paren nonterminal represents anything in a FROM that -// is contained inside parentheses. This can be either a subquery or -// a grouping of table and subqueries. -// -%type seltablist_paren {Select*} -%destructor seltablist_paren {sqlite3SelectDelete($$);} -seltablist_paren(A) ::= select(S). {A = S;} -seltablist_paren(A) ::= seltablist(F). { - A = sqlite3SelectNew(0,F,0,0,0,0,0,-1,0); -} +%endif // SQLITE_OMIT_SUBQUERY %type dbnm {Token} dbnm(A) ::= . {A.z=0; A.n=0;} @@ -692,11 +694,6 @@ expr(A) ::= PLUS(B) expr(X). [UPLUS] { A = sqlite3Expr(TK_UPLUS, X, 0, 0); sqlite3ExprSpan(A,&B,&X->span); } -expr(A) ::= LP(B) select(X) RP(E). { - A = sqlite3Expr(TK_SELECT, 0, 0, 0); - if( A ) A->pSelect = X; - sqlite3ExprSpan(A,&B,&E); -} %type between_op {int} between_op(A) ::= BETWEEN. {A = 0;} between_op(A) ::= NOT BETWEEN. {A = 1;} @@ -717,20 +714,33 @@ expr(A) ::= expr(X) in_op(N) LP exprlist(Y) RP(E). [IN] { if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0); sqlite3ExprSpan(A,&X->span,&E); } -expr(A) ::= expr(X) in_op(N) LP select(Y) RP(E). [IN] { - A = sqlite3Expr(TK_IN, X, 0, 0); - if( A ) A->pSelect = Y; - if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0); - sqlite3ExprSpan(A,&X->span,&E); -} -expr(A) ::= expr(X) in_op(N) nm(Y) dbnm(Z). [IN] { - SrcList *pSrc = sqlite3SrcListAppend(0,&Y,&Z); - A = sqlite3Expr(TK_IN, X, 0, 0); - if( A ) A->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,-1,0); - if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0); - sqlite3ExprSpan(A,&X->span,Z.z?&Z:&Y); -} - +%ifndef SQLITE_OMIT_SUBQUERY + expr(A) ::= LP(B) select(X) RP(E). { + A = sqlite3Expr(TK_SELECT, 0, 0, 0); + if( A ) A->pSelect = X; + sqlite3ExprSpan(A,&B,&E); + } + expr(A) ::= expr(X) in_op(N) LP select(Y) RP(E). [IN] { + A = sqlite3Expr(TK_IN, X, 0, 0); + if( A ) A->pSelect = Y; + if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0); + sqlite3ExprSpan(A,&X->span,&E); + } + expr(A) ::= expr(X) in_op(N) nm(Y) dbnm(Z). [IN] { + SrcList *pSrc = sqlite3SrcListAppend(0,&Y,&Z); + A = sqlite3Expr(TK_IN, X, 0, 0); + if( A ) A->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,-1,0); + if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0); + sqlite3ExprSpan(A,&X->span,Z.z?&Z:&Y); + } + expr(A) ::= EXISTS(B) LP select(Y) RP(E). { + Expr *p = A = sqlite3Expr(TK_EXISTS, 0, 0, 0); + if( p ){ + p->pSelect = Y; + sqlite3ExprSpan(p,&B,&E); + } + } +%endif // SQLITE_OMIT_SUBQUERY /* CASE expressions */ expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). { diff --git a/src/select.c b/src/select.c index f26ebe1a07..a91abbef27 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.230 2005/01/20 13:03:10 danielk1977 Exp $ +** $Id: select.c,v 1.231 2005/01/20 13:36:20 drh Exp $ */ #include "sqliteInt.h" @@ -504,6 +504,7 @@ static int selectInnerLoop( ** store the results in the appropriate memory cell and break out ** of the scan loop. */ + case SRT_Exists: case SRT_Mem: { assert( nColumn==1 ); if( pOrderBy ){ @@ -617,6 +618,7 @@ static void generateSortTail( sqlite3VdbeAddOp(v, OP_PutStrKey, (iParm&0x0000FFFF), 0); break; } + case SRT_Exists: case SRT_Mem: { assert( nColumn==1 ); sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1); @@ -2373,6 +2375,7 @@ int sqlite3Select( /* If writing to memory or generating a set ** only a single column may be output. */ + assert( eDest!=SRT_Exists || pEList->nExpr==1 ); if( (eDest==SRT_Mem || eDest==SRT_Set) && pEList->nExpr>1 ){ sqlite3ErrorMsg(pParse, "only a single result allowed for " "a SELECT that is part of an expression"); @@ -2460,6 +2463,7 @@ int sqlite3Select( /* Generate code for all sub-queries in the FROM clause */ +#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) for(i=0; inSrc; i++){ const char *zSavedAuthContext = 0; int needRestoreContext; @@ -2486,6 +2490,7 @@ int sqlite3Select( pHaving = p->pHaving; isDistinct = p->isDistinct; } +#endif /* Check for the special case of a min() or max() function by itself ** in the result set. @@ -2590,10 +2595,10 @@ int sqlite3Select( } } - /* Initialize the memory cell to NULL + /* Initialize the memory cell to NULL for SRT_Mem or 0 for SRT_Exists */ - if( eDest==SRT_Mem ){ - sqlite3VdbeAddOp(v, OP_String8, 0, 0); + if( eDest==SRT_Mem || eDest==SRT_Exists ){ + sqlite3VdbeAddOp(v, eDest==SRT_Mem ? OP_String8 : OP_Integer, 0, 0); sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1); } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 963e13beba..745dd48737 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.358 2005/01/20 02:14:31 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.359 2005/01/20 13:36:20 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -832,6 +832,7 @@ struct Expr { #define EP_Agg 0x0002 /* Contains one or more aggregate functions */ #define EP_Resolved 0x0004 /* IDs have been resolved to COLUMNs */ #define EP_Error 0x0008 /* Expression contains one or more errors */ +#define EP_Not 0x0010 /* Operator preceeded by NOT */ /* ** These macros can be used to test, set, or clear bits in the @@ -1016,6 +1017,7 @@ struct Select { #define SRT_Discard 9 /* Do not save the results anywhere */ #define SRT_Sorter 10 /* Store results in the sorter */ #define SRT_Subroutine 11 /* Call a subroutine to handle results */ +#define SRT_Exists 12 /* Put 0 or 1 in a memory cell */ /* ** When a SELECT uses aggregate functions (like "count(*)" or "avg(f1)") diff --git a/tool/mkkeywordhash.c b/tool/mkkeywordhash.c index b1005c41ca..952d5d34a6 100644 --- a/tool/mkkeywordhash.c +++ b/tool/mkkeywordhash.c @@ -80,20 +80,25 @@ struct Keyword { #else # define REINDEX 1024 #endif +#ifdef SQLITE_OMIT_SUBQUERY +# define SUBQUERY 0 +#else +# define SUBQUERY 2048 +#endif #ifdef SQLITE_OMIT_TRIGGER # define TRIGGER 0 #else -# define TRIGGER 2048 +# define TRIGGER 4096 #endif #ifdef SQLITE_OMIT_VACUUM # define VACUUM 0 #else -# define VACUUM 4096 +# define VACUUM 8192 #endif #ifdef SQLITE_OMIT_VIEW # define VIEW 0 #else -# define VIEW 8192 +# define VIEW 16384 #endif @@ -146,6 +151,7 @@ static Keyword aKeywordTable[] = { { "ESCAPE", "TK_ESCAPE", ALWAYS }, { "EXCEPT", "TK_EXCEPT", COMPOUND }, { "EXCLUSIVE", "TK_EXCLUSIVE", ALWAYS }, + { "EXISTS", "TK_EXISTS", SUBQUERY }, { "EXPLAIN", "TK_EXPLAIN", EXPLAIN }, { "FAIL", "TK_FAIL", CONFLICT|TRIGGER }, { "FETCH", "TK_FETCH", CURSOR },