1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Modify sub-query handling. Tickets #1083 and #1084. (CVS 2286)

FossilOrigin-Name: b1b50f315873a8614920d1e3af4a07fb29a7ff6a
This commit is contained in:
danielk1977
2005-01-29 08:32:43 +00:00
parent c9ec413a08
commit b3bce66232
27 changed files with 833 additions and 449 deletions

View File

@@ -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

View File

@@ -1 +1 @@
95ecb2745f3fc69d370fc3961800db56297acb68
b1b50f315873a8614920d1e3af4a07fb29a7ff6a

View 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

View 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);

View 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);
}

View 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,6 +752,7 @@ static int lookupName(
pNC->nRef++;
/* assert( zTab==0 || pEList==0 ); */
if( pSrcList ){
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
Table *pTab = pItem->pTab;
Column *pCol;
@@ -787,6 +790,7 @@ static int lookupName(
}
}
}
}
#ifndef SQLITE_OMIT_TRIGGER
/* If we have not already resolved the name, then maybe
@@ -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,42 +1304,21 @@ 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;
if( pExpr->pSelect ){
sqlite3VdbeAddOp(v, OP_AggContextPop, 0, 0);
}
if( label<0 ){
sqlite3VdbeResolveLabel(v, label);
}
return;
}
#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;
}
/*
** Generate an instruction that will put the integer describe by
** text z[0..n-1] on the stack.
@@ -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

View 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;
}
}

View 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;
}

View 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);
}

View 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);
}

View 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 );
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 ){
if( sqlite3ExprIsInteger(pE, &iCol) ){
if( 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 ){
}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;
}

View 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*);

View 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;

View 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);
}

View 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: {

View 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*);

View 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 */

View 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->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;

View 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);
}
if( p->pLeft ){
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->pList ){
return mask;
}
static Bitmask exprListTableUsage(ExprMaskSet *pMaskSet, ExprList *pList){
int i;
for(i=0; i<p->pList->nExpr; i++){
mask |= exprTableUsage(pMaskSet, p->pList->a[i].pExpr);
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);
}

View 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}

View 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 {
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 {
} {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 {
} {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 {
} {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 {
} {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 {
} {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 {
} {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 {
} {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 {
} {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}}
} {1 {no such collation sequence: string_compare}}
} ;# ifcapable compound
#

View 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 {
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;
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 {
} {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}
} {5 4 453 2 hello 4 xyz 1}
}
do_test insert3-2.1 {
execsql {

View 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.
#

View 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 {

View 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

View 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