]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Modify sub-query handling. Tickets #1083 and #1084. (CVS 2286)
authordanielk1977 <danielk1977@noemail.net>
Sat, 29 Jan 2005 08:32:43 +0000 (08:32 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Sat, 29 Jan 2005 08:32:43 +0000 (08:32 +0000)
FossilOrigin-Name: b1b50f315873a8614920d1e3af4a07fb29a7ff6a

27 files changed:
manifest
manifest.uuid
src/auth.c
src/build.c
src/delete.c
src/expr.c
src/insert.c
src/main.c
src/pager.c
src/parse.y
src/select.c
src/sqliteInt.h
src/trigger.c
src/update.c
src/vdbe.c
src/vdbe.h
src/vdbeInt.h
src/vdbeaux.c
src/where.c
test/bind.test
test/collate3.test
test/insert3.test
test/misc4.test
test/select6.test
test/subquery.test
test/trigger2.test
test/view.test

index f3c9ed8a9443e776c50e3ff0c6c9e74dc263be04..5812a1a7368cba25a0eb1006f97f6c4f38b53259 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-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
@@ -28,21 +28,21 @@ F sqlite3.1 01fdb467ce387a83248857c92f9e801df9e4611c
 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
@@ -52,16 +52,16 @@ F src/os_unix.c 1f17ceff056c64939e5f2e98bf909fc64d0929ca
 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
@@ -70,18 +70,18 @@ F src/test3.c 683e1e3819152ffd35da2f201e507228921148d0
 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
@@ -96,7 +96,7 @@ F test/autovacuum_ioerr.test 9cf27275ca47b72e188a47c53b61b6d583a01d24
 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
@@ -109,7 +109,7 @@ F test/capi3.test f50dd4666deba96275f9927fe8ec089a3d8c0efa
 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
@@ -135,7 +135,7 @@ F test/index.test 51e01a0928b4b61228917ddd8c6c0e2466547f6f
 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
@@ -157,7 +157,7 @@ F test/minmax.test 9429a06f1f93acf76fcacafd17160a4392e88526
 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
@@ -180,10 +180,10 @@ F test/select2.test 01b9cbc06e5ed662ce0289aa5f47314d54541e82
 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
@@ -196,7 +196,7 @@ F test/threadtest2.c 97a830d53c24c42290501fdfba4a6e5bdd34748b
 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
@@ -208,7 +208,7 @@ F test/update.test 7669ca789d62c258b678e8aa7a22a57eac10f2cf
 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
@@ -272,7 +272,7 @@ F www/tclsqlite.tcl e73f8f8e5f20e8277619433f7970060ab01088fc
 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
index 0e3d6f6784ae522c32e5f6aabfe943110c62d137..f927db229ca5e8e3deaf378caace2e1d28da6b7d 100644 (file)
@@ -1 +1 @@
-95ecb2745f3fc69d370fc3961800db56297acb68
\ No newline at end of file
+b1b50f315873a8614920d1e3af4a07fb29a7ff6a
\ No newline at end of file
index 6aa69c87475b3b38bf0601e1e14d09d073ac6f18..aa387cc603a20fd05945e68bc500e8255b596005 100644 (file)
@@ -14,7 +14,7 @@
 ** 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"
 
@@ -115,10 +115,10 @@ void sqlite3AuthRead(
 
   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
index 2b2602226a8a88e98999eedb14975610800f32ce..f43ee301b2e04c4f23a851d012a695150f4cf2a3 100644 (file)
@@ -22,7 +22,7 @@
 **     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>
@@ -95,7 +95,7 @@ void sqlite3FinishCoding(Parse *pParse){
     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 ){
@@ -104,7 +104,6 @@ void sqlite3FinishCoding(Parse *pParse){
   pParse->nTab = 0;
   pParse->nMem = 0;
   pParse->nSet = 0;
-  pParse->nAgg = 0;
   pParse->nVar = 0;
   pParse->cookieMask = 0;
   pParse->cookieGoto = 0;
@@ -896,7 +895,6 @@ void sqlite3AddDefaultValue(Parse *pParse, Expr *pExpr){
   }else{
     sqlite3ExprDelete(pCol->pDflt);
     pCol->pDflt = sqlite3ExprDup(pExpr);
-    sqlite3ExprResolveNames(pParse,0,0,0,pExpr,0,0);
   }
   sqlite3ExprDelete(pExpr);
 }
@@ -1439,7 +1437,7 @@ void sqlite3EndTable(Parse *pParse, Token *pEnd, Select *pSelect){
       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);
index 50a25ab6fc948641af3c2dbb7a7b2b783dd344b1..b160bdaba258763b9802986970882a15a2bcf22d 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** in order to generate code for DELETE FROM statements.
 **
-** $Id: delete.c,v 1.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"
 
@@ -90,6 +90,7 @@ void sqlite3DeleteFrom(
   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 */
@@ -148,11 +149,14 @@ void sqlite3DeleteFrom(
     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;
   }
 
@@ -176,7 +180,7 @@ void sqlite3DeleteFrom(
   */
   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);
   }
 
index 2f22842a7f982447d57fa4b00f2355432f88dbd6..815d0b064fbc1eca097a6209e38ed162a09da838 100644 (file)
@@ -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.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>
@@ -516,6 +516,8 @@ Select *sqlite3SelectDup(Select *p){
   pNew->iOffset = -1;
   pNew->ppOpenTemp = 0;
   pNew->pFetch = 0;
+  pNew->isResolved = 0;
+  pNew->isAgg = 0;
   return pNew;
 }
 #else
@@ -750,40 +752,42 @@ static int lookupName(
 
     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;
+          }
         }
       }
     }
@@ -926,7 +930,7 @@ static int lookupName(
   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;
@@ -991,10 +995,11 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
   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
@@ -1017,7 +1022,6 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
     /* 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;
     }
@@ -1031,7 +1035,7 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
       Token *pDb;
       Expr *pRight;
 
-      if( pSrcList==0 ) break;
+      /* if( pSrcList==0 ) break; */
       pRight = pExpr->pRight;
       if( pRight->op==TK_ID ){
         pDb = 0;
@@ -1052,7 +1056,6 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
     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: {
@@ -1105,13 +1108,24 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
       */
       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
@@ -1134,31 +1148,13 @@ static int sqlite3ExprCodeSubquery(Parse*, NameContext*, Expr*);
 ** 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);
 }
@@ -1186,28 +1182,36 @@ struct QueryCoder {
 ** 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>)'
@@ -1238,7 +1242,7 @@ static int codeSubqueryStep(void *pArg, Expr *pExpr){
         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,
@@ -1266,10 +1270,7 @@ static int codeSubqueryStep(void *pArg, Expr *pExpr){
           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 */
@@ -1280,7 +1281,7 @@ static int codeSubqueryStep(void *pArg, Expr *pExpr){
         }
       }
       sqlite3VdbeChangeP3(v, addr, (void *)&keyInfo, P3_KEYINFO);
-      return 1;
+      break;
     }
 
     case TK_EXISTS:
@@ -1289,18 +1290,9 @@ static int codeSubqueryStep(void *pArg, Expr *pExpr){
       ** 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 ){
@@ -1312,41 +1304,20 @@ static int codeSubqueryStep(void *pArg, Expr *pExpr){
         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
@@ -1556,10 +1527,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
 #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;
@@ -1567,6 +1535,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
     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
index 5dbc1397da317f64f953da9c172355055c6488f0..1795055e253fb2ba9c1c69845aac7914cdc4fe7d 100644 (file)
@@ -12,7 +12,7 @@
 ** 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"
 
@@ -312,8 +312,11 @@ void sqlite3Insert(
     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 );
@@ -372,15 +375,16 @@ void sqlite3Insert(
     /* 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;
       }
     }
index e993b816171003df4e9ef62f3efee5cfa5c4ad9d..dfcab944b5910a6db205e5f89ef13b7af05d3a74 100644 (file)
@@ -14,7 +14,7 @@
 ** 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"
@@ -1266,7 +1266,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt){
     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;
 }
index 2ec7561c38d36573d2e55803f33de0ec362d96b2..e8b5a14309713b38859c37b251365070a8a793ff 100644 (file)
@@ -18,7 +18,7 @@
 ** 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"
@@ -1802,7 +1802,19 @@ int sqlite3pager_close(Pager *pPager){
     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);
       }
index d8482fb694d5465d4e0c398bbbc768e4aa1ce585..78875a6790cea65b7752b7eae954969219c56b01 100644 (file)
@@ -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.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}
@@ -317,7 +317,7 @@ cmd ::= DROP VIEW fullname(X). {
 //////////////////////// 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);
 }
 
@@ -609,7 +609,7 @@ expr(A) ::= VARIABLE(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);
 }
index 97c2da0a35ff9b26b2180c132881707a8eee77c7..ab4265266972ff12a3d859477741bb9060b244b8 100644 (file)
@@ -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.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"
 
@@ -314,12 +314,14 @@ void sqlite3SelectDelete(Select *p){
 /*
 ** 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
@@ -669,12 +671,10 @@ static void generateSortTail(
 ** 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
@@ -684,11 +684,18 @@ static const char *columnType(Parse *pParse, SrcList *pTabList, Expr *pExpr){
 
   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 ){
@@ -700,8 +707,11 @@ static const char *columnType(Parse *pParse, SrcList *pTabList, Expr *pExpr){
     }
 #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
@@ -723,9 +733,11 @@ static void generateColumnTypes(
 ){
   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.
@@ -860,6 +872,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
     char *zName;
     char *zBasename;
     int cnt;
+    NameContext sNC;
     
     /* Get an appropriate name for the column
     */
@@ -899,7 +912,8 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
     /* 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 ){
@@ -975,6 +989,7 @@ static int prepSelectStmt(Parse *pParse, Select *p){
         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 ){
@@ -1492,7 +1507,7 @@ static int multiSelect(
       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;
         }
@@ -1501,7 +1516,7 @@ static int multiSelect(
         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;
@@ -1550,7 +1565,8 @@ static int multiSelect(
 
       /* 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;
       }
@@ -1569,7 +1585,7 @@ static int multiSelect(
       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;
@@ -1638,7 +1654,7 @@ static int multiSelect(
 
       /* 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;
       }
@@ -1658,7 +1674,7 @@ static int multiSelect(
       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;
@@ -1757,7 +1773,7 @@ static int multiSelect(
         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{
@@ -1797,6 +1813,7 @@ multi_select_end:
 ** 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 ){
@@ -1824,17 +1841,25 @@ static void substExpr(Expr *pExpr, int iTable, ExprList *pEList){
   }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
@@ -2236,42 +2261,184 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
 ** 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.
 **
@@ -2332,13 +2499,12 @@ int sqlite3Select(
   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 */
@@ -2348,6 +2514,7 @@ int sqlite3Select(
   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;
@@ -2366,14 +2533,26 @@ int sqlite3Select(
   }
 #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
@@ -2381,13 +2560,6 @@ int sqlite3Select(
   */
   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.
   */
@@ -2412,39 +2584,6 @@ int sqlite3Select(
       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
@@ -2493,7 +2632,7 @@ int sqlite3Select(
       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;
     }
@@ -2523,7 +2662,7 @@ int sqlite3Select(
   if( pParent && pParentAgg &&
       flattenSubquery(pParse, pParent, parentTab, *pParentAgg, isAgg) ){
     if( isAgg ) *pParentAgg = 1;
-    return rc;
+    goto select_end;
   }
 #endif
 
@@ -2555,7 +2694,6 @@ int sqlite3Select(
 
   /* Do an analysis of aggregate expressions.
   */
-  sqliteAggregateInfoReset(pParse);
   if( isAgg || pGroupBy ){
     assert( pParse->nAgg==0 );
     isAgg = 1;
@@ -2746,6 +2884,6 @@ int sqlite3Select(
   ** successful coding of the SELECT.
   */
 select_end:
-  sqliteAggregateInfoReset(pParse);
+  restoreAggregateInfo(pParse, &sAggInfo);
   return rc;
 }
index 4f95805a972a3e541b593ab97c33bff65edd6c57..524d5a4d8c9365f2fd815c742f4a3cad8b3f8b08 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** 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_
@@ -838,6 +838,7 @@ struct Expr {
 #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 
@@ -983,6 +984,39 @@ struct Fetch {
   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.
@@ -1007,6 +1041,8 @@ struct Select {
   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 */
 };
 
 /*
@@ -1076,6 +1112,8 @@ struct Parse {
   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 */
@@ -1085,15 +1123,11 @@ struct Parse {
   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 */
@@ -1103,6 +1137,9 @@ struct Parse {
   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 */
 };
 
 /*
@@ -1275,38 +1312,6 @@ typedef struct {
   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.
@@ -1413,8 +1418,7 @@ void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
 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*);
@@ -1444,8 +1448,7 @@ char *sqlite3NameFromToken(Token*);
 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*);
@@ -1573,6 +1576,8 @@ void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
 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*);
index ef4acefc02f87099652d47c9bbfa91864802e6d3..eccc810e9be328832bd4c1e74f1b6ce12b326018 100644 (file)
@@ -640,7 +640,8 @@ static int codeTriggerProgram(
        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;
       }
@@ -744,11 +745,12 @@ int sqlite3CodeRowTrigger(
  
     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;
@@ -763,7 +765,7 @@ int sqlite3CodeRowTrigger(
       /* 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;
index 2158938cfb37f8dcb85dcf9bf151fe59010e551a..81e5db951f2988d43c20d2806eacd9bb6fd6d04e 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle UPDATE statements.
 **
-** $Id: update.c,v 1.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"
 
@@ -49,6 +49,7 @@ void sqlite3Update(
   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 */
@@ -113,6 +114,11 @@ void sqlite3Update(
     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
@@ -121,8 +127,7 @@ void sqlite3Update(
   */
   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++){
@@ -198,7 +203,7 @@ void sqlite3Update(
   /* 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;
   }
 
@@ -221,7 +226,7 @@ void sqlite3Update(
   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);
   }
 
index 029f4ac786dc147e1e8ab9adad5baed8cc7d30fc..31218cb64ca9e0cfe9417e18ce7e406d8388b755 100644 (file)
@@ -43,7 +43,7 @@
 ** 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"
@@ -3957,6 +3957,31 @@ case OP_ListReset: {
   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 * * * 
 **
@@ -4185,8 +4210,8 @@ case OP_MemIncr: {
 
 /* 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.
@@ -4196,18 +4221,18 @@ case OP_MemIncr: {
 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;
 }
 
@@ -4219,8 +4244,8 @@ case OP_AggReset: {
 */
 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;
 }
 
@@ -4255,9 +4280,9 @@ case OP_AggFunc: {
     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;
@@ -4301,18 +4326,18 @@ case OP_AggFocus: {
   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;
@@ -4330,10 +4355,10 @@ case OP_AggFocus: {
 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;
@@ -4348,22 +4373,22 @@ case OP_AggSet: {
 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 ){
@@ -4388,16 +4413,16 @@ case OP_AggNext: {
   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;
     }
@@ -4410,14 +4435,14 @@ case OP_AggNext: {
     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;
@@ -4519,7 +4544,6 @@ case OP_Expire: {
 }
 
 
-
 /* An other opcode is illegal...
 */
 default: {
index edef241de07cedec64d2dd51a81c71a3e88cbfb9..d0e9fb188ace3c891c898cffcc3d2f365f582297 100644 (file)
@@ -15,7 +15,7 @@
 ** 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_
@@ -110,7 +110,7 @@ int sqlite3VdbeFindOp(Vdbe*, int, int, int);
 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*);
index da64f762d038c6ad2e8ae6d27ef0ae4bdb4da9d6..42682d1e25a4e3727f26a63668a648347f391611 100644 (file)
@@ -321,7 +321,9 @@ struct 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 */
index 28a83f54dac61fe3ba739bcdffd695c9c8f2436e..6d77d725f41335dc8c998c1e3ed26f5ab700e029 100644 (file)
@@ -586,6 +586,7 @@ void sqlite3VdbeMakeReady(
   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;
@@ -615,6 +616,7 @@ void sqlite3VdbeMakeReady(
       + 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];
@@ -625,15 +627,20 @@ void sqlite3VdbeMakeReady(
       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
@@ -733,8 +740,10 @@ static void freeAggElem(AggElem *pElem, Agg *pAgg){
 */
 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 );
 
@@ -886,7 +895,9 @@ static void Cleanup(Vdbe *p){
     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;
index 1054bf55baf700451eef2e2a75b0098058d648db..86d539a392e22e5ee114cf9c8268332d1793129b 100644 (file)
@@ -16,7 +16,7 @@
 ** so is applicable.  Because this module is responsible for selecting
 ** indices, you might also think of this module as the "query optimizer".
 **
-** $Id: where.c,v 1.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"
 
@@ -191,6 +191,7 @@ static void createMask(ExprMaskSet *pMaskSet, int iCursor){
 ** 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;
@@ -198,16 +199,25 @@ static Bitmask exprTableUsage(ExprMaskSet *pMaskSet, Expr *p){
     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;
@@ -479,14 +489,20 @@ static void codeEqualityTerm(
   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);
 }
index 5ac13440310110871d41ed18e40cef40041d7548..fa363f47f2c51cbd70d8c257445204f93bdee753 100644 (file)
@@ -11,7 +11,7 @@
 # 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]
@@ -478,16 +478,16 @@ do_test bind-10.15 {
 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}
index 02fff218a96c8ca5ebf152fb2f2cc2a735292e90..7a471c0dea9659f0d44bea0e27ca7355546e24e0 100644 (file)
@@ -11,7 +11,7 @@
 # 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
@@ -131,51 +131,51 @@ do_test collate3-2.8 {
 } {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
 
 #
index b505f637c2080c95395d0749828f4b20de1ddf13..b2999ff954518bf7d561020ee5a3f15f2aa4b780 100644 (file)
@@ -11,7 +11,7 @@
 # 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
@@ -58,18 +58,21 @@ do_test insert3-1.3 {
     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 {
index 0ce75a598f843bc27c0a11d24b3fd3fb50901756..872d587a5dee087b7ff813076ed8b1d9051c3c01 100644 (file)
@@ -13,7 +13,7 @@
 # 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
@@ -119,8 +119,21 @@ ifcapable subquery {
         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.
 #
index 14e280ae5c5493e03df06c85724ac40019fc454c..acb9fb92bb9c3d7147bc8b58f948d5075982916e 100644 (file)
@@ -12,7 +12,7 @@
 # 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
@@ -157,19 +157,19 @@ do_test select6-2.9 {
   }
 } {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 {
index 0e517da4359768222cd023de8d5cb4d704bb1257..a5d9bc630da80fa8c9d7e4369946a8aa102dfb41 100644 (file)
@@ -11,7 +11,7 @@
 # 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]
@@ -59,5 +59,183 @@ do_test subquery-1.4 {
   }
 } {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
+
+
index 616b6031ab1ee065e649734ebe3433d405f855e5..9dc03ef44b939084d7cded6452589e3bd4f8e40e 100644 (file)
@@ -122,8 +122,8 @@ ifcapable subquery {
       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 {
index 6f30a943a3f6256a3bcfe5da65f1966c80ff3a8a..77f7057e63a7a3b2842aa8f650ee4b1cfd472be9 100644 (file)
@@ -11,7 +11,7 @@
 # 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
 
@@ -154,7 +154,7 @@ do_test  view-3.4 {
     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