diff --git a/manifest b/manifest index de12c9c225..6fea4d19d7 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 61fbf41b31..8536c32b9b 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 3862a29aba..71e86e14cb 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 bf2683fb30..c3fd7ff8f0 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 851071356f..c58911d179 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 eb683f59b1..abc2ea07b8 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 8960a7ad93..ef7c54d280 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,12 +646,190 @@ 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 @@ -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; inExpr; 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, ®Free1, @@ -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, ®Free1); 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, ®Free1); 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( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) 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; ipList->nExpr; i++){ - if( !sqlite3ExprCompare(pA->pList->a[i].pExpr, pB->pList->a[i].pExpr) ){ - return 0; - } - } - }else if( pB->pList ){ + if( ExprHasProperty(pA, EP_xIsSelect) || ExprHasProperty(pB, EP_xIsSelect) ){ return 0; } - if( pA->pSelect || pB->pSelect ) 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->x.pList && pB->x.pList ){ + if( pA->x.pList->nExpr!=pB->x.pList->nExpr ) return 0; + for(i=0; ix.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( pA->x.pList || pB->x.pList ){ + 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 07671ff6ba..3deffc003c 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 @@ -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 0ab647e12f..faeb6b03e8 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 156237fcc7..436683659c 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 4b5c3124cb..491c8da09d 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 ad35d5420c..8497e69e20 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; inCol; 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 a4448d9ad0..e2dbaf52fa 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 d6f58fc70e..af44730eff 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 @@ -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 943f0ef4e6..286805e499 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->iColumnnExpr ); - 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; inFunc; 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; ipList); + 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 9d400fef47..440771f922 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 " IN (, ...)". +** Expr.x.pSelect is used if the expression is a sub-select or an expression of +** the form " 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 " IN ( IN ( IN ()" */ 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. @@ -1452,6 +1495,23 @@ struct Expr { #define ExprSetProperty(E,P) (E)->flags|=(P) #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 @@ -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 6563b14629..98f8d835d0 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 cd1fd218f9..dc4a48d4f9 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; inCol; 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 0b9ad1981e..0fec59a4ca 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+nnMem ); - pIn1 = &p->aMem[p1]; - assert( p2>0 ); - assert( p2+nnMem ); - pOut = &p->aMem[p2]; + assert( n>0 && p1>0 && p2>0 ); assert( p1+n<=p2 || p2+n<=p1 ); + + pIn1 = &p->aMem[p1]; + pOut = &p->aMem[p2]; 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->p3p2 || pOp->p3>=pOp->p2+n ); pArg = &p->aMem[pOp->p2]; for(i=0; i0 ); assert( pKeyInfo!=0 ); p1 = pOp->p1; - assert( p1>0 && p1+n-1nMem ); + assert( p1>0 && p1+n<=p->nMem+1 ); p2 = pOp->p2; - assert( p2>0 && p2+n-1nMem ); + assert( p2>0 && p2+n<=p->nMem+1 ); for(i=0; ip1; 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 && inCursor ); 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 312e389399..e8aad38629 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 8ff7939fc7..c34ce2562b 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 d3274b5408..e5a327a79e 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)isPrepareV2 && (rc&0xff)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 9bc5beff47..f2accd846b 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 9a3a9c27b6..4ed4cd95d3 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 @@ -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 89e3f31e94..22b6e07baa 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 9a2ab1afee..95a4ee039c 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 44b6ae2913..046fb2ed36 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 } }