From 2d401ab8f92295657b9cdab689ebd0f92c58ac51 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 10 Jan 2008 23:50:11 +0000 Subject: [PATCH] More work toward converting the VM into a register-based machine. (CVS 4704) FossilOrigin-Name: 8cbd46517f407b3b1ce187b623db10f00aa415ea --- manifest | 36 ++++----- manifest.uuid | 2 +- src/analyze.c | 56 ++++++++------ src/build.c | 26 ++++--- src/delete.c | 47 ++++++++---- src/expr.c | 50 +++++++----- src/insert.c | 79 +++++++++++-------- src/pragma.c | 164 +++++++++++++++++++++------------------- src/select.c | 196 +++++------------------------------------------- src/sqliteInt.h | 10 +-- src/trigger.c | 37 ++------- src/update.c | 38 ++++++---- src/vdbe.c | 128 ++++++------------------------- src/vdbeaux.c | 1 - src/vdbeblob.c | 14 ++-- 15 files changed, 348 insertions(+), 536 deletions(-) diff --git a/manifest b/manifest index afef6b1e09..4edcaa42bb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Continuing\swork\stoward\sregisterizing\sthe\scode\sgenerator.\s(CVS\s4703) -D 2008-01-10T03:46:36 +C More\swork\stoward\sconverting\sthe\sVM\sinto\sa\sregister-based\smachine.\s(CVS\s4704) +D 2008-01-10T23:50:11 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -79,24 +79,24 @@ F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc F sqlite3.def a96c1d0d39362b763d2ddba220a32da41a15c4b4 F sqlite3.pc.in abed4664817e1cd500f2276142c71958087c16bc F src/alter.c 5a54f58d9481ac14c4e58b702f3f8758dee84d04 -F src/analyze.c 6cd38a981cac4491d71f99bfc10df32139b3a16a +F src/analyze.c 52cbc3577c962975445d3e1341cba046f228d21e F src/attach.c 61f0cae7b1a0e7c3b5f5286be5dc1a7c4d7112d2 F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627 F src/btmutex.c 5d39da37c9d1282f3c6f9967afae6a34ee36b7ff F src/btree.c 5164b32950cfd41f2c5c31e8ff82c4a499918aef F src/btree.h 19dcf5ad23c17b98855da548e9a8e3eb4429d5eb F src/btreeInt.h 1c5a9da165718ef7de81e35ce9ab5d9ba9283f76 -F src/build.c 785139de34c0141208f7f70865bcc603e29faf70 +F src/build.c e5bb1ddf630d4fbd042bf6a09168fe2feb4f7549 F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0 F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131 F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6 -F src/delete.c 4f760fb7e9b0bb3cf05534bb9d43ea9e726b7e74 +F src/delete.c 44eac0a8a1bad1e62ee64e59e07a5a97a838bd0f F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b -F src/expr.c 522ba17fa6253a98dc6451e600341277ea43d5c6 +F src/expr.c 560fbd4aff7c65e716e0310f85f044141abd9523 F src/func.c 996071cf0af9d967e58b69fce1909555059ebc7d F src/hash.c 45a7005aac044b6c86bd7e49c44bc15d30006d6c F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53 -F src/insert.c b8406b40cc1cac732932ef587cbc0da006bfd68b +F src/insert.c 405cf0550252cdd3ba5b14ce1545571c82e35250 F src/journal.c 807bed7a158979ac8d63953e1774e8d85bff65e2 F src/legacy.c 4ac53191fad2e3c4d59bde1228879b2dc5a96d66 F src/limits.h 71ab25f17e35e0a9f3f6f234b8ed49cc56731d35 @@ -127,16 +127,16 @@ F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b F src/pager.c 0cb6ccea4b9615627d61d7c4417cedc45776d429 F src/pager.h f504f7ae84060fee0416a853e368d3d113c3d6fa F src/parse.y 2ae06e8d3190faace49c5b82e7cea1fc60d084a1 -F src/pragma.c bc6063d91d56a8b3cdad9e3478bba86700759cc4 +F src/pragma.c 1d3d9deefcf325e14a99b94f9f506f1a90a9232b F src/prepare.c c31a879d6795f4765fd0b113675c6debbc96b7fd F src/printf.c eb27822ba2eec669161409ca31279a24c26ac910 F src/random.c 4a22746501bf36b0a088c66e38dde5daba6a35da -F src/select.c 095296a572c296c9ce718768c6c984d33b239e5a +F src/select.c ff00897172bad962c7f775f0a1daa19e2a3ed80a F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c 5391e889384d2062249f668110d64ed16f601c4b F src/sqlite.h.in 2a7e3776534bbe6ff2cdc058f3abebe91e7e429f F src/sqlite3ext.h a93f59cdee3638dc0c9c086f80df743a4e68c3cb -F src/sqliteInt.h 0606321d38df78adef2325e0b51cd3963731f290 +F src/sqliteInt.h ba917f5ed26ab1b47d3814d624e36a73dfe4c5bd F src/sqliteLimit.h ee4430f88f69bf63527967bb35ca52af7b0ccb1e F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4 F src/tclsqlite.c 9923abeffc9b3d7dad58e92b319661521f60debf @@ -163,17 +163,17 @@ F src/test_server.c a6ece6c835e7eae835054124e09e947e422b1ac5 F src/test_tclvar.c b2d1115e4d489179d3f029e765211b2ad527ba59 F src/test_thread.c e297dd41db0b249646e69f97d36ec13e56e8b730 F src/tokenize.c a4e04438c11fed2c67ec47fe3edbef9cca2d1b48 -F src/trigger.c 1e77b3c21c129ad01f7f23a497ae1d224b4e5bc4 -F src/update.c 18f2f3af050399da584fe94548d7e15aa45e884d +F src/trigger.c 69df777f7626507d04ef23b9cb185d31ebd8e91a +F src/update.c aad823f97a930e6982264299863837d4c6107d3b F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736 F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624 F src/vacuum.c 3f34f278809bf3eb0b62ec46ff779e9c385b28f0 -F src/vdbe.c b094a8834bc44e790aef0b0024daf45570b7d56e +F src/vdbe.c 2a62b69e8344f28438ba0a007582be93b33b53ca F src/vdbe.h a9166e1601f5b74c20516a74182773a20baee43e F src/vdbeInt.h 31bd686595356284d5484592e2dc6e58025aa346 F src/vdbeapi.c f14174843bf4be2c9afdf2ef48b61e7c3ac62d7c -F src/vdbeaux.c 53cc9e2d3a870fe64f23c43b9417f28118e58d8f -F src/vdbeblob.c b90f7494c408d47ce6835000b01e40b371e27baf +F src/vdbeaux.c db33a4c2477546da05e772352be43896d24d51d5 +F src/vdbeblob.c e386d49d8354aa5a58f0a7f2794303442c149120 F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6 F src/vdbemem.c a94f3e9e85578ba457133ad3446fc6114a03ec5a F src/vtab.c 03014b2bfa8096ecac5fcdc80d34cd76e06af52a @@ -605,7 +605,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P 05fbca91085cb1b271a05e62181596b4f6f1bb9e -R 44353c14eaa458d109462754e477c6c2 +P 173698c963473ab1b9db88b23a2de82e4097b96d +R 8bf48b53bfdac6453062e461bf371d81 U drh -Z d88167e0b41893f49eaf4061856356de +Z e7ee9d7977b0629978f5e3008b2a0c6d diff --git a/manifest.uuid b/manifest.uuid index 486aad7ba6..71320c1f2d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -173698c963473ab1b9db88b23a2de82e4097b96d \ No newline at end of file +8cbd46517f407b3b1ce187b623db10f00aa415ea \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index 2560dd8a70..d1873f0f50 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.36 2008/01/09 23:04:12 drh Exp $ +** @(#) $Id: analyze.c,v 1.37 2008/01/10 23:50:11 drh Exp $ */ #ifndef SQLITE_OMIT_ANALYZE #include "sqliteInt.h" @@ -120,6 +120,12 @@ static void analyzeOneTable( iIdxCur = pParse->nTab; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); + int regFields; /* Register block for building records */ + int regRec; /* Register holding completed record */ + int regTemp; /* Temporary use register */ + int regCol; /* Content of a column from the table being analyzed */ + int regRowid; /* Rowid for the inserted record */ + int regF2; /* Open a cursor to the index to be analyzed */ @@ -128,8 +134,11 @@ static void analyzeOneTable( (char *)pKey, P4_KEYINFO_HANDOFF); VdbeComment((v, "%s", pIdx->zName)); nCol = pIdx->nColumn; - if( iMem+nCol*2>=pParse->nMem ){ - pParse->nMem = iMem+nCol*2+1; + regFields = iMem+nCol*2; + regTemp = regRowid = regCol = regFields+3; + regRec = regCol+1; + if( regRec>pParse->nMem ){ + pParse->nMem = regRec; } sqlite3VdbeAddOp2(v, OP_SetNumColumns, iIdxCur, nCol+1); @@ -160,15 +169,15 @@ static void analyzeOneTable( topOfLoop = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_AddImm, iMem, 1); for(i=0; i0 then it is always the case the D>0 so division by zero ** is never possible. */ - sqlite3VdbeAddOp1(v, OP_SCopy, iMem); - addr = sqlite3VdbeAddOp0(v, OP_IfNot); - sqlite3VdbeAddOp1(v, OP_NewRowid, iStatCur); - sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pTab->zName, 0); - sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pIdx->zName, 0); - sqlite3VdbeAddOp1(v, OP_SCopy, iMem); + addr = sqlite3VdbeAddOp1(v, OP_IfNot, iMem); + sqlite3VdbeAddOp4(v, OP_String8, 0, regFields, 0, pTab->zName, 0); + sqlite3VdbeAddOp4(v, OP_String8, 0, regFields+1, 0, pIdx->zName, 0); + regF2 = regFields+2; + sqlite3VdbeAddOp2(v, OP_SCopy, iMem, regF2); for(i=0; i @@ -2222,6 +2222,8 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ int tnum; /* Root page of index */ Vdbe *v; /* Generate code into this virtual machine */ KeyInfo *pKey; /* KeyInfo for index */ + int regIdxKey; /* Registers containing the index key */ + int regRecord; /* Register holding assemblied index record */ sqlite3 *db = pParse->db; /* The database connection */ int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); @@ -2252,19 +2254,23 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ } sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); - sqlite3GenerateIndexKey(v, pIndex, iTab); + regRecord = sqlite3GetTempReg(pParse); + regIdxKey = sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord); if( pIndex->onError!=OE_None ){ - int curaddr = sqlite3VdbeCurrentAddr(v); - int addr2 = curaddr+4; - sqlite3VdbeChangeP2(v, curaddr-1, addr2); - sqlite3VdbeAddOp1(v, OP_Rowid, iTab); - sqlite3VdbeAddOp2(v, OP_AddImm, 0, 1); - sqlite3VdbeAddOp4(v, OP_IsUnique, iIdx, addr2, 0, 0, P4_INT32); + int j1, j2; + int regRowid; + + regRowid = regIdxKey + pIndex->nColumn; + j1 = sqlite3VdbeAddOp3(v, OP_IsNull, regIdxKey, 0, pIndex->nColumn); + j2 = sqlite3VdbeAddOp4(v, OP_IsUnique, iIdx, + 0, regRowid, (char*)regRecord, P4_INT32); sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort, 0, "indexed columns are not unique", P4_STATIC); - assert( db->mallocFailed || addr2==sqlite3VdbeCurrentAddr(v) ); + sqlite3VdbeJumpHere(v, j1); + sqlite3VdbeJumpHere(v, j2); } - sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, 0); + sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord); + sqlite3ReleaseTempReg(pParse, regRecord); sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp1(v, OP_Close, iTab); diff --git a/src/delete.c b/src/delete.c index 80c2ab43ef..18a16ed557 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.155 2008/01/09 23:04:12 drh Exp $ +** $Id: delete.c,v 1.156 2008/01/10 23:50:11 drh Exp $ */ #include "sqliteInt.h" @@ -390,7 +390,7 @@ void sqlite3DeleteFrom( }else #endif { - sqlite3GenerateRowDelete(db, v, pTab, iCur, iRowid, pParse->nested==0); + sqlite3GenerateRowDelete(pParse, pTab, iCur, iRowid, pParse->nested==0); } } @@ -455,16 +455,18 @@ delete_from_cleanup: ** entries that point to that record. */ void sqlite3GenerateRowDelete( - sqlite3 *db, /* The database containing the index */ - Vdbe *v, /* Generate code into this VDBE */ + Parse *pParse, /* Parsing context */ Table *pTab, /* Table containing the row to be deleted */ int iCur, /* Cursor number for the table */ int iRowid, /* Memory cell that contains the rowid to delete */ int count /* Increment the row change counter */ ){ int addr; + Vdbe *v; + + v = pParse->pVdbe; addr = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowid); - sqlite3GenerateRowIndexDelete(v, pTab, iCur, 0); + sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, 0); sqlite3VdbeAddOp2(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0)); if( count ){ sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC); @@ -489,7 +491,7 @@ void sqlite3GenerateRowDelete( ** deleted. */ void sqlite3GenerateRowIndexDelete( - Vdbe *v, /* Generate code into this VDBE */ + Parse *pParse, /* Parsing and code generating context */ Table *pTab, /* Table containing the row to be deleted */ int iCur, /* Cursor number for the table */ int *aRegIdx /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */ @@ -499,8 +501,8 @@ void sqlite3GenerateRowIndexDelete( for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ if( aRegIdx!=0 && aRegIdx[i-1]==0 ) continue; - sqlite3GenerateIndexKey(v, pIdx, iCur); - sqlite3VdbeAddOp1(v, OP_IdxDelete, iCur+i); + sqlite3GenerateIndexKey(pParse, pIdx, iCur, 0); + sqlite3VdbeAddOp2(pParse->pVdbe, OP_IdxDelete, iCur+i, 0); } } @@ -509,25 +511,38 @@ void sqlite3GenerateRowIndexDelete( ** of the tack. The key with be for index pIdx which is an index on pTab. ** iCur is the index of a cursor open on the pTab table and pointing to ** the entry that needs indexing. +** +** Return a register number which is the first in a block of +** registers that holds the elements of the index key. The +** block of registers has already been deallocated by the time +** this routine returns. */ -void sqlite3GenerateIndexKey( - Vdbe *v, /* Generate code into this VDBE */ +int sqlite3GenerateIndexKey( + Parse *pParse, /* Parsing context */ Index *pIdx, /* The index for which to generate a key */ - int iCur /* Cursor number for the pIdx->pTable table */ + int iCur, /* Cursor number for the pIdx->pTable table */ + int regOut /* Write the new index key to this register */ ){ + Vdbe *v = pParse->pVdbe; int j; Table *pTab = pIdx->pTable; + int regBase; + int nCol; - sqlite3VdbeAddOp1(v, OP_Rowid, iCur); - for(j=0; jnColumn; j++){ + nCol = pIdx->nColumn; + regBase = sqlite3GetTempRange(pParse, nCol+1); + sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regBase+nCol); + for(j=0; jaiColumn[j]; if( idx==pTab->iPKey ){ - sqlite3VdbeAddOp1(v, OP_Copy, -j); + sqlite3VdbeAddOp2(v, OP_SCopy, regBase+nCol, regBase+j); }else{ - sqlite3VdbeAddOp2(v, OP_Column, iCur, idx); + sqlite3VdbeAddOp3(v, OP_Column, iCur, idx, regBase+j); sqlite3ColumnDefault(v, pTab, idx); } } - sqlite3VdbeAddOp1(v, OP_MakeIdxRec, pIdx->nColumn); + sqlite3VdbeAddOp3(v, OP_RegMakeRec, regBase, nCol+1, regOut); sqlite3IndexAffinityStr(v, pIdx); + sqlite3ReleaseTempRange(pParse, regBase, nCol+1); + return regBase; } diff --git a/src/expr.c b/src/expr.c index c1cb722c5d..88636411e6 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.341 2008/01/10 03:46:36 drh Exp $ +** $Id: expr.c,v 1.342 2008/01/10 23:50:11 drh Exp $ */ #include "sqliteInt.h" #include @@ -1550,7 +1550,7 @@ struct QueryCoder { ** The returned value indicates the structure type, as follows: ** ** IN_INDEX_ROWID - The cursor was opened on a database table. -** IN_INDEX_INDEX - The cursor was opened on a database indec. +** IN_INDEX_INDEX - The cursor was opened on a database index. ** IN_INDEX_EPH - The cursor was opened on a specially created and ** populated epheremal table. ** @@ -1765,6 +1765,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ int i; ExprList *pList = pExpr->pList; struct ExprList_item *pItem; + int r1, r2; if( !affinity ){ affinity = SQLITE_AFF_NONE; @@ -1772,6 +1773,8 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ keyInfo.aColl[0] = pExpr->pLeft->pColl; /* Loop through each expression in . */ + r1 = sqlite3GetTempReg(pParse); + r2 = sqlite3GetTempReg(pParse); for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){ Expr *pE2 = pItem->pExpr; @@ -1786,10 +1789,12 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ } /* Evaluate the expression and insert it into the temp table */ - sqlite3ExprCode(pParse, pE2, 0); - sqlite3VdbeAddOp4(v, OP_MakeRecord, 1, 0, 0, &affinity, 1); - sqlite3VdbeAddOp1(v, OP_IdxInsert, pExpr->iTable); + sqlite3ExprCode(pParse, pE2, r1); + sqlite3VdbeAddOp4(v, OP_RegMakeRec, r1, 1, r2, &affinity, 1); + sqlite3VdbeAddOp2(v, OP_IdxInsert, pExpr->iTable, r2); } + sqlite3ReleaseTempReg(pParse, r1); + sqlite3ReleaseTempReg(pParse, r2); } sqlite3VdbeChangeP4(v, addr, (void *)&keyInfo, P4_KEYINFO); break; @@ -2230,6 +2235,7 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ int j1, j2, j3, j4, j5; char affinity; int eType; + int r1, r2, r3; eType = sqlite3FindInIndex(pParse, pExpr, 0); @@ -2239,29 +2245,35 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ */ affinity = comparisonAffinity(pExpr); - sqlite3VdbeAddOp1(v, OP_Integer, 1); + if( target ){ + r1 = target; + }else{ + r1 = sqlite3GetTempReg(pParse); + } + inReg = r1; + sqlite3VdbeAddOp2(v, OP_Integer, 1, r1); /* Code the from " IN (...)". The temporary table ** pExpr->iTable contains the values that make up the (...) set. */ - sqlite3ExprCode(pParse, pExpr->pLeft, 0); - sqlite3VdbeAddOp0(v, OP_SCopy); - j1 = sqlite3VdbeAddOp0(v, OP_NotNull); - sqlite3VdbeAddOp1(v, OP_Pop, 2); - sqlite3VdbeAddOp0(v, OP_Null); + r2 = sqlite3ExprCode(pParse, pExpr->pLeft, -1); + j1 = sqlite3VdbeAddOp1(v, OP_NotNull, r2); + sqlite3VdbeAddOp2(v, OP_Null, 0, r1); j2 = sqlite3VdbeAddOp0(v, OP_Goto); sqlite3VdbeJumpHere(v, j1); if( eType==IN_INDEX_ROWID ){ - j3 = sqlite3VdbeAddOp3(v, OP_MustBeInt, 0, 0, 1); - j4 = sqlite3VdbeAddOp1(v, OP_NotExists, pExpr->iTable); + j3 = sqlite3VdbeAddOp3(v, OP_MustBeInt, r2, 0, 1); + j4 = sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, 0, r2); j5 = sqlite3VdbeAddOp0(v, OP_Goto); sqlite3VdbeJumpHere(v, j3); sqlite3VdbeJumpHere(v, j4); }else{ - sqlite3VdbeAddOp4(v, OP_MakeRecord, 1, 0, 0, &affinity, 1); - j5 = sqlite3VdbeAddOp1(v, OP_Found, pExpr->iTable); + r3 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp4(v, OP_RegMakeRec, r2, 1, r3, &affinity, 1); + j5 = sqlite3VdbeAddOp3(v, OP_Found, pExpr->iTable, 0, r3); + sqlite3ReleaseTempReg(pParse, r3); } - sqlite3VdbeAddOp2(v, OP_AddImm, 0, -1); + sqlite3VdbeAddOp2(v, OP_AddImm, r1, -1); sqlite3VdbeJumpHere(v, j2); sqlite3VdbeJumpHere(v, j5); break; @@ -2384,19 +2396,19 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ ** not cached. If the expression is cached, its result is stored in a ** memory location. */ -void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr){ +void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){ Vdbe *v = pParse->pVdbe; VdbeOp *pOp; int iMem; int addr1, addr2; if( v==0 ) return; addr1 = sqlite3VdbeCurrentAddr(v); - sqlite3ExprCode(pParse, pExpr, 0); + sqlite3ExprCode(pParse, pExpr, target); addr2 = sqlite3VdbeCurrentAddr(v); if( addr2>addr1+1 || ((pOp = sqlite3VdbeGetOp(v, addr1))!=0 && pOp->opcode==OP_Function) ){ iMem = pExpr->iTable = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Copy, 0, iMem); + sqlite3VdbeAddOp2(v, OP_Copy, target, iMem); pExpr->op = TK_REGISTER; } } diff --git a/src/insert.c b/src/insert.c index 72585705d5..7577f46774 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.221 2008/01/10 03:46:36 drh Exp $ +** $Id: insert.c,v 1.222 2008/01/10 23:50:11 drh Exp $ */ #include "sqliteInt.h" @@ -28,6 +28,9 @@ ** 'c' NUMERIC ** 'd' INTEGER ** 'e' REAL +** +** An extra 'b' is appended to the end of the string to cover the +** rowid that appears as the last column in every index. */ void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){ if( !pIdx->zColAff ){ @@ -42,14 +45,15 @@ void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){ int n; Table *pTab = pIdx->pTable; sqlite3 *db = sqlite3VdbeDb(v); - pIdx->zColAff = (char *)sqlite3DbMallocZero(db, pIdx->nColumn+1); + pIdx->zColAff = (char *)sqlite3DbMallocZero(db, pIdx->nColumn+2); if( !pIdx->zColAff ){ return; } for(n=0; nnColumn; n++){ pIdx->zColAff[n] = pTab->aCol[pIdx->aiColumn[n]].affinity; } - pIdx->zColAff[pIdx->nColumn] = '\0'; + pIdx->zColAff[n++] = SQLITE_AFF_NONE; + pIdx->zColAff[n] = 0; } sqlite3VdbeChangeP4(v, -1, pIdx->zColAff, 0); @@ -679,6 +683,9 @@ void sqlite3Insert( */ endOfLoop = sqlite3VdbeMakeLabel(v); if( triggers_exist & TRIGGER_BEFORE ){ + int regRowid; + int regCols; + int regRec; /* build the NEW.* reference row. Note that if there is an INTEGER ** PRIMARY KEY into which a NULL is being inserted, that NULL will be @@ -686,20 +693,19 @@ void sqlite3Insert( ** we do not know what the unique ID will be (because the insert has ** not happened yet) so we substitute a rowid of -1 */ + regRowid = sqlite3GetTempReg(pParse); if( keyColumn<0 ){ - sqlite3VdbeAddOp2(v, OP_Integer, -1, 0); + sqlite3VdbeAddOp2(v, OP_Integer, -1, regRowid); }else if( useTempTable ){ - sqlite3VdbeAddOp2(v, OP_Column, srcTab, keyColumn); + sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regRowid); }else{ int j1; assert( pSelect==0 ); /* Otherwise useTempTable is true */ - sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, 0); - sqlite3VdbeAddOp0(v, OP_SCopy); - j1 = sqlite3VdbeAddOp0(v, OP_NotNull); - sqlite3VdbeAddOp1(v, OP_Pop, 1); - sqlite3VdbeAddOp1(v, OP_Integer, -1); + sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, regRowid); + j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid); + sqlite3VdbeAddOp2(v, OP_Integer, -1, regRowid); sqlite3VdbeJumpHere(v, j1); - sqlite3VdbeAddOp0(v, OP_MustBeInt); + sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid); } /* Cannot have triggers on a virtual table. If it were possible, @@ -709,6 +715,7 @@ void sqlite3Insert( /* Create the new column data */ + regCols = sqlite3GetTempRange(pParse, pTab->nCol); for(i=0; inCol; i++){ if( pColumn==0 ){ j = i; @@ -718,15 +725,16 @@ void sqlite3Insert( } } if( pColumn && j>=pColumn->nId ){ - sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, 0); + sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i); }else if( useTempTable ){ - sqlite3VdbeAddOp2(v, OP_Column, srcTab, j); + sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i); }else{ assert( pSelect==0 ); /* Otherwise useTempTable is true */ - sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr); + sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i); } } - sqlite3VdbeAddOp2(v, OP_MakeRecord, pTab->nCol, 0); + regRec = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_RegMakeRec, regCols, pTab->nCol, regRec); /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger, ** do not attempt any conversions before assembling the record. @@ -736,7 +744,10 @@ void sqlite3Insert( if( !isView ){ sqlite3TableAffinityStr(v, pTab); } - sqlite3CodeInsert(pParse, newIdx, OPFLAG_APPEND); + sqlite3VdbeAddOp3(v, OP_Insert, newIdx, regRec, regRowid); + sqlite3ReleaseTempReg(pParse, regRec); + sqlite3ReleaseTempReg(pParse, regRowid); + sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol); /* Fire BEFORE or INSTEAD OF triggers */ if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_BEFORE, pTab, @@ -1123,7 +1134,7 @@ void sqlite3GenerateConstraintChecks( break; } case OE_Replace: { - sqlite3GenerateRowIndexDelete(v, pTab, baseCur, 0); + sqlite3GenerateRowIndexDelete(pParse, pTab, baseCur, 0); if( isUpdate ){ sqlite3VdbeAddOp3(v, OP_MoveGe, baseCur, 0, regRowid-hasTwoRowids); } @@ -1148,20 +1159,25 @@ void sqlite3GenerateConstraintChecks( ** Add the new records to the indices as we go. */ for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){ + int regIdx; + int regR; + if( aRegIdx[iCur]==0 ) continue; /* Skip unused indices */ /* Create a key for accessing the index entry */ - sqlite3VdbeAddOp1(v, OP_SCopy, regRowid); + regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn+1); for(i=0; inColumn; i++){ int idx = pIdx->aiColumn[i]; if( idx==pTab->iPKey ){ - sqlite3VdbeAddOp1(v, OP_SCopy, regRowid); + sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i); }else{ - sqlite3VdbeAddOp1(v, OP_SCopy, regData+idx); + sqlite3VdbeAddOp2(v, OP_SCopy, regData+idx, regIdx+i); } } - j2 = sqlite3VdbeAddOp3(v, OP_MakeIdxRec, pIdx->nColumn, 0, aRegIdx[iCur]); + sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i); + sqlite3VdbeAddOp3(v, OP_RegMakeRec, regIdx, pIdx->nColumn+1, aRegIdx[iCur]); sqlite3IndexAffinityStr(v, pIdx); + sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1); /* Find out what action to take in case there is an indexing conflict */ onError = pIdx->onError; @@ -1178,9 +1194,11 @@ void sqlite3GenerateConstraintChecks( /* Check to see if the new index entry will be unique */ - sqlite3VdbeAddOp1(v, OP_SCopy, aRegIdx[iCur]); - sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids); - j3 = sqlite3VdbeAddOp4(v, OP_IsUnique, baseCur+iCur+1, 0, 0, 0, P4_INT32); + j2 = sqlite3VdbeAddOp3(v, OP_IsNull, regIdx, 0, pIdx->nColumn); + regR = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp2(v, OP_SCopy, regRowid-hasTwoRowids, regR); + j3 = sqlite3VdbeAddOp4(v, OP_IsUnique, baseCur+iCur+1, 0, + regR, (char*)aRegIdx[iCur], P4_INT32); /* Generate code that executes if the new index entry is not unique */ assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail @@ -1217,26 +1235,21 @@ void sqlite3GenerateConstraintChecks( } case OE_Ignore: { assert( seenReplace==0 ); - sqlite3VdbeAddOp1(v, OP_Pop, 2+hasTwoRowids); sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); break; } case OE_Replace: { - int iRowid = sqlite3StackToReg(pParse, 1); - sqlite3GenerateRowDelete(pParse->db, v, pTab, baseCur, iRowid, 0); + sqlite3GenerateRowDelete(pParse, pTab, baseCur, regR, 0); if( isUpdate ){ - sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids); - sqlite3VdbeAddOp2(v, OP_MoveGe, baseCur, 0); + sqlite3VdbeAddOp3(v, OP_MoveGe, baseCur, 0, regRowid-hasTwoRowids); } seenReplace = 1; break; } } - sqlite3VdbeJumpHere(v, j3); - sqlite3VdbeAddOp1(v, OP_Pop, 1); -#if NULL_DISTINCT_FOR_UNIQUE sqlite3VdbeJumpHere(v, j2); -#endif + sqlite3VdbeJumpHere(v, j3); + sqlite3ReleaseTempReg(pParse, regR); } } diff --git a/src/pragma.c b/src/pragma.c index 63c3dc3cbe..9fffdfff24 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.164 2008/01/09 23:04:12 drh Exp $ +** $Id: pragma.c,v 1.165 2008/01/10 23:50:11 drh Exp $ */ #include "sqliteInt.h" #include @@ -252,6 +252,7 @@ void sqlite3Pragma( Db *pDb; Vdbe *v = sqlite3GetVdbe(pParse); if( v==0 ) return; + pParse->nMem = 1; /* Interpret the [database.] part of the pragma statement. iDb is the ** index of the database this pragma is being applied to in db.aDb[]. */ @@ -419,8 +420,8 @@ void sqlite3Pragma( } sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "locking_mode", P4_STATIC); - sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, zRet, 0); - sqlite3VdbeAddOp2(v, OP_Callback, 1, 0); + sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, zRet, 0); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); }else #endif /* SQLITE_OMIT_PAGER_PRAGMAS */ @@ -495,7 +496,7 @@ void sqlite3Pragma( sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3VdbeAddOp2(v, OP_Integer, iLimit, 1); addr = sqlite3VdbeAddOp1(v, OP_IncrVacuum, iDb); - sqlite3VdbeAddOp0(v, OP_Callback); + sqlite3VdbeAddOp1(v, OP_ResultRow, 1); sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr); sqlite3VdbeJumpHere(v, addr); @@ -564,8 +565,8 @@ void sqlite3Pragma( sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "temp_store_directory", P4_STATIC); - sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, sqlite3_temp_directory, 0); - sqlite3VdbeAddOp2(v, OP_Callback, 1, 0); + sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, sqlite3_temp_directory, 0); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); } }else{ if( zRight[0] @@ -643,6 +644,7 @@ void sqlite3Pragma( int nHidden = 0; Column *pCol; sqlite3VdbeSetNumCols(v, 6); + pParse->nMem = 6; sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", P4_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P4_STATIC); sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", P4_STATIC); @@ -656,18 +658,18 @@ void sqlite3Pragma( nHidden++; continue; } - sqlite3VdbeAddOp2(v, OP_Integer, i-nHidden, 0); - sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pCol->zName, 0); - sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, + sqlite3VdbeAddOp2(v, OP_Integer, i-nHidden, 1); + sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pCol->zName, 0); + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pCol->zType ? pCol->zType : "", 0); - sqlite3VdbeAddOp2(v, OP_Integer, pCol->notNull, 0); + sqlite3VdbeAddOp2(v, OP_Integer, pCol->notNull, 4); if( pCol->pDflt && (pDflt = &pCol->pDflt->span)->z ){ - sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, (char*)pDflt->z, pDflt->n); + sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pDflt->z, pDflt->n); }else{ - sqlite3VdbeAddOp2(v, OP_Null, 0, 0); + sqlite3VdbeAddOp2(v, OP_Null, 0, 5); } - sqlite3VdbeAddOp2(v, OP_Integer, pCol->isPrimKey, 0); - sqlite3VdbeAddOp2(v, OP_Callback, 6, 0); + sqlite3VdbeAddOp2(v, OP_Integer, pCol->isPrimKey, 6); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6); } } }else @@ -681,16 +683,17 @@ void sqlite3Pragma( int i; pTab = pIdx->pTable; sqlite3VdbeSetNumCols(v, 3); + pParse->nMem = 3; sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", P4_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", P4_STATIC); sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", P4_STATIC); for(i=0; inColumn; i++){ int cnum = pIdx->aiColumn[i]; - sqlite3VdbeAddOp2(v, OP_Integer, i, 0); - sqlite3VdbeAddOp2(v, OP_Integer, cnum, 0); + sqlite3VdbeAddOp2(v, OP_Integer, i, 1); + sqlite3VdbeAddOp2(v, OP_Integer, cnum, 2); assert( pTab->nCol>cnum ); - sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pTab->aCol[cnum].zName, 0); - sqlite3VdbeAddOp2(v, OP_Callback, 3, 0); + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pTab->aCol[cnum].zName, 0); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); } } }else @@ -706,14 +709,15 @@ void sqlite3Pragma( if( pIdx ){ int i = 0; sqlite3VdbeSetNumCols(v, 3); + pParse->nMem = 3; sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P4_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P4_STATIC); sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", P4_STATIC); while(pIdx){ - sqlite3VdbeAddOp2(v, OP_Integer, i, 0); - sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pIdx->zName, 0); - sqlite3VdbeAddOp2(v, OP_Integer, pIdx->onError!=OE_None, 0); - sqlite3VdbeAddOp2(v, OP_Callback, 3, 0); + sqlite3VdbeAddOp2(v, OP_Integer, i, 1); + sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0); + sqlite3VdbeAddOp2(v, OP_Integer, pIdx->onError!=OE_None, 3); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); ++i; pIdx = pIdx->pNext; } @@ -725,17 +729,18 @@ void sqlite3Pragma( int i; if( sqlite3ReadSchema(pParse) ) goto pragma_out; sqlite3VdbeSetNumCols(v, 3); + pParse->nMem = 3; sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P4_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P4_STATIC); sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "file", P4_STATIC); for(i=0; inDb; i++){ if( db->aDb[i].pBt==0 ) continue; assert( db->aDb[i].zName!=0 ); - sqlite3VdbeAddOp2(v, OP_Integer, i, 0); - sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, db->aDb[i].zName, 0); - sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, + sqlite3VdbeAddOp2(v, OP_Integer, i, 1); + sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, db->aDb[i].zName, 0); + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, sqlite3BtreeGetFilename(db->aDb[i].pBt), 0); - sqlite3VdbeAddOp2(v, OP_Callback, 3, 0); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); } }else @@ -743,13 +748,14 @@ void sqlite3Pragma( int i = 0; HashElem *p; sqlite3VdbeSetNumCols(v, 2); + pParse->nMem = 2; sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P4_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P4_STATIC); for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){ CollSeq *pColl = (CollSeq *)sqliteHashData(p); - sqlite3VdbeAddOp2(v, OP_Integer, i++, 0); - sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pColl->zName, 0); - sqlite3VdbeAddOp2(v, OP_Callback, 2, 0); + sqlite3VdbeAddOp2(v, OP_Integer, i++, 1); + sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pColl->zName, 0); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2); } }else #endif /* SQLITE_OMIT_SCHEMA_PRAGMAS */ @@ -766,6 +772,7 @@ void sqlite3Pragma( if( pFK ){ int i = 0; sqlite3VdbeSetNumCols(v, 5); + pParse->nMem = 5; sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", P4_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", P4_STATIC); sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", P4_STATIC); @@ -775,13 +782,13 @@ void sqlite3Pragma( int j; for(j=0; jnCol; j++){ char *zCol = pFK->aCol[j].zCol; - sqlite3VdbeAddOp2(v, OP_Integer, i, 0); - sqlite3VdbeAddOp2(v, OP_Integer, j, 0); - sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pFK->zTo, 0); - sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, + sqlite3VdbeAddOp2(v, OP_Integer, i, 1); + sqlite3VdbeAddOp2(v, OP_Integer, j, 2); + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pFK->zTo, 0); + sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, pTab->aCol[pFK->aCol[j].iFrom].zName, 0); - sqlite3VdbeAddOp4(v, zCol ? OP_String8 : OP_Null, 0, 0, 0, zCol, 0); - sqlite3VdbeAddOp2(v, OP_Callback, 5, 0); + sqlite3VdbeAddOp4(v, zCol ? OP_String8 : OP_Null, 0, 5, 0, zCol, 0); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5); } ++i; pFK = pFK->pNextFrom; @@ -831,17 +838,17 @@ void sqlite3Pragma( ** error message */ static const VdbeOpList endCode[] = { - { OP_SCopy, 1, 0, 0}, - { OP_Integer, 0, 0, 0}, - { OP_Ne, 0, 0, 0}, /* 2 */ - { OP_String8, 0, 0, 0}, /* 3 */ - { OP_Callback, 1, 0, 0}, + { OP_AddImm, 1, 0, 0}, /* 0 */ + { OP_IfNeg, 1, 0, 0}, /* 1 */ + { OP_String8, 0, 3, 0}, /* 2 */ + { OP_ResultRow, 3, 1, 0}, }; int isQuick = (zLeft[0]=='q'); /* Initialize the VDBE program */ if( sqlite3ReadSchema(pParse) ) goto pragma_out; + pParse->nMem = 6; sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", P4_STATIC); @@ -853,8 +860,7 @@ void sqlite3Pragma( mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX; } } - sqlite3VdbeAddOp2(v, OP_Integer, mxErr, 1); - pParse->nMem = 1; + sqlite3VdbeAddOp2(v, OP_Integer, mxErr, 1); /* reg[1] holds errors left */ /* Do an integrity check on each database file */ for(i=0; inDb; i++){ @@ -865,11 +871,14 @@ void sqlite3Pragma( if( OMIT_TEMPDB && i==1 ) continue; sqlite3CodeVerifySchema(pParse, i); - addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); + addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Halt if out of errors */ sqlite3VdbeAddOp2(v, OP_Halt, 0, 0); sqlite3VdbeJumpHere(v, addr); /* Do an integrity check of the B-Tree + ** + ** Begin by filling registers 2, 3, ... with the root pages numbers + ** for all tables and indices in the database. */ pTbls = &db->aDb[i].pSchema->tblHash; for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ @@ -883,9 +892,13 @@ void sqlite3Pragma( } } if( cnt==0 ) continue; + + /* Make sure sufficient number of registers have been allocated */ if( pParse->nMem < cnt+3 ){ pParse->nMem = cnt+3; } + + /* Do the b-tree integrity checks */ sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1); sqlite3VdbeChangeP5(v, i); addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); @@ -904,28 +917,28 @@ void sqlite3Pragma( int loopTop; if( pTab->pIndex==0 ) continue; - addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); + addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Stop if out of errors */ sqlite3VdbeAddOp2(v, OP_Halt, 0, 0); sqlite3VdbeJumpHere(v, addr); sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead); - sqlite3VdbeAddOp2(v, OP_Integer, 0, 2); + sqlite3VdbeAddOp2(v, OP_Integer, 0, 2); /* reg(2) will count entries */ loopTop = sqlite3VdbeAddOp2(v, OP_Rewind, 1, 0); - sqlite3VdbeAddOp2(v, OP_AddImm, 2, 1); + sqlite3VdbeAddOp2(v, OP_AddImm, 2, 1); /* increment entry count */ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int jmp2; static const VdbeOpList idxErr[] = { { OP_AddImm, 1, -1, 0}, - { OP_String8, 0, 0, 0}, /* 1 */ - { OP_Rowid, 1, 0, 0}, - { OP_String8, 0, 0, 0}, /* 3 */ - { OP_String8, 0, 0, 0}, /* 4 */ - { OP_Concat, 0, 0, 0}, - { OP_Concat, 0, 0, 0}, - { OP_Concat, 0, 0, 0}, - { OP_Callback, 1, 0, 0}, + { OP_String8, 0, 3, 0}, /* 1 */ + { OP_Rowid, 1, 4, 0}, + { OP_String8, 0, 5, 0}, /* 3 */ + { OP_String8, 0, 6, 0}, /* 4 */ + { OP_Concat, 4, 3, 3}, + { OP_Concat, 5, 3, 3}, + { OP_Concat, 6, 3, 3}, + { OP_ResultRow, 3, 1, 0}, }; - sqlite3GenerateIndexKey(v, pIdx, 1); - jmp2 = sqlite3VdbeAddOp2(v, OP_Found, j+2, 0); + sqlite3GenerateIndexKey(pParse, pIdx, 1, 3); + jmp2 = sqlite3VdbeAddOp3(v, OP_Found, j+2, 0, 3); addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr); sqlite3VdbeChangeP4(v, addr+1, "rowid ", P4_STATIC); sqlite3VdbeChangeP4(v, addr+3, " missing from index ", P4_STATIC); @@ -940,14 +953,12 @@ void sqlite3Pragma( { OP_Rewind, 0, 0, 0}, /* 1 */ { OP_AddImm, 3, 1, 0}, { OP_Next, 0, 0, 0}, /* 3 */ - { OP_SCopy, 2, 0, 0}, - { OP_SCopy, 3, 0, 0}, - { OP_Eq, 0, 0, 0}, /* 6 */ + { OP_Eq, 2, 0, 3}, /* 4 */ { OP_AddImm, 1, -1, 0}, - { OP_String8, 0, 0, 0}, /* 8 */ - { OP_String8, 0, 0, 0}, /* 9 */ - { OP_Concat, 0, 0, 0}, - { OP_Callback, 1, 0, 0}, + { OP_String8, 0, 2, 0}, /* 6 */ + { OP_String8, 0, 3, 0}, /* 7 */ + { OP_Concat, 3, 2, 2}, + { OP_ResultRow, 2, 1, 0}, }; if( pIdx->tnum==0 ) continue; addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); @@ -958,17 +969,17 @@ void sqlite3Pragma( sqlite3VdbeChangeP2(v, addr+1, addr+4); sqlite3VdbeChangeP1(v, addr+3, j+2); sqlite3VdbeChangeP2(v, addr+3, addr+2); - sqlite3VdbeJumpHere(v, addr+6); - sqlite3VdbeChangeP4(v, addr+8, + sqlite3VdbeJumpHere(v, addr+4); + sqlite3VdbeChangeP4(v, addr+6, "wrong # of entries in index ", P4_STATIC); - sqlite3VdbeChangeP4(v, addr+9, pIdx->zName, P4_STATIC); + sqlite3VdbeChangeP4(v, addr+7, pIdx->zName, P4_STATIC); } } } addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode); - sqlite3VdbeChangeP1(v, addr+1, mxErr); - sqlite3VdbeChangeP4(v, addr+3, "ok", P4_STATIC); - sqlite3VdbeJumpHere(v, addr+2); + sqlite3VdbeChangeP2(v, addr, -mxErr); + sqlite3VdbeJumpHere(v, addr+1); + sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC); }else #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ @@ -1015,14 +1026,14 @@ void sqlite3Pragma( if( sqlite3ReadSchema(pParse) ) goto pragma_out; sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "encoding", P4_STATIC); - sqlite3VdbeAddOp2(v, OP_String8, 0, 0); + sqlite3VdbeAddOp2(v, OP_String8, 0, 1); for(pEnc=&encnames[0]; pEnc->zName; pEnc++){ if( pEnc->enc==ENC(pParse->db) ){ sqlite3VdbeChangeP4(v, -1, pEnc->zName, P4_STATIC); break; } } - sqlite3VdbeAddOp2(v, OP_Callback, 1, 0); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); }else{ /* "PRAGMA encoding = XXX" */ /* Only change the value of sqlite.enc if the database handle is not ** initialized. If the main database exists, the new sqlite.enc value @@ -1109,8 +1120,8 @@ void sqlite3Pragma( }else{ /* Read the specified cookie value */ static const VdbeOpList readCookie[] = { - { OP_ReadCookie, 0, 0, 0}, /* 0 */ - { OP_Callback, 1, 0, 0} + { OP_ReadCookie, 0, 1, 0}, /* 0 */ + { OP_ResultRow, 1, 1, 0} }; int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie); sqlite3VdbeChangeP1(v, addr, iDb); @@ -1132,6 +1143,7 @@ void sqlite3Pragma( int i; Vdbe *v = sqlite3GetVdbe(pParse); sqlite3VdbeSetNumCols(v, 2); + pParse->nMem = 2; sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "database", P4_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "status", P4_STATIC); for(i=0; inDb; i++){ @@ -1140,7 +1152,7 @@ void sqlite3Pragma( const char *zState = "unknown"; int j; if( db->aDb[i].zName==0 ) continue; - sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, db->aDb[i].zName, P4_STATIC); + sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, db->aDb[i].zName, P4_STATIC); pBt = db->aDb[i].pBt; if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){ zState = "closed"; @@ -1148,8 +1160,8 @@ void sqlite3Pragma( SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){ zState = azLockName[j]; } - sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, zState, P4_STATIC); - sqlite3VdbeAddOp2(v, OP_Callback, 2, 0); + sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, zState, P4_STATIC); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2); } }else #endif diff --git a/src/select.c b/src/select.c index f7ab87c9ee..65aa362269 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.396 2008/01/10 03:46:36 drh Exp $ +** $Id: select.c,v 1.397 2008/01/10 23:50:11 drh Exp $ */ #include "sqliteInt.h" @@ -769,6 +769,9 @@ static void generateSortTail( int eDest = pDest->eDest; int iParm = pDest->iParm; + int regRow; + int regRowid; + iTab = pOrderBy->iECursor; if( eDest==SRT_Callback || eDest==SRT_Subroutine ){ pseudoTab = pParse->nTab++; @@ -777,35 +780,30 @@ static void generateSortTail( } addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, brk); codeOffset(v, p, cont, 0); - if( eDest==SRT_Callback || eDest==SRT_Subroutine ){ - sqlite3VdbeAddOp2(v, OP_Integer, 1, 0); - } - sqlite3VdbeAddOp2(v, OP_Column, iTab, pOrderBy->nExpr + 1); + regRow = sqlite3GetTempReg(pParse); + regRowid = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_Column, iTab, pOrderBy->nExpr + 1, regRow); switch( eDest ){ case SRT_Table: case SRT_EphemTab: { - sqlite3VdbeAddOp1(v, OP_NewRowid, iParm); - sqlite3VdbeAddOp2(v, OP_Pull, 1, 0); - sqlite3CodeInsert(pParse, iParm, OPFLAG_APPEND); + sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid); + sqlite3VdbeAddOp3(v, OP_Insert, iParm, regRow, regRowid); + sqlite3VdbeChangeP5(v, OPFLAG_APPEND); break; } #ifndef SQLITE_OMIT_SUBQUERY case SRT_Set: { - int j1, j2; + int j1; assert( nColumn==1 ); - sqlite3VdbeAddOp0(v, OP_SCopy); - j1 = sqlite3VdbeAddOp0(v, OP_NotNull); - sqlite3VdbeAddOp1(v, OP_Pop, 1); - j2 = sqlite3VdbeAddOp0(v, OP_Goto); + j1 = sqlite3VdbeAddOp1(v, OP_IsNull, regRow); + sqlite3VdbeAddOp4(v, OP_RegMakeRec, regRow, 1, regRow, &p->affinity, 1); + sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRow); sqlite3VdbeJumpHere(v, j1); - sqlite3VdbeAddOp4(v, OP_MakeRecord, 1, 0, 0, &p->affinity, 1); - sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, 0); - sqlite3VdbeJumpHere(v, j2); break; } case SRT_Mem: { assert( nColumn==1 ); - sqlite3VdbeAddOp2(v, OP_Move, 0, iParm); + sqlite3VdbeAddOp2(v, OP_Move, regRow, iParm); /* The LIMIT clause will terminate the loop for us */ break; } @@ -813,7 +811,8 @@ static void generateSortTail( case SRT_Callback: case SRT_Subroutine: { int i; - sqlite3CodeInsert(pParse, pseudoTab, 0); + sqlite3VdbeAddOp2(v, OP_Integer, 1, regRowid); + sqlite3VdbeAddOp3(v, OP_Insert, pseudoTab, regRow, regRowid); for(i=0; iiMem+i); } @@ -829,6 +828,8 @@ static void generateSortTail( break; } } + sqlite3ReleaseTempReg(pParse, regRow); + sqlite3ReleaseTempReg(pParse, regRowid); /* Jump to the end of the loop when the LIMIT is reached */ @@ -2651,165 +2652,6 @@ static int minMaxQuery(Parse *pParse, Select *p){ return ORDERBY_NORMAL; } -/* -** Analyze the SELECT statement passed in as an argument to see if it -** is a simple min() or max() query. If it is and this query can be -** satisfied using a single seek to the beginning or end of an index, -** then generate the code for this SELECT and return 1. If this is not a -** simple min() or max() query, then return 0; -** -** A simply min() or max() query looks like this: -** -** SELECT min(a) FROM table; -** SELECT max(a) FROM table; -** -** The query may have only a single table in its FROM argument. There -** can be no GROUP BY or HAVING or WHERE clauses. The result set must -** be the min() or max() of a single column of the table. The column -** in the min() or max() function must be indexed. -** -** The parameters to this routine are the same as for sqlite3Select(). -** See the header comment on that routine for additional information. -*/ -#if 0 -static int simpleMinMaxQuery(Parse *pParse, Select *p, SelectDest *pDest){ - Expr *pExpr; - int iCol; - Table *pTab; - Index *pIdx; - int base; - Vdbe *v; - int seekOp; - ExprList *pEList, *pList, eList; - struct ExprList_item eListItem; - SrcList *pSrc; - int brk; - int iDb; - - /* Check to see if this query is a simple min() or max() query. Return - ** zero if it is not. - */ - if( p->pGroupBy || p->pHaving || p->pWhere ) return 0; - pSrc = p->pSrc; - if( pSrc->nSrc!=1 ) return 0; - pEList = p->pEList; - if( pEList->nExpr!=1 ) return 0; - pExpr = pEList->a[0].pExpr; - if( pExpr->op!=TK_AGG_FUNCTION ) return 0; - pList = pExpr->pList; - if( pList==0 || pList->nExpr!=1 ) return 0; - if( pExpr->token.n!=3 ) return 0; - if( sqlite3StrNICmp((char*)pExpr->token.z,"min",3)==0 ){ - seekOp = OP_Rewind; - }else if( sqlite3StrNICmp((char*)pExpr->token.z,"max",3)==0 ){ - seekOp = OP_Last; - }else{ - return 0; - } - pExpr = pList->a[0].pExpr; - if( pExpr->op!=TK_COLUMN ) return 0; - iCol = pExpr->iColumn; - pTab = pSrc->a[0].pTab; - - /* This optimization cannot be used with virtual tables. */ - if( IsVirtual(pTab) ) return 0; - - /* If we get to here, it means the query is of the correct form. - ** Check to make sure we have an index and make pIdx point to the - ** appropriate index. If the min() or max() is on an INTEGER PRIMARY - ** key column, no index is necessary so set pIdx to NULL. If no - ** usable index is found, return 0. - */ - if( iCol<0 ){ - pIdx = 0; - }else{ - CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr); - if( pColl==0 ) return 0; - for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - assert( pIdx->nColumn>=1 ); - if( pIdx->aiColumn[0]==iCol && - 0==sqlite3StrICmp(pIdx->azColl[0], pColl->zName) ){ - break; - } - } - if( pIdx==0 ) return 0; - } - - /* Identify column types if we will be using the callback. This - ** step is skipped if the output is going to a table or a memory cell. - ** The column names have already been generated in the calling function. - */ - v = sqlite3GetVdbe(pParse); - if( v==0 ) return 0; - - /* If the output is destined for a temporary table, open that table. - */ - if( pDest->eDest==SRT_EphemTab ){ - sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iParm, 1); - } - - /* Generating code to find the min or the max. Basically all we have - ** to do is find the first or the last entry in the chosen index. If - ** the min() or max() is on the INTEGER PRIMARY KEY, then find the first - ** or last entry in the main table. - */ - iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - assert( iDb>=0 || pTab->isEphem ); - sqlite3CodeVerifySchema(pParse, iDb); - sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); - base = pSrc->a[0].iCursor; - brk = sqlite3VdbeMakeLabel(v); - computeLimitRegisters(pParse, p, brk); - if( pSrc->a[0].pSelect==0 ){ - sqlite3OpenTable(pParse, base, iDb, pTab, OP_OpenRead); - } - if( pIdx==0 ){ - sqlite3VdbeAddOp2(v, seekOp, base, 0); - }else{ - /* Even though the cursor used to open the index here is closed - ** as soon as a single value has been read from it, allocate it - ** using (pParse->nTab++) to prevent the cursor id from being - ** reused. This is important for statements of the form - ** "INSERT INTO x SELECT max() FROM x". - */ - int iIdx; - KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); - iIdx = pParse->nTab++; - assert( pIdx->pSchema==pTab->pSchema ); - sqlite3VdbeAddOp4(v, OP_OpenRead, iIdx, pIdx->tnum, iDb, - (char*)pKey, P4_KEYINFO_HANDOFF); - if( seekOp==OP_Rewind ){ - sqlite3VdbeAddOp2(v, OP_Null, 0, 0); - sqlite3VdbeAddOp2(v, OP_MakeRecord, 1, 0); - seekOp = OP_MoveGt; - } - if( pIdx->aSortOrder[0]==SQLITE_SO_DESC ){ - /* Ticket #2514: invert the seek operator if we are using - ** a descending index. */ - if( seekOp==OP_Last ){ - seekOp = OP_Rewind; - }else{ - assert( seekOp==OP_MoveGt ); - seekOp = OP_MoveLt; - } - } - sqlite3VdbeAddOp2(v, seekOp, iIdx, 0); - sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdx, 0); - sqlite3VdbeAddOp2(v, OP_Close, iIdx, 0); - sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0); - } - eList.nExpr = 1; - memset(&eListItem, 0, sizeof(eListItem)); - eList.a = &eListItem; - eList.a[0].pExpr = pExpr; - selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, pDest, brk, brk, 0); - sqlite3VdbeResolveLabel(v, brk); - sqlite3VdbeAddOp2(v, OP_Close, base, 0); - - return 1; -} -#endif - /* ** This routine resolves any names used in the result set of the ** supplied SELECT statement. If the SELECT statement being resolved diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 6f6842acde..52ee5db32f 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.646 2008/01/10 03:46:36 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.647 2008/01/10 23:50:11 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1766,7 +1766,7 @@ WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u8); void sqlite3WhereEnd(WhereInfo*); void sqlite3ExprCodeGetColumn(Vdbe*, Table*, int, int, int); int sqlite3ExprCode(Parse*, Expr*, int); -void sqlite3ExprCodeAndCache(Parse*, Expr*); +void sqlite3ExprCodeAndCache(Parse*, Expr*, int); int sqlite3ExprCodeExprList(Parse*, ExprList*, int); void sqlite3ExprIfTrue(Parse*, Expr*, int, int); void sqlite3ExprIfFalse(Parse*, Expr*, int, int); @@ -1795,9 +1795,9 @@ int sqlite3ExprIsConstantNotJoin(Expr*); int sqlite3ExprIsConstantOrFunction(Expr*); int sqlite3ExprIsInteger(Expr*, int*); int sqlite3IsRowid(const char*); -void sqlite3GenerateRowDelete(sqlite3*, Vdbe*, Table*, int, int, int); -void sqlite3GenerateRowIndexDelete(Vdbe*, Table*, int, int*); -void sqlite3GenerateIndexKey(Vdbe*, Index*, int); +void sqlite3GenerateRowDelete(Parse*, Table*, int, int, int); +void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int*); +int sqlite3GenerateIndexKey(Parse*, Index*, int, int); void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int, int*,int,int,int,int); void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*,int,int,int,int); diff --git a/src/trigger.c b/src/trigger.c index bd928916c9..0204cae180 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -227,43 +227,20 @@ void sqlite3FinishTrigger( ** build the sqlite_master entry */ if( !db->init.busy ){ - static const VdbeOpList insertTrig[] = { - { OP_NewRowid, 0, 0, 0 }, - { OP_String8, 0, 0, 0 }, /* 1: "trigger" */ - { OP_String8, 0, 0, 0 }, /* 2: trigger name */ - { OP_String8, 0, 0, 0 }, /* 3: table name */ - { OP_Integer, 0, 0, 0 }, - { OP_String8, 0, 0, 0 }, /* 5: "CREATE TRIGGER " */ - { OP_String8, 0, 0, 0 }, /* 6: SQL */ - { OP_Concat, 0, 0, 0 }, - { OP_MakeRecord, 5, 0, 0 }, /* 8: "aaada" */ - { OP_Move, 0, 0, 0 }, /* 9: Store data */ - { OP_Move, 0, 0, 0 }, /* 10: Store key */ - { OP_Insert, 0, 0, 0 }, - }; - int addr; Vdbe *v; - int iKey = ++pParse->nMem; - int iData = ++pParse->nMem; + char *z; /* Make an entry in the sqlite_master table */ v = sqlite3GetVdbe(pParse); if( v==0 ) goto triggerfinish_cleanup; sqlite3BeginWriteOperation(pParse, 0, iDb); - sqlite3OpenMasterTable(pParse, iDb); - addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig); - sqlite3VdbeChangeP4(v, addr+1, "trigger", P4_STATIC); - sqlite3VdbeChangeP4(v, addr+2, pTrig->name, 0); - sqlite3VdbeChangeP4(v, addr+3, pTrig->table, 0); - sqlite3VdbeChangeP4(v, addr+5, "CREATE TRIGGER ", P4_STATIC); - sqlite3VdbeChangeP4(v, addr+6, (char*)pAll->z, pAll->n); - sqlite3VdbeChangeP4(v, addr+8, "aaada", P4_STATIC); - sqlite3VdbeChangeP2(v, addr+9, iData); - sqlite3VdbeChangeP2(v, addr+10, iKey); - sqlite3VdbeChangeP2(v, addr+11, iData); - sqlite3VdbeChangeP3(v, addr+11, iKey); + z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n); + sqlite3NestedParse(pParse, + "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", + db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pTrig->name, + pTrig->table, z); + sqlite3_free(z); sqlite3ChangeCookie(db, v, iDb); - sqlite3VdbeAddOp2(v, OP_Close, 0, 0); sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, sqlite3MPrintf( db, "type='trigger' AND name='%q'", pTrig->name), P4_DYNAMIC ); diff --git a/src/update.c b/src/update.c index 0457075464..6d1a21f414 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.166 2008/01/09 23:04:12 drh Exp $ +** $Id: update.c,v 1.167 2008/01/10 23:50:11 drh Exp $ */ #include "sqliteInt.h" @@ -404,50 +404,60 @@ void sqlite3Update( sqlite3VdbeAddOp2(v, OP_StackDepth, -1, 0); if( triggers_exist ){ + int regRowid; + int regRow; + int regCols; + /* Make cursor iCur point to the record that is being updated. */ sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid); /* Generate the OLD table */ - sqlite3VdbeAddOp2(v, OP_Rowid, iCur, 0); + regRowid = sqlite3GetTempReg(pParse); + regRow = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regRowid); if( !old_col_mask ){ - sqlite3VdbeAddOp2(v, OP_Null, 0, 0); + sqlite3VdbeAddOp2(v, OP_Null, 0, regRow); }else{ - sqlite3VdbeAddOp1(v, OP_RowData, iCur); + sqlite3VdbeAddOp2(v, OP_RowData, iCur, regRow); } - sqlite3CodeInsert(pParse, oldIdx, 0); + sqlite3VdbeAddOp3(v, OP_Insert, oldIdx, regRow, regRowid); /* Generate the NEW table */ if( chngRowid ){ - sqlite3ExprCodeAndCache(pParse, pRowidExpr); + sqlite3ExprCodeAndCache(pParse, pRowidExpr, regRowid); }else{ - sqlite3VdbeAddOp2(v, OP_Rowid, iCur, 0); + sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regRowid); } + regCols = sqlite3GetTempRange(pParse, pTab->nCol); for(i=0; inCol; i++){ if( i==pTab->iPKey ){ - sqlite3VdbeAddOp2(v, OP_Null, 0, 0); + sqlite3VdbeAddOp2(v, OP_Null, 0, regCols+i); continue; } j = aXRef[i]; if( new_col_mask&((u32)1<a[j].pExpr); + sqlite3ExprCodeAndCache(pParse, pChanges->a[j].pExpr, regCols+i); } }else{ - sqlite3VdbeAddOp2(v, OP_Null, 0, 0); + sqlite3VdbeAddOp2(v, OP_Null, 0, regCols+i); } } - sqlite3VdbeAddOp2(v, OP_MakeRecord, pTab->nCol, 0); + sqlite3VdbeAddOp3(v, OP_RegMakeRec, regCols, pTab->nCol, regRow); if( !isView ){ sqlite3TableAffinityStr(v, pTab); } + sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol); if( pParse->nErr ) goto update_cleanup; - sqlite3CodeInsert(pParse, newIdx, 0); + sqlite3VdbeAddOp3(v, OP_Insert, newIdx, regRow, regRowid); + sqlite3ReleaseTempReg(pParse, regRowid); + sqlite3ReleaseTempReg(pParse, regRow); sqlite3VdbeAddOp2(v, OP_Goto, 0, iBeginBeforeTrigger); sqlite3VdbeJumpHere(v, iEndBeforeTrigger); @@ -495,7 +505,7 @@ void sqlite3Update( /* Delete the old indices for the current record. */ - sqlite3GenerateRowIndexDelete(v, pTab, iCur, aRegIdx); + sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, aRegIdx); /* If changing the record number, delete the old record. */ diff --git a/src/vdbe.c b/src/vdbe.c index b5063fb4a5..66c49af600 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.691 2008/01/09 23:04:12 drh Exp $ +** $Id: vdbe.c,v 1.692 2008/01/10 23:50:11 drh Exp $ */ #include "sqliteInt.h" #include @@ -1121,10 +1121,12 @@ case OP_SCopy: { assert( pOp->p2<=p->nMem ); pOut = &p->aMem[pOp->p2]; } + assert( pOut!=pIn1 ); if( pOp->opcode==OP_Move ){ rc = sqlite3VdbeMemMove(pOut, pIn1); if( pOp->p1==0 ) pTos--; }else{ + Release(pOut); sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); if( pOp->opcode==OP_Copy ){ Deephemeralize(pOut); @@ -1168,56 +1170,6 @@ case OP_Pull: { /* no-push */ break; } -/* Opcode: Callback P1 * * -** -** The top P1 values on the stack represent a single result row from -** a query. This opcode causes the sqlite3_step() call to terminate -** with an SQLITE_ROW return code and it sets up the sqlite3_stmt -** structure to provide access to the top P1 values as the result -** row. When the sqlite3_step() function is run again, the top P1 -** values will be automatically popped from the stack before the next -** instruction executes. -*/ -case OP_Callback: { /* no-push */ - Mem *pMem; - Mem *pFirstColumn; - assert( p->nResColumn==pOp->p1 ); - - /* Data in the pager might be moved or changed out from under us - ** in between the return from this sqlite3_step() call and the - ** next call to sqlite3_step(). So deephermeralize everything on - ** the stack. Note that ephemeral data is never stored in memory - ** cells so we do not have to worry about them. - */ - pFirstColumn = &pTos[1-pOp->p1]; - for(pMem = p->aStack; pMemcacheCtr = (p->cacheCtr + 2)|1; - - /* Make sure the results of the current row are \000 terminated - ** and have an assigned type. The results are deephemeralized as - ** as side effect. - */ - for(; pMem<=pTos; pMem++ ){ - sqlite3VdbeMemNulTerminate(pMem); - storeTypeInfo(pMem, encoding); - } - - /* Set up the statement structure so that it will pop the current - ** results from the stack when the statement returns. - */ - p->pResultSet = pFirstColumn; - p->nCallback++; - p->popStack = pOp->p1; - p->pc = pc + 1; - p->pTos = pTos; - rc = SQLITE_ROW; - goto vdbe_return; -} - /* Opcode: ResultRow P1 P2 * ** ** The registers P1 throught P1+P2-1 contain a single row of @@ -1988,9 +1940,8 @@ case OP_Not: { /* same as TK_NOT, no-push, in1 */ nPop = 0; if( pIn1->flags & MEM_Null ) break; /* Do nothing to NULLs */ sqlite3VdbeMemIntegerify(pIn1); - assert( (pIn1->flags & MEM_Dyn)==0 ); pIn1->u.i = !pIn1->u.i; - pIn1->flags = MEM_Int; + assert( pIn1->flags==MEM_Int ); break; } @@ -2004,9 +1955,8 @@ case OP_BitNot: { /* same as TK_BITNOT, no-push, in1 */ nPop = 0; if( pIn1->flags & MEM_Null ) break; /* Do nothing to NULLs */ sqlite3VdbeMemIntegerify(pIn1); - assert( (pIn1->flags & MEM_Dyn)==0 ); pIn1->u.i = ~pIn1->u.i; - pIn1->flags = MEM_Int; + assert( pIn1->flags==MEM_Int ); break; } @@ -2078,17 +2028,25 @@ case OP_StackIsNull: { /* no-push, jump */ break; } -/* Opcode: IsNull P1 P2 * * * +/* Opcode: IsNull P1 P2 P3 * * ** -** Jump to P2 if the value in register P1 is NULL. +** Jump to P2 if the value in register P1 is NULL. If P3 is greater +** than zero, then check all values reg(P1), reg(P1+1), +** reg(P1+2), ..., reg(P1+P3-1). ** ** If P1 is 0 then use the top of the stack instead of a register ** and pop the stack regardless of whether or not the jump is taken. */ case OP_IsNull: { /* same as TK_ISNULL, no-push, jump, in1 */ - if( (pIn1->flags & MEM_Null)!=0 ){ - pc = pOp->p2 - 1; - } + int n = pOp->p3; + assert( pOp->p3==0 || pOp->p1>0 ); + do{ + if( (pIn1->flags & MEM_Null)!=0 ){ + pc = pOp->p2 - 1; + break; + } + pIn1++; + }while( --n > 0 ); break; } @@ -2409,15 +2367,6 @@ op_column_out: ** macros defined in sqliteInt.h. ** ** If P4 is NULL then all index fields have the affinity NONE. -** -** See also OP_MakeIdxRec -*/ -/* Opcode: MakeIdxRec P1 P2 P4 -** -** This opcode works just OP_MakeRecord except that it reads an extra -** integer from the stack (thus reading a total of abs(P1+1) entries) -** and appends that extra integer to the end of the record as a varint. -** This results in an index key. */ /* ** Opcode: RegMakeRec P1 P2 P3 P4 * @@ -2428,17 +2377,7 @@ op_column_out: ** There is no jump on NULL - that can be done with a separate ** OP_AnyNull opcode. */ -/* -** Opcode: RegMakeIRec P1 P2 P4 -** -** Works like OP_MakeIdxRec except data is taken from registers -** rather than from the stack. The P1 register is an integer which -** is the number of register to use in building the new record. -** Data is taken from P1+1, P1+2, ..., P1+mem[P1]. -*/ case OP_RegMakeRec: -case OP_RegMakeIRec: -case OP_MakeIdxRec: /* jump */ case OP_MakeRecord: { /* jump */ /* Assuming the record contains N fields, the record format looks ** like this: @@ -2457,7 +2396,6 @@ case OP_MakeRecord: { /* jump */ */ u8 *zNewRecord; /* A buffer to hold the data for the new record */ Mem *pRec; /* The new record */ - Mem *pRowid = 0; /* Rowid appended to the new record */ u64 nData = 0; /* Number of bytes of data space */ int nHdr = 0; /* Number of bytes of header space */ u64 nByte = 0; /* Data space required for this record */ @@ -2470,24 +2408,22 @@ case OP_MakeRecord: { /* jump */ int leaveOnStack; /* If true, leave the entries on the stack */ int nField; /* Number of fields in the record */ int jumpIfNull; /* Jump here if non-zero and any entries are NULL. */ - int addRowid; /* True to append a rowid column at the end */ char *zAffinity; /* The affinity string for the record */ int file_format; /* File format to use for encoding */ int i; /* Space used in zNewRecord[] */ char zTemp[NBFS]; /* Space to hold small records */ if( pOp->p1<0 ){ - assert( pOp->opcode==OP_MakeRecord || pOp->opcode==OP_MakeIdxRec ); + assert( pOp->opcode==OP_MakeRecord ); leaveOnStack = 1; nField = -pOp->p1; }else{ leaveOnStack = 0; nField = pOp->p1; } - addRowid = pOp->opcode==OP_MakeIdxRec || pOp->opcode==OP_RegMakeIRec; zAffinity = pOp->p4.z; - if( pOp->opcode==OP_RegMakeRec || pOp->opcode==OP_RegMakeIRec ){ + if( pOp->opcode==OP_RegMakeRec ){ assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=p->nMem ); pData0 = &p->aMem[nField]; nField = pOp->p2; @@ -2530,20 +2466,6 @@ case OP_MakeRecord: { /* jump */ } } - /* If we have to append a varint rowid to this record, set pRowid - ** to the value of the rowid and increase nByte by the amount of space - ** required to store it. - */ - if( addRowid ){ - pRowid = &pData0[-1]; - assert( pRowid>=p->aStack ); - sqlite3VdbeMemIntegerify(pRowid); - serial_type = sqlite3VdbeSerialType(pRowid, 0); - nData += sqlite3VdbeSerialTypeLen(serial_type); - nHdr += sqlite3VarintLen(serial_type); - nZero = 0; - } - /* Add the initial header varint and total the size */ nHdr += nVarint = sqlite3VarintLen(nHdr); if( nVarintp3==0 ){ pOut = ++pTos; @@ -3434,7 +3350,7 @@ case OP_IsUnique: { /* no-push, jump, in3 */ */ nPop = 0; pIn3->u.i = v; - pIn3->flags = MEM_Int; + assert( pIn3->flags==MEM_Int ); } break; } diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 296e8e73ce..39bbcd0dfa 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -395,7 +395,6 @@ void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){ ** This routine is useful for setting a jump destination. */ void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){ - assert( val>=0 ); assert( p==0 || p->magic==VDBE_MAGIC_INIT ); if( p && addr>=0 && p->nOp>addr && p->aOp ){ p->aOp[addr].p2 = val; diff --git a/src/vdbeblob.c b/src/vdbeblob.c index 864aadd9b7..1fa71f1218 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -12,7 +12,7 @@ ** ** This file contains code used to implement incremental BLOB I/O. ** -** $Id: vdbeblob.c,v 1.17 2008/01/03 07:54:24 danielk1977 Exp $ +** $Id: vdbeblob.c,v 1.18 2008/01/10 23:50:11 drh Exp $ */ #include "sqliteInt.h" @@ -54,7 +54,7 @@ int sqlite3_blob_open( ** vdbe program will take advantage of the various transaction, ** locking and error handling infrastructure built into the vdbe. ** - ** After seeking the cursor, the vdbe executes an OP_Callback. + ** After seeking the cursor, the vdbe executes an OP_ResultRow. ** Code external to the Vdbe then "borrows" the b-tree cursor and ** uses it to implement the blob_read(), blob_write() and ** blob_bytes() functions. @@ -74,10 +74,10 @@ int sqlite3_blob_open( {OP_OpenWrite, 0, 0, 0}, /* 3: Open cursor 0 for read/write */ {OP_SetNumColumns, 0, 0, 0}, /* 4: Num cols for cursor */ - {OP_Variable, 1, 0, 0}, /* 5: Push the rowid to the stack */ - {OP_NotExists, 0, 10, 0}, /* 6: Seek the cursor */ - {OP_Column, 0, 0, 0}, /* 7 */ - {OP_Callback, 0, 0, 0}, /* 8 */ + {OP_Variable, 1, 1, 0}, /* 5: Push the rowid to the stack */ + {OP_NotExists, 0, 10, 1}, /* 6: Seek the cursor */ + {OP_Column, 0, 0, 1}, /* 7 */ + {OP_ResultRow, 1, 0, 0}, /* 8 */ {OP_Close, 0, 0, 0}, /* 9 */ {OP_Halt, 0, 0, 0}, /* 10 */ }; @@ -181,7 +181,7 @@ int sqlite3_blob_open( */ sqlite3VdbeChangeP2(v, 4, pTab->nCol+1); if( !db->mallocFailed ){ - sqlite3VdbeMakeReady(v, 1, 0, 1, 0); + sqlite3VdbeMakeReady(v, 1, 1, 1, 0); } }