-C Modification\sto\sschema.test\sso\sthat\sit\sworks\swith\sSQLITE_OMIT_TRIGGER\sand\sSQLITE_OMIT_UTF16\sdefined.\s(CVS\s2285)
-D 2005-01-29T01:54:18
+C Modify\ssub-query\shandling.\sTickets\s#1083\sand\s#1084.\s(CVS\s2286)
+D 2005-01-29T08:32:44
F Makefile.in ffd81f5e926d40b457071b4de8d7c1fa18f39b5a
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1
F sqlite3.def dbaeb20c153e1d366e8f421b55a573f5dfc00863
F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a
F src/attach.c f78f76bc6a8e5e487ca53636e21ccba2484a9a61
-F src/auth.c 4b15c85335417752cc1045eae18b8186e08c8184
+F src/auth.c 18c5a0befe20f3a58a41e3ddd78f372faeeefe1f
F src/btree.c e68ae12c8b12ef9d45d58d931c36c184055a3880
F src/btree.h 74d19cf40ab49fd69abe9e4e12a6c321ad86c497
-F src/build.c c894a91251c226eb40c54b6f86cbee166ab13334
+F src/build.c e35b7f93c4761b7e757dcce908d336a9adf9b43d
F src/cursor.c de73c00aefc4747ad59b5105cf38bbff0667922e
F src/date.c f3d1f5cd1503dabf426a198f3ebef5afbc122a7f
-F src/delete.c b3accca9c38d9a67dbd724f67b04151a13735ebd
+F src/delete.c 4b94395b52a8f7785acd71135c2ce54f3f5550b3
F src/experimental.c 8cc66b2be6a011055d75ef19ed2584bcfbb585ad
-F src/expr.c abadaf7b858084949ac36316a335384498c5b0e2
+F src/expr.c 9965ce8a6f416377ddcace8fb1d796101cf02ea9
F src/func.c f096b6771cc0aaa11790aca95773a50a8f74ba73
F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
-F src/insert.c 037eb46630f027d0f93584db180d08ce163f3dbb
+F src/insert.c 6ab596846d52bd63d6227f9128a29e4f5b2cf524
F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b
-F src/main.c 302e21bdaa015f590fdb7e69d50f45788da0fb0b
+F src/main.c 612531a2e6fba994274732acae76d7d19b9f90fd
F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070
F src/os.h ae44064dc118b20d39450cb331409a775e8bb1c6
F src/os_common.h 0e7f428ba0a6c40a61bc56c4e96f493231301b73
F src/os_unix.h f3097815e041e82e24d92505e1ff61ba24172d13
F src/os_win.c 3c0b0a3bc33318cf555a1cd130232ad1b9a5a711
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
-F src/pager.c 886a1ae43365ae3b2599d8c6eb6091d5dc91ca7c
+F src/pager.c d21565d0e844712809140632062a7b72b768fdff
F src/pager.h 9eba8c53dd91eae7f3f90743b2ee242da02a9862
-F src/parse.y 5f2c197fcb63c6aed1787da436ec5a35247ab7a4
+F src/parse.y 959948ee97434a7bab3aa04094cd5be6b7501e8d
F src/pragma.c c893f03104e94e0921861bd2d3dbd80c47515f7b
F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
-F src/select.c 32fe60f1aff8a540b709008451013f480dc22d55
+F src/select.c b34d70980c08b6d324b06bee9f63ef91c18c6010
F src/shell.c 1f0da77ef0520afd6df71f4781076021874310f3
F src/sqlite.h.in 7d7c28344e2bd770491b56ed9169be20859c707d
-F src/sqliteInt.h be6fa5e31c65e2b8e10112ee47a6e63ec7de37b5
+F src/sqliteInt.h d5052f5a9badbde9e746e40522e8ab823b1670d5
F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
F src/tclsqlite.c 101994a2c4c0eaa69f1de9bfe4a02167f6049e7d
F src/test1.c 8c320f043b869c08fca86c4f01de027774eb85a8
F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df
F src/test5.c 64f08b2a50ef371a1bd68ff206829e7b1b9997f5
F src/tokenize.c 88bef43fe3e3c8865a7447f934296ac13238c4f6
-F src/trigger.c 5da126eeedca7d25c892311f21f909ff1f3825ba
-F src/update.c 6e5c6eb660a5508c449c6d637571e24ef13f70a1
+F src/trigger.c 038c8e128d4551cd016426cd11bbf5c478816481
+F src/update.c b6f4668c11059f86b71581187d09197fa28ec4be
F src/utf.c bda5eb85039ef16f2d17004c1e18c96e1ab0a80c
F src/util.c a858b93ba06bbafab55ba41e4d58538eb51f4b6a
F src/vacuum.c 1a9db113a027461daaf44724c71dd1ebbd064203
-F src/vdbe.c 8e877a9cdc92f30a71510e427db5e99d1f989c54
-F src/vdbe.h 067ca8d6750ba4f69a50284765e5883dee860181
-F src/vdbeInt.h 24d411de9efc6919a1e580069a597182be269bcf
+F src/vdbe.c 84ccc6be09e13ee5825f32a94b289117cc903ab2
+F src/vdbe.h bb9186484f749a839c6c43953e79a6530253f7cd
+F src/vdbeInt.h e80721cd8ff611789e20743eec43363a9fb5a48e
F src/vdbeapi.c 467caa6e6fb9247528b1c7ab9132ae1b4748e8ac
-F src/vdbeaux.c 083c5fcde08120d7857dcac2b296a1eb7e390a18
+F src/vdbeaux.c 8d8cc8992cb78cab35e034fa81ad0c1a771c39f1
F src/vdbemem.c 62fe89471b656a922e9879be005abf690509ead3
-F src/where.c f4127cc2633ee0f74790ab7f09f5af832489e44e
+F src/where.c b733d3a2e866bb31a3c5d0acf94d8dc599d55a81
F tclinstaller.tcl 36478c3bbfc5b93ceac42d94e3c736937b808432
F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3
F test/alter.test b146ddd669b45a880d40bfdacd6037666137c3f4
F test/autovacuum_ioerr2.test 8feb1cfb4d8177c639cd1e0b8c41d3c88a2a1518
F test/bigfile.test d3744a8821ce9abb8697f2826a3e3d22b719e89f
F test/bigrow.test f0aeb7573dcb8caaafea76454be3ade29b7fc747
-F test/bind.test d83cf2cdc5e2aae3066bbb9c6d12db51e6512fc9
+F test/bind.test bc33135f91d1b59572ad2bcbc84d2201c5d4455d
F test/blob.test fc41fe95bdc10da51f0dee73ce86e75ce1d6eb9d
F test/btree.test 8aa7424aeec844df990273fe36447e5d7e407261
F test/btree2.test dbce930b549d5ac883a7d8905c976209ea241db3
F test/capi3b.test 5b6a66f9f295f79f443b5d3f33187fa5ef6cf336
F test/collate1.test f79736d2ebf5492167ee4d1f4ab4c09dda776b03
F test/collate2.test 224a632ba04907c049804b08162efd234aa7871f
-F test/collate3.test 210fab018450eeb085e4190cd7ca0aabd99b8c11
+F test/collate3.test 51362bdfb43a72bd2b087d90b2623b0695538e7a
F test/collate4.test b8668612691c4dcf90f67a8df1eeb1544e7fdaf8
F test/collate5.test 581775b94604b7435dc6a5c6e72fbbf7d69e3830
F test/collate6.test 6c9470d1606ee3e564675b229653e320c49ec638
F test/index2.test 9ad98243fd7fe833795a9cc662f371f0eed4ff4f
F test/insert.test f39cb2306199c6f9d8959b843c9199d799217055
F test/insert2.test 420cb5c23912732219aad87420abdd7b994b1cad
-F test/insert3.test fa7cb5b01709a1bca3e28c82c80c1d44386b3676
+F test/insert3.test c67f0240b1c17e71fa2ed8bb6de064928f549f95
F test/interrupt.test 5b4d8389e6cf2d01b94f87cfd02d9df1073bfb2d
F test/intpkey.test b57cf5236fde1bd8cbc1388fa0c91908f6fd9194
F test/ioerr.test 3155522a4fd73c714a78fc3403cced7252a130f3
F test/misc1.test ff817d3740458884fea535b44821ec7e84700457
F test/misc2.test fc052267d5178367f955538ae34aae1b2f696a92
F test/misc3.test 7bd937e2c62bcc6be71939faf068d506467b1e03
-F test/misc4.test 145e301fdf10bd47059132db932523814201dc2a
+F test/misc4.test f44ad10982592bb77f1ae6d7876890b3af9605c1
F test/misuse.test 1c7fee3c4c0cb4008717ecccf5c72281fac0008e
F test/notnull.test 7a08117a71e74b0321aaa937dbeb41a09d6eb1d0
F test/null.test 69c62daf1630bf54c87bbc7ef2e22012e58d6da8
F test/select3.test 9de435aa84fc406708cd8dc1b1d60e7f27cea685
F test/select4.test c239f516aa31f42f2ef7c6d7cd01105f08f934ca
F test/select5.test 2d414f712bff8e590091e08f9b7287600731be00
-F test/select6.test ba1b4dd18a85bf9070c6df8d933ac4cfcacea6a6
+F test/select6.test 6e5a1a70a788cdbe515d1252dd0917d7e9d1d71e
F test/select7.test 8f3362336c10d828ab6fe9c1b8897b484da8b592
F test/sort.test 87882e6c72a75d45e98a1c802c1ded0eac557d85
-F test/subquery.test a3ed9f11a4e576ff31b539ab5d65953dc3d27a81
+F test/subquery.test ecec0780e2c8b101068e8780a012dcf1ef5194f4
F test/subselect.test 3f3f7a940dc3195c3139f4d530385cb54665d614
F test/table.test a2a58cae70ef2511cbf27d40fb8f570106a2677e
F test/tableapi.test 6a66d58b37d46dc0f2b3c7d4bd2617d209399bd1
F test/trace.test a54fa8df0d01cf827289a7659d78959e8fd2f955
F test/trans.test 29645b344d2b9b6792793562b12340177ddd8f96
F test/trigger1.test 9db1a7c91930baa2dc60ce72c7e969900bf2ae8a
-F test/trigger2.test cf497cd1cecf46774558d2ca80017a7a68f38473
+F test/trigger2.test cbc8fe3775904d5b49ff26888aa39df7341fae7c
F test/trigger3.test 9102fd3933db294dc654b5aee9edfe9e94f2b9e2
F test/trigger4.test e7c0812b14750754602468f15495260e8c6625e0
F test/trigger5.test 619391a3e9fc194081d22cefd830d811e7badf83
F test/utf16.test 459c2f5ab80c60092c603630a348c32d6e59c558
F test/vacuum.test f18eccdee5b538d46298c64d6a060cfbf97bbc23
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
-F test/view.test 5aac4c79eb86e297a53c8c4a2543dc193034e66d
+F test/view.test a34c5488932cb9f3daf5797b395da6444e570b98
F test/where.test ffb790dfda75d977bae7a1f5830351623f76861b
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
F tool/lemon.c 4a3b5ccc76d959b8caa5f127d23a7e14d4470b4e
F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618
F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
F www/whentouse.tcl 3e522a06ad41992023c80ca29a048ae2331ca5bd
-P 522c094f799220468780acb77731edb715bf5e3c
-R 9002e89543be697066b39cd89912bc24
+P 95ecb2745f3fc69d370fc3961800db56297acb68
+R fe4aca512646cc7b9406c540eeb0d8a2
U danielk1977
-Z e3ae9b709b41b90ac9746a34ed6aa9ba
+Z 3506c9b8c122ebd01b86eeaa686e6ed6
-95ecb2745f3fc69d370fc3961800db56297acb68
\ No newline at end of file
+b1b50f315873a8614920d1e3af4a07fb29a7ff6a
\ No newline at end of file
** systems that do not need this facility may omit it by recompiling
** the library with -DSQLITE_OMIT_AUTHORIZATION=1
**
-** $Id: auth.c,v 1.20 2005/01/22 03:03:54 drh Exp $
+** $Id: auth.c,v 1.21 2005/01/29 08:32:44 danielk1977 Exp $
*/
#include "sqliteInt.h"
if( db->xAuth==0 ) return;
assert( pExpr->op==TK_COLUMN );
- for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){
+ for(iSrc=0; pTabList && iSrc<pTabList->nSrc; iSrc++){
if( pExpr->iTable==pTabList->a[iSrc].iCursor ) break;
}
- if( iSrc>=0 && iSrc<pTabList->nSrc ){
+ if( iSrc>=0 && pTabList && iSrc<pTabList->nSrc ){
pTab = pTabList->a[iSrc].pTab;
}else if( (pStack = pParse->trigStack)!=0 ){
/* This must be an attempt to read the NEW or OLD pseudo-tables
** COMMIT
** ROLLBACK
**
-** $Id: build.c,v 1.300 2005/01/27 00:33:38 danielk1977 Exp $
+** $Id: build.c,v 1.301 2005/01/29 08:32:45 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
sqlite3VdbeTrace(v, trace);
sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem+3,
- pParse->nTab+3, pParse->explain);
+ pParse->nTab+3, pParse->nMaxDepth+1, pParse->explain);
pParse->rc = pParse->nErr ? SQLITE_ERROR : SQLITE_DONE;
pParse->colNamesSet = 0;
}else if( pParse->rc==SQLITE_OK ){
pParse->nTab = 0;
pParse->nMem = 0;
pParse->nSet = 0;
- pParse->nAgg = 0;
pParse->nVar = 0;
pParse->cookieMask = 0;
pParse->cookieGoto = 0;
}else{
sqlite3ExprDelete(pCol->pDflt);
pCol->pDflt = sqlite3ExprDup(pExpr);
- sqlite3ExprResolveNames(pParse,0,0,0,pExpr,0,0);
}
sqlite3ExprDelete(pExpr);
}
sqlite3VdbeAddOp(v, OP_Integer, p->iDb, 0);
sqlite3VdbeAddOp(v, OP_OpenWrite, 1, 0);
pParse->nTab = 2;
- sqlite3Select(pParse, pSelect, SRT_Table, 1, 0, 0, 0, 0, 0);
+ sqlite3Select(pParse, pSelect, SRT_Table, 1, 0, 0, 0, 0);
sqlite3VdbeAddOp(v, OP_Close, 1, 0);
if( pParse->nErr==0 ){
pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSelect);
** 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.99 2005/01/20 11:32:24 danielk1977 Exp $
+** $Id: delete.c,v 1.100 2005/01/29 08:32:45 danielk1977 Exp $
*/
#include "sqliteInt.h"
sqlite3 *db; /* Main database structure */
AuthContext sContext; /* Authorization context */
int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */
+ NameContext sNC; /* Name context to resolve expressions in */
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to delete from a view */
oldIdx = pParse->nTab++;
}
- /* Resolve the column names in all the expressions.
+ /* Resolve the column names in the WHERE clause.
*/
assert( pTabList->nSrc==1 );
iCur = pTabList->a[0].iCursor = pParse->nTab++;
- if( sqlite3ExprResolveNames(pParse, pTabList, 0, 0, pWhere, 0, 1) ){
+ memset(&sNC, 0, sizeof(sNC));
+ sNC.pParse = pParse;
+ sNC.pSrcList = pTabList;
+ if( sqlite3ExprResolveNames(&sNC, pWhere) ){
goto delete_from_cleanup;
}
*/
if( isView ){
Select *pView = sqlite3SelectDup(pTab->pSelect);
- sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0, 0);
+ sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
sqlite3SelectDelete(pView);
}
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
-** $Id: expr.c,v 1.188 2005/01/23 22:41:37 danielk1977 Exp $
+** $Id: expr.c,v 1.189 2005/01/29 08:32:45 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
pNew->iOffset = -1;
pNew->ppOpenTemp = 0;
pNew->pFetch = 0;
+ pNew->isResolved = 0;
+ pNew->isAgg = 0;
return pNew;
}
#else
pNC->nRef++;
/* assert( zTab==0 || pEList==0 ); */
- for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
- Table *pTab = pItem->pTab;
- Column *pCol;
-
- if( pTab==0 ) continue;
- assert( pTab->nCol>0 );
- if( zTab ){
- if( pItem->zAlias ){
- char *zTabName = pItem->zAlias;
- if( sqlite3StrICmp(zTabName, zTab)!=0 ) continue;
- }else{
- char *zTabName = pTab->zName;
- if( zTabName==0 || sqlite3StrICmp(zTabName, zTab)!=0 ) continue;
- if( zDb!=0 && sqlite3StrICmp(db->aDb[pTab->iDb].zName, zDb)!=0 ){
- continue;
+ if( pSrcList ){
+ for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
+ Table *pTab = pItem->pTab;
+ Column *pCol;
+
+ if( pTab==0 ) continue;
+ assert( pTab->nCol>0 );
+ if( zTab ){
+ if( pItem->zAlias ){
+ char *zTabName = pItem->zAlias;
+ if( sqlite3StrICmp(zTabName, zTab)!=0 ) continue;
+ }else{
+ char *zTabName = pTab->zName;
+ if( zTabName==0 || sqlite3StrICmp(zTabName, zTab)!=0 ) continue;
+ if( zDb!=0 && sqlite3StrICmp(db->aDb[pTab->iDb].zName, zDb)!=0 ){
+ continue;
+ }
}
}
- }
- if( 0==(cntTab++) ){
- pExpr->iTable = pItem->iCursor;
- pExpr->iDb = pTab->iDb;
- pMatch = pItem;
- }
- for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
- if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
- cnt++;
+ if( 0==(cntTab++) ){
pExpr->iTable = pItem->iCursor;
- pMatch = pItem;
pExpr->iDb = pTab->iDb;
- /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
- pExpr->iColumn = j==pTab->iPKey ? -1 : j;
- pExpr->affinity = pTab->aCol[j].affinity;
- pExpr->pColl = pTab->aCol[j].pColl;
- break;
+ pMatch = pItem;
+ }
+ for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
+ if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
+ cnt++;
+ pExpr->iTable = pItem->iCursor;
+ pMatch = pItem;
+ pExpr->iDb = pTab->iDb;
+ /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
+ pExpr->iColumn = j==pTab->iPKey ? -1 : j;
+ pExpr->affinity = pTab->aCol[j].affinity;
+ pExpr->pColl = pTab->aCol[j].pColl;
+ break;
+ }
}
}
}
pExpr->pRight = 0;
pExpr->op = TK_COLUMN;
if( cnt==1 ){
- assert( pNC!=0 && pNC->pSrcList!=0 );
+ assert( pNC!=0 );
sqlite3AuthRead(pParse, pExpr, pNC->pSrcList);
}
return cnt!=1;
SrcList *pSrcList;
Parse *pParse;
+ if( pExpr==0 ) return 1;
assert( pNC!=0 );
pSrcList = pNC->pSrcList;
pParse = pNC->pParse;
- if( pExpr==0 ) return 1;
+
if( ExprHasAnyProperty(pExpr, EP_Resolved) ) return 1;
ExprSetProperty(pExpr, EP_Resolved);
#ifndef NDEBUG
/* A lone identifier is the name of a column.
*/
case TK_ID: {
- if( pSrcList==0 ) break;
lookupName(pParse, 0, 0, &pExpr->token, pNC, pExpr);
return 1;
}
Token *pDb;
Expr *pRight;
- if( pSrcList==0 ) break;
+ /* if( pSrcList==0 ) break; */
pRight = pExpr->pRight;
if( pRight->op==TK_ID ){
pDb = 0;
case TK_CTIME:
case TK_CTIMESTAMP:
case TK_CDATE:
- /* Note: The above three were a seperate case in sqlmoto. Reason? */
case TK_GLOB:
case TK_LIKE:
case TK_FUNCTION: {
*/
return is_agg;
}
+#ifndef SQLITE_OMIT_SUBQUERY
+ case TK_SELECT:
+ case TK_EXISTS:
+#endif
+ case TK_IN: {
+ if( pExpr->pSelect ){
+ int nRef = pNC->nRef;
+ sqlite3SelectResolve(pParse, pExpr->pSelect, pNC);
+ assert( pNC->nRef>=nRef );
+ if( nRef!=pNC->nRef ){
+ ExprSetProperty(pExpr, EP_VarSelect);
+ }
+ }
+ }
}
return 0;
}
-/* Forward declaration */
-static int sqlite3ExprCodeSubquery(Parse*, NameContext*, Expr*);
-
/*
** This routine walks an expression tree and resolves references to
** table columns. Nodes of the form ID.ID or ID resolve into an
** property on the expression.
*/
int sqlite3ExprResolveNames(
- Parse *pParse, /* The parser context */
- SrcList *pSrcList, /* List of tables used to resolve column names */
- ExprList *pEList, /* List of expressions used to resolve "AS" */
- NameContext *pNC, /* Namespace of enclosing statement */
- Expr *pExpr, /* The expression to be analyzed. */
- int allowAgg, /* True to allow aggregate expressions */
- int codeSubquery /* If true, then generate code for subqueries too */
+ NameContext *pNC, /* Namespace to resolve expressions in. */
+ Expr *pExpr /* The expression to be analyzed. */
){
- NameContext sNC;
-
if( pExpr==0 ) return 0;
- memset(&sNC, 0, sizeof(sNC));
- sNC.pSrcList = pSrcList;
- sNC.pParse = pParse;
- sNC.pEList = pEList;
- sNC.allowAgg = allowAgg;
- sNC.pNext = pNC;
- walkExprTree(pExpr, nameResolverStep, &sNC);
- if( sNC.hasAgg ){
- ExprSetProperty(pExpr, EP_Agg);
- }
- if( sNC.nErr>0 ){
+ walkExprTree(pExpr, nameResolverStep, pNC);
+ if( pNC->nErr>0 ){
ExprSetProperty(pExpr, EP_Error);
- }else if( codeSubquery && sqlite3ExprCodeSubquery(pParse, &sNC, pExpr) ){
- return 1;
}
return ExprHasProperty(pExpr, EP_Error);
}
** The first form is handled by creating a set holding the list
** of allowed values. The second form causes the SELECT to generate
** a temporary table.
-**
-** This routine also looks for scalar SELECTs that are part of an expression.
-** If it finds any, it generates code to write the value of that select
-** into a memory cell.
-**
-** This routine is a callback for wallExprTree() used to implement
-** 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;
+void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
+ int label = 0; /* Address after sub-select code */
+ Vdbe *v = sqlite3GetVdbe(pParse);
+ if( v==0 ) return;
+
+ /* If this is not a variable (correlated) select, then execute
+ ** it only once. Unless this is part of a trigger program. In
+ ** that case re-execute every time (this could be optimized).
+ */
+ if( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->trigStack ){
+ int mem = pParse->nMem++;
+ sqlite3VdbeAddOp(v, OP_MemLoad, mem, 0);
+ label = sqlite3VdbeMakeLabel(v);
+ sqlite3VdbeAddOp(v, OP_If, 0, label);
+ sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
+ sqlite3VdbeAddOp(v, OP_MemStore, mem, 1);
+ }
+
+ if( pExpr->pSelect ){
+ sqlite3VdbeAddOp(v, OP_AggContextPush, 0, 0);
+ }
switch( pExpr->op ){
case TK_IN: {
char affinity;
- Vdbe *v = sqlite3GetVdbe(pParse);
KeyInfo keyInfo;
int addr; /* Address of OP_OpenTemp instruction */
- if( v==0 ) return 2;
affinity = sqlite3ExprAffinity(pExpr->pLeft);
/* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)'
int iParm = pExpr->iTable + (((int)affinity)<<16);
ExprList *pEList;
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
- sqlite3Select(pParse, pExpr->pSelect, SRT_Set, iParm, 0, 0, 0, 0, 0);
+ sqlite3Select(pParse, pExpr->pSelect, SRT_Set, iParm, 0, 0, 0, 0);
pEList = pExpr->pSelect->pEList;
if( pEList && pEList->nExpr>0 ){
keyInfo.aColl[0] = binaryCompareCollSeq(pParse, pExpr->pLeft,
if( !sqlite3ExprIsConstant(pE2) ){
sqlite3ErrorMsg(pParse,
"right-hand side of IN operator must be constant");
- return 2;
- }
- if( sqlite3ExprResolveNames(pParse, 0, 0, 0, pE2, 0, 0) ){
- return 2;
+ return;
}
/* Evaluate the expression and insert it into the temp table */
}
}
sqlite3VdbeChangeP3(v, addr, (void *)&keyInfo, P3_KEYINFO);
- return 1;
+ break;
}
case TK_EXISTS:
** value of this select in a memory cell and record the number
** of the memory cell in iColumn.
*/
- NameContext *pNC;
- int nRef;
- Vdbe *v;
- int addr;
int sop;
Select *pSel;
- pNC = pCoder->pNC;
- if( pNC ) nRef = pNC->nRef;
- sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
- v = sqlite3GetVdbe(pParse);
- addr = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
pExpr->iColumn = pParse->nMem++;
pSel = pExpr->pSelect;
if( pExpr->op==TK_SELECT ){
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;
- sqlite3VdbeAddOp(v, OP_Return, 0, 0);
- sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
- }else{
- /* Subquery value is constant. evaluate only once. */
- pExpr->iTable = -1;
- sqlite3VdbeChangeP2(v, addr, addr+1);
- }
- return 1;
+ sqlite3Select(pParse, pSel, sop, pExpr->iColumn, 0, 0, 0, 0);
+ break;
}
}
- return 0;
-}
-#endif /* SQLITE_OMIT_SUBQUERY */
-/*
-** Generate code to evaluate subqueries and IN operators contained
-** in expression pExpr.
-*/
-static int sqlite3ExprCodeSubquery(
- Parse *pParse, /* Parser */
- 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;
+ if( pExpr->pSelect ){
+ sqlite3VdbeAddOp(v, OP_AggContextPop, 0, 0);
+ }
+ if( label<0 ){
+ sqlite3VdbeResolveLabel(v, label);
+ }
+ return;
}
+#endif /* SQLITE_OMIT_SUBQUERY */
/*
** Generate an instruction that will put the integer describe by
#ifndef SQLITE_OMIT_SUBQUERY
case TK_EXISTS:
case TK_SELECT: {
- if( pExpr->iTable>=0 ){
- sqlite3VdbeAddOp(v, OP_Gosub, 0, pExpr->iTable);
- VdbeComment((v, "# run subquery"));
- }
+ sqlite3CodeSubselect(pParse, pExpr);
sqlite3VdbeAddOp(v, OP_MemLoad, pExpr->iColumn, 0);
VdbeComment((v, "# load subquery result"));
break;
case TK_IN: {
int addr;
char affinity;
+ sqlite3CodeSubselect(pParse, pExpr);
/* Figure out the affinity to use to create a key from the results
** of the expression. affinityStr stores a static string suitable for
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
-** $Id: insert.c,v 1.134 2005/01/20 11:32:24 danielk1977 Exp $
+** $Id: insert.c,v 1.135 2005/01/29 08:32:45 danielk1977 Exp $
*/
#include "sqliteInt.h"
iInitCode = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
iSelectLoop = sqlite3VdbeCurrentAddr(v);
iInsertBlock = sqlite3VdbeMakeLabel(v);
- rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock,0,0,0,0,0);
+
+ /* Resolve the expressions in the SELECT statement and execute it. */
+ rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock,0,0,0,0);
if( rc || pParse->nErr || sqlite3_malloc_failed ) goto insert_cleanup;
+
iCleanup = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp(v, OP_Goto, 0, iCleanup);
assert( pSelect->pEList );
/* This is the case if the data for the INSERT is coming from a VALUES
** clause
*/
- SrcList dummy;
+ NameContext sNC;
+ memset(&sNC, 0, sizeof(sNC));
+ sNC.pParse = pParse;
assert( pList!=0 );
srcTab = -1;
useTempTable = 0;
assert( pList );
nColumn = pList->nExpr;
- dummy.nSrc = 0;
for(i=0; i<nColumn; i++){
- if( sqlite3ExprResolveNames(pParse,&dummy,0,0,pList->a[i].pExpr,0,1) ){
+ if( sqlite3ExprResolveNames(&sNC, pList->a[i].pExpr) ){
goto insert_cleanup;
}
}
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
-** $Id: main.c,v 1.275 2005/01/25 04:27:55 danielk1977 Exp $
+** $Id: main.c,v 1.276 2005/01/29 08:32:45 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
rc = SQLITE_OK;
}else{
rc = sqlite3VdbeReset((Vdbe*)pStmt);
- sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0);
+ sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0, 0);
}
return rc;
}
** file simultaneously, or one process from reading the database while
** another is writing.
**
-** @(#) $Id: pager.c,v 1.186 2005/01/22 03:39:39 danielk1977 Exp $
+** @(#) $Id: pager.c,v 1.187 2005/01/29 08:32:45 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
case PAGER_RESERVED:
case PAGER_SYNCED:
case PAGER_EXCLUSIVE: {
+ /* We ignore any IO errors that occur during the rollback
+ ** operation. So disable IO error simulation so that testing
+ ** works more easily.
+ */
+#if defined(SQLITE_TEST) && (defined(OS_UNIX) || defined(OS_WIN))
+ extern int sqlite3_io_error_pending;
+ int ioerr_cnt = sqlite3_io_error_pending;
+ sqlite3_io_error_pending = -1;
+#endif
sqlite3pager_rollback(pPager);
+#if defined(SQLITE_TEST) && (defined(OS_UNIX) || defined(OS_WIN))
+ sqlite3_io_error_pending = ioerr_cnt;
+#endif
if( !MEMDB ){
sqlite3OsUnlock(&pPager->fd, NO_LOCK);
}
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
-** @(#) $Id: parse.y,v 1.162 2005/01/21 03:12:15 danielk1977 Exp $
+** @(#) $Id: parse.y,v 1.163 2005/01/29 08:32:45 danielk1977 Exp $
*/
%token_prefix TK_
%token_type {Token}
//////////////////////// The SELECT statement /////////////////////////////////
//
cmd ::= select(X). {
- sqlite3Select(pParse, X, SRT_Callback, 0, 0, 0, 0, 0, 0);
+ sqlite3Select(pParse, X, SRT_Callback, 0, 0, 0, 0, 0);
sqlite3SelectDelete(X);
}
Expr *pExpr = A = sqlite3Expr(TK_VARIABLE, 0, 0, pToken);
sqlite3ExprAssignVarNumber(pParse, pExpr);
}
-term(A) ::= ID(X) LP exprlist(Y) RP(E). {
+expr(A) ::= ID(X) LP exprlist(Y) RP(E). {
A = sqlite3ExprFunction(Y, &X);
sqlite3ExprSpan(A,&X,&E);
}
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
-** $Id: select.c,v 1.234 2005/01/26 03:58:36 danielk1977 Exp $
+** $Id: select.c,v 1.235 2005/01/29 08:32:45 danielk1977 Exp $
*/
#include "sqliteInt.h"
/*
** Delete the aggregate information from the parse structure.
*/
+#if 0
static void sqliteAggregateInfoReset(Parse *pParse){
sqliteFree(pParse->aAgg);
pParse->aAgg = 0;
pParse->nAgg = 0;
pParse->useAgg = 0;
}
+#endif
/*
** Insert code into "v" that will push the record on the top of the
** The declaration type for an expression is either TEXT, NUMERIC or ANY.
** The declaration type for a ROWID field is INTEGER.
*/
-static const char *columnType(Parse *pParse, SrcList *pTabList, Expr *pExpr){
+static const char *columnType(NameContext *pNC, Expr *pExpr){
char const *zType;
int j;
- if( pExpr==0 || pTabList==0 ) return 0;
-
- sqlite3ExprResolveNames(pParse, pTabList, 0, 0, pExpr, 1, 0);
+ if( pExpr==0 || pNC->pSrcList==0 ) return 0;
/* The TK_AS operator can only occur in ORDER BY, GROUP BY, HAVING,
** and LIMIT clauses. But pExpr originates in the result set of a
switch( pExpr->op ){
case TK_COLUMN: {
- Table *pTab;
+ Table *pTab = 0;
int iCol = pExpr->iColumn;
- for(j=0; j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable; j++){}
- assert( j<pTabList->nSrc );
- pTab = pTabList->a[j].pTab;
+ while( pNC && !pTab ){
+ SrcList *pTabList = pNC->pSrcList;
+ for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++);
+ if( j<pTabList->nSrc ){
+ pTab = pTabList->a[j].pTab;
+ }else{
+ pNC = pNC->pNext;
+ }
+ }
+ assert( pTab );
if( iCol<0 ) iCol = pTab->iPKey;
assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
if( iCol<0 ){
}
#ifndef SQLITE_OMIT_SUBQUERY
case TK_SELECT: {
+ NameContext sNC;
Select *pS = pExpr->pSelect;
- zType = columnType(pParse, pS->pSrc, pS->pEList->a[0].pExpr);
+ sNC.pSrcList = pExpr->pSelect->pSrc;
+ sNC.pNext = pNC;
+ zType = columnType(&sNC, pS->pEList->a[0].pExpr);
break;
}
#endif
){
Vdbe *v = pParse->pVdbe;
int i;
+ NameContext sNC;
+ sNC.pSrcList = pTabList;
for(i=0; i<pEList->nExpr; i++){
Expr *p = pEList->a[i].pExpr;
- const char *zType = columnType(pParse, pTabList, p);
+ const char *zType = columnType(&sNC, p);
if( zType==0 ) continue;
/* The vdbe must make it's own copy of the column-type, in case the
** schema is reset before this virtual machine is deleted.
char *zName;
char *zBasename;
int cnt;
+ NameContext sNC;
/* Get an appropriate name for the column
*/
/* Get the typename, type affinity, and collating sequence for the
** column.
*/
- zType = sqliteStrDup(columnType(pParse, pSelect->pSrc ,p));
+ sNC.pSrcList = pSelect->pSrc;
+ zType = sqliteStrDup(columnType(&sNC, p));
pCol->zType = zType;
pCol->affinity = SQLITE_AFF_NUMERIC;
if( zType ){
pFrom->zAlias =
sqlite3MPrintf("sqlite_subquery_%p_", (void*)pFrom->pSelect);
}
+ sqlite3SelectResolve(pParse, pFrom->pSelect, 0);
pFrom->pTab = pTab =
sqlite3ResultSetOfSelect(pParse, pFrom->zAlias, pFrom->pSelect);
if( pTab==0 ){
if( p->pOrderBy==0 ){
pPrior->nLimit = p->nLimit;
pPrior->nOffset = p->nOffset;
- rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0, aff, 0);
+ rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0, aff);
if( rc ){
goto multi_select_end;
}
p->iOffset = pPrior->iOffset;
p->nLimit = -1;
p->nOffset = 0;
- rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0, aff, 0);
+ rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0, aff);
p->pPrior = pPrior;
if( rc ){
goto multi_select_end;
/* Code the SELECT statements to our left
*/
- rc = sqlite3Select(pParse, pPrior, priorOp, unionTab, 0, 0, 0, aff, 0);
+ assert( !pPrior->pOrderBy );
+ rc = sqlite3Select(pParse, pPrior, priorOp, unionTab, 0, 0, 0, aff);
if( rc ){
goto multi_select_end;
}
p->nLimit = -1;
nOffset = p->nOffset;
p->nOffset = 0;
- rc = sqlite3Select(pParse, p, op, unionTab, 0, 0, 0, aff, 0);
+ rc = sqlite3Select(pParse, p, op, unionTab, 0, 0, 0, aff);
p->pPrior = pPrior;
p->pOrderBy = pOrderBy;
p->nLimit = nLimit;
/* Code the SELECTs to our left into temporary table "tab1".
*/
- rc = sqlite3Select(pParse, pPrior, SRT_Union, tab1, 0, 0, 0, aff, 0);
+ rc = sqlite3Select(pParse, pPrior, SRT_Union, tab1, 0, 0, 0, aff);
if( rc ){
goto multi_select_end;
}
p->nLimit = -1;
nOffset = p->nOffset;
p->nOffset = 0;
- rc = sqlite3Select(pParse, p, SRT_Union, tab2, 0, 0, 0, aff, 0);
+ rc = sqlite3Select(pParse, p, SRT_Union, tab2, 0, 0, 0, aff);
p->pPrior = pPrior;
p->nLimit = nLimit;
p->nOffset = nOffset;
Expr *pExpr = pOrderByTerm->pExpr;
char *zName = pOrderByTerm->zName;
assert( pExpr->op==TK_COLUMN && pExpr->iColumn<nCol );
- assert( !pExpr->pColl );
+ /* assert( !pExpr->pColl ); */
if( zName ){
pExpr->pColl = sqlite3LocateCollSeq(pParse, zName, -1);
}else{
** of the subquery rather the result set of the subquery.
*/
static void substExprList(ExprList*,int,ExprList*); /* Forward Decl */
+static void substSelect(Select *, int, ExprList *); /* Forward Decl */
static void substExpr(Expr *pExpr, int iTable, ExprList *pEList){
if( pExpr==0 ) return;
if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){
}else{
substExpr(pExpr->pLeft, iTable, pEList);
substExpr(pExpr->pRight, iTable, pEList);
+ substSelect(pExpr->pSelect, iTable, pEList);
substExprList(pExpr->pList, iTable, pEList);
}
}
-static void
-substExprList(ExprList *pList, int iTable, ExprList *pEList){
+static void substExprList(ExprList *pList, int iTable, ExprList *pEList){
int i;
if( pList==0 ) return;
for(i=0; i<pList->nExpr; i++){
substExpr(pList->a[i].pExpr, iTable, pEList);
}
}
+static void substSelect(Select *p, int iTable, ExprList *pEList){
+ if( !p ) return;
+ substExprList(p->pEList, iTable, pEList);
+ substExprList(p->pGroupBy, iTable, pEList);
+ substExprList(p->pOrderBy, iTable, pEList);
+ substExpr(p->pHaving, iTable, pEList);
+ substExpr(p->pWhere, iTable, pEList);
+}
#endif /* !defined(SQLITE_OMIT_VIEW) */
#ifndef SQLITE_OMIT_VIEW
** corresponding entry in the result set.
*/
static int processOrderGroupBy(
- Parse *pParse, /* Parsing context */
+ NameContext *pNC, /* Name context of the SELECT statement. */
ExprList *pOrderBy, /* The ORDER BY or GROUP BY clause to be processed */
- SrcList *pTabList, /* The FROM clause */
- ExprList *pEList, /* The result set */
- NameContext *pNC, /* Name context for enclosing query */
- int isAgg, /* True if aggregate functions are involved */
const char *zType /* Either "ORDER" or "GROUP", as appropriate */
){
int i;
+ ExprList *pEList = pNC->pEList; /* The result set of the SELECT */
+ Parse *pParse = pNC->pParse; /* The result set of the SELECT */
+ assert( pEList );
+
if( pOrderBy==0 ) return 0;
for(i=0; i<pOrderBy->nExpr; i++){
int iCol;
Expr *pE = pOrderBy->a[i].pExpr;
- if( sqlite3ExprIsInteger(pE, &iCol) && iCol>0 && iCol<=pEList->nExpr ){
- sqlite3ExprDelete(pE);
- pE = pOrderBy->a[i].pExpr = sqlite3ExprDup(pEList->a[iCol-1].pExpr);
- }
- if( sqlite3ExprResolveNames(pParse, pTabList, pEList, pNC, pE, isAgg, 1) ){
- return 1;
- }
- if( sqlite3ExprIsConstant(pE) ){
- if( sqlite3ExprIsInteger(pE, &iCol)==0 ){
- sqlite3ErrorMsg(pParse,
- "%s BY terms must not be non-integer constants", zType);
- return 1;
- }else if( iCol<=0 || iCol>pEList->nExpr ){
+ if( sqlite3ExprIsInteger(pE, &iCol) ){
+ if( iCol>0 && iCol<=pEList->nExpr ){
+ sqlite3ExprDelete(pE);
+ pE = pOrderBy->a[i].pExpr = sqlite3ExprDup(pEList->a[iCol-1].pExpr);
+ }else{
sqlite3ErrorMsg(pParse,
"%s BY column number %d out of range - should be "
"between 1 and %d", zType, iCol, pEList->nExpr);
return 1;
}
}
+ if( sqlite3ExprResolveNames(pNC, pE) ){
+ return 1;
+ }
+ if( sqlite3ExprIsConstant(pE) ){
+ sqlite3ErrorMsg(pParse,
+ "%s BY terms must not be non-integer constants", zType);
+ return 1;
+ }
}
return 0;
}
+/*
+** This routine resolves any names used in the result set of the
+** supplied SELECT statement. If the SELECT statement being resolved
+** is a sub-select, then pOuterNC is a pointer to the NameContext
+** of the parent SELECT.
+*/
+int sqlite3SelectResolve(
+ Parse *pParse, /* The parser context */
+ Select *p, /* The SELECT statement being coded. */
+ NameContext *pOuterNC /* The outer name context. May be NULL. */
+){
+ ExprList *pEList; /* Result set. */
+ int i; /* For-loop variable used in multiple places */
+ NameContext sNC; /* Local name-context */
+
+ /* If this routine has run before, return immediately. */
+ if( p->isResolved ){
+ assert( !pOuterNC );
+ return SQLITE_OK;
+ }
+ p->isResolved = 1;
+
+ /* If there have already been errors, do nothing. */
+ if( pParse->nErr>0 ){
+ return SQLITE_ERROR;
+ }
+
+ /* Prepare the select statement. This call will allocate all cursors
+ ** required to handle the tables and subqueries in the FROM clause.
+ */
+ if( prepSelectStmt(pParse, p) ){
+ return SQLITE_ERROR;
+ }
+
+ /* Set up the local name-context to pass to ExprResolveNames(). */
+ sNC.pNext = pOuterNC;
+ sNC.pParse = pParse;
+ sNC.pSrcList = p->pSrc;
+ sNC.allowAgg = 1;
+ sNC.hasAgg = 0;
+ sNC.nErr = 0;
+ sNC.nRef = 0;
+ sNC.pEList = 0;
+
+ /* NameContext.nDepth stores the depth of recursion for this query. For
+ ** an outer query (e.g. SELECT * FROM sqlite_master) this is 1. For
+ ** a subquery it is 2. For a subquery of a subquery, 3. And so on.
+ ** Parse.nMaxDepth is the maximum depth for any subquery resolved so
+ ** far. This is used to determine the number of aggregate contexts
+ ** required at runtime.
+ */
+ sNC.nDepth = (pOuterNC?pOuterNC->nDepth+1:1);
+ if( sNC.nDepth>pParse->nMaxDepth ){
+ pParse->nMaxDepth = sNC.nDepth;
+ }
+
+ /* Resolve names in the result set. */
+ pEList = p->pEList;
+ if( !pEList ) return SQLITE_ERROR;
+ for(i=0; i<pEList->nExpr; i++){
+ Expr *pX = pEList->a[i].pExpr;
+ if( sqlite3ExprResolveNames(&sNC, pX) ){
+ return SQLITE_ERROR;
+ }
+ }
+
+ /* If there are no aggregate functions in the result-set, and no GROUP BY
+ ** expression, do not allow aggregates in any of the other expressions.
+ */
+ assert( !p->isAgg );
+ if( p->pGroupBy || sNC.hasAgg ){
+ p->isAgg = 1;
+ }else{
+ sNC.allowAgg = 0;
+ }
+
+ /* If a HAVING clause is present, then there must be a GROUP BY clause.
+ */
+ if( p->pHaving && !p->pGroupBy ){
+ sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING");
+ return SQLITE_ERROR;
+ }
+
+ /* Add the expression list to the name-context before parsing the
+ ** other expressions in the SELECT statement. This is so that
+ ** expressions in the WHERE clause (etc.) can refer to expressions by
+ ** aliases in the result set.
+ **
+ ** Minor point: If this is the case, then the expression will be
+ ** re-evaluated for each reference to it.
+ */
+ sNC.pEList = p->pEList;
+ if( sqlite3ExprResolveNames(&sNC, p->pWhere) ||
+ sqlite3ExprResolveNames(&sNC, p->pHaving) ||
+ processOrderGroupBy(&sNC, p->pOrderBy, "ORDER") ||
+ processOrderGroupBy(&sNC, p->pGroupBy, "GROUP")
+ ){
+ return SQLITE_ERROR;
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** An instance of the following struct is used by sqlite3Select()
+** to save aggregate related information from the Parse object
+** at the start of each call and to restore it at the end. See
+** saveAggregateInfo() and restoreAggregateInfo().
+*/
+struct AggregateInfo {
+ u8 useAgg;
+ int nAgg;
+ AggExpr *aAgg;
+};
+typedef struct AggregateInfo AggregateInfo;
+
+/*
+** Copy aggregate related information from the Parse structure
+** into the AggregateInfo structure. Zero the aggregate related
+** values in the Parse struct.
+*/
+static void saveAggregateInfo(Parse *pParse, AggregateInfo *pInfo){
+ pInfo->aAgg = pParse->aAgg;
+ pInfo->nAgg = pParse->nAgg;
+ pInfo->useAgg = pParse->useAgg;
+ pParse->aAgg = 0;
+ pParse->nAgg = 0;
+ pParse->useAgg = 0;
+}
+
+/*
+** Copy aggregate related information from the AggregateInfo struct
+** back into the Parse structure. The aggregate related information
+** currently stored in the Parse structure is deleted.
+*/
+static void restoreAggregateInfo(Parse *pParse, AggregateInfo *pInfo){
+ sqliteFree(pParse->aAgg);
+ pParse->aAgg = pInfo->aAgg;
+ pParse->nAgg = pInfo->nAgg;
+ pParse->useAgg = pInfo->useAgg;
+}
+
/*
** Generate code for the given SELECT statement.
**
Select *pParent, /* Another SELECT for which this is a sub-query */
int parentTab, /* Index in pParent->pSrc of this query */
int *pParentAgg, /* True if pParent uses aggregate functions */
- char *aff, /* If eDest is SRT_Union, the affinity string */
- NameContext *pNC /* Namespace of the next outer query */
+ char *aff /* If eDest is SRT_Union, the affinity string */
){
int i;
WhereInfo *pWInfo;
Vdbe *v;
- int isAgg = 0; /* True for select lists like "count(*)" */
+ int isAgg; /* True for select lists like "count(*)" */
ExprList *pEList; /* List of columns to extract. */
SrcList *pTabList; /* List of tables to select from */
Expr *pWhere; /* The WHERE clause. May be NULL */
int isDistinct; /* True if the DISTINCT keyword is present */
int distinct; /* Table to use for the distinct set */
int rc = 1; /* Value to return from this function */
+ AggregateInfo sAggInfo;
if( sqlite3_malloc_failed || pParse->nErr || p==0 ) return 1;
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
}
#endif
+ saveAggregateInfo(pParse, &sAggInfo);
+ pOrderBy = p->pOrderBy;
+ if( eDest==SRT_Union || eDest==SRT_Except || eDest==SRT_Discard ){
+ p->pOrderBy = 0;
+ }
+ if( sqlite3SelectResolve(pParse, p, 0) ){
+ goto select_end;
+ }
+ p->pOrderBy = pOrderBy;
+
/* Make local copies of the parameters for this query.
*/
pTabList = p->pSrc;
pWhere = p->pWhere;
- pOrderBy = p->pOrderBy;
pGroupBy = p->pGroupBy;
pHaving = p->pHaving;
+ isAgg = p->isAgg;
isDistinct = p->isDistinct;
+ pEList = p->pEList;
+ if( pEList==0 ) goto select_end;
/*
** Do not even attempt to generate any code if we have already seen
*/
if( pParse->nErr>0 ) goto select_end;
- if( prepSelectStmt(pParse, p) ){
- goto select_end;
- }
- pWhere = p->pWhere;
- pEList = p->pEList;
- if( pEList==0 ) goto select_end;
-
/* If writing to memory or generating a set
** only a single column may be output.
*/
break;
}
- /* At this point, we should have allocated all the cursors that we
- ** need to handle subquerys and temporary tables.
- **
- ** Resolve the column names and do a semantics check on all the expressions.
- */
- for(i=0; i<pEList->nExpr; i++){
- Expr *pX = pEList->a[i].pExpr;
- if( sqlite3ExprResolveNames(pParse, pTabList, 0, pNC, pX, 1, 1) ){
- goto select_end;
- }
- if( ExprHasProperty(pX, EP_Agg) ) isAgg = 1;
- }
- if( sqlite3ExprResolveNames(pParse, pTabList, pEList, pNC, pWhere, 0, 1) ){
- goto select_end;
- }
- if( pHaving ){
- if( pGroupBy==0 ){
- sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING");
- goto select_end;
- }
- if( sqlite3ExprResolveNames(pParse, pTabList, pEList, pNC, pHaving, 1, 1) ){
- goto select_end;
- }
- }
- if( pGroupBy ){
- isAgg = 1;
- }
- if( processOrderGroupBy(pParse,pOrderBy,pTabList,pEList,pNC,isAgg,"ORDER")
- || processOrderGroupBy(pParse,pGroupBy,pTabList,pEList,pNC,isAgg,"GROUP")
- ){
- goto select_end;
- }
-
/* We cannot use a SQL cursor on a join or on a DISTINCT query
*/
#ifndef SQLITE_OMIT_CURSOR
needRestoreContext = 0;
}
sqlite3Select(pParse, pTabList->a[i].pSelect, SRT_TempTable,
- pTabList->a[i].iCursor, p, i, &isAgg, 0, 0);
+ pTabList->a[i].iCursor, p, i, &isAgg, 0);
if( needRestoreContext ){
pParse->zAuthContext = zSavedAuthContext;
}
if( pParent && pParentAgg &&
flattenSubquery(pParse, pParent, parentTab, *pParentAgg, isAgg) ){
if( isAgg ) *pParentAgg = 1;
- return rc;
+ goto select_end;
}
#endif
/* Do an analysis of aggregate expressions.
*/
- sqliteAggregateInfoReset(pParse);
if( isAgg || pGroupBy ){
assert( pParse->nAgg==0 );
isAgg = 1;
** successful coding of the SELECT.
*/
select_end:
- sqliteAggregateInfoReset(pParse);
+ restoreAggregateInfo(pParse, &sAggInfo);
return rc;
}
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.363 2005/01/22 03:03:55 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.364 2005/01/29 08:32:45 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
#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 */
+#define EP_VarSelect 0x0020 /* pSelect is correlated, not constant */
/*
** These macros can be used to test, set, or clear bits in the
int doRewind; /* True to rewind cursor before starting */
};
+/*
+** A NameContext defines a context in which to resolve table and column
+** names. The context consists of a list of tables (the pSrcList) field and
+** a list of named expression (pEList). The named expression list may
+** be NULL. The pSrc corresponds to the FROM clause of a SELECT or
+** to the table being operated on by INSERT, UPDATE, or DELETE. The
+** pEList corresponds to the result set of a SELECT and is NULL for
+** other statements.
+**
+** NameContexts can be nested. When resolving names, the inner-most
+** context is searched first. If no match is found, the next outer
+** context is checked. If there is still no match, the next context
+** is checked. This process continues until either a match is found
+** or all contexts are check. When a match is found, the nRef member of
+** the context containing the match is incremented.
+**
+** Each subquery gets a new NameContext. The pNext field points to the
+** NameContext in the parent query. Thus the process of scanning the
+** NameContext list corresponds to searching through successively outer
+** subqueries looking for a match.
+*/
+struct NameContext {
+ Parse *pParse; /* The parser */
+ SrcList *pSrcList; /* One or more tables used to resolve names */
+ ExprList *pEList; /* Optional list of named expressions */
+ int nRef; /* Number of names resolved by this context */
+ int nErr; /* Number of errors encountered while resolving names */
+ u8 allowAgg; /* Aggregate functions allowed here */
+ u8 hasAgg;
+ int nDepth; /* Depth of subquery recursion. 1 for no recursion */
+ NameContext *pNext; /* Next outer name context. NULL for outermost */
+};
+
/*
** An instance of the following structure contains all information
** needed to generate code for a single SELECT statement.
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
IdList **ppOpenTemp; /* OP_OpenTemp addresses used by multi-selects */
Fetch *pFetch; /* If this stmt is part of a FETCH command */
+ u8 isResolved; /* True once sqlite3SelectResolve() has run. */
+ u8 isAgg; /* True if this is an aggregate query */
};
/*
int cookieValue[MAX_ATTACHED+2]; /* Values of cookies to verify */
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
u32 writeMask; /* Start a write transaction on these databases */
+ u8 useAgg; /* If true, extract field values from the aggregator
+ ** while generating expressions. Normally false */
/* Above is constant between recursions. Below is reset before and after
** each recursion */
int nVarExprAlloc; /* Number of allocated slots in apVarExpr[] */
Expr **apVarExpr; /* Pointers to :aaa and $aaaa wildcard expressions */
u8 explain; /* True if the EXPLAIN flag is found on the query */
- u8 useAgg; /* If true, extract field values from the aggregator
- ** while generating expressions. Normally false */
#ifndef SQLITE_OMIT_CURSOR
u8 fetchDir; /* The direction argument to the FETCH command */
int dirArg1; /* First argument to the direction */
int dirArg2; /* Second argument to the direction */
#endif
- int nAgg; /* Number of aggregate expressions */
- AggExpr *aAgg; /* An array of aggregate expressions */
Token sErrToken; /* The token at which the error occurred */
Token sNameToken; /* Token with unqualified schema object name */
Token sLastToken; /* The last token parsed */
Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
TriggerStack *trigStack; /* Trigger actions being coded */
const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
+ int nAgg; /* Number of aggregate expressions */
+ AggExpr *aAgg; /* An array of aggregate expressions */
+ int nMaxDepth; /* Maximum depth of subquery recursion */
};
/*
char **pzErrMsg; /* Error message stored here */
} InitData;
-/*
-** A NameContext defines a context in which to resolve table and column
-** names. The context consists of a list of tables (the pSrcList) field and
-** a list of named expression (pEList). The named expression list may
-** be NULL. The pSrc corresponds to the FROM clause of a SELECT or
-** to the table being operated on by INSERT, UPDATE, or DELETE. The
-** pEList corresponds to the result set of a SELECT and is NULL for
-** other statements.
-**
-** NameContexts can be nested. When resolving names, the inner-most
-** context is searched first. If no match is found, the next outer
-** context is checked. If there is still no match, the next context
-** is checked. This process continues until either a match is found
-** or all contexts are check. When a match is found, the nRef member of
-** the context containing the match is incremented.
-**
-** Each subquery gets a new NameContext. The pNext field points to the
-** NameContext in the parent query. Thus the process of scanning the
-** NameContext list corresponds to searching through successively outer
-** subqueries looking for a match.
-*/
-struct NameContext {
- Parse *pParse; /* The parser */
- SrcList *pSrcList; /* One or more tables used to resolve names */
- ExprList *pEList; /* Optional list of named expressions */
- int nRef; /* Number of names resolved by this context */
- int nErr; /* Number of errors encountered while resolving names */
- u8 allowAgg; /* Aggregate functions allowed here */
- u8 hasAgg; /* Expression actually contains aggregate functions */
- NameContext *pNext; /* Next outer name context. NULL for outermost */
-};
-
/*
** Each SQL cursor (a cursor created by the DECLARE ... CURSOR syntax)
** is represented by an instance of the following structure.
void sqlite3DropIndex(Parse*, SrcList*);
void sqlite3AddKeyType(Vdbe*, ExprList*);
void sqlite3AddIdxKeyType(Vdbe*, Index*);
-int sqlite3Select(Parse*, Select*, int, int, Select*, int, int*,
- char *aff, NameContext*);
+int sqlite3Select(Parse*, Select*, int, int, Select*, int, int*, char *aff);
Select *sqlite3SelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*,
int,int,int);
void sqlite3SelectDelete(Select*);
int sqlite3ExprCheck(Parse*, Expr*, int, int*);
int sqlite3ExprCompare(Expr*, Expr*);
int sqliteFuncId(Token*);
-int sqlite3ExprResolveNames(Parse*, SrcList*, ExprList*, NameContext*,
- Expr*, int, int);
+int sqlite3ExprResolveNames(NameContext *, Expr *);
int sqlite3ExprAnalyzeAggregates(Parse*, Expr*);
Vdbe *sqlite3GetVdbe(Parse*);
void sqlite3Randomness(int, void*);
int sqlite3GetToken(const unsigned char *, int *);
void sqlite3NestedParse(Parse*, const char*, ...);
void sqlite3ExpirePreparedStatements(sqlite3*);
+void sqlite3CodeSubselect(Parse *, Expr *);
+int sqlite3SelectResolve(Parse *, Select *, NameContext *);
#ifndef SQLITE_OMIT_CURSOR
void sqlite3CursorDelete(SqlCursor*);
Select * ss = sqlite3SelectDup(pTriggerStep->pSelect);
assert(ss);
assert(ss->pSrc);
- sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0, 0);
+ sqlite3SelectResolve(pParse, ss, 0);
+ sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0);
sqlite3SelectDelete(ss);
break;
}
if( fire_this ){
int endTrigger;
- SrcList dummyTablist;
Expr * whenExpr;
AuthContext sContext;
+ NameContext sNC;
- dummyTablist.nSrc = 0;
+ memset(&sNC, 0, sizeof(sNC));
+ sNC.pParse = pParse;
/* Push an entry on to the trigger stack */
trigStackEntry.pTrigger = pTrigger;
/* code the WHEN clause */
endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
whenExpr = sqlite3ExprDup(pTrigger->pWhen);
- if( sqlite3ExprResolveNames(pParse, &dummyTablist, 0, 0, whenExpr, 0,1) ){
+ if( sqlite3ExprResolveNames(&sNC, whenExpr) ){
pParse->trigStack = trigStackEntry.pNext;
sqlite3ExprDelete(whenExpr);
return 1;
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
-** $Id: update.c,v 1.103 2005/01/19 23:24:51 drh Exp $
+** $Id: update.c,v 1.104 2005/01/29 08:32:45 danielk1977 Exp $
*/
#include "sqliteInt.h"
Expr *pRecnoExpr = 0; /* Expression defining the new record number */
int openAll = 0; /* True if all indices need to be opened */
AuthContext sContext; /* The authorization context */
+ NameContext sNC; /* The name-context to resolve expressions in */
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* Trying to update a view */
pParse->nTab++;
}
+ /* Initialize the name-context */
+ memset(&sNC, 0, sizeof(sNC));
+ sNC.pParse = pParse;
+ sNC.pSrcList = pTabList;
+
/* Resolve the column names in all the expressions of the
** of the UPDATE statement. Also find the column index
** for each column to be updated in the pChanges array. For each
*/
chngRecno = 0;
for(i=0; i<pChanges->nExpr; i++){
- if( sqlite3ExprResolveNames(pParse, pTabList, 0, 0,
- pChanges->a[i].pExpr, 0, 1) ){
+ if( sqlite3ExprResolveNames(&sNC, pChanges->a[i].pExpr) ){
goto update_cleanup;
}
for(j=0; j<pTab->nCol; j++){
/* Resolve the column names in all the expressions in the
** WHERE clause.
*/
- if( sqlite3ExprResolveNames(pParse, pTabList, 0, 0, pWhere, 0, 1) ){
+ if( sqlite3ExprResolveNames(&sNC, pWhere) ){
goto update_cleanup;
}
if( isView ){
Select *pView;
pView = sqlite3SelectDup(pTab->pSelect);
- sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0, 0);
+ sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
sqlite3SelectDelete(pView);
}
** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
-** $Id: vdbe.c,v 1.448 2005/01/27 00:33:21 drh Exp $
+** $Id: vdbe.c,v 1.449 2005/01/29 08:32:45 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
break;
}
+#ifndef SQLITE_OMIT_SUBQUERY
+/* Opcode: AggContextPush * * *
+**
+** Save the state of the current aggregator. It is restored an
+** AggContextPop opcode.
+**
+*/
+case OP_AggContextPush: {
+ p->pAgg++;
+ assert( p->pAgg<&p->apAgg[p->nAgg] );
+ break;
+}
+
+/* Opcode: AggContextPop * * *
+**
+** Restore the aggregator to the state it was in when AggContextPush
+** was last called. Any data in the current aggregator is deleted.
+*/
+case OP_AggContextPop: {
+ p->pAgg--;
+ assert( p->pAgg>=p->apAgg );
+ break;
+}
+#endif
+
#ifndef SQLITE_OMIT_TRIGGER
/* Opcode: ContextPush * * *
**
/* Opcode: AggReset P1 P2 P3
**
-** Reset the aggregator so that it no longer contains any data.
-** Future aggregator elements will contain P2 values each and be sorted
+** Reset the current aggregator context so that it no longer contains any
+** data. Future aggregator elements will contain P2 values each and be sorted
** using the KeyInfo structure pointed to by P3.
**
** If P1 is non-zero, then only a single aggregator row is available (i.e.
case OP_AggReset: {
assert( !pOp->p3 || pOp->p3type==P3_KEYINFO );
if( pOp->p1 ){
- rc = sqlite3VdbeAggReset(0, &p->agg, (KeyInfo *)pOp->p3);
- p->agg.nMem = pOp->p2; /* Agg.nMem is used by AggInsert() */
- rc = AggInsert(&p->agg, 0, 0);
+ rc = sqlite3VdbeAggReset(0, p->pAgg, (KeyInfo *)pOp->p3);
+ p->pAgg->nMem = pOp->p2; /* Agg.nMem is used by AggInsert() */
+ rc = AggInsert(p->pAgg, 0, 0);
}else{
- rc = sqlite3VdbeAggReset(db, &p->agg, (KeyInfo *)pOp->p3);
- p->agg.nMem = pOp->p2;
+ rc = sqlite3VdbeAggReset(db, p->pAgg, (KeyInfo *)pOp->p3);
+ p->pAgg->nMem = pOp->p2;
}
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
- p->agg.apFunc = sqliteMalloc( p->agg.nMem*sizeof(p->agg.apFunc[0]) );
- if( p->agg.apFunc==0 ) goto no_mem;
+ p->pAgg->apFunc = sqliteMalloc( p->pAgg->nMem*sizeof(p->pAgg->apFunc[0]) );
+ if( p->pAgg->apFunc==0 ) goto no_mem;
break;
}
*/
case OP_AggInit: {
int i = pOp->p2;
- assert( i>=0 && i<p->agg.nMem );
- p->agg.apFunc[i] = (FuncDef*)pOp->p3;
+ assert( i>=0 && i<p->pAgg->nMem );
+ p->pAgg->apFunc[i] = (FuncDef*)pOp->p3;
break;
}
storeTypeInfo(pRec, db->enc);
}
i = pTos->i;
- assert( i>=0 && i<p->agg.nMem );
+ assert( i>=0 && i<p->pAgg->nMem );
ctx.pFunc = (FuncDef*)pOp->p3;
- pMem = &p->agg.pCurrent->aMem[i];
+ pMem = &p->pAgg->pCurrent->aMem[i];
ctx.s.z = pMem->zShort; /* Space used for small aggregate contexts */
ctx.pAgg = pMem->z;
ctx.cnt = ++pMem->i;
Stringify(pTos, db->enc);
zKey = pTos->z;
nKey = pTos->n;
- assert( p->agg.pBtree );
- assert( p->agg.pCsr );
- rc = sqlite3BtreeMoveto(p->agg.pCsr, zKey, nKey, &res);
+ assert( p->pAgg->pBtree );
+ assert( p->pAgg->pCsr );
+ rc = sqlite3BtreeMoveto(p->pAgg->pCsr, zKey, nKey, &res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
if( res==0 ){
- rc = sqlite3BtreeData(p->agg.pCsr, 0, sizeof(AggElem*),
- (char *)&p->agg.pCurrent);
+ rc = sqlite3BtreeData(p->pAgg->pCsr, 0, sizeof(AggElem*),
+ (char *)&p->pAgg->pCurrent);
pc = pOp->p2 - 1;
}else{
- rc = AggInsert(&p->agg, zKey, nKey);
+ rc = AggInsert(p->pAgg, zKey, nKey);
}
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
case OP_AggSet: {
AggElem *pFocus;
int i = pOp->p2;
- pFocus = p->agg.pCurrent;
+ pFocus = p->pAgg->pCurrent;
assert( pTos>=p->aStack );
if( pFocus==0 ) goto no_mem;
- assert( i>=0 && i<p->agg.nMem );
+ assert( i>=0 && i<p->pAgg->nMem );
rc = sqlite3VdbeMemMove(&pFocus->aMem[i], pTos);
pTos--;
break;
case OP_AggGet: {
AggElem *pFocus;
int i = pOp->p2;
- pFocus = p->agg.pCurrent;
+ pFocus = p->pAgg->pCurrent;
if( pFocus==0 ){
int res;
if( sqlite3_malloc_failed ) goto no_mem;
- rc = sqlite3BtreeFirst(p->agg.pCsr, &res);
+ rc = sqlite3BtreeFirst(p->pAgg->pCsr, &res);
if( rc!=SQLITE_OK ){
return rc;
}
if( res!=0 ){
- rc = AggInsert(&p->agg,"",1);
- pFocus = p->agg.pCurrent;
+ rc = AggInsert(p->pAgg, "", 1);
+ pFocus = p->pAgg->pCurrent;
}else{
- rc = sqlite3BtreeData(p->agg.pCsr, 0, 4, (char *)&pFocus);
+ rc = sqlite3BtreeData(p->pAgg->pCsr, 0, 4, (char *)&pFocus);
}
}
- assert( i>=0 && i<p->agg.nMem );
+ assert( i>=0 && i<p->pAgg->nMem );
pTos++;
sqlite3VdbeMemShallowCopy(pTos, &pFocus->aMem[i], MEM_Ephem);
if( pTos->flags&MEM_Str ){
int res;
assert( rc==SQLITE_OK );
CHECK_FOR_INTERRUPT;
- if( p->agg.searching==0 ){
- p->agg.searching = 1;
- if( p->agg.pCsr ){
- rc = sqlite3BtreeFirst(p->agg.pCsr, &res);
+ if( p->pAgg->searching==0 ){
+ p->pAgg->searching = 1;
+ if( p->pAgg->pCsr ){
+ rc = sqlite3BtreeFirst(p->pAgg->pCsr, &res);
}else{
res = 0;
}
}else{
- if( p->agg.pCsr ){
- rc = sqlite3BtreeNext(p->agg.pCsr, &res);
+ if( p->pAgg->pCsr ){
+ rc = sqlite3BtreeNext(p->pAgg->pCsr, &res);
}else{
res = 1;
}
sqlite3_context ctx;
Mem *aMem;
- if( p->agg.pCsr ){
- rc = sqlite3BtreeData(p->agg.pCsr, 0, sizeof(AggElem*),
- (char *)&p->agg.pCurrent);
+ if( p->pAgg->pCsr ){
+ rc = sqlite3BtreeData(p->pAgg->pCsr, 0, sizeof(AggElem*),
+ (char *)&p->pAgg->pCurrent);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
}
- aMem = p->agg.pCurrent->aMem;
- for(i=0; i<p->agg.nMem; i++){
- FuncDef *pFunc = p->agg.apFunc[i];
+ aMem = p->pAgg->pCurrent->aMem;
+ for(i=0; i<p->pAgg->nMem; i++){
+ FuncDef *pFunc = p->pAgg->apFunc[i];
Mem *pMem = &aMem[i];
if( pFunc==0 || pFunc->xFinalize==0 ) continue;
ctx.s.flags = MEM_Null;
}
-
/* An other opcode is illegal...
*/
default: {
** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
-** $Id: vdbe.h,v 1.91 2004/09/06 17:24:13 drh Exp $
+** $Id: vdbe.h,v 1.92 2005/01/29 08:32:45 danielk1977 Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
int sqlite3VdbeMakeLabel(Vdbe*);
void sqlite3VdbeDelete(Vdbe*);
-void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int);
+void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int);
int sqlite3VdbeFinalize(Vdbe*);
void sqlite3VdbeResolveLabel(Vdbe*, int);
int sqlite3VdbeCurrentAddr(Vdbe*);
int magic; /* Magic number for sanity checking */
int nMem; /* Number of memory locations currently allocated */
Mem *aMem; /* The memory locations */
- Agg agg; /* Aggregate information */
+ int nAgg; /* Number of elements in apAgg */
+ Agg *apAgg; /* Array of aggregate contexts */
+ Agg *pAgg; /* Current aggregate context */
int nCallback; /* Number of callbacks invoked so far */
Keylist *pList; /* A list of ROWIDs */
int contextStackTop; /* Index of top element in the context stack */
int nVar, /* Number of '?' see in the SQL statement */
int nMem, /* Number of memory cells to allocate */
int nCursor, /* Number of cursors to allocate */
+ int nAgg, /* Number of aggregate contexts required */
int isExplain /* True if the EXPLAIN keywords is present */
){
int n;
+ nVar*sizeof(char*) /* azVar */
+ nMem*sizeof(Mem) /* aMem */
+ nCursor*sizeof(Cursor*) /* apCsr */
+ + nAgg*sizeof(Agg) /* Aggregate contexts */
);
if( !sqlite3_malloc_failed ){
p->aMem = &p->aStack[n];
p->apArg = (Mem**)&p->aVar[nVar];
p->azVar = (char**)&p->apArg[n];
p->apCsr = (Cursor**)&p->azVar[nVar];
+ if( nAgg>0 ){
+ p->nAgg = nAgg;
+ p->apAgg = (Agg*)&p->apCsr[nCursor];
+ }
p->nCursor = nCursor;
for(n=0; n<nVar; n++){
p->aVar[n].flags = MEM_Null;
}
- for(n=0; n<nMem; n++){
- p->aMem[n].flags = MEM_Null;
- }
}
}
+ p->pAgg = p->apAgg;
+ for(n=0; n<p->nMem; n++){
+ p->aMem[n].flags = MEM_Null;
+ }
#ifdef SQLITE_DEBUG
if( (p->db->flags & SQLITE_VdbeListing)!=0
*/
int sqlite3VdbeAggReset(sqlite3 *db, Agg *pAgg, KeyInfo *pKeyInfo){
int rc = 0;
- BtCursor *pCsr = pAgg->pCsr;
+ BtCursor *pCsr;
+ if( !pAgg ) return SQLITE_OK;
+ pCsr = pAgg->pCsr;
assert( (pCsr && pAgg->nTab>0) || (!pCsr && pAgg->nTab==0)
|| sqlite3_malloc_failed );
sqliteFree(p->contextStack);
}
sqlite3VdbeSorterReset(p);
- sqlite3VdbeAggReset(0, &p->agg, 0);
+ for(i=0; i<p->nAgg; i++){
+ sqlite3VdbeAggReset(0, &p->apAgg[i], 0);
+ }
p->contextStack = 0;
p->contextStackDepth = 0;
p->contextStackTop = 0;
** 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.131 2005/01/20 22:48:48 drh Exp $
+** $Id: where.c,v 1.132 2005/01/29 08:32:45 danielk1977 Exp $
*/
#include "sqliteInt.h"
** sets their opcodes to TK_COLUMN and their Expr.iTable fields to
** the VDBE cursor number of the table.
*/
+static Bitmask exprListTableUsage(ExprMaskSet *, ExprList *);
static Bitmask exprTableUsage(ExprMaskSet *pMaskSet, Expr *p){
Bitmask mask = 0;
if( p==0 ) return 0;
mask = getMask(pMaskSet, p->iTable);
return mask;
}
- if( p->pRight ){
- mask = exprTableUsage(pMaskSet, p->pRight);
+ mask = exprTableUsage(pMaskSet, p->pRight);
+ mask |= exprTableUsage(pMaskSet, p->pLeft);
+ mask |= exprListTableUsage(pMaskSet, p->pList);
+ if( p->pSelect ){
+ Select *pS = p->pSelect;
+ mask |= exprListTableUsage(pMaskSet, pS->pEList);
+ mask |= exprListTableUsage(pMaskSet, pS->pGroupBy);
+ mask |= exprListTableUsage(pMaskSet, pS->pOrderBy);
+ mask |= exprTableUsage(pMaskSet, pS->pWhere);
+ mask |= exprTableUsage(pMaskSet, pS->pHaving);
}
- if( p->pLeft ){
- mask |= exprTableUsage(pMaskSet, p->pLeft);
- }
- if( p->pList ){
- int i;
- for(i=0; i<p->pList->nExpr; i++){
- mask |= exprTableUsage(pMaskSet, p->pList->a[i].pExpr);
+ return mask;
+}
+static Bitmask exprListTableUsage(ExprMaskSet *pMaskSet, ExprList *pList){
+ int i;
+ Bitmask mask = 0;
+ if( pList ){
+ for(i=0; i<pList->nExpr; i++){
+ mask |= exprTableUsage(pMaskSet, pList->a[i].pExpr);
}
}
return mask;
if( pX->op!=TK_IN ){
assert( pX->op==TK_EQ );
sqlite3ExprCode(pParse, pX->pRight);
+#ifndef SQLITE_OMIT_SUBQUERY
}else{
- int iTab = pX->iTable;
+ int iTab;
Vdbe *v = pParse->pVdbe;
+
+ sqlite3CodeSubselect(pParse, pX);
+ iTab = pX->iTable;
sqlite3VdbeAddOp(v, OP_Rewind, iTab, brk);
sqlite3VdbeAddOp(v, OP_KeyAsData, iTab, 1);
+ VdbeComment((v, "# %.*s", pX->span.n, pX->span.z));
pLevel->inP2 = sqlite3VdbeAddOp(v, OP_Column, iTab, 0);
pLevel->inOp = OP_Next;
pLevel->inP1 = iTab;
+#endif
}
disableTerm(pLevel, &pTerm->p);
}
# This file implements regression tests for SQLite library. The
# focus of this script testing the sqlite_bind API.
#
-# $Id: bind.test,v 1.27 2005/01/20 02:17:02 danielk1977 Exp $
+# $Id: bind.test,v 1.28 2005/01/29 08:32:46 danielk1977 Exp $
#
set testdir [file dirname $argv0]
do_test bind-10.16 {
sqlite3_bind_parameter_name $VM 1
} :abc
-do_test bind-10.16 {
+do_test bind-10.17 {
sqlite3_bind_parameter_name $VM 2
} {}
-do_test bind-10.16 {
+do_test bind-10.18 {
sqlite3_bind_parameter_name $VM 3
} {}
-do_test bind-10.16 {
+do_test bind-10.19 {
sqlite3_bind_parameter_name $VM 4
} {?4}
-do_test bind-10.16 {
+do_test bind-10.20 {
sqlite3_bind_parameter_name $VM 5
} :pqr
catch {sqlite3_finalize $VM}
# This file implements regression tests for SQLite library. The
# focus of this script is page cache subsystem.
#
-# $Id: collate3.test,v 1.9 2005/01/26 03:58:36 danielk1977 Exp $
+# $Id: collate3.test,v 1.10 2005/01/29 08:32:46 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
} {1 {no such collation sequence: string_compare}}
ifcapable compound {
-do_test collate3-2.9 {
- catchsql {
- SELECT c1 FROM collate3t1 UNION SELECT c1 FROM collate3t1;
- }
-} {1 {no such collation sequence: string_compare}}
-do_test collate3-2.10 {
- catchsql {
- SELECT c1 FROM collate3t1 EXCEPT SELECT c1 FROM collate3t1;
- }
-} {1 {no such collation sequence: string_compare}}
-do_test collate3-2.11 {
- catchsql {
- SELECT c1 FROM collate3t1 INTERSECT SELECT c1 FROM collate3t1;
- }
-} {1 {no such collation sequence: string_compare}}
-do_test collate3-2.12 {
- catchsql {
- SELECT c1 FROM collate3t1 UNION ALL SELECT c1 FROM collate3t1;
- }
-} {0 {}}
-do_test collate3-2.13 {
- catchsql {
- SELECT 10 UNION ALL SELECT 20 ORDER BY 1 COLLATE string_compare;
- }
-} {1 {no such collation sequence: string_compare}}
-do_test collate3-2.14 {
- catchsql {
- SELECT 10 INTERSECT SELECT 20 ORDER BY 1 COLLATE string_compare;
- }
-} {1 {no such collation sequence: string_compare}}
-do_test collate3-2.15 {
- catchsql {
- SELECT 10 EXCEPT SELECT 20 ORDER BY 1 COLLATE string_compare;
- }
-} {1 {no such collation sequence: string_compare}}
-do_test collate3-2.16 {
- catchsql {
- SELECT 10 UNION SELECT 20 ORDER BY 1 COLLATE string_compare;
- }
-} {1 {no such collation sequence: string_compare}}
-do_test collate3-2.17 {
- catchsql {
- SELECT c1 FROM collate3t1 UNION ALL SELECT c1 FROM collate3t1 ORDER BY 1;
- }
-} {1 {no such collation sequence: string_compare}}
+ do_test collate3-2.9 {
+ catchsql {
+ SELECT c1 FROM collate3t1 UNION SELECT c1 FROM collate3t1;
+ }
+ } {1 {no such collation sequence: string_compare}}
+ do_test collate3-2.10 {
+ catchsql {
+ SELECT c1 FROM collate3t1 EXCEPT SELECT c1 FROM collate3t1;
+ }
+ } {1 {no such collation sequence: string_compare}}
+ do_test collate3-2.11 {
+ catchsql {
+ SELECT c1 FROM collate3t1 INTERSECT SELECT c1 FROM collate3t1;
+ }
+ } {1 {no such collation sequence: string_compare}}
+ do_test collate3-2.12 {
+ catchsql {
+ SELECT c1 FROM collate3t1 UNION ALL SELECT c1 FROM collate3t1;
+ }
+ } {0 {}}
+ do_test collate3-2.13 {
+ catchsql {
+ SELECT 10 UNION ALL SELECT 20 ORDER BY 1 COLLATE string_compare;
+ }
+ } {1 {no such collation sequence: string_compare}}
+ do_test collate3-2.14 {
+ catchsql {
+ SELECT 10 INTERSECT SELECT 20 ORDER BY 1 COLLATE string_compare;
+ }
+ } {1 {no such collation sequence: string_compare}}
+ do_test collate3-2.15 {
+ catchsql {
+ SELECT 10 EXCEPT SELECT 20 ORDER BY 1 COLLATE string_compare;
+ }
+ } {1 {no such collation sequence: string_compare}}
+ do_test collate3-2.16 {
+ catchsql {
+ SELECT 10 UNION SELECT 20 ORDER BY 1 COLLATE string_compare;
+ }
+ } {1 {no such collation sequence: string_compare}}
+ do_test collate3-2.17 {
+ catchsql {
+ SELECT c1 FROM collate3t1 UNION ALL SELECT c1 FROM collate3t1 ORDER BY 1;
+ }
+ } {1 {no such collation sequence: string_compare}}
} ;# ifcapable compound
#
# This file implements regression tests for SQLite library. The
# focus of this file is testing corner cases of the INSERT statement.
#
-# $Id: insert3.test,v 1.2 2005/01/15 00:36:37 drh Exp $
+# $Id: insert3.test,v 1.3 2005/01/29 08:32:46 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
SELECT * FROM log2 ORDER BY x;
}
} {hi 1}
-do_test insert3-1.4 {
- execsql {
- INSERT INTO t1 SELECT * FROM t1;
- SELECT 'a:', x, y FROM log UNION ALL SELECT 'b:', x, y FROM log2 ORDER BY x;
- }
-} {a: 5 4 b: 10 2 b: 20 1 a: 453 2 a: hello 4 b: hi 2 b: world 1}
-do_test insert3-1.5 {
- execsql {
- INSERT INTO t1(a) VALUES('xyz');
- SELECT * FROM log ORDER BY x;
- }
-} {5 4 453 2 hello 4 xyz 1}
+ifcapable compound {
+ do_test insert3-1.4 {
+ execsql {
+ INSERT INTO t1 SELECT * FROM t1;
+ SELECT 'a:', x, y FROM log UNION ALL
+ SELECT 'b:', x, y FROM log2 ORDER BY x;
+ }
+ } {a: 5 4 b: 10 2 b: 20 1 a: 453 2 a: hello 4 b: hi 2 b: world 1}
+ do_test insert3-1.5 {
+ execsql {
+ INSERT INTO t1(a) VALUES('xyz');
+ SELECT * FROM log ORDER BY x;
+ }
+ } {5 4 453 2 hello 4 xyz 1}
+}
do_test insert3-2.1 {
execsql {
# This file implements tests for miscellanous features that were
# left out of other test files.
#
-# $Id: misc4.test,v 1.13 2005/01/21 03:12:16 danielk1977 Exp $
+# $Id: misc4.test,v 1.14 2005/01/29 08:32:46 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
where a.key=x.key;
}
} {01 data01 01 3.0 +1 data+1 +1 7.0}
+
+ # This test case tests the same property as misc4-4.1, but it is
+ # a bit smaller which makes it easier to work with while debugging.
+ do_test misc4-4.2 {
+ execsql {
+ CREATE TABLE ab(a TEXT, b TEXT);
+ INSERT INTO ab VALUES('01', '1');
+ }
+ execsql {
+ select * from ab, (select b from ab) as x where x.b = ab.a;
+ }
+ } {}
}
+
# Ticket #1036. When creating tables from a SELECT on a view, use the
# short names of columns.
#
# focus of this file is testing SELECT statements that contain
# subqueries in their FROM clause.
#
-# $Id: select6.test,v 1.16 2005/01/21 03:12:16 danielk1977 Exp $
+# $Id: select6.test,v 1.17 2005/01/29 08:32:46 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
}
} {1 1 1 2 2 3 3 4 7 4 8 15 5 5 20}
-do_test sqlite6-3.1 {
+do_test select6-3.1 {
execsql2 {
SELECT * FROM (SELECT * FROM (SELECT * FROM t1 WHERE x=3));
}
} {x 3 y 2}
-do_test sqlite6-3.2 {
+do_test select6-3.2 {
execsql {
SELECT * FROM
(SELECT a.q, a.p, b.r
FROM (SELECT count(*) as p , b as q FROM t2 GROUP BY q) AS a,
(SELECT max(a) as r, b as s FROM t2 GROUP BY s) as b
WHERE a.q=b.s ORDER BY a.q)
- ORDER BY q
+ ORDER BY "a.q"
}
} {1 1 1 2 2 3 3 4 7 4 8 15 5 5 20}
do_test select6-3.3 {
# This file implements regression tests for SQLite library. The
# focus of this script is testing correlated subqueries
#
-# $Id: subquery.test,v 1.2 2005/01/21 11:55:28 danielk1977 Exp $
+# $Id: subquery.test,v 1.3 2005/01/29 08:32:47 danielk1977 Exp $
#
set testdir [file dirname $argv0]
}
} {13 31 57}
+# Simple tests to make sure correlated subqueries in WHERE clauses
+# are used by the query optimizer correctly.
+do_test subquery-1.5 {
+ execsql {
+ SELECT a, x FROM t1, t2 WHERE t1.a = (SELECT x);
+ }
+} {1 1 3 3 5 5 7 7}
+do_test subquery-1.6 {
+ execsql {
+ CREATE INDEX i1 ON t1(a);
+ SELECT a, x FROM t1, t2 WHERE t1.a = (SELECT x);
+ }
+} {1 1 3 3 5 5 7 7}
+do_test subquery-1.7 {
+ execsql {
+ SELECT a, x FROM t2, t1 WHERE t1.a = (SELECT x);
+ }
+} {1 1 3 3 5 5 7 7}
+
+# Try an aggregate in both the subquery and the parent query.
+do_test subquery-1.6 {
+ execsql {
+ SELECT count(*) FROM t1 WHERE a > (SELECT count(*) FROM t2);
+ }
+} {2}
+
+
+#------------------------------------------------------------------
+# The following test cases - subquery-2.* - are not logically
+# organized. They're here largely because they were failing during
+# one stage of development of sub-queries.
+#
+do_test subquery-2.1 {
+ execsql {
+ SELECT (SELECT 10);
+ }
+} {10}
+do_test subquery-2.2.1 {
+ execsql {
+ CREATE TABLE t3(a PRIMARY KEY, b);
+ INSERT INTO t3 VALUES(1, 2);
+ INSERT INTO t3 VALUES(3, 1);
+ }
+} {}
+do_test subquery-2.2.2 {
+ execsql {
+ SELECT * FROM t3 WHERE a IN (SELECT b FROM t3);
+ }
+} {1 2}
+do_test subquery-2.2.3 {
+ execsql {
+ DROP TABLE t3;
+ }
+} {}
+do_test subquery-2.3.1 {
+ execsql {
+ CREATE TABLE t3(a TEXT);
+ INSERT INTO t3 VALUES('10');
+ }
+} {}
+do_test subquery-2.3.2 {
+ execsql {
+ SELECT a IN (10.0, 20) FROM t3;
+ }
+} {0}
+do_test subquery-2.3.3 {
+ execsql {
+ DROP TABLE t3;
+ }
+} {}
+do_test subquery-2.4.1 {
+ execsql {
+ CREATE TABLE t3(a TEXT);
+ INSERT INTO t3 VALUES('XX');
+ }
+} {}
+do_test subquery-2.4.2 {
+ execsql {
+ SELECT count(*) FROM t3 WHERE a IN (SELECT 'XX')
+ }
+} {1}
+do_test subquery-2.4.3 {
+ execsql {
+ DROP TABLE t3;
+ }
+} {}
+do_test subquery-2.5.1 {
+ execsql {
+ CREATE TABLE t3(a INTEGER);
+ INSERT INTO t3 VALUES(10);
+
+ CREATE TABLE t4(x TEXT);
+ INSERT INTO t4 VALUES('10.0');
+ }
+} {}
+do_test subquery-2.5.2 {
+ execsql {
+ SELECT * FROM t4 WHERE x IN (SELECT a FROM t3);
+ }
+} {10.0}
+do_test subquery-2.5.3 {
+ execsql {
+ CREATE INDEX t4i ON t4(x);
+ SELECT * FROM t4 WHERE x IN (SELECT a FROM t3);
+ }
+} {10.0}
+do_test subquery-2.5.4 {
+ execsql {
+ DROP TABLE t3;
+ DROP TABLE t4;
+ }
+} {}
+
+#------------------------------------------------------------------
+# The following test cases - subquery-3.* - test tickets that
+# were raised during development of correlated subqueries.
+#
+
+# Ticket 1083
+ifcapable view {
+ do_test subquery-3.1 {
+ catchsql { DROP TABLE t1; }
+ catchsql { DROP TABLE t2; }
+ execsql {
+ CREATE TABLE t1(a,b);
+ INSERT INTO t1 VALUES(1,2);
+ CREATE VIEW v1 AS SELECT b FROM t1 WHERE a>0;
+ CREATE TABLE t2(p,q);
+ INSERT INTO t2 VALUES(2,9);
+ SELECT * FROM v1 WHERE EXISTS(SELECT * FROM t2 WHERE p=v1.b);
+ }
+ } {2}
+}
+
+# Ticket 1084
+do_test subquery-3.2 {
+ catchsql {
+ CREATE TABLE t1(a,b);
+ INSERT INTO t1 VALUES(1,2);
+ }
+ execsql {
+ SELECT (SELECT t1.a) FROM t1;
+ }
+} {1}
+
+#------------------------------------------------------------------
+# These tests - subquery-4.* - use the TCL statement cache to try
+# and expose bugs to do with re-using statements that have been
+# passed to sqlite3_reset().
+#
+# One problem was that VDBE memory cells were not being initialised
+# to NULL on the second and subsequent executions.
+#
+do_test subquery-4.1.1 {
+ execsql {
+ SELECT (SELECT a FROM t1);
+ }
+} {1}
+do_test subquery-4.2 {
+ execsql {
+ DELETE FROM t1;
+ SELECT (SELECT a FROM t1);
+ }
+} {{}}
+do_test subquery-4.2.1 {
+ execsql {
+ CREATE TABLE t3(a PRIMARY KEY);
+ INSERT INTO t3 VALUES(10);
+ }
+ execsql {INSERT INTO t3 VALUES((SELECT max(a) FROM t3)+1)}
+} {}
+do_test subquery-4.2.2 {
+ execsql {INSERT INTO t3 VALUES((SELECT max(a) FROM t3)+1)}
+} {}
+
+
finish_test
+
+
set r
} [list 1 1 2 4 6 10 20 \
2 1 2 13 24 10 20 \
- 3 3 4 13 24 30 40 \
- 4 3 4 40 60 30 40 \
+ 3 3 4 13 24 30 40 \
+ 4 3 4 40 60 30 40 \
1 1 2 13 24 10 20 ]
execsql {
# This file implements regression tests for SQLite library. The
# focus of this file is testing VIEW statements.
#
-# $Id: view.test,v 1.22 2005/01/21 04:25:47 danielk1977 Exp $
+# $Id: view.test,v 1.23 2005/01/29 08:32:47 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
SELECT * FROM v3 LIMIT 4;
}
} {b 2 b 3 b 5 b 6}
-do_test view-3.5 {
+do_test view-3.5 {
execsql2 {
CREATE VIEW v4 AS
SELECT a, b FROM t1