aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--manifest62
-rw-r--r--manifest.uuid2
-rw-r--r--src/analyze.c4
-rw-r--r--src/attach.c12
-rw-r--r--src/build.c44
-rw-r--r--src/delete.c8
-rw-r--r--src/expr.c383
-rw-r--r--src/func.c11
-rw-r--r--src/insert.c6
-rw-r--r--src/mem2.c3
-rw-r--r--src/parse.y24
-rw-r--r--src/pragma.c9
-rw-r--r--src/prepare.c8
-rw-r--r--src/resolve.c19
-rw-r--r--src/select.c62
-rw-r--r--src/sqliteInt.h118
-rw-r--r--src/trigger.c27
-rw-r--r--src/update.c6
-rw-r--r--src/vdbe.c33
-rw-r--r--src/vdbe.h4
-rw-r--r--src/vdbeInt.h7
-rw-r--r--src/vdbeapi.c11
-rw-r--r--src/vdbeaux.c50
-rw-r--r--src/walker.c9
-rw-r--r--src/where.c65
-rw-r--r--test/default.test17
-rw-r--r--test/tester.tcl16
27 files changed, 659 insertions, 361 deletions
diff --git a/manifest b/manifest
index de12c9c22..6fea4d19d 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Make\ssure\sthe\sauto_vacuum=INCREMENTAL\ssetting\sis\spreserved\sacross\sa\sVACUUM.\nTicket\s#3663.\s(CVS\s6304)
-D 2009-02-18T20:31:18
+C Changes\sto\sreduce\sthe\sheap\sspace\sconsumed\sby\striggers,\sviews\sand\stables\sin\sthe\sin-memory\srepresentation\sof\sthe\sschema.\sAlso\sto\sreduce\sthe\sspace\sused\sby\sprepared\sstatements\sslightly.\s(CVS\s6305)
+D 2009-02-19T14:39:25
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in 1d83fa2b1fd326b9e121012bd1ff9740537e12b3
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -98,8 +98,8 @@ F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
F sqlite3.def a1be7b9a4b8b51ac41c6ff6e8e44a14ef66b338b
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
F src/alter.c f93d13aae63ea1a5ee604d76041be354311d08a5
-F src/analyze.c fc6056826fe67aa0856d4e01591be8f9266ac415
-F src/attach.c 81d37d1948f409146a7b22b96998fd90649d1fd3
+F src/analyze.c 2ca143d83ce545992cab74efeb5e8a446c61ab4b
+F src/attach.c d34589d5c85d81e755e4a8fc946d313915a6fa6d
F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
F src/backup.c 2d3f31148d7b086c5c72d9edcd04fc2751b0aa6e
F src/bitvec.c 44f7059ac1f874d364b34af31b9617e52223ba75
@@ -107,19 +107,19 @@ F src/btmutex.c 63c5cc4ad5715690767ffcb741e185d7bc35ec1a
F src/btree.c 086fdb4505aa00275d6873829aeb51bf57da8d16
F src/btree.h 4eab72af6adf95f0b08b61a72ef9781bdb0bf63f
F src/btreeInt.h 0a4884e6152d7cae9c741e91b830064c19fd2c05
-F src/build.c a394b2511c5c768f14a9d7c1c31606b9fa569f1b
+F src/build.c 0860029ca6e29b2bfcadbbe90084e02af98d768f
F src/callback.c 5f10bca853e59a2c272bbfd5b720303f8b69e520
F src/complete.c cb14e06dbe79dee031031f0d9e686ff306afe07c
F src/date.c 0d804df3bbda46329946a01ff5c75c3f4f135218
-F src/delete.c 6249005bdd8f85db6ec5f31ddb5c07de023693cc
-F src/expr.c e60f69f624a03a8f493900b071b3affbfa699585
+F src/delete.c 8d2fb05b32b5dea65277a574fedb0ebaa5dd877c
+F src/expr.c 2e62c2621c0375125cacb93ad6686bb2911b629e
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
-F src/func.c 35d6f4a98c5fd5d504fd92a9197bae3220bbac39
+F src/func.c 2fb36cd7cc24e16845db203187d1e52811b0fa9c
F src/global.c 448419c44ce0701104c2121b0e06919b44514c0c
F src/hash.c 5824e6ff7ba78cd34c8d6cd724367713583e5b55
F src/hash.h 28f38ebb1006a5beedcb013bcdfe31befe7437ae
F src/hwtime.h 4a1d45f4cae1f402ea19686acf24acf4f0cb53cb
-F src/insert.c f6db1e6f43aae337e64a755208abb6ff124edc19
+F src/insert.c 6bd2464ec48ddcb1d9c6fbfd294de91b5dd47075
F src/journal.c e00df0c0da8413ab6e1bb7d7cab5665d4a9000d0
F src/legacy.c 8b3b95d48d202614946d7ce7256e7ba898905c3b
F src/loadext.c 3f96631089fc4f3871a67f02f2e4fc7ea4d51edc
@@ -127,7 +127,7 @@ F src/main.c 4912460dab29e4d37e4ba1d78320c6a77bb95ad8
F src/malloc.c 552d993ee414ead65cafcaa636e22c84085999cb
F src/mem0.c f2f84062d1f35814d6535c9f9e33de3bfb3b132c
F src/mem1.c 3bfb39e4f60b0179713a7c087b2d4f0dc205735f
-F src/mem2.c 6f46eef2c2cce452ae38f5b98c2632712e858bc9
+F src/mem2.c 692c5b50141f49c32d85d7c0c39c751f6d520093
F src/mem3.c 67153ec933e08b70714055e872efb58a6b287939
F src/mem5.c 838309b521c96a2a34507f74a5a739d28de4aac6
F src/memjournal.c 17e9281ea5d7981e3e7b0dd3274921ecba4f773c
@@ -145,21 +145,21 @@ F src/os_unix.c 4e916cafbf5ec0166213ac62d680ebbe12b8c5a7
F src/os_win.c 45cb430884da7e9360a55a0fcd5c2c44c22dd79d
F src/pager.c d62fd62f7c0ad257019c21158b597fdbb0182529
F src/pager.h 0c9f3520c00d8a3b8e792ca56c9a11b6b02b4b0f
-F src/parse.y 4f4d16aee0d11f69fec2adb77dac88878043ed8d
+F src/parse.y 5202dc712407fd6723f6639b88b86ddf8b33aef5
F src/pcache.c fcf7738c83c4d3e9d45836b2334c8a368cc41274
F src/pcache.h 9b927ccc5a538e31b4c3bc7eec4f976db42a1324
F src/pcache1.c dabb8ab14827e090321f17150ce96fda172974e8
-F src/pragma.c 04c13c79fd559d769f5bcb3aa661b32d484b1e7b
-F src/prepare.c 9ec504ddd4a8e34e5fb502033312da6a78f5f76a
+F src/pragma.c 9ed2acb94efee8059efcc52c2e2140b43170831e
+F src/prepare.c d0bbb4b1a8b9c1db6d13788929839bb63764680e
F src/printf.c 9866a9a9c4a90f6d4147407f373df3fd5d5f9b6f
F src/random.c 676b9d7ac820fe81e6fb2394ac8c10cff7f38628
-F src/resolve.c 18dc9f0df1d60048e012ce6632251063e0dd356a
+F src/resolve.c b3aa625ec135d53a7e80c86c25ad56de46e0b415
F src/rowset.c ba9375f37053d422dd76965a9c370a13b6e1aac4
-F src/select.c 164934bd8a9fae29e4d21530688dbac53b420da6
+F src/select.c fc21f384db6207a987141859ac770d83c669c933
F src/shell.c f109ebbb50132926ebbc173a6c2d8838d5d78527
F src/sqlite.h.in 14f4d065bafed8500ea558a75a8e2be89c784d61
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
-F src/sqliteInt.h 55cc7e45a7fcc166be62b984168dd69159d877eb
+F src/sqliteInt.h 8bd8f5bb583832df68034525c1d763a35cd0365f
F src/sqliteLimit.h ffe93f5a0c4e7bd13e70cd7bf84cfb5c3465f45d
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
F src/table.c 332ab0ea691e63862e2a8bdfe2c0617ee61062a3
@@ -195,21 +195,21 @@ F src/test_tclvar.c 9e42fa59d3d2f064b7ab8628e7ab2dc8a9fe93d4
F src/test_thread.c adb9175c466e1f487295b5b957603fc0a88ea293
F src/test_wsd.c c297d7d6b8a990239e1bd25935e81d612d8ae31d
F src/tokenize.c 6987fb7f0d6a87ac53499aee568cabb05eb4bea8
-F src/trigger.c ca6d78f7c1314053800386ca64361e487774fda3
-F src/update.c 8c4925f9ca664effc8a1faaad67449d2074567b1
+F src/trigger.c 9957e16e5445478f2cc60e26ac1bc836bb18d21a
+F src/update.c 9edb83cc4322fb2dc5b7a0087cdb8fa00391f402
F src/utf.c 1da9c832dba0fa8f865b5b902d93f420a1ee4245
F src/util.c 1363f64351f3b544790f3c523439354c02f8c4e9
F src/vacuum.c 4929a585ef0fb1dfaf46302f8a9c4aa30c2d9cf5
-F src/vdbe.c 02e70c48ffd11aa470060fa03a2bfa65d72bc8df
-F src/vdbe.h 03516f28bf5aca00a53c4dccd6c313f96adb94f6
-F src/vdbeInt.h 13cb4868ea579b5a8f6b6b5098caa99cd5a14078
-F src/vdbeapi.c b23c4b1686f150a0ddc36459c8e3876be62638e1
-F src/vdbeaux.c 75c3ac2a3c37747ae66ea0935f8f48bb1879234a
+F src/vdbe.c d7b996a5b75753ade4471fbe0452a684dc047d72
+F src/vdbe.h d70a68bee196ab228914a3902c79dbd24342a0f2
+F src/vdbeInt.h 9dd984cf80ef4f2970266b05f1dbb5622ac3817b
+F src/vdbeapi.c f94fe2eb6f48687e918f0df7eed1409cff9dcf58
+F src/vdbeaux.c f636fd01adbab85675167a25cf194eddd58b13dd
F src/vdbeblob.c b0dcebfafedcf9c0addc7901ad98f6f986c08935
F src/vdbemem.c 543a79d722734d2f8b7ad70f08218c30bcc5bbf5
F src/vtab.c e39e011d7443a8d574b1b9cde207a35522e6df43
-F src/walker.c 488c2660e13224ff70c0c82761118efb547f8f0d
-F src/where.c 63bb752784b352d8e226dc6b1ec02f0d19fed916
+F src/walker.c 42bd3f00ca2ef5ae842304ec0d59903ef051412d
+F src/where.c 2284de47b03e285a142926bc8a8022983c455a76
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/alias.test 597662c5d777a122f9a3df0047ea5c5bd383a911
F test/all.test 14165b3e32715b700b5f0cbf8f6e3833dda0be45
@@ -299,7 +299,7 @@ F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
F test/createtab.test 199cf68f44e5d9e87a0b8afc7130fdeb4def3272
F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
F test/date.test bb2cc648333c04d09e8e23cfc0cddc398c334a92
-F test/default.test 252298e42a680146b1dd64f563b95bdf088d94fb
+F test/default.test 6faf23ccb300114924353007795aa9a8ec0aa9dc
F test/delete.test f171c1011395a8dd63169438fe1d8cc625eb7442
F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa
F test/delete3.test 555e84a00a99230b7d049d477a324a631126a6ab
@@ -552,7 +552,7 @@ F test/tableapi.test 505031f15b18a750184d967d2c896cf88fcc969c
F test/tclsqlite.test 413a8a887d89ea8fa7055e8d118ffb03b0a4c91a
F test/tempdb.test b88ac8a19823cf771d742bf61eef93ef337c06b1
F test/temptable.test 5d8ca46be28cc06c887c5a77df650843b7edbae1
-F test/tester.tcl b28d5eb97e95b19eacdb5afb38db2c8558f398b0
+F test/tester.tcl 66546f6766029384360b24cacb3896376c5f5f69
F test/thread001.test 06c45ed9597d478e7bbdc2a8937e1ebea2a20a32
F test/thread002.test 3c03900f03fd2fe8e2fbb1bbdef7fa8206fdb7ad
F test/thread003.test 6d360c15afe7f6ef6186801d2cb8407bccbe3aa3
@@ -701,7 +701,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
-P 419eb48b6b4238526850091eef28af503b6c4579
-R 379eb6edfb0135905a7c816f1113ae71
-U drh
-Z bfca2c680cc89c0b0c6a5ad192f03b32
+P ded04f12f41504e4a3ecd5164f0d4cbbde5e16f7
+R beea4442dc6507223c6db2a960f9f40a
+U danielk1977
+Z 5a9e5027f061557095d1ee54ae664ed7
diff --git a/manifest.uuid b/manifest.uuid
index 61fbf41b3..8536c32b9 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-ded04f12f41504e4a3ecd5164f0d4cbbde5e16f7 \ No newline at end of file
+d9f6ffbc5ea090ba0daac571fc9a6c68b9c864e4 \ No newline at end of file
diff --git a/src/analyze.c b/src/analyze.c
index 3862a29ab..71e86e14c 100644
--- a/src/analyze.c
+++ b/src/analyze.c
@@ -11,7 +11,7 @@
*************************************************************************
** This file contains code associated with the ANALYZE command.
**
-** @(#) $Id: analyze.c,v 1.48 2009/02/13 16:59:53 drh Exp $
+** @(#) $Id: analyze.c,v 1.49 2009/02/19 14:39:25 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_ANALYZE
#include "sqliteInt.h"
@@ -117,7 +117,7 @@ static void analyzeOneTable(
/* Establish a read-lock on the table at the shared-cache level. */
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
- iIdxCur = pParse->nTab;
+ iIdxCur = pParse->nTab++;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
int regFields; /* Register block for building records */
diff --git a/src/attach.c b/src/attach.c
index bf2683fb3..c3fd7ff8f 100644
--- a/src/attach.c
+++ b/src/attach.c
@@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to implement the ATTACH and DETACH commands.
**
-** $Id: attach.c,v 1.82 2009/02/03 16:51:25 danielk1977 Exp $
+** $Id: attach.c,v 1.83 2009/02/19 14:39:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -488,11 +488,11 @@ int sqlite3FixExpr(
Expr *pExpr /* The expression to be fixed to one database */
){
while( pExpr ){
- if( sqlite3FixSelect(pFix, pExpr->pSelect) ){
- return 1;
- }
- if( sqlite3FixExprList(pFix, pExpr->pList) ){
- return 1;
+ if( ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_SpanOnly) ) break;
+ if( ExprHasProperty(pExpr, EP_xIsSelect) ){
+ if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;
+ }else{
+ if( sqlite3FixExprList(pFix, pExpr->x.pList) ) return 1;
}
if( sqlite3FixExpr(pFix, pExpr->pRight) ){
return 1;
diff --git a/src/build.c b/src/build.c
index 851071356..c58911d17 100644
--- a/src/build.c
+++ b/src/build.c
@@ -22,7 +22,7 @@
** COMMIT
** ROLLBACK
**
-** $Id: build.c,v 1.518 2009/02/13 03:43:32 drh Exp $
+** $Id: build.c,v 1.519 2009/02/19 14:39:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -178,19 +178,6 @@ void sqlite3FinishCoding(Parse *pParse){
codeTableLocks(pParse);
sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->cookieGoto);
}
-
-#ifndef SQLITE_OMIT_TRACE
- if( !db->init.busy ){
- /* Change the P4 argument of the first opcode (which will always be
- ** an OP_Trace) to be the complete text of the current SQL statement.
- */
- VdbeOp *pOp = sqlite3VdbeGetOp(v, 0);
- if( pOp && pOp->opcode==OP_Trace ){
- sqlite3VdbeChangeP4(v, 0, pParse->zSql,
- (int)(pParse->zTail - pParse->zSql));
- }
- }
-#endif /* SQLITE_OMIT_TRACE */
}
@@ -202,8 +189,8 @@ void sqlite3FinishCoding(Parse *pParse){
sqlite3VdbeTrace(v, trace);
#endif
assert( pParse->disableColCache==0 ); /* Disables and re-enables match */
- sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem+3,
- pParse->nTab+3, pParse->explain);
+ sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem,
+ pParse->nTab, pParse->explain);
pParse->rc = SQLITE_DONE;
pParse->colNamesSet = 0;
}else if( pParse->rc==SQLITE_OK ){
@@ -618,6 +605,9 @@ void sqlite3OpenMasterTable(Parse *p, int iDb){
sqlite3TableLock(p, iDb, MASTER_ROOT, 1, SCHEMA_TABLE(iDb));
sqlite3VdbeAddOp2(v, OP_SetNumColumns, 0, 5);/* sqlite_master has 5 columns */
sqlite3VdbeAddOp3(v, OP_OpenWrite, 0, MASTER_ROOT, iDb);
+ if( p->nTab==0 ){
+ p->nTab = 1;
+ }
}
/*
@@ -1116,12 +1106,12 @@ void sqlite3AddDefaultValue(Parse *pParse, Expr *pExpr){
sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
pCol->zName);
}else{
- Expr *pCopy;
+ /* A copy of pExpr is used instead of the original, as pExpr contains
+ ** tokens that point to volatile memory. The 'span' of the expression
+ ** is required by pragma table_info.
+ */
sqlite3ExprDelete(db, pCol->pDflt);
- pCol->pDflt = pCopy = sqlite3ExprDup(db, pExpr);
- if( pCopy ){
- sqlite3TokenCopy(db, &pCopy->span, &pExpr->span);
- }
+ pCol->pDflt = sqlite3ExprDup(db, pExpr, EXPRDUP_REDUCE|EXPRDUP_SPAN);
}
}
sqlite3ExprDelete(db, pExpr);
@@ -1217,7 +1207,7 @@ void sqlite3AddCheckConstraint(
** to malloced space and not the (ephemeral) text of the CREATE TABLE
** statement */
pTab->pCheck = sqlite3ExprAnd(db, pTab->pCheck,
- sqlite3ExprDup(db, pCheckExpr));
+ sqlite3ExprDup(db, pCheckExpr, 0));
}
#endif
sqlite3ExprDelete(db, pCheckExpr);
@@ -1540,7 +1530,7 @@ void sqlite3EndTable(
SelectDest dest;
Table *pSelTab;
- assert(pParse->nTab==0);
+ assert(pParse->nTab==1);
sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb);
sqlite3VdbeChangeP5(v, 1);
pParse->nTab = 2;
@@ -1701,7 +1691,7 @@ void sqlite3CreateView(
** allocated rather than point to the input string - which means that
** they will persist after the current sqlite3_exec() call returns.
*/
- p->pSelect = sqlite3SelectDup(db, pSelect);
+ p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
sqlite3SelectDelete(db, pSelect);
if( db->mallocFailed ){
return;
@@ -1783,7 +1773,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
** statement that defines the view.
*/
assert( pTable->pSelect );
- pSel = sqlite3SelectDup(db, pTable->pSelect);
+ pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
if( pSel ){
n = pParse->nTab;
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
@@ -2277,8 +2267,8 @@ void sqlite3DeferForeignKey(Parse *pParse, int isDeferred){
*/
static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
Table *pTab = pIndex->pTable; /* The table that is indexed */
- int iTab = pParse->nTab; /* Btree cursor used for pTab */
- int iIdx = pParse->nTab+1; /* Btree cursor used for pIndex */
+ int iTab = pParse->nTab++; /* Btree cursor used for pTab */
+ int iIdx = pParse->nTab++; /* Btree cursor used for pIndex */
int addr1; /* Address of top of loop */
int tnum; /* Root page of index */
Vdbe *v; /* Generate code into this virtual machine */
diff --git a/src/delete.c b/src/delete.c
index eb683f59b..abc2ea07b 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -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.191 2008/12/23 23:56:22 drh Exp $
+** $Id: delete.c,v 1.192 2009/02/19 14:39:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -99,12 +99,12 @@ void sqlite3MaterializeView(
Select *pDup;
sqlite3 *db = pParse->db;
- pDup = sqlite3SelectDup(db, pView->pSelect);
+ pDup = sqlite3SelectDup(db, pView->pSelect, 0);
if( pWhere ){
SrcList *pFrom;
Token viewName;
- pWhere = sqlite3ExprDup(db, pWhere);
+ pWhere = sqlite3ExprDup(db, pWhere, 0);
viewName.z = (u8*)pView->zName;
viewName.n = (unsigned int)sqlite3Strlen30((const char*)viewName.z);
pFrom = sqlite3SrcListAppendFromTerm(pParse, 0, 0, 0, &viewName, pDup, 0,0);
@@ -174,7 +174,7 @@ Expr *sqlite3LimitWhere(
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
** and the SELECT subtree. */
- pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc);
+ pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0);
if( pSelectSrc == 0 ) {
sqlite3ExprListDelete(pParse->db, pEList);
goto limit_where_cleanup_2;
diff --git a/src/expr.c b/src/expr.c
index 8960a7ad9..ef7c54d28 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -12,7 +12,7 @@
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
-** $Id: expr.c,v 1.411 2009/02/04 03:59:25 shane Exp $
+** $Id: expr.c,v 1.412 2009/02/19 14:39:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -35,7 +35,8 @@
char sqlite3ExprAffinity(Expr *pExpr){
int op = pExpr->op;
if( op==TK_SELECT ){
- return sqlite3ExprAffinity(pExpr->pSelect->pEList->a[0].pExpr);
+ assert( pExpr->flags&EP_xIsSelect );
+ return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
}
#ifndef SQLITE_OMIT_CAST
if( op==TK_CAST ){
@@ -155,11 +156,9 @@ static char comparisonAffinity(Expr *pExpr){
aff = sqlite3ExprAffinity(pExpr->pLeft);
if( pExpr->pRight ){
aff = sqlite3CompareAffinity(pExpr->pRight, aff);
- }
- else if( pExpr->pSelect ){
- aff = sqlite3CompareAffinity(pExpr->pSelect->pEList->a[0].pExpr, aff);
- }
- else if( !aff ){
+ }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
+ aff = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr, aff);
+ }else if( !aff ){
aff = SQLITE_AFF_NONE;
}
return aff;
@@ -345,8 +344,11 @@ static void exprSetHeight(Expr *p){
int nHeight = 0;
heightOfExpr(p->pLeft, &nHeight);
heightOfExpr(p->pRight, &nHeight);
- heightOfExprList(p->pList, &nHeight);
- heightOfSelect(p->pSelect, &nHeight);
+ if( ExprHasProperty(p, EP_xIsSelect) ){
+ heightOfSelect(p->x.pSelect, &nHeight);
+ }else{
+ heightOfExprList(p->x.pList, &nHeight);
+ }
p->nHeight = nHeight + 1;
}
@@ -510,7 +512,8 @@ Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *pToken){
return 0;
}
pNew->op = TK_FUNCTION;
- pNew->pList = pList;
+ pNew->x.pList = pList;
+ assert( !ExprHasProperty(pNew, EP_xIsSelect) );
assert( pToken->dyn==0 );
pNew->token = *pToken;
pNew->span = pNew->token;
@@ -607,12 +610,22 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
** Substructure is deleted.
*/
void sqlite3ExprClear(sqlite3 *db, Expr *p){
- if( p->span.dyn ) sqlite3DbFree(db, (char*)p->span.z);
if( p->token.dyn ) sqlite3DbFree(db, (char*)p->token.z);
- sqlite3ExprDelete(db, p->pLeft);
- sqlite3ExprDelete(db, p->pRight);
- sqlite3ExprListDelete(db, p->pList);
- sqlite3SelectDelete(db, p->pSelect);
+ if( !ExprHasAnyProperty(p, EP_TokenOnly|EP_SpanOnly) ){
+ if( p->span.dyn ) sqlite3DbFree(db, (char*)p->span.z);
+ if( ExprHasProperty(p, EP_Reduced) ){
+ if( p->pLeft ) sqlite3ExprClear(db, p->pLeft);
+ if( p->pRight ) sqlite3ExprClear(db, p->pRight);
+ }else{
+ sqlite3ExprDelete(db, p->pLeft);
+ sqlite3ExprDelete(db, p->pRight);
+ }
+ if( ExprHasProperty(p, EP_xIsSelect) ){
+ sqlite3SelectDelete(db, p->x.pSelect);
+ }else{
+ sqlite3ExprListDelete(db, p->x.pList);
+ }
+ }
}
/*
@@ -633,13 +646,191 @@ void sqlite3DequoteExpr(sqlite3 *db, Expr *p){
return;
}
ExprSetProperty(p, EP_Dequoted);
- if( p->token.dyn==0 ){
+ if( p->token.dyn==0 && !ExprHasProperty(p, EP_Reduced) ){
sqlite3TokenCopy(db, &p->token, &p->token);
}
sqlite3Dequote((char*)p->token.z);
}
/*
+** Return the number of bytes allocated for the expression structure
+** passed as the first argument. This is always one of EXPR_FULLSIZE,
+** EXPR_REDUCEDSIZE or EXPR_TOKENONLYSIZE.
+*/
+static int exprStructSize(Expr *p){
+ if( ExprHasProperty(p, EP_TokenOnly) ) return EXPR_TOKENONLYSIZE;
+ if( ExprHasProperty(p, EP_SpanOnly) ) return EXPR_SPANONLYSIZE;
+ if( ExprHasProperty(p, EP_Reduced) ) return EXPR_REDUCEDSIZE;
+ return EXPR_FULLSIZE;
+}
+
+/*
+** sqlite3ExprDup() has been called to create a copy of expression p with
+** the EXPRDUP_XXX flags passed as the second argument. This function
+** returns the space required for the copy of the Expr structure only.
+** This is always one of EXPR_FULLSIZE, EXPR_REDUCEDSIZE or EXPR_TOKENONLYSIZE.
+*/
+static int dupedExprStructSize(Expr *p, int flags){
+ int nSize;
+ if( 0==(flags&EXPRDUP_REDUCE) ){
+ nSize = EXPR_FULLSIZE;
+ }else if( p->pLeft || p->pRight || p->pColl || p->x.pList ){
+ nSize = EXPR_REDUCEDSIZE;
+ }else if( flags&EXPRDUP_SPAN ){
+ nSize = EXPR_SPANONLYSIZE;
+ }else{
+ nSize = EXPR_TOKENONLYSIZE;
+ }
+ return nSize;
+}
+
+/*
+** sqlite3ExprDup() has been called to create a copy of expression p with
+** the EXPRDUP_XXX passed as the second argument. This function returns
+** the space in bytes required to store the copy of the Expr structure
+** and the copies of the Expr.token.z and Expr.span.z (if applicable)
+** string buffers.
+*/
+static int dupedExprNodeSize(Expr *p, int flags){
+ int nByte = dupedExprStructSize(p, flags) + (p->token.z ? p->token.n + 1 : 0);
+ if( flags&EXPRDUP_SPAN && (p->token.z!=p->span.z || p->token.n!=p->span.n) ){
+ nByte += p->span.n;
+ }
+ return (nByte+7)&~7;
+}
+
+/*
+** Return the number of bytes required to create a duplicate of the
+** expression passed as the first argument. The second argument is a
+** mask containing EXPRDUP_XXX flags.
+**
+** The value returned includes space to create a copy of the Expr struct
+** itself and the buffer referred to by Expr.token, if any. If the
+** EXPRDUP_SPAN flag is set, then space to create a copy of the buffer
+** refered to by Expr.span is also included.
+**
+** If the EXPRDUP_REDUCE flag is set, then the return value includes
+** space to duplicate all Expr nodes in the tree formed by Expr.pLeft
+** and Expr.pRight variables (but not for any structures pointed to or
+** descended from the Expr.x.pList or Expr.x.pSelect variables).
+*/
+static int dupedExprSize(Expr *p, int flags){
+ int nByte = 0;
+ if( p ){
+ nByte = dupedExprNodeSize(p, flags);
+ if( flags&EXPRDUP_REDUCE ){
+ int f = flags&(~EXPRDUP_SPAN);
+ nByte += dupedExprSize(p->pLeft, f) + dupedExprSize(p->pRight, f);
+ }
+ }
+ return nByte;
+}
+
+/*
+** This function is similar to sqlite3ExprDup(), except that if pzBuffer
+** is not NULL then *pzBuffer is assumed to point to a buffer large enough
+** to store the copy of expression p, the copies of p->token and p->span
+** (if applicable), and the copies of the p->pLeft and p->pRight expressions,
+** if any. Before returning, *pzBuffer is set to the first byte passed the
+** portion of the buffer copied into by this function.
+*/
+static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
+ Expr *pNew = 0; /* Value to return */
+ if( p ){
+ const int isRequireSpan = (flags&EXPRDUP_SPAN);
+ const int isReduced = (flags&EXPRDUP_REDUCE);
+ u8 *zAlloc;
+
+ assert( pzBuffer==0 || isReduced );
+
+ /* Figure out where to write the new Expr structure. */
+ if( pzBuffer ){
+ zAlloc = *pzBuffer;
+ }else{
+ zAlloc = sqlite3DbMallocRaw(db, dupedExprSize(p, flags));
+ }
+ pNew = (Expr *)zAlloc;
+
+ if( pNew ){
+ /* Set nNewSize to the size allocated for the structure pointed to
+ ** by pNew. This is either EXPR_FULLSIZE, EXPR_REDUCEDSIZE or
+ ** EXPR_TOKENONLYSIZE. nToken is set to the number of bytes consumed
+ ** by the copy of the p->token.z string (if any).
+ */
+ const int nNewSize = dupedExprStructSize(p, flags);
+ const int nToken = (p->token.z ? p->token.n + 1 : 0);
+ if( isReduced ){
+ assert( ExprHasProperty(p, EP_Reduced)==0 );
+ memcpy(zAlloc, p, nNewSize);
+ }else{
+ int nSize = exprStructSize(p);
+ memcpy(zAlloc, p, nSize);
+ memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
+ }
+
+ /* Set the EP_Reduced and EP_TokenOnly flags appropriately. */
+ pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_SpanOnly);
+ switch( nNewSize ){
+ case EXPR_REDUCEDSIZE: pNew->flags |= EP_Reduced; break;
+ case EXPR_TOKENONLYSIZE: pNew->flags |= EP_TokenOnly; break;
+ case EXPR_SPANONLYSIZE: pNew->flags |= EP_SpanOnly; break;
+ }
+
+ /* Copy the p->token string, if any. */
+ if( nToken ){
+ unsigned char *zToken = &zAlloc[nNewSize];
+ memcpy(zToken, p->token.z, nToken-1);
+ zToken[nToken-1] = '\0';
+ pNew->token.dyn = 0;
+ pNew->token.z = zToken;
+ }
+
+ if( 0==((p->flags|pNew->flags) & EP_TokenOnly) ){
+ /* Fill in the pNew->span token, if required. */
+ if( isRequireSpan ){
+ if( p->token.z!=p->span.z || p->token.n!=p->span.n ){
+ pNew->span.z = &zAlloc[nNewSize+nToken];
+ memcpy((char *)pNew->span.z, p->span.z, p->span.n);
+ pNew->span.dyn = 0;
+ }else{
+ pNew->span.z = pNew->token.z;
+ pNew->span.n = pNew->token.n;
+ }
+ }else{
+ pNew->span.z = 0;
+ pNew->span.n = 0;
+ }
+ }
+
+ if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_SpanOnly)) ){
+ /* Fill in the pNew->x.pSelect or pNew->x.pList member. */
+ if( ExprHasProperty(p, EP_xIsSelect) ){
+ pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, isReduced);
+ }else{
+ pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, isReduced);
+ }
+ }
+
+ /* Fill in pNew->pLeft and pNew->pRight. */
+ if( ExprHasAnyProperty(pNew, EP_Reduced|EP_TokenOnly|EP_SpanOnly) ){
+ zAlloc += dupedExprNodeSize(p, flags);
+ if( ExprHasProperty(pNew, EP_Reduced) ){
+ pNew->pLeft = exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc);
+ pNew->pRight = exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc);
+ }
+ if( pzBuffer ){
+ *pzBuffer = zAlloc;
+ }
+ }else if( !ExprHasAnyProperty(p, EP_TokenOnly|EP_SpanOnly) ){
+ pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0);
+ pNew->pRight = sqlite3ExprDup(db, p->pRight, 0);
+ }
+ }
+ }
+ return pNew;
+}
+
+/*
** The following group of routines make deep copies of expressions,
** expression lists, ID lists, and select statements. The copies can
** be deleted (by being passed to their respective ...Delete() routines)
@@ -650,25 +841,19 @@ void sqlite3DequoteExpr(sqlite3 *db, Expr *p){
** by subsequent calls to sqlite*ListAppend() routines.
**
** Any tables that the SrcList might point to are not duplicated.
+**
+** The flags parameter contains a combination of the EXPRDUP_XXX flags. If
+** the EXPRDUP_SPAN flag is set in the argument parameter, then the
+** Expr.span field of the input expression is copied. If EXPRDUP_SPAN is
+** clear, then the Expr.span field of the returned expression structure
+** is zeroed.
+**
+** If the EXPRDUP_REDUCE flag is set, then the structure returned is a
+** truncated version of the usual Expr structure that will be stored as
+** part of the in-memory representation of the database schema.
*/
-Expr *sqlite3ExprDup(sqlite3 *db, Expr *p){
- Expr *pNew;
- if( p==0 ) return 0;
- pNew = sqlite3DbMallocRaw(db, sizeof(*p) );
- if( pNew==0 ) return 0;
- memcpy(pNew, p, sizeof(*pNew));
- if( p->token.z!=0 ){
- pNew->token.z = (u8*)sqlite3DbStrNDup(db, (char*)p->token.z, p->token.n);
- pNew->token.dyn = 1;
- }else{
- assert( pNew->token.z==0 );
- }
- pNew->span.z = 0;
- pNew->pLeft = sqlite3ExprDup(db, p->pLeft);
- pNew->pRight = sqlite3ExprDup(db, p->pRight);
- pNew->pList = sqlite3ExprListDup(db, p->pList);
- pNew->pSelect = sqlite3SelectDup(db, p->pSelect);
- return pNew;
+Expr *sqlite3ExprDup(sqlite3 *db, Expr *p, int flags){
+ return exprDup(db, p, flags, 0);
}
void sqlite3TokenCopy(sqlite3 *db, Token *pTo, Token *pFrom){
if( pTo->dyn ) sqlite3DbFree(db, (char*)pTo->z);
@@ -680,7 +865,7 @@ void sqlite3TokenCopy(sqlite3 *db, Token *pTo, Token *pFrom){
pTo->z = 0;
}
}
-ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p){
+ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
ExprList *pNew;
struct ExprList_item *pItem, *pOldItem;
int i;
@@ -696,17 +881,9 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p){
}
pOldItem = p->a;
for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){
- Expr *pNewExpr, *pOldExpr;
- pItem->pExpr = pNewExpr = sqlite3ExprDup(db, pOldExpr = pOldItem->pExpr);
- if( pOldExpr->span.z!=0 && pNewExpr ){
- /* Always make a copy of the span for top-level expressions in the
- ** expression list. The logic in SELECT processing that determines
- ** the names of columns in the result set needs this information */
- sqlite3TokenCopy(db, &pNewExpr->span, &pOldExpr->span);
- }
- assert( pNewExpr==0 || pNewExpr->span.z!=0
- || pOldExpr->span.z==0
- || db->mallocFailed );
+ Expr *pNewExpr;
+ Expr *pOldExpr = pOldItem->pExpr;
+ pItem->pExpr = pNewExpr = sqlite3ExprDup(db, pOldExpr, flags);
pItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
pItem->sortOrder = pOldItem->sortOrder;
pItem->done = 0;
@@ -724,7 +901,7 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p){
*/
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) \
|| !defined(SQLITE_OMIT_SUBQUERY)
-SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p){
+SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
SrcList *pNew;
int i;
int nByte;
@@ -750,8 +927,8 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p){
if( pTab ){
pTab->nRef++;
}
- pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect);
- pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn);
+ pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags);
+ pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn, flags);
pNewItem->pUsing = sqlite3IdListDup(db, pOldItem->pUsing);
pNewItem->colUsed = pOldItem->colUsed;
}
@@ -777,21 +954,24 @@ IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
}
return pNew;
}
-Select *sqlite3SelectDup(sqlite3 *db, Select *p){
+Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
Select *pNew;
if( p==0 ) return 0;
pNew = sqlite3DbMallocRaw(db, sizeof(*p) );
if( pNew==0 ) return 0;
- pNew->pEList = sqlite3ExprListDup(db, p->pEList);
- pNew->pSrc = sqlite3SrcListDup(db, p->pSrc);
- pNew->pWhere = sqlite3ExprDup(db, p->pWhere);
- pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy);
- pNew->pHaving = sqlite3ExprDup(db, p->pHaving);
- pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy);
+ /* Always make a copy of the span for top-level expressions in the
+ ** expression list. The logic in SELECT processing that determines
+ ** the names of columns in the result set needs this information */
+ pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags|EXPRDUP_SPAN);
+ pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags);
+ pNew->pWhere = sqlite3ExprDup(db, p->pWhere, flags);
+ pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy, flags);
+ pNew->pHaving = sqlite3ExprDup(db, p->pHaving, flags);
+ pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, flags);
pNew->op = p->op;
- pNew->pPrior = sqlite3SelectDup(db, p->pPrior);
- pNew->pLimit = sqlite3ExprDup(db, p->pLimit);
- pNew->pOffset = sqlite3ExprDup(db, p->pOffset);
+ pNew->pPrior = sqlite3SelectDup(db, p->pPrior, flags);
+ pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags);
+ pNew->pOffset = sqlite3ExprDup(db, p->pOffset, flags);
pNew->iLimit = 0;
pNew->iOffset = 0;
pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
@@ -802,7 +982,7 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *p){
return pNew;
}
#else
-Select *sqlite3SelectDup(sqlite3 *db, Select *p){
+Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
assert( p==0 );
return 0;
}
@@ -1143,7 +1323,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
** If this is the case, it may be possible to use an existing table
** or index instead of generating an epheremal table.
*/
- p = pX->pSelect;
+ p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
if( isCandidateForInOpt(p) ){
sqlite3 *db = pParse->db;
Index *pIdx;
@@ -1222,7 +1402,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
eType = IN_INDEX_EPH;
if( prNotFound ){
*prNotFound = rMayHaveNull = ++pParse->nMem;
- }else if( pX->pLeft->iColumn<0 && pX->pSelect==0 ){
+ }else if( pX->pLeft->iColumn<0 && !ExprHasAnyProperty(pX, EP_xIsSelect) ){
eType = IN_INDEX_ROWID;
}
sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID);
@@ -1311,7 +1491,7 @@ void sqlite3CodeSubselect(
memset(&keyInfo, 0, sizeof(keyInfo));
keyInfo.nField = 1;
- if( pExpr->pSelect ){
+ if( ExprHasProperty(pExpr, EP_xIsSelect) ){
/* Case 1: expr IN (SELECT ...)
**
** Generate code to write the results of the select into the temporary
@@ -1324,15 +1504,15 @@ void sqlite3CodeSubselect(
sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
dest.affinity = (u8)affinity;
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
- if( sqlite3Select(pParse, pExpr->pSelect, &dest) ){
+ if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){
return;
}
- pEList = pExpr->pSelect->pEList;
+ pEList = pExpr->x.pSelect->pEList;
if( pEList && pEList->nExpr>0 ){
keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
pEList->a[0].pExpr);
}
- }else if( pExpr->pList ){
+ }else if( pExpr->x.pList ){
/* Case 2: expr IN (exprlist)
**
** For each expression, build an index key from the evaluation and
@@ -1341,7 +1521,7 @@ void sqlite3CodeSubselect(
** a column, use numeric affinity.
*/
int i;
- ExprList *pList = pExpr->pList;
+ ExprList *pList = pExpr->x.pList;
struct ExprList_item *pItem;
int r1, r2, r3;
@@ -1401,7 +1581,8 @@ void sqlite3CodeSubselect(
Select *pSel;
SelectDest dest;
- pSel = pExpr->pSelect;
+ assert( ExprHasProperty(pExpr, EP_xIsSelect) );
+ pSel = pExpr->x.pSelect;
sqlite3SelectDestInit(&dest, 0, ++pParse->nMem);
if( pExpr->op==TK_SELECT ){
dest.eDest = SRT_Mem;
@@ -1985,7 +2166,9 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
}
case TK_CONST_FUNC:
case TK_FUNCTION: {
- ExprList *pList = pExpr->pList;
+ ExprList *pList = (
+ ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_SpanOnly) ? 0 : pExpr->x.pList
+ );
int nExpr = pList ? pList->nExpr : 0;
FuncDef *pDef;
int nId;
@@ -1995,6 +2178,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
u8 enc = ENC(db);
CollSeq *pColl = 0;
+ assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
testcase( op==TK_CONST_FUNC );
testcase( op==TK_FUNCTION );
zId = (char*)pExpr->token.z;
@@ -2162,7 +2346,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
*/
case TK_BETWEEN: {
Expr *pLeft = pExpr->pLeft;
- struct ExprList_item *pLItem = pExpr->pList->a;
+ struct ExprList_item *pLItem = pExpr->x.pList->a;
Expr *pRight = pLItem->pExpr;
codeCompareOperands(pParse, pLeft, &r1, &regFree1,
@@ -2222,10 +2406,10 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
Expr *pX; /* The X expression */
Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */
- assert(pExpr->pList);
- assert((pExpr->pList->nExpr % 2) == 0);
- assert(pExpr->pList->nExpr > 0);
- pEList = pExpr->pList;
+ assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList );
+ assert((pExpr->x.pList->nExpr % 2) == 0);
+ assert(pExpr->x.pList->nExpr > 0);
+ pEList = pExpr->x.pList;
aListelem = pEList->a;
nExpr = pEList->nExpr;
endLabel = sqlite3VdbeMakeLabel(v);
@@ -2273,15 +2457,15 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
"RAISE() may only be used within a trigger-program");
return 0;
}
- if( pExpr->iColumn!=OE_Ignore ){
- assert( pExpr->iColumn==OE_Rollback ||
- pExpr->iColumn == OE_Abort ||
- pExpr->iColumn == OE_Fail );
+ if( pExpr->affinity!=OE_Ignore ){
+ assert( pExpr->affinity==OE_Rollback ||
+ pExpr->affinity == OE_Abort ||
+ pExpr->affinity == OE_Fail );
sqlite3DequoteExpr(db, pExpr);
- sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->iColumn, 0,
+ sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->affinity, 0,
(char*)pExpr->token.z, pExpr->token.n);
} else {
- assert( pExpr->iColumn == OE_Ignore );
+ assert( pExpr->affinity == OE_Ignore );
sqlite3VdbeAddOp2(v, OP_ContextPop, 0, 0);
sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->trigStack->ignoreJump);
VdbeComment((v, "raise(IGNORE)"));
@@ -2438,7 +2622,8 @@ static int evalConstExpr(Walker *pWalker, Expr *pExpr){
** Mark them this way to avoid generated unneeded OP_SCopy
** instructions.
*/
- ExprList *pList = pExpr->pList;
+ ExprList *pList = pExpr->x.pList;
+ assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
if( pList ){
int i = pList->nExpr;
struct ExprList_item *pItem = pList->a;
@@ -2614,16 +2799,17 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
Expr compRight;
Expr exprX;
+ assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
exprX = *pExpr->pLeft;
exprAnd.op = TK_AND;
exprAnd.pLeft = &compLeft;
exprAnd.pRight = &compRight;
compLeft.op = TK_GE;
compLeft.pLeft = &exprX;
- compLeft.pRight = pExpr->pList->a[0].pExpr;
+ compLeft.pRight = pExpr->x.pList->a[0].pExpr;
compRight.op = TK_LE;
compRight.pLeft = &exprX;
- compRight.pRight = pExpr->pList->a[1].pExpr;
+ compRight.pRight = pExpr->x.pList->a[1].pExpr;
exprX.iTable = sqlite3ExprCodeTemp(pParse, &exprX, &regFree1);
testcase( regFree1==0 );
exprX.op = TK_REGISTER;
@@ -2765,16 +2951,17 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
Expr compRight;
Expr exprX;
+ assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
exprX = *pExpr->pLeft;
exprAnd.op = TK_AND;
exprAnd.pLeft = &compLeft;
exprAnd.pRight = &compRight;
compLeft.op = TK_GE;
compLeft.pLeft = &exprX;
- compLeft.pRight = pExpr->pList->a[0].pExpr;
+ compLeft.pRight = pExpr->x.pList->a[0].pExpr;
compRight.op = TK_LE;
compRight.pLeft = &exprX;
- compRight.pRight = pExpr->pList->a[1].pExpr;
+ compRight.pRight = pExpr->x.pList->a[1].pExpr;
exprX.iTable = sqlite3ExprCodeTemp(pParse, &exprX, &regFree1);
testcase( regFree1==0 );
exprX.op = TK_REGISTER;
@@ -2813,22 +3000,25 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
if( pA==0||pB==0 ){
return pB==pA;
}
- if( pA->op!=pB->op ) return 0;
+ if( ExprHasProperty(pA, EP_xIsSelect) || ExprHasProperty(pB, EP_xIsSelect) ){
+ return 0;
+ }
if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 0;
+ if( pA->op!=pB->op ) return 0;
if( !sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 0;
if( !sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 0;
- if( pA->pList ){
- if( pB->pList==0 ) return 0;
- if( pA->pList->nExpr!=pB->pList->nExpr ) return 0;
- for(i=0; i<pA->pList->nExpr; i++){
- if( !sqlite3ExprCompare(pA->pList->a[i].pExpr, pB->pList->a[i].pExpr) ){
- return 0;
- }
+
+ if( pA->x.pList && pB->x.pList ){
+ if( pA->x.pList->nExpr!=pB->x.pList->nExpr ) return 0;
+ for(i=0; i<pA->x.pList->nExpr; i++){
+ Expr *pExprA = pA->x.pList->a[i].pExpr;
+ Expr *pExprB = pB->x.pList->a[i].pExpr;
+ if( !sqlite3ExprCompare(pExprA, pExprB) ) return 0;
}
- }else if( pB->pList ){
+ }else if( pA->x.pList || pB->x.pList ){
return 0;
}
- if( pA->pSelect || pB->pSelect ) return 0;
+
if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 0;
if( pA->op!=TK_COLUMN && pA->token.z ){
if( pB->token.z==0 ) return 0;
@@ -2976,12 +3166,13 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
u8 enc = ENC(pParse->db);
i = addAggInfoFunc(pParse->db, pAggInfo);
if( i>=0 ){
+ assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
pItem = &pAggInfo->aFunc[i];
pItem->pExpr = pExpr;
pItem->iMem = ++pParse->nMem;
pItem->pFunc = sqlite3FindFunction(pParse->db,
(char*)pExpr->token.z, pExpr->token.n,
- pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0);
+ pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0);
if( pExpr->flags & EP_Distinct ){
pItem->iDistinct = pParse->nTab++;
}else{
diff --git a/src/func.c b/src/func.c
index 07671ff6b..3deffc003 100644
--- a/src/func.c
+++ b/src/func.c
@@ -16,7 +16,7 @@
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
-** $Id: func.c,v 1.222 2009/02/04 03:59:25 shane Exp $
+** $Id: func.c,v 1.223 2009/02/19 14:39:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
@@ -1323,12 +1323,13 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
*/
int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
FuncDef *pDef;
- if( pExpr->op!=TK_FUNCTION || !pExpr->pList ){
- return 0;
- }
- if( pExpr->pList->nExpr!=2 ){
+ if( pExpr->op!=TK_FUNCTION
+ || !pExpr->x.pList
+ || pExpr->x.pList->nExpr!=2
+ ){
return 0;
}
+ assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
pDef = sqlite3FindFunction(db, (char*)pExpr->token.z, pExpr->token.n, 2,
SQLITE_UTF8, 0);
if( pDef==0 || (pDef->flags & SQLITE_FUNC_LIKE)==0 ){
diff --git a/src/insert.c b/src/insert.c
index 0ab647e12..faeb6b03e 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -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.256 2008/12/10 21:19:57 drh Exp $
+** $Id: insert.c,v 1.257 2009/02/19 14:39:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -168,7 +168,7 @@ static int autoIncBegin(
if( pTab->tabFlags & TF_Autoincrement ){
Vdbe *v = pParse->pVdbe;
Db *pDb = &pParse->db->aDb[iDb];
- int iCur = pParse->nTab;
+ int iCur = pParse->nTab++;
int addr; /* Address of the top of the loop */
assert( v );
pParse->nMem++; /* Holds name of table */
@@ -217,7 +217,7 @@ static void autoIncEnd(
int memId /* Memory cell holding the maximum rowid */
){
if( pTab->tabFlags & TF_Autoincrement ){
- int iCur = pParse->nTab;
+ int iCur = pParse->nTab++;
Vdbe *v = pParse->pVdbe;
Db *pDb = &pParse->db->aDb[iDb];
int j1;
diff --git a/src/mem2.c b/src/mem2.c
index 156237fcc..436683659 100644
--- a/src/mem2.c
+++ b/src/mem2.c
@@ -19,7 +19,7 @@
** This file contains implementations of the low-level memory allocation
** routines specified in the sqlite3_mem_methods object.
**
-** $Id: mem2.c,v 1.43 2009/02/05 03:00:06 shane Exp $
+** $Id: mem2.c,v 1.44 2009/02/19 14:39:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -248,6 +248,7 @@ static void *sqlite3MemMalloc(int nByte){
void *aAddr[40];
pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1;
memcpy(pBt, &aAddr[1], pHdr->nBacktrace*sizeof(void*));
+ assert(pBt[0]);
if( mem.xBacktrace ){
mem.xBacktrace(nByte, pHdr->nBacktrace-1, &aAddr[1]);
}
diff --git a/src/parse.y b/src/parse.y
index 4b5c3124c..491c8da09 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -14,7 +14,7 @@
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
-** @(#) $Id: parse.y,v 1.268 2009/01/29 19:27:47 drh Exp $
+** @(#) $Id: parse.y,v 1.269 2009/02/19 14:39:25 danielk1977 Exp $
*/
// All token codes are small integers with #defines that begin with "TK_"
@@ -824,7 +824,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
pList = sqlite3ExprListAppend(pParse,pList, Y, 0);
A = sqlite3PExpr(pParse, TK_BETWEEN, W, 0, 0);
if( A ){
- A->pList = pList;
+ A->x.pList = pList;
}else{
sqlite3ExprListDelete(pParse->db, pList);
}
@@ -838,7 +838,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
expr(A) ::= expr(X) in_op(N) LP exprlist(Y) RP(E). [IN] {
A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
if( A ){
- A->pList = Y;
+ A->x.pList = Y;
sqlite3ExprSetHeight(pParse, A);
}else{
sqlite3ExprListDelete(pParse->db, Y);
@@ -849,7 +849,8 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
expr(A) ::= LP(B) select(X) RP(E). {
A = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
if( A ){
- A->pSelect = X;
+ A->x.pSelect = X;
+ ExprSetProperty(A, EP_xIsSelect);
sqlite3ExprSetHeight(pParse, A);
}else{
sqlite3SelectDelete(pParse->db, X);
@@ -859,7 +860,8 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
expr(A) ::= expr(X) in_op(N) LP select(Y) RP(E). [IN] {
A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
if( A ){
- A->pSelect = Y;
+ A->x.pSelect = Y;
+ ExprSetProperty(A, EP_xIsSelect);
sqlite3ExprSetHeight(pParse, A);
}else{
sqlite3SelectDelete(pParse->db, Y);
@@ -871,7 +873,8 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&Y,&Z);
A = sqlite3PExpr(pParse, TK_IN, X, 0, 0);
if( A ){
- A->pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
+ A->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
+ ExprSetProperty(A, EP_xIsSelect);
sqlite3ExprSetHeight(pParse, A);
}else{
sqlite3SrcListDelete(pParse->db, pSrc);
@@ -882,7 +885,8 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
expr(A) ::= EXISTS(B) LP select(Y) RP(E). {
Expr *p = A = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
if( p ){
- p->pSelect = Y;
+ p->x.pSelect = Y;
+ ExprSetProperty(A, EP_xIsSelect);
sqlite3ExprSpan(p,&B,&E);
sqlite3ExprSetHeight(pParse, A);
}else{
@@ -895,7 +899,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
A = sqlite3PExpr(pParse, TK_CASE, X, Z, 0);
if( A ){
- A->pList = Y;
+ A->x.pList = Y;
sqlite3ExprSetHeight(pParse, A);
}else{
sqlite3ExprListDelete(pParse->db, Y);
@@ -1100,14 +1104,14 @@ trigger_cmd(A) ::= select(X). {A = sqlite3TriggerSelectStep(pParse->db, X); }
expr(A) ::= RAISE(X) LP IGNORE RP(Y). {
A = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0);
if( A ){
- A->iColumn = OE_Ignore;
+ A->affinity = OE_Ignore;
sqlite3ExprSpan(A, &X, &Y);
}
}
expr(A) ::= RAISE(X) LP raisetype(T) COMMA nm(Z) RP(Y). {
A = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &Z);
if( A ) {
- A->iColumn = T;
+ A->affinity = T;
sqlite3ExprSpan(A, &X, &Y);
}
}
diff --git a/src/pragma.c b/src/pragma.c
index ad35d5420..8497e69e2 100644
--- a/src/pragma.c
+++ b/src/pragma.c
@@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to implement the PRAGMA command.
**
-** $Id: pragma.c,v 1.202 2009/01/20 16:53:41 danielk1977 Exp $
+** $Id: pragma.c,v 1.203 2009/02/19 14:39:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -831,7 +831,6 @@ void sqlite3Pragma(
sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "pk", SQLITE_STATIC);
sqlite3ViewGetColumnNames(pParse, pTab);
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
- const Token *pDflt;
if( IsHiddenColumn(pCol) ){
nHidden++;
continue;
@@ -842,9 +841,9 @@ void sqlite3Pragma(
pCol->zType ? pCol->zType : "", 0);
sqlite3VdbeAddOp2(v, OP_Integer, (pCol->notNull ? 1 : 0), 4);
if( pCol->pDflt ){
- pDflt = &pCol->pDflt->span;
- assert( pDflt->z );
- sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pDflt->z, pDflt->n);
+ const Token *p = &pCol->pDflt->span;
+ assert( p->z );
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)p->z, p->n);
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
}
diff --git a/src/prepare.c b/src/prepare.c
index a4448d9ad..e2dbaf52f 100644
--- a/src/prepare.c
+++ b/src/prepare.c
@@ -13,7 +13,7 @@
** interface, and routines that contribute to loading the database schema
** from disk.
**
-** $Id: prepare.c,v 1.105 2009/01/20 16:53:41 danielk1977 Exp $
+** $Id: prepare.c,v 1.106 2009/02/19 14:39:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -621,8 +621,10 @@ static int sqlite3Prepare(
rc = SQLITE_MISUSE;
}
- if( saveSqlFlag ){
- sqlite3VdbeSetSql(sParse.pVdbe, zSql, (int)(sParse.zTail - zSql));
+ assert( db->init.busy==0 || saveSqlFlag==0 );
+ if( db->init.busy==0 ){
+ Vdbe *pVdbe = sParse.pVdbe;
+ sqlite3VdbeSetSql(pVdbe, zSql, (int)(sParse.zTail-zSql), saveSqlFlag);
}
if( rc!=SQLITE_OK || db->mallocFailed ){
sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
diff --git a/src/resolve.c b/src/resolve.c
index d6f58fc70..af44730ef 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -14,7 +14,7 @@
** resolve all identifiers by associating them with a particular
** table and column.
**
-** $Id: resolve.c,v 1.15 2008/12/10 19:26:24 drh Exp $
+** $Id: resolve.c,v 1.16 2009/02/19 14:39:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
@@ -63,7 +63,7 @@ static void resolveAlias(
assert( pOrig!=0 );
assert( pOrig->flags & EP_Resolved );
db = pParse->db;
- pDup = sqlite3ExprDup(db, pOrig);
+ pDup = sqlite3ExprDup(db, pOrig, 0);
if( pDup==0 ) return;
if( pDup->op!=TK_COLUMN && zType[0]!='G' ){
pDup = sqlite3PExpr(pParse, TK_AS, pDup, 0, 0);
@@ -282,8 +282,8 @@ static int lookupName(
if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
Expr *pOrig;
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
- assert( pExpr->pList==0 );
- assert( pExpr->pSelect==0 );
+ assert( pExpr->x.pList==0 );
+ assert( pExpr->x.pSelect==0 );
pOrig = pEList->a[j].pExpr;
if( !pNC->allowAgg && ExprHasProperty(pOrig, EP_Agg) ){
sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs);
@@ -474,8 +474,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
*/
case TK_CONST_FUNC:
case TK_FUNCTION: {
- ExprList *pList = pExpr->pList; /* The argument list */
- int n = pList ? pList->nExpr : 0; /* Number of arguments */
+ ExprList *pList = pExpr->x.pList; /* The argument list */
+ int n = pList ? pList->nExpr : 0; /* Number of arguments */
int no_such_func = 0; /* True if no such function exists */
int wrong_num_args = 0; /* True if wrong number of arguments */
int is_agg = 0; /* True if is an aggregate function */
@@ -485,6 +485,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
FuncDef *pDef; /* Information about the function */
u8 enc = ENC(pParse->db); /* The database encoding */
+ assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
zId = (char*)pExpr->token.z;
nId = pExpr->token.n;
pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
@@ -541,14 +542,14 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
case TK_EXISTS:
#endif
case TK_IN: {
- if( pExpr->pSelect ){
+ if( ExprHasProperty(pExpr, EP_xIsSelect) ){
int nRef = pNC->nRef;
#ifndef SQLITE_OMIT_CHECK
if( pNC->isCheck ){
sqlite3ErrorMsg(pParse,"subqueries prohibited in CHECK constraints");
}
#endif
- sqlite3WalkSelect(pWalker, pExpr->pSelect);
+ sqlite3WalkSelect(pWalker, pExpr->x.pSelect);
assert( pNC->nRef>=nRef );
if( nRef!=pNC->nRef ){
ExprSetProperty(pExpr, EP_VarSelect);
@@ -736,7 +737,7 @@ static int resolveCompoundOrderBy(
}else{
iCol = resolveAsName(pParse, pEList, pE);
if( iCol==0 ){
- pDup = sqlite3ExprDup(db, pE);
+ pDup = sqlite3ExprDup(db, pE, 0);
if( !db->mallocFailed ){
assert(pDup);
iCol = resolveOrderByTermToExprList(pParse, pSelect, pDup);
diff --git a/src/select.c b/src/select.c
index 943f0ef4e..286805e49 100644
--- a/src/select.c
+++ b/src/select.c
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
-** $Id: select.c,v 1.499 2009/02/09 13:19:28 drh Exp $
+** $Id: select.c,v 1.500 2009/02/19 14:39:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -987,8 +987,9 @@ static const char *columnType(
** statement.
*/
NameContext sNC;
- Select *pS = pExpr->pSelect;
+ Select *pS = pExpr->x.pSelect;
Expr *p = pS->pEList->a[0].pExpr;
+ assert( ExprHasProperty(pExpr, EP_xIsSelect) );
sNC.pSrcList = pS->pSrc;
sNC.pNext = pNC;
sNC.pParse = pNC->pParse;
@@ -2141,7 +2142,7 @@ static int multiSelectOrderBy(
/* Reattach the ORDER BY clause to the query.
*/
p->pOrderBy = pOrderBy;
- pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, pOrderBy);
+ pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, pOrderBy, 0);
/* Allocate a range of temporary registers and the KeyInfo needed
** for the logic that removes duplicate result rows when the
@@ -2392,23 +2393,26 @@ static void substExpr(
}else{
Expr *pNew;
assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
- assert( pExpr->pLeft==0 && pExpr->pRight==0 && pExpr->pList==0 );
+ assert( pExpr->pLeft==0 && pExpr->pRight==0 );
pNew = pEList->a[pExpr->iColumn].pExpr;
assert( pNew!=0 );
pExpr->op = pNew->op;
assert( pExpr->pLeft==0 );
- pExpr->pLeft = sqlite3ExprDup(db, pNew->pLeft);
+ pExpr->pLeft = sqlite3ExprDup(db, pNew->pLeft, 0);
assert( pExpr->pRight==0 );
- pExpr->pRight = sqlite3ExprDup(db, pNew->pRight);
- assert( pExpr->pList==0 );
- pExpr->pList = sqlite3ExprListDup(db, pNew->pList);
+ pExpr->pRight = sqlite3ExprDup(db, pNew->pRight, 0);
pExpr->iTable = pNew->iTable;
pExpr->pTab = pNew->pTab;
pExpr->iColumn = pNew->iColumn;
pExpr->iAgg = pNew->iAgg;
sqlite3TokenCopy(db, &pExpr->token, &pNew->token);
sqlite3TokenCopy(db, &pExpr->span, &pNew->span);
- pExpr->pSelect = sqlite3SelectDup(db, pNew->pSelect);
+ assert( pExpr->x.pList==0 && pExpr->x.pSelect==0 );
+ if( ExprHasProperty(pNew, EP_xIsSelect) ){
+ pExpr->x.pSelect = sqlite3SelectDup(db, pNew->x.pSelect, 0);
+ }else{
+ pExpr->x.pList = sqlite3ExprListDup(db, pNew->x.pList, 0);
+ }
pExpr->flags = pNew->flags;
pExpr->pAggInfo = pNew->pAggInfo;
pNew->pAggInfo = 0;
@@ -2416,8 +2420,11 @@ static void substExpr(
}else{
substExpr(db, pExpr->pLeft, iTable, pEList);
substExpr(db, pExpr->pRight, iTable, pEList);
- substSelect(db, pExpr->pSelect, iTable, pEList);
- substExprList(db, pExpr->pList, iTable, pEList);
+ if( ExprHasProperty(pExpr, EP_xIsSelect) ){
+ substSelect(db, pExpr->x.pSelect, iTable, pEList);
+ }else{
+ substExprList(db, pExpr->x.pList, iTable, pEList);
+ }
}
}
static void substExprList(
@@ -2729,7 +2736,7 @@ static int flattenSubquery(
p->pSrc = 0;
p->pPrior = 0;
p->pLimit = 0;
- pNew = sqlite3SelectDup(db, p);
+ pNew = sqlite3SelectDup(db, p, 0);
p->pLimit = pLimit;
p->pOrderBy = pOrderBy;
p->pSrc = pSrc;
@@ -2873,7 +2880,7 @@ static int flattenSubquery(
substExprList(db, pParent->pOrderBy, iParent, pSub->pEList);
}
if( pSub->pWhere ){
- pWhere = sqlite3ExprDup(db, pSub->pWhere);
+ pWhere = sqlite3ExprDup(db, pSub->pWhere, 0);
}else{
pWhere = 0;
}
@@ -2883,9 +2890,9 @@ static int flattenSubquery(
pParent->pWhere = pWhere;
substExpr(db, pParent->pHaving, iParent, pSub->pEList);
pParent->pHaving = sqlite3ExprAnd(db, pParent->pHaving,
- sqlite3ExprDup(db, pSub->pHaving));
+ sqlite3ExprDup(db, pSub->pHaving, 0));
assert( pParent->pGroupBy==0 );
- pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy);
+ pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0);
}else{
substExpr(db, pParent->pWhere, iParent, pSub->pEList);
pParent->pWhere = sqlite3ExprAnd(db, pParent->pWhere, pWhere);
@@ -2934,7 +2941,8 @@ static u8 minMaxQuery(Select *p){
if( pEList->nExpr!=1 ) return WHERE_ORDERBY_NORMAL;
pExpr = pEList->a[0].pExpr;
- pEList = pExpr->pList;
+ if( ExprHasProperty(pExpr, EP_xIsSelect) ) return 0;
+ pEList = pExpr->x.pList;
if( pExpr->op!=TK_AGG_FUNCTION || pEList==0 || pEList->nExpr!=1 ) return 0;
if( pEList->a[0].pExpr->op!=TK_AGG_COLUMN ) return WHERE_ORDERBY_NORMAL;
if( pExpr->token.n!=3 ) return WHERE_ORDERBY_NORMAL;
@@ -3065,7 +3073,7 @@ static int selectExpander(Walker *pWalker, Select *p){
** in the inner view.
*/
if( pFrom->pSelect==0 ){
- pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect);
+ pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
sqlite3WalkSelect(pWalker, pFrom->pSelect);
}
}
@@ -3364,12 +3372,13 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
sqlite3VdbeAddOp2(v, OP_Null, 0, pFunc->iMem);
if( pFunc->iDistinct>=0 ){
Expr *pE = pFunc->pExpr;
- if( pE->pList==0 || pE->pList->nExpr!=1 ){
+ assert( !ExprHasProperty(pE, EP_xIsSelect) );
+ if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
"argument");
pFunc->iDistinct = -1;
}else{
- KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->pList);
+ KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList);
sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0,
(char*)pKeyInfo, P4_KEYINFO_HANDOFF);
}
@@ -3386,7 +3395,8 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
int i;
struct AggInfo_func *pF;
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
- ExprList *pList = pF->pExpr->pList;
+ ExprList *pList = pF->pExpr->x.pList;
+ assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
sqlite3VdbeAddOp4(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0, 0,
(void*)pF->pFunc, P4_FUNCDEF);
}
@@ -3407,7 +3417,8 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
int nArg;
int addrNext = 0;
int regAgg;
- ExprList *pList = pF->pExpr->pList;
+ ExprList *pList = pF->pExpr->x.pList;
+ assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
if( pList ){
nArg = pList->nExpr;
regAgg = sqlite3GetTempRange(pParse, nArg);
@@ -3657,7 +3668,7 @@ int sqlite3Select(
** GROUP BY might use an index, DISTINCT never does.
*/
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct && !p->pGroupBy ){
- p->pGroupBy = sqlite3ExprListDup(db, p->pEList);
+ p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
pGroupBy = p->pGroupBy;
p->selFlags &= ~SF_Distinct;
isDistinct = 0;
@@ -3780,7 +3791,8 @@ int sqlite3Select(
}
sAggInfo.nAccumulator = sAggInfo.nColumn;
for(i=0; i<sAggInfo.nFunc; i++){
- sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->pList);
+ assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) );
+ sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList);
}
if( db->mallocFailed ) goto select_end;
@@ -4018,7 +4030,9 @@ int sqlite3Select(
*/
flag = minMaxQuery(p);
if( flag ){
- pDel = pMinMax = sqlite3ExprListDup(db, p->pEList->a[0].pExpr->pList);
+ assert( !ExprHasProperty(p->pEList->a[0].pExpr, EP_xIsSelect) );
+ pMinMax = sqlite3ExprListDup(db, p->pEList->a[0].pExpr->x.pList,0);
+ pDel = pMinMax;
if( pMinMax && !db->mallocFailed ){
pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0;
pMinMax->a[0].pExpr->op = TK_COLUMN;
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 9d400fef4..440771f92 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.833 2009/02/05 16:53:43 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.834 2009/02/19 14:39:25 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@@ -1363,19 +1363,27 @@ struct AggInfo {
** Each node of an expression in the parse tree is an instance
** of this structure.
**
-** Expr.op is the opcode. The integer parser token codes are reused
-** as opcodes here. For example, the parser defines TK_GE to be an integer
-** code representing the ">=" operator. This same integer code is reused
+** Expr.op is the opcode. The integer parser token codes are reused
+** as opcodes here. For example, the parser defines TK_GE to be an integer
+** code representing the ">=" operator. This same integer code is reused
** to represent the greater-than-or-equal-to operator in the expression
** tree.
**
-** Expr.pRight and Expr.pLeft are subexpressions. Expr.pList is a list
-** of argument if the expression is a function.
+** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB,
+** or TK_STRING), then Expr.token contains the text of the SQL literal. If
+** the expression is a variable (TK_VARIABLE), then Expr.token contains the
+** variable name. Finally, if the expression is an SQL function (TK_FUNCTION),
+** then Expr.token contains the name of the function.
**
-** Expr.token is the operator token for this node. For some expressions
-** that have subexpressions, Expr.token can be the complete text that gave
-** rise to the Expr. In the latter case, the token is marked as being
-** a compound token.
+** Expr.pRight and Expr.pLeft are the left and right subexpressions of a
+** binary operator. Either or both may be NULL.
+**
+** Expr.x.pList is a list of arguments if the expression is an SQL function,
+** a CASE expression or an IN expression of the form "<lhs> IN (<y>, <z>...)".
+** Expr.x.pSelect is used if the expression is a sub-select or an expression of
+** the form "<lhs> IN (SELECT ...)". If the EP_xIsSelect bit is set in the
+** Expr.flags mask, then Expr.x.pSelect is valid. Otherwise, Expr.x.pList is
+** valid.
**
** An expression of the form ID or ID.ID refers to a column in a table.
** For such expressions, Expr.op is set to TK_COLUMN and Expr.iTable is
@@ -1385,10 +1393,9 @@ struct AggInfo {
** value is also stored in the Expr.iAgg column in the aggregate so that
** it can be accessed after all aggregates are computed.
**
-** If the expression is a function, the Expr.iTable is an integer code
-** representing which function. If the expression is an unbound variable
-** marker (a question mark character '?' in the original SQL) then the
-** Expr.iTable holds the index number for that variable.
+** If the expression is an unbound variable marker (a question mark
+** character '?' in the original SQL) then the Expr.iTable holds the index
+** number for that variable.
**
** If the expression is a subquery then Expr.iColumn holds an integer
** register number containing the result of the subquery. If the
@@ -1396,32 +1403,62 @@ struct AggInfo {
** gives a different answer at different times during statement processing
** then iTable is the address of a subroutine that computes the subquery.
**
-** The Expr.pSelect field points to a SELECT statement. The SELECT might
-** be the right operand of an IN operator. Or, if a scalar SELECT appears
-** in an expression the opcode is TK_SELECT and Expr.pSelect is the only
-** operand.
-**
** If the Expr is of type OP_Column, and the table it is selecting from
** is a disk table or the "old.*" pseudo-table, then pTab points to the
** corresponding table definition.
+**
+** ALLOCATION NOTES:
+**
+** Expr structures may be stored as part of the in-memory database schema,
+** for example as part of trigger, view or table definitions. In this case,
+** the amount of memory consumed by complex expressions may be significant.
+** For this reason, less than sizeof(Expr) bytes may be allocated for some
+** Expr structs stored as part of the in-memory database schema.
+**
+** If the EP_Reduced flag is set in Expr.flags, then only EXPR_REDUCEDSIZE
+** bytes of space are allocated for the expression structure. This is enough
+** space to store all fields up to and including the "Token span;" field.
+**
+** If the EP_TokenOnly flag is set in Expr.flags, then only EXPR_TOKENONLYSIZE
+** bytes of space are allocated for the expression structure. This is enough
+** space to store all fields up to and including the "Token token;" field.
*/
struct Expr {
u8 op; /* Operation performed by this node */
char affinity; /* The affinity of the column or 0 if not a column */
u16 flags; /* Various flags. See below */
- CollSeq *pColl; /* The collation type of the column or 0 */
- Expr *pLeft, *pRight; /* Left and right subnodes */
- ExprList *pList; /* A list of expressions used as function arguments
- ** or in "<expr> IN (<expr-list)" */
Token token; /* An operand token */
+
+ /* If the EP_TokenOnly flag is set in the Expr.flags mask, then no
+ ** space is allocated for the fields below this point. An attempt to
+ ** access them will result in a segfault or malfunction.
+ *********************************************************************/
+
Token span; /* Complete text of the expression */
+
+ /* If the EP_SpanOnly flag is set in the Expr.flags mask, then no
+ ** space is allocated for the fields below this point. An attempt to
+ ** access them will result in a segfault or malfunction.
+ *********************************************************************/
+
+ Expr *pLeft; /* Left subnode */
+ Expr *pRight; /* Right subnode */
+ union {
+ ExprList *pList; /* Function arguments or in "<expr> IN (<expr-list)" */
+ Select *pSelect; /* Used for sub-selects and "<expr> IN (<select>)" */
+ } x;
+ CollSeq *pColl; /* The collation type of the column or 0 */
+
+ /* If the EP_Reduced flag is set in the Expr.flags mask, then no
+ ** space is allocated for the fields below this point. An attempt to
+ ** access them will result in a segfault or malfunction.
+ *********************************************************************/
+
int iTable, iColumn; /* When op==TK_COLUMN, then this expr node means the
** iColumn-th field of the iTable-th table. */
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
int iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
int iRightJoinTable; /* If EP_FromJoin, the right table of the join */
- Select *pSelect; /* When the expression is a sub-select. Also the
- ** right side of "<expr> IN (<select>)" */
Table *pTab; /* Table for TK_COLUMN expressions. */
#if SQLITE_MAX_EXPR_DEPTH>0
int nHeight; /* Height of the tree headed by this node */
@@ -1443,6 +1480,12 @@ struct Expr {
#define EP_AnyAff 0x0200 /* Can take a cached column of any affinity */
#define EP_FixedDest 0x0400 /* Result needed in a specific register */
#define EP_IntValue 0x0800 /* Integer value contained in iTable */
+#define EP_xIsSelect 0x1000 /* x.pSelect is valid (otherwise x.pList is) */
+
+#define EP_Reduced 0x2000 /* Expr struct is EXPR_REDUCEDSIZE bytes only */
+#define EP_TokenOnly 0x4000 /* Expr struct is EXPR_TOKENONLYSIZE bytes only */
+#define EP_SpanOnly 0x8000 /* Expr struct is EXPR_SPANONLYSIZE bytes only */
+
/*
** These macros can be used to test, set, or clear bits in the
** Expr.flags field.
@@ -1453,6 +1496,23 @@ struct Expr {
#define ExprClearProperty(E,P) (E)->flags&=~(P)
/*
+** Macros to determine the number of bytes required by a normal Expr
+** struct, an Expr struct with the EP_Reduced flag set in Expr.flags
+** and an Expr struct with the EP_TokenOnly flag set.
+*/
+#define EXPR_FULLSIZE sizeof(Expr)
+#define EXPR_REDUCEDSIZE ((int)(&((Expr*)(0))->iTable))
+#define EXPR_TOKENONLYSIZE ((int)(&((Expr*)(0))->span))
+#define EXPR_SPANONLYSIZE ((int)(&((Expr*)(0))->pLeft))
+
+/*
+** Flags passed to the sqlite3ExprDup() function. See the header comment
+** above sqlite3ExprDup() for details.
+*/
+#define EXPRDUP_REDUCE 0x0001
+#define EXPRDUP_SPAN 0x0002
+
+/*
** A list of expressions. Each expression may optionally have a
** name. An expr/name combination can be used in several ways, such
** as the list of "expr AS ID" fields following a "SELECT" or in the
@@ -2379,12 +2439,12 @@ void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int,
void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*, int, int, int);
int sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
void sqlite3BeginWriteOperation(Parse*, int, int);
-Expr *sqlite3ExprDup(sqlite3*,Expr*);
+Expr *sqlite3ExprDup(sqlite3*,Expr*,int);
void sqlite3TokenCopy(sqlite3*,Token*, Token*);
-ExprList *sqlite3ExprListDup(sqlite3*,ExprList*);
-SrcList *sqlite3SrcListDup(sqlite3*,SrcList*);
+ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int);
+SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
IdList *sqlite3IdListDup(sqlite3*,IdList*);
-Select *sqlite3SelectDup(sqlite3*,Select*);
+Select *sqlite3SelectDup(sqlite3*,Select*,int);
void sqlite3FuncDefInsert(FuncDefHash*, FuncDef*);
FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,int);
void sqlite3RegisterBuiltinFunctions(sqlite3*);
diff --git a/src/trigger.c b/src/trigger.c
index 6563b1462..98f8d835d 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -10,7 +10,7 @@
*************************************************************************
**
**
-** $Id: trigger.c,v 1.133 2008/12/26 07:56:39 danielk1977 Exp $
+** $Id: trigger.c,v 1.134 2009/02/19 14:39:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -182,7 +182,7 @@ void sqlite3BeginTrigger(
pTrigger->pTabSchema = pTab->pSchema;
pTrigger->op = (u8)op;
pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
- pTrigger->pWhen = sqlite3ExprDup(db, pWhen);
+ pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
pTrigger->pColumns = sqlite3IdListDup(db, pColumns);
sqlite3TokenCopy(db, &pTrigger->nameToken,pName);
assert( pParse->pNewTrigger==0 );
@@ -292,17 +292,17 @@ static void sqlitePersistTriggerStep(sqlite3 *db, TriggerStep *p){
p->target.dyn = 1;
}
if( p->pSelect ){
- Select *pNew = sqlite3SelectDup(db, p->pSelect);
+ Select *pNew = sqlite3SelectDup(db, p->pSelect, 1);
sqlite3SelectDelete(db, p->pSelect);
p->pSelect = pNew;
}
if( p->pWhere ){
- Expr *pNew = sqlite3ExprDup(db, p->pWhere);
+ Expr *pNew = sqlite3ExprDup(db, p->pWhere, EXPRDUP_REDUCE);
sqlite3ExprDelete(db, p->pWhere);
p->pWhere = pNew;
}
if( p->pExprList ){
- ExprList *pNew = sqlite3ExprListDup(db, p->pExprList);
+ ExprList *pNew = sqlite3ExprListDup(db, p->pExprList, 1);
sqlite3ExprListDelete(db, p->pExprList);
p->pExprList = pNew;
}
@@ -546,6 +546,9 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddOp2(v, OP_Close, 0, 0);
sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->name, 0);
+ if( pParse->nMem<3 ){
+ pParse->nMem = 3;
+ }
}
}
@@ -677,7 +680,7 @@ static int codeTriggerProgram(
pParse->trigStack->orconf = orconf;
switch( pTriggerStep->op ){
case TK_SELECT: {
- Select *ss = sqlite3SelectDup(db, pTriggerStep->pSelect);
+ Select *ss = sqlite3SelectDup(db, pTriggerStep->pSelect, 0);
if( ss ){
SelectDest dest;
@@ -692,8 +695,8 @@ static int codeTriggerProgram(
pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
sqlite3Update(pParse, pSrc,
- sqlite3ExprListDup(db, pTriggerStep->pExprList),
- sqlite3ExprDup(db, pTriggerStep->pWhere), orconf);
+ sqlite3ExprListDup(db, pTriggerStep->pExprList, 0),
+ sqlite3ExprDup(db, pTriggerStep->pWhere, 0), orconf);
sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
break;
}
@@ -702,8 +705,8 @@ static int codeTriggerProgram(
pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
sqlite3Insert(pParse, pSrc,
- sqlite3ExprListDup(db, pTriggerStep->pExprList),
- sqlite3SelectDup(db, pTriggerStep->pSelect),
+ sqlite3ExprListDup(db, pTriggerStep->pExprList, 0),
+ sqlite3SelectDup(db, pTriggerStep->pSelect, 0),
sqlite3IdListDup(db, pTriggerStep->pIdList), orconf);
sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
break;
@@ -713,7 +716,7 @@ static int codeTriggerProgram(
sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
pSrc = targetSrcList(pParse, pTriggerStep);
sqlite3DeleteFrom(pParse, pSrc,
- sqlite3ExprDup(db, pTriggerStep->pWhere));
+ sqlite3ExprDup(db, pTriggerStep->pWhere, 0));
sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
break;
}
@@ -830,7 +833,7 @@ int sqlite3CodeRowTrigger(
/* code the WHEN clause */
endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe);
- whenExpr = sqlite3ExprDup(db, p->pWhen);
+ whenExpr = sqlite3ExprDup(db, p->pWhen, 0);
if( db->mallocFailed || sqlite3ResolveExprNames(&sNC, whenExpr) ){
pParse->trigStack = trigStackEntry.pNext;
sqlite3ExprDelete(db, whenExpr);
diff --git a/src/update.c b/src/update.c
index cd1fd218f..dc4a48d4f 100644
--- a/src/update.c
+++ b/src/update.c
@@ -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.191 2008/12/23 23:56:22 drh Exp $
+** $Id: update.c,v 1.192 2009/02/19 14:39:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -633,12 +633,12 @@ static void updateVirtualTable(
sqlite3CreateIdExpr(pParse, "_rowid_"), 0);
if( pRowid ){
pEList = sqlite3ExprListAppend(pParse, pEList,
- sqlite3ExprDup(db, pRowid), 0);
+ sqlite3ExprDup(db, pRowid, 0), 0);
}
assert( pTab->iPKey<0 );
for(i=0; i<pTab->nCol; i++){
if( aXRef[i]>=0 ){
- pExpr = sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr);
+ pExpr = sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr, 0);
}else{
pExpr = sqlite3CreateIdExpr(pParse, pTab->aCol[i].zName);
}
diff --git a/src/vdbe.c b/src/vdbe.c
index 0b9ad1981..0fec59a4c 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -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.817 2009/02/16 17:55:47 shane Exp $
+** $Id: vdbe.c,v 1.818 2009/02/19 14:39:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
@@ -1002,15 +1002,14 @@ case OP_Move: {
int n = pOp->p3;
int p1 = pOp->p1;
int p2 = pOp->p2;
- assert( n>0 );
- assert( p1>0 );
- assert( p1+n<p->nMem );
+ assert( n>0 && p1>0 && p2>0 );
+ assert( p1+n<=p2 || p2+n<=p1 );
+
pIn1 = &p->aMem[p1];
- assert( p2>0 );
- assert( p2+n<p->nMem );
pOut = &p->aMem[p2];
- assert( p1+n<=p2 || p2+n<=p1 );
while( n-- ){
+ assert( pOut<=&p->aMem[p->nMem] );
+ assert( pIn1<=&p->aMem[p->nMem] );
zMalloc = pOut->zMalloc;
pOut->zMalloc = 0;
sqlite3VdbeMemMove(pOut, pIn1);
@@ -1076,7 +1075,7 @@ case OP_ResultRow: {
int i;
assert( p->nResColumn==pOp->p2 );
assert( pOp->p1>0 );
- assert( pOp->p1+pOp->p2<=p->nMem );
+ assert( pOp->p1+pOp->p2<=p->nMem+1 );
/* Invalidate all ephemeral cursor row caches */
p->cacheCtr = (p->cacheCtr + 2)|1;
@@ -1095,7 +1094,6 @@ case OP_ResultRow: {
/* Return SQLITE_ROW
*/
- p->nCallback++;
p->pc = pc + 1;
rc = SQLITE_ROW;
goto vdbe_return;
@@ -1300,7 +1298,7 @@ case OP_Function: {
apVal = p->apArg;
assert( apVal || n==0 );
- assert( n==0 || (pOp->p2>0 && pOp->p2+n<=p->nMem) );
+ assert( n==0 || (pOp->p2>0 && pOp->p2+n<=p->nMem+1) );
assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
pArg = &p->aMem[pOp->p2];
for(i=0; i<n; i++, pArg++){
@@ -1736,9 +1734,9 @@ case OP_Compare: {
assert( n>0 );
assert( pKeyInfo!=0 );
p1 = pOp->p1;
- assert( p1>0 && p1+n-1<p->nMem );
+ assert( p1>0 && p1+n<=p->nMem+1 );
p2 = pOp->p2;
- assert( p2>0 && p2+n-1<p->nMem );
+ assert( p2>0 && p2+n<=p->nMem+1 );
for(i=0; i<n; i++){
int idx = aPermute ? aPermute[i] : i;
CollSeq *pColl; /* Collating sequence to use on this term */
@@ -2253,7 +2251,7 @@ case OP_MakeRecord: {
nField = pOp->p1;
zAffinity = pOp->p4.z;
- assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=p->nMem );
+ assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=p->nMem+1 );
pData0 = &p->aMem[nField];
nField = pOp->p2;
pLast = &pData0[nField-1];
@@ -4066,7 +4064,7 @@ case OP_IdxDelete: {
VdbeCursor *pC;
BtCursor *pCrsr;
assert( pOp->p3>0 );
- assert( pOp->p2>0 && pOp->p2+pOp->p3<=p->nMem );
+ assert( pOp->p2>0 && pOp->p2+pOp->p3<=p->nMem+1 );
assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 );
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
@@ -5204,13 +5202,14 @@ case OP_Pagecount: { /* out2-prerelease */
** the UTF-8 string contained in P4 is emitted on the trace callback.
*/
case OP_Trace: {
- if( pOp->p4.z ){
+ char *zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
+ if( zTrace ){
if( db->xTrace ){
- db->xTrace(db->pTraceArg, pOp->p4.z);
+ db->xTrace(db->pTraceArg, zTrace);
}
#ifdef SQLITE_DEBUG
if( (db->flags & SQLITE_SqlTrace)!=0 ){
- sqlite3DebugPrintf("SQL-trace: %s\n", pOp->p4.z);
+ sqlite3DebugPrintf("SQL-trace: %s\n", zTrace);
}
#endif /* SQLITE_DEBUG */
}
diff --git a/src/vdbe.h b/src/vdbe.h
index 312e38939..e8aad3862 100644
--- a/src/vdbe.h
+++ b/src/vdbe.h
@@ -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.139 2008/10/31 10:53:23 danielk1977 Exp $
+** $Id: vdbe.h,v 1.140 2009/02/19 14:39:25 danielk1977 Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
@@ -181,7 +181,7 @@ void sqlite3VdbeSetNumCols(Vdbe*,int);
int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*));
void sqlite3VdbeCountChanges(Vdbe*);
sqlite3 *sqlite3VdbeDb(Vdbe*);
-void sqlite3VdbeSetSql(Vdbe*, const char *z, int n);
+void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, int);
void sqlite3VdbeSwap(Vdbe*,Vdbe*);
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index 8ff7939fc..c34ce2562 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -15,7 +15,7 @@
** 6000 lines long) it was split up into several smaller files and
** this header information was factored out.
**
-** $Id: vdbeInt.h,v 1.162 2009/02/03 15:39:01 drh Exp $
+** $Id: vdbeInt.h,v 1.163 2009/02/19 14:39:25 danielk1977 Exp $
*/
#ifndef _VDBEINT_H_
#define _VDBEINT_H_
@@ -279,16 +279,13 @@ struct Vdbe {
u32 magic; /* Magic number for sanity checking */
int nMem; /* Number of memory locations currently allocated */
Mem *aMem; /* The memory locations */
- int nCallback; /* Number of callbacks invoked so far */
int cacheCtr; /* VdbeCursor row cache generation counter */
int contextStackTop; /* Index of top element in the context stack */
int contextStackDepth; /* The size of the "context" stack */
Context *contextStack; /* Stack used by opcodes ContextPush & ContextPop*/
int pc; /* The program counter */
int rc; /* Value to return */
- unsigned uniqueCnt; /* Used by OP_MakeRecord when P2!=0 */
int errorAction; /* Recovery action to do in case of an error */
- int inTempTrans; /* True if temp database is transactioned */
int nResColumn; /* Number of columns in one row of the result set */
char **azResColumn; /* Values for one row of result */
char *zErrMsg; /* Error message written here */
@@ -300,12 +297,12 @@ struct Vdbe {
u8 inVtabMethod; /* See comments above */
u8 usesStmtJournal; /* True if uses a statement journal */
u8 readOnly; /* True for read-only statements */
+ u8 isPrepareV2; /* True if prepared with prepare_v2() */
int nChange; /* Number of db changes made since last reset */
i64 startTime; /* Time when query started - used for profiling */
int btreeMask; /* Bitmask of db->aDb[] entries referenced */
BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
int aCounter[2]; /* Counters used by sqlite3_stmt_status() */
- int nSql; /* Number of bytes in zSql */
char *zSql; /* Text of the SQL statement that generated this */
#ifdef SQLITE_DEBUG
FILE *trace; /* Write an execution trace here, if not NULL */
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index d3274b540..e5a327a79 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -13,7 +13,7 @@
** This file contains code use to implement APIs that are part of the
** VDBE.
**
-** $Id: vdbeapi.c,v 1.151 2009/02/04 03:59:25 shane Exp $
+** $Id: vdbeapi.c,v 1.152 2009/02/19 14:39:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
@@ -488,15 +488,14 @@ static int sqlite3Step(Vdbe *p){
#ifndef SQLITE_OMIT_TRACE
/* Invoke the profile callback if there is one
*/
- if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy && p->nOp>0
- && p->aOp[0].opcode==OP_Trace && p->aOp[0].p4.z!=0 ){
+ if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy && p->zSql ){
double rNow;
u64 elapseTime;
sqlite3OsCurrentTime(db->pVfs, &rNow);
elapseTime = (u64)((rNow - (int)rNow)*3600.0*24.0*1000000000.0);
elapseTime -= p->startTime;
- db->xProfile(db->pProfileArg, p->aOp[0].p4.z, elapseTime);
+ db->xProfile(db->pProfileArg, p->zSql, elapseTime);
}
#endif
@@ -505,7 +504,7 @@ static int sqlite3Step(Vdbe *p){
p->rc = sqlite3ApiExit(p->db, p->rc);
end_of_step:
assert( (rc&0xff)==rc );
- if( p->zSql && (rc&0xff)<SQLITE_ROW ){
+ if( p->isPrepareV2 && (rc&0xff)<SQLITE_ROW ){
/* This behavior occurs if sqlite3_prepare_v2() was used to build
** the prepared statement. Return error codes directly */
p->db->errCode = p->rc;
@@ -549,7 +548,7 @@ int sqlite3_step(sqlite3_stmt *pStmt){
sqlite3_reset(pStmt);
v->expired = 0;
}
- if( rc==SQLITE_SCHEMA && v->zSql && db->pErr ){
+ if( rc==SQLITE_SCHEMA && v->isPrepareV2 && db->pErr ){
/* This case occurs after failing to recompile an sql statement.
** The error message from the SQL compiler has already been loaded
** into the database handle. This block copies the error message
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 9bc5beff4..f2accd846 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -14,7 +14,7 @@
** to version 2.8.7, all this code was combined into the vdbe.c source file.
** But that file was getting too big so this subroutines were split out.
**
-** $Id: vdbeaux.c,v 1.435 2009/02/03 16:51:25 danielk1977 Exp $
+** $Id: vdbeaux.c,v 1.436 2009/02/19 14:39:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
@@ -52,17 +52,22 @@ Vdbe *sqlite3VdbeCreate(sqlite3 *db){
/*
** Remember the SQL string for a prepared statement.
*/
-void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n){
+void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){
if( p==0 ) return;
+#ifdef SQLITE_OMIT_TRACE
+ if( !isPrepareV2 ) return;
+#endif
assert( p->zSql==0 );
p->zSql = sqlite3DbStrNDup(p->db, z, n);
+ p->isPrepareV2 = isPrepareV2;
}
/*
** Return the SQL associated with a prepared statement
*/
const char *sqlite3_sql(sqlite3_stmt *pStmt){
- return ((Vdbe *)pStmt)->zSql;
+ Vdbe *p = (Vdbe *)pStmt;
+ return (p->isPrepareV2 ? p->zSql : 0);
}
/*
@@ -71,7 +76,6 @@ const char *sqlite3_sql(sqlite3_stmt *pStmt){
void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
Vdbe tmp, *pTmp;
char *zTmp;
- int nTmp;
tmp = *pA;
*pA = *pB;
*pB = tmp;
@@ -84,9 +88,7 @@ void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
zTmp = pA->zSql;
pA->zSql = pB->zSql;
pB->zSql = zTmp;
- nTmp = pA->nSql;
- pA->nSql = pB->nSql;
- pB->nSql = nTmp;
+ pB->isPrepareV2 = pA->isPrepareV2;
}
#ifdef SQLITE_DEBUG
@@ -1007,6 +1009,14 @@ void sqlite3VdbeIOTraceSql(Vdbe *p){
**
** This is the only way to move a VDBE from VDBE_MAGIC_INIT to
** VDBE_MAGIC_RUN.
+**
+** This function may be called more than once on a single virtual machine.
+** The first call is made while compiling the SQL statement. Subsequent
+** calls are made as part of the process of resetting a statement to be
+** re-executed (from a call to sqlite3_reset()). The nVar, nMem, nCursor
+** and isExplain parameters are only passed correct values the first time
+** the function is called. On subsequent calls, from sqlite3_reset(), nVar
+** is passed -1 and nMem, nCursor and isExplain are all passed zero.
*/
void sqlite3VdbeMakeReady(
Vdbe *p, /* The VDBE */
@@ -1039,23 +1049,26 @@ void sqlite3VdbeMakeReady(
*/
nMem += nCursor;
- /*
- ** Allocation space for registers.
+ /* Allocate space for memory registers, SQL variables, VDBE cursors and
+ ** an array to marshal SQL function arguments in. This is only done the
+ ** first time this function is called for a given VDBE, not when it is
+ ** being called from sqlite3_reset() to reset the virtual machine.
*/
- if( p->aMem==0 ){
+ if( nVar>=0 ){
+ int nByte;
int nArg; /* Maximum number of args passed to a user function. */
resolveP2Values(p, &nArg);
- assert( nVar>=0 );
if( isExplain && nMem<10 ){
nMem = 10;
}
- p->aMem = sqlite3DbMallocZero(db,
- nMem*sizeof(Mem) /* aMem */
- + nVar*sizeof(Mem) /* aVar */
- + nArg*sizeof(Mem*) /* apArg */
- + nVar*sizeof(char*) /* azVar */
- + nCursor*sizeof(VdbeCursor*)+1 /* apCsr */
- );
+ nByte = nMem*sizeof(Mem) /* aMem */
+ + nVar*sizeof(Mem) /* aVar */
+ + nArg*sizeof(Mem*) /* apArg */
+ + nVar*sizeof(char*) /* azVar */
+ + nCursor*sizeof(VdbeCursor*); /* apCsr */
+ if( nByte ){
+ p->aMem = sqlite3DbMallocZero(db, nByte);
+ }
if( !db->mallocFailed ){
p->aMem--; /* aMem[] goes from 1..nMem */
p->nMem = nMem; /* not from 0..nMem-1 */
@@ -1084,7 +1097,6 @@ void sqlite3VdbeMakeReady(
p->pc = -1;
p->rc = SQLITE_OK;
- p->uniqueCnt = 0;
p->errorAction = OE_Abort;
p->explain |= isExplain;
p->magic = VDBE_MAGIC_RUN;
diff --git a/src/walker.c b/src/walker.c
index 9a3a9c27b..4ed4cd95d 100644
--- a/src/walker.c
+++ b/src/walker.c
@@ -12,7 +12,7 @@
** This file contains routines used for walking the parser tree for
** an SQL statement.
**
-** $Id: walker.c,v 1.1 2008/08/20 16:35:10 drh Exp $
+** $Id: walker.c,v 1.2 2009/02/19 14:39:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
@@ -45,9 +45,10 @@ int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
if( rc==WRC_Continue ){
if( sqlite3WalkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
if( sqlite3WalkExpr(pWalker, pExpr->pRight) ) return WRC_Abort;
- if( sqlite3WalkExprList(pWalker, pExpr->pList) ) return WRC_Abort;
- if( sqlite3WalkSelect(pWalker, pExpr->pSelect) ){
- return WRC_Abort;
+ if( ExprHasProperty(pExpr, EP_xIsSelect) ){
+ if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
+ }else{
+ if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
}
}
return rc & WRC_Abort;
diff --git a/src/where.c b/src/where.c
index 89e3f31e9..22b6e07ba 100644
--- a/src/where.c
+++ b/src/where.c
@@ -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.368 2009/02/04 03:59:25 shane Exp $
+** $Id: where.c,v 1.369 2009/02/19 14:39:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -431,8 +431,11 @@ static Bitmask exprTableUsage(WhereMaskSet *pMaskSet, Expr *p){
}
mask = exprTableUsage(pMaskSet, p->pRight);
mask |= exprTableUsage(pMaskSet, p->pLeft);
- mask |= exprListTableUsage(pMaskSet, p->pList);
- mask |= exprSelectTableUsage(pMaskSet, p->pSelect);
+ if( ExprHasProperty(p, EP_xIsSelect) ){
+ mask |= exprSelectTableUsage(pMaskSet, p->x.pSelect);
+ }else{
+ mask |= exprListTableUsage(pMaskSet, p->x.pList);
+ }
return mask;
}
static Bitmask exprListTableUsage(WhereMaskSet *pMaskSet, ExprList *pList){
@@ -634,7 +637,7 @@ static int isLikeOrGlob(
#ifdef SQLITE_EBCDIC
if( *pnoCase ) return 0;
#endif
- pList = pExpr->pList;
+ pList = pExpr->x.pList;
pRight = pList->a[0].pExpr;
if( pRight->op!=TK_STRING ){
return 0;
@@ -689,7 +692,7 @@ static int isMatchOfColumn(
sqlite3StrNICmp((const char*)pExpr->token.z,"match",5)!=0 ){
return 0;
}
- pList = pExpr->pList;
+ pList = pExpr->x.pList;
if( pList->nExpr!=2 ){
return 0;
}
@@ -953,17 +956,18 @@ static void exprAnalyzeOrTerm(
assert( pOrTerm->eOperator==WO_EQ );
assert( pOrTerm->leftCursor==iCursor );
assert( pOrTerm->u.leftColumn==iColumn );
- pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight);
+ pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0);
pList = sqlite3ExprListAppend(pWC->pParse, pList, pDup, 0);
pLeft = pOrTerm->pExpr->pLeft;
}
assert( pLeft!=0 );
- pDup = sqlite3ExprDup(db, pLeft);
+ pDup = sqlite3ExprDup(db, pLeft, 0);
pNew = sqlite3Expr(db, TK_IN, pDup, 0, 0);
if( pNew ){
int idxNew;
transferJoinMarkings(pNew, pExpr);
- pNew->pList = pList;
+ assert( !ExprHasProperty(pNew, EP_xIsSelect) );
+ pNew->x.pList = pList;
idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew==0 );
exprAnalyze(pSrc, pWC, idxNew);
@@ -1026,8 +1030,11 @@ static void exprAnalyze(
op = pExpr->op;
if( op==TK_IN ){
assert( pExpr->pRight==0 );
- pTerm->prereqRight = exprListTableUsage(pMaskSet, pExpr->pList)
- | exprSelectTableUsage(pMaskSet, pExpr->pSelect);
+ if( ExprHasProperty(pExpr, EP_xIsSelect) ){
+ pTerm->prereqRight = exprSelectTableUsage(pMaskSet, pExpr->x.pSelect);
+ }else{
+ pTerm->prereqRight = exprListTableUsage(pMaskSet, pExpr->x.pList);
+ }
}else if( op==TK_ISNULL ){
pTerm->prereqRight = 0;
}else{
@@ -1057,7 +1064,7 @@ static void exprAnalyze(
Expr *pDup;
if( pTerm->leftCursor>=0 ){
int idxNew;
- pDup = sqlite3ExprDup(db, pExpr);
+ pDup = sqlite3ExprDup(db, pExpr, 0);
if( db->mallocFailed ){
sqlite3ExprDelete(db, pDup);
return;
@@ -1100,7 +1107,7 @@ static void exprAnalyze(
** BETWEEN term is skipped.
*/
else if( pExpr->op==TK_BETWEEN && pWC->op==TK_AND ){
- ExprList *pList = pExpr->pList;
+ ExprList *pList = pExpr->x.pList;
int i;
static const u8 ops[] = {TK_GE, TK_LE};
assert( pList!=0 );
@@ -1108,8 +1115,8 @@ static void exprAnalyze(
for(i=0; i<2; i++){
Expr *pNewExpr;
int idxNew;
- pNewExpr = sqlite3Expr(db, ops[i], sqlite3ExprDup(db, pExpr->pLeft),
- sqlite3ExprDup(db, pList->a[i].pExpr), 0);
+ pNewExpr = sqlite3Expr(db, ops[i], sqlite3ExprDup(db, pExpr->pLeft, 0),
+ sqlite3ExprDup(db, pList->a[i].pExpr, 0), 0);
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew==0 );
exprAnalyze(pSrc, pWC, idxNew);
@@ -1148,18 +1155,18 @@ static void exprAnalyze(
Expr *pNewExpr1, *pNewExpr2;
int idxNew1, idxNew2;
- pLeft = pExpr->pList->a[1].pExpr;
- pRight = pExpr->pList->a[0].pExpr;
+ pLeft = pExpr->x.pList->a[1].pExpr;
+ pRight = pExpr->x.pList->a[0].pExpr;
pStr1 = sqlite3PExpr(pParse, TK_STRING, 0, 0, 0);
if( pStr1 ){
sqlite3TokenCopy(db, &pStr1->token, &pRight->token);
pStr1->token.n = nPattern;
pStr1->flags = EP_Dequoted;
}
- pStr2 = sqlite3ExprDup(db, pStr1);
+ pStr2 = sqlite3ExprDup(db, pStr1, 0);
if( !db->mallocFailed ){
u8 c, *pC;
- assert( pStr2->token.dyn );
+ /* assert( pStr2->token.dyn ); */
pC = (u8*)&pStr2->token.z[nPattern-1];
c = *pC;
if( noCase ){
@@ -1168,11 +1175,11 @@ static void exprAnalyze(
}
*pC = c + 1;
}
- pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprDup(db,pLeft), pStr1, 0);
+ pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprDup(db,pLeft,0),pStr1,0);
idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew1==0 );
exprAnalyze(pSrc, pWC, idxNew1);
- pNewExpr2 = sqlite3PExpr(pParse, TK_LT, sqlite3ExprDup(db,pLeft), pStr2, 0);
+ pNewExpr2 = sqlite3PExpr(pParse, TK_LT, sqlite3ExprDup(db,pLeft,0),pStr2,0);
idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew2==0 );
exprAnalyze(pSrc, pWC, idxNew2);
@@ -1198,13 +1205,13 @@ static void exprAnalyze(
WhereTerm *pNewTerm;
Bitmask prereqColumn, prereqExpr;
- pRight = pExpr->pList->a[0].pExpr;
- pLeft = pExpr->pList->a[1].pExpr;
+ pRight = pExpr->x.pList->a[0].pExpr;
+ pLeft = pExpr->x.pList->a[1].pExpr;
prereqExpr = exprTableUsage(pMaskSet, pRight);
prereqColumn = exprTableUsage(pMaskSet, pLeft);
if( (prereqExpr & prereqColumn)==0 ){
Expr *pNewExpr;
- pNewExpr = sqlite3Expr(db, TK_MATCH, 0, sqlite3ExprDup(db, pRight), 0);
+ pNewExpr = sqlite3Expr(db, TK_MATCH, 0, sqlite3ExprDup(db, pRight, 0), 0);
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew==0 );
pNewTerm = &pWC->a[idxNew];
@@ -1776,10 +1783,12 @@ static void bestIndex(
pCost->rCost = 0;
pCost->nRow = 1;
return;
- }else if( (pExpr = pTerm->pExpr)->pList!=0 ){
+ }else if( !ExprHasProperty((pExpr = pTerm->pExpr), EP_xIsSelect)
+ && pExpr->x.pList
+ ){
/* Rowid IN (LIST): cost is NlogN where N is the number of list
** elements. */
- pCost->rCost = pCost->nRow = pExpr->pList->nExpr;
+ pCost->rCost = pCost->nRow = pExpr->x.pList->nExpr;
pCost->rCost *= estLog(pCost->rCost);
}else{
/* Rowid IN (SELECT): cost is NlogN where N is the number of rows
@@ -1925,10 +1934,10 @@ static void bestIndex(
if( pTerm->eOperator & WO_IN ){
Expr *pExpr = pTerm->pExpr;
wsFlags |= WHERE_COLUMN_IN;
- if( pExpr->pSelect!=0 ){
+ if( ExprHasProperty(pExpr, EP_xIsSelect) ){
inMultiplier *= 25;
- }else if( pExpr->pList ){
- inMultiplier *= pExpr->pList->nExpr + 1;
+ }else if( pExpr->x.pList ){
+ inMultiplier *= pExpr->x.pList->nExpr + 1;
}
}
}
diff --git a/test/default.test b/test/default.test
index 9a2ab1afe..95a4ee039 100644
--- a/test/default.test
+++ b/test/default.test
@@ -12,7 +12,7 @@
# focus of this file is testing corner cases of the DEFAULT syntax
# on table definitions.
#
-# $Id: default.test,v 1.2 2005/08/20 03:03:04 drh Exp $
+# $Id: default.test,v 1.3 2009/02/19 14:39:25 danielk1977 Exp $
#
set testdir [file dirname $argv0]
@@ -49,4 +49,19 @@ do_test default-1.3 {
}
} {1 {default value of column [y] is not constant}}
+ifcapable pragma {
+ do_test default-2.1 {
+ execsql {
+ CREATE TABLE t4(c DEFAULT 'abc');
+ PRAGMA table_info(t4);
+ }
+ } {0 c {} 0 'abc' 0}
+ do_test default-2.2 {
+ execsql {
+ INSERT INTO t4 DEFAULT VALUES;
+ PRAGMA table_info(t4);
+ }
+ } {0 c {} 0 'abc' 0}
+}
+
finish_test
diff --git a/test/tester.tcl b/test/tester.tcl
index 44b6ae291..046fb2ed3 100644
--- a/test/tester.tcl
+++ b/test/tester.tcl
@@ -11,7 +11,7 @@
# This file implements some common TCL routines used for regression
# testing the SQLite library
#
-# $Id: tester.tcl,v 1.139 2009/02/05 16:31:46 drh Exp $
+# $Id: tester.tcl,v 1.140 2009/02/19 14:39:25 danielk1977 Exp $
#
# What for user input before continuing. This gives an opportunity
@@ -895,16 +895,16 @@ proc memdebug_log_sql {{filename mallocs.sql}} {
set database temp
- set tbl "CREATE TABLE ${database}.malloc(nCall, nByte"
- for {set ii 1} {$ii <= $nFrame} {incr ii} {
- append tbl ", f${ii}"
- }
- append tbl ");\n"
+ set tbl "CREATE TABLE ${database}.malloc(zTest, nCall, nByte, lStack);"
set sql ""
foreach e $data {
- append sql "INSERT INTO ${database}.malloc VALUES([join $e ,]);\n"
- foreach f [lrange $e 2 end] {
+ set nCall [lindex $e 0]
+ set nByte [lindex $e 1]
+ set lStack [lrange $e 2 end]
+ append sql "INSERT INTO ${database}.malloc VALUES"
+ append sql "('test', $nCall, $nByte, '$lStack');\n"
+ foreach f $lStack {
set frames($f) 1
}
}