From: drh Date: Tue, 8 Jan 2008 02:57:55 +0000 (+0000) Subject: Progress toward registerification of the constraint checking logic for X-Git-Tag: version-3.6.10~1484 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=aa9b8963b546117c970411fab3b90c6166bb7581;p=thirdparty%2Fsqlite.git Progress toward registerification of the constraint checking logic for INSERT and UPDATE. (CVS 4693) FossilOrigin-Name: b9bf509e39f5ac38c2149d2a648f68e5df5ae9e3 --- diff --git a/manifest b/manifest index 06f45be099..02b0ee81f4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Registerify\sthe\sAUTOINCREMENT\sprocessing\sand\sthe\sOP_IsNull\sand\sOP_NotNull\noperators.\s(CVS\s4692) -D 2008-01-07T19:20:25 +C Progress\stoward\sregisterification\sof\sthe\sconstraint\schecking\slogic\sfor\nINSERT\sand\sUPDATE.\s(CVS\s4693) +D 2008-01-08T02:57:56 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -90,13 +90,13 @@ F src/build.c 22b50a462d7b2be82e29071069d1c3daf29e953f F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0 F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131 F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6 -F src/delete.c 09c7b312a061d08df8a95b1f75cb10c6af14114a +F src/delete.c d78e46b259a94a5f98a1bceee206c5fd21276ae7 F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b -F src/expr.c f84b4901dff3bacd08ece3f0de09318a5a298121 +F src/expr.c 6f2a852227ba2abd5ad0916f539c1f2159da28b4 F src/func.c 996071cf0af9d967e58b69fce1909555059ebc7d F src/hash.c 45a7005aac044b6c86bd7e49c44bc15d30006d6c F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53 -F src/insert.c 9c1a6501d79c9c4e674e0e2c3bc4a5207f9b3b95 +F src/insert.c 3a45102002b611aa1707bb6c6c5c148547d2630a F src/journal.c 807bed7a158979ac8d63953e1774e8d85bff65e2 F src/legacy.c 4ac53191fad2e3c4d59bde1228879b2dc5a96d66 F src/limits.h 71ab25f17e35e0a9f3f6f234b8ed49cc56731d35 @@ -136,7 +136,7 @@ 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 95cdddce11ee871fad1d91d6b6e405969dcc405f +F src/sqliteInt.h 964754dcd508ddf0dd0b326072ad80678452e5c2 F src/sqliteLimit.h ee4430f88f69bf63527967bb35ca52af7b0ccb1e F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4 F src/tclsqlite.c 9923abeffc9b3d7dad58e92b319661521f60debf @@ -164,18 +164,18 @@ F src/test_tclvar.c b2d1115e4d489179d3f029e765211b2ad527ba59 F src/test_thread.c e297dd41db0b249646e69f97d36ec13e56e8b730 F src/tokenize.c a4e04438c11fed2c67ec47fe3edbef9cca2d1b48 F src/trigger.c 33071215111825634b85567bfc36c14094eebe54 -F src/update.c 38e9e4c27896df2d189927e3b483cadf5641f47c +F src/update.c acd1c38dbbf253183fe2a8e5be0b3f3fee59be15 F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736 F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624 F src/vacuum.c 3f34f278809bf3eb0b62ec46ff779e9c385b28f0 -F src/vdbe.c 3d849013558e52b2c85134fc6ed655d6dc00ace7 +F src/vdbe.c e71595acce83c585c31ac0551cee1c8cf9540fd2 F src/vdbe.h bb128757b84280504a1243c450fd13ead248ede5 F src/vdbeInt.h 31bd686595356284d5484592e2dc6e58025aa346 F src/vdbeapi.c f14174843bf4be2c9afdf2ef48b61e7c3ac62d7c -F src/vdbeaux.c 75b7d3e42c94310f28f6f7d3e08b69797fbe8a78 +F src/vdbeaux.c b6241be0277795ecd902743366434704f03b7636 F src/vdbeblob.c b90f7494c408d47ce6835000b01e40b371e27baf F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6 -F src/vdbemem.c 123994fcd344993d2fb050a83b91b341bbbd08b4 +F src/vdbemem.c a94f3e9e85578ba457133ad3446fc6114a03ec5a F src/vtab.c 03014b2bfa8096ecac5fcdc80d34cd76e06af52a F src/where.c 306fafa709ced14b1c816d38b96a8f4446ec1eeb F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617 @@ -604,7 +604,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P 38020592f15c072e0d221ae2e0df13508ac4bd49 -R dde2d5dbca593f8bc201758cd5d40a3d +P aa48867cfa04da265b906e5b583bc7ac6b6a1157 +R af4f73c6bffdbedd3861a3c5eb6d920e U drh -Z 07f47472df3751ae71471b817e3e70f7 +Z 313f66697e8ae592eab31fdd061363d6 diff --git a/manifest.uuid b/manifest.uuid index 8eebc9f5c4..bf6b8b32fb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -aa48867cfa04da265b906e5b583bc7ac6b6a1157 \ No newline at end of file +b9bf509e39f5ac38c2149d2a648f68e5df5ae9e3 \ No newline at end of file diff --git a/src/delete.c b/src/delete.c index 65333f6356..2a416e93d2 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.152 2008/01/06 00:25:22 drh Exp $ +** $Id: delete.c,v 1.153 2008/01/08 02:57:56 drh Exp $ */ #include "sqliteInt.h" @@ -492,13 +492,13 @@ void sqlite3GenerateRowIndexDelete( Vdbe *v, /* Generate code into this VDBE */ Table *pTab, /* Table containing the row to be deleted */ int iCur, /* Cursor number for the table */ - char *aIdxUsed /* Only delete if aIdxUsed!=0 && aIdxUsed[i]!=0 */ + int *aRegIdx /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */ ){ int i; Index *pIdx; for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ - if( aIdxUsed!=0 && aIdxUsed[i-1]==0 ) continue; + if( aRegIdx!=0 && aRegIdx[i-1]==0 ) continue; sqlite3GenerateIndexKey(v, pIdx, iCur); sqlite3VdbeAddOp1(v, OP_IdxDelete, iCur+i); } diff --git a/src/expr.c b/src/expr.c index d332e4f866..651f1cd9ac 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.336 2008/01/07 19:20:25 drh Exp $ +** $Id: expr.c,v 1.337 2008/01/08 02:57:56 drh Exp $ */ #include "sqliteInt.h" #include @@ -1944,15 +1944,12 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ Vdbe *v = pParse->pVdbe; int op; int inReg = 0; - int stackChng = 0; int origTarget = target; assert( v!=0 || pParse->db->mallocFailed ); if( v==0 ) return 0; if( target<0 ){ target = ++pParse->nMem; - }else if( target==0 ){ - stackChng = 1; } if( pExpr==0 ){ @@ -1979,9 +1976,8 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ case TK_COLUMN: { if( pExpr->iTable<0 ){ /* This only happens when coding check constraints */ - assert( pParse->ckOffset>0 ); - sqlite3VdbeAddOp1(v, OP_SCopy, -(pParse->ckOffset-pExpr->iColumn-1)); - /* inReg = -(pParse->ckOffset-pExpr->iColumn-1); */ + assert( pParse->ckBase>0 ); + inReg = pExpr->iColumn + pParse->ckBase; }else{ sqlite3ExprCodeGetColumn(v, pExpr->pTab, pExpr->iColumn, pExpr->iTable, target); @@ -2052,7 +2048,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ assert( to_op==OP_ToInt || aff!=SQLITE_AFF_INTEGER ); assert( to_op==OP_ToReal || aff!=SQLITE_AFF_REAL ); sqlite3VdbeAddOp1(v, to_op, target); - stackChng = 0; inReg = target; break; } @@ -2072,7 +2067,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ sqlite3ExprCode(pParse, pExpr->pLeft, 0); sqlite3ExprCode(pParse, pExpr->pRight, 0); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, 0, 0); - stackChng = -1; break; } case TK_AND: @@ -2099,12 +2093,9 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ assert( TK_LSHIFT==OP_ShiftLeft ); assert( TK_RSHIFT==OP_ShiftRight ); assert( TK_CONCAT==OP_Concat ); - r1 = sqlite3ExprCode(pParse, pExpr->pLeft, 0); - r2 = sqlite3ExprCode(pParse, pExpr->pRight, 0); + r1 = sqlite3ExprCode(pParse, pExpr->pLeft, -1); + r2 = sqlite3ExprCode(pParse, pExpr->pRight, -1); sqlite3VdbeAddOp3(v, op, r2, r1, target); - if( r1==0 ) stackChng--; - if( r2==0 ) stackChng--; - if( target==0 ) stackChng++; inReg = target; break; } @@ -2129,7 +2120,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ assert( TK_NOT==OP_Not ); sqlite3ExprCode(pParse, pExpr->pLeft, 0); sqlite3VdbeAddOp0(v, op); - stackChng = 0; break; } case TK_ISNULL: @@ -2142,7 +2132,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ addr = sqlite3VdbeAddOp0(v, op); sqlite3VdbeAddOp2(v, OP_AddImm, target, -1); sqlite3VdbeJumpHere(v, addr); - stackChng = 0; inReg = target; break; } @@ -2207,7 +2196,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ } sqlite3VdbeAddOp4(v, OP_Function, constMask, nExpr, 0, (char*)pDef, P4_FUNCDEF); - stackChng = 1-nExpr; break; } #ifndef SQLITE_OMIT_SUBQUERY @@ -2224,7 +2212,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ case TK_IN: { int j1, j2, j3, j4, j5; char affinity; - int ckOffset = pParse->ckOffset; int eType; eType = sqlite3FindInIndex(pParse, pExpr, 0); @@ -2236,7 +2223,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ affinity = comparisonAffinity(pExpr); sqlite3VdbeAddOp1(v, OP_Integer, 1); - pParse->ckOffset = (ckOffset ? (ckOffset+1) : 0); /* Code the from " IN (...)". The temporary table ** pExpr->iTable contains the values that make up the (...) set. @@ -2282,7 +2268,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ } case TK_UPLUS: { inReg = sqlite3ExprCode(pParse, pExpr->pLeft, origTarget); - stackChng = 0; break; } case TK_CASE: { @@ -2349,7 +2334,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->trigStack->ignoreJump); VdbeComment((v, "raise(IGNORE)")); } - stackChng = 0; break; } #endif @@ -2360,11 +2344,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ }else{ target = inReg; } - stackChng = 0; - } - if( pParse->ckOffset ){ - pParse->ckOffset += stackChng; - assert( pParse->ckOffset ); } return target; } @@ -2443,7 +2422,6 @@ int sqlite3ExprCodeExprList( void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ Vdbe *v = pParse->pVdbe; int op = 0; - int ckOffset = pParse->ckOffset; if( v==0 || pExpr==0 ) return; op = pExpr->op; switch( op ){ @@ -2518,7 +2496,6 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ break; } } - pParse->ckOffset = ckOffset; } /* @@ -2532,7 +2509,6 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ Vdbe *v = pParse->pVdbe; int op = 0; - int ckOffset = pParse->ckOffset; if( v==0 || pExpr==0 ) return; /* The value of pExpr->op and op are related as follows: @@ -2629,7 +2605,6 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ break; } } - pParse->ckOffset = ckOffset; } /* diff --git a/src/insert.c b/src/insert.c index c4fe10717c..a9ba0ea2ee 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.215 2008/01/07 19:20:25 drh Exp $ +** $Id: insert.c,v 1.216 2008/01/08 02:57:56 drh Exp $ */ #include "sqliteInt.h" @@ -373,6 +373,7 @@ void sqlite3Insert( int regRowid; /* registers holding insert rowid */ int regData; /* register holding first column to insert */ int regRecord; /* Holds the assemblied row record */ + int *aRegIdx = 0; /* One register allocated to each index */ #ifndef SQLITE_OMIT_TRIGGER @@ -631,8 +632,18 @@ void sqlite3Insert( /* If this is not a view, open the table and and all indices */ if( !isView ){ + int nIdx; + int i; + base = pParse->nTab; - sqlite3OpenTableAndIndices(pParse, pTab, base, OP_OpenWrite); + nIdx = sqlite3OpenTableAndIndices(pParse, pTab, base, OP_OpenWrite); + aRegIdx = sqlite3DbMallocZero(db, sizeof(int)*(nIdx+1)); + if( aRegIdx==0 ){ + goto insert_cleanup; + } + for(i=0; inMem; + } } /* If the data source is a temporary table, then we have to create @@ -830,9 +841,9 @@ void sqlite3Insert( #endif { sqlite3RegToStack(pParse, regIns, pTab->nCol+1); - sqlite3GenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0, + sqlite3GenerateConstraintChecks(pParse, pTab, base, aRegIdx, keyColumn>=0, 0, onError, endOfLoop); - sqlite3CompleteInsertion(pParse, pTab, base, 0,0,0, + sqlite3CompleteInsertion(pParse, pTab, base, aRegIdx,0,0, (triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1, appendFlag); } @@ -895,6 +906,7 @@ insert_cleanup: sqlite3ExprListDelete(pList); sqlite3SelectDelete(pSelect); sqlite3IdListDelete(pColumn); + sqlite3_free(aRegIdx); } /* @@ -919,11 +931,11 @@ insert_cleanup: ** and rowidChng are 1. isUpdate is true for UPDATEs and false for ** INSERTs and rowidChng is true if the record number is being changed. ** -** The code generated by this routine pushes additional entries onto -** the stack which are the keys for new index entries for the new record. -** The order of index keys is the same as the order of the indices on -** the pTable->pIndex list. A key is only created for index i if -** aIdxUsed!=0 and aIdxUsed[i]!=0. +** The code generated by this routine store new index entries into +** registers identified by aRegIdx[]. No index entry is created for +** indices where aRegIdx[i]==0. The order of indices in aRegIdx[] is +** the same as the order of indices on the linked list of indices +** attached to the table. ** ** This routine also generates code to check constraints. NOT NULL, ** CHECK, and UNIQUE constraints are all checked. If a constraint fails, @@ -968,7 +980,7 @@ insert_cleanup: ** cursor number "base". All indices of pTab must also have open ** read/write cursors with cursor number base+i for the i-th cursor. ** Except, if there is no possibility of a REPLACE action then -** cursors do not need to be open for indices where aIdxUsed[i]==0. +** cursors do not need to be open for indices where aRegIdx[i]==0. ** ** If the isUpdate flag is true, it means that the "base" cursor is ** initially pointing to an entry that is being updated. The isUpdate @@ -980,7 +992,7 @@ void sqlite3GenerateConstraintChecks( Parse *pParse, /* The parser context */ Table *pTab, /* the table into which we are inserting */ int base, /* Index of a read/write cursor pointing at pTab */ - char *aIdxUsed, /* Which indices are used. NULL means all are used */ + int *aRegIdx, /* Register used by each index. 0 for unused indices */ int rowidChng, /* True if the record number will change */ int isUpdate, /* True for UPDATE, False for INSERT */ int overrideError, /* Override onError to this if not OE_Default */ @@ -990,19 +1002,26 @@ void sqlite3GenerateConstraintChecks( Vdbe *v; int nCol; int onError; - int addr; - int extra; + int j1, j2, j3; /* Address of jump instructions */ int iCur; Index *pIdx; int seenReplace = 0; - int jumpInst1=0, jumpInst2; int hasTwoRowids = (isUpdate && rowidChng); + int regRowid, regData; + v = sqlite3GetVdbe(pParse); assert( v!=0 ); assert( pTab->pSelect==0 ); /* This table is not a VIEW */ nCol = pTab->nCol; + /* Copy rowids and data into registers + */ + regRowid = sqlite3StackToReg(pParse, nCol+1+hasTwoRowids); + sqlite3RegToStack(pParse, regRowid, nCol+1+hasTwoRowids); + if( hasTwoRowids ) regRowid++; + regData = regRowid+1; + /* Test all NOT NULL constraints. */ for(i=0; iaCol[i].pDflt==0 ){ onError = OE_Abort; } - sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol-1-i)); - addr = sqlite3VdbeAddOp0(v, OP_NotNull); + j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regData+i); assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail || onError==OE_Ignore || onError==OE_Replace ); switch( onError ){ @@ -1041,11 +1059,12 @@ void sqlite3GenerateConstraintChecks( } case OE_Replace: { sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, 0); + sqlite3VdbeAddOp2(v, OP_Copy, 0, regData+i); sqlite3VdbeAddOp1(v, OP_Push, nCol-i); break; } } - sqlite3VdbeJumpHere(v, addr); + sqlite3VdbeJumpHere(v, j1); } /* Test all CHECK constraints @@ -1053,11 +1072,8 @@ void sqlite3GenerateConstraintChecks( #ifndef SQLITE_OMIT_CHECK if( pTab->pCheck && (pParse->db->flags & SQLITE_IgnoreChecks)==0 ){ int allOk = sqlite3VdbeMakeLabel(v); - assert( pParse->ckOffset==0 ); - pParse->ckOffset = nCol; + pParse->ckBase = regData; sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, 1); - assert( pParse->ckOffset==nCol ); - pParse->ckOffset = 0; onError = overrideError!=OE_Default ? overrideError : OE_Abort; if( onError==OE_Ignore ){ sqlite3VdbeAddOp2(v, OP_Pop, nCol+1+hasTwoRowids, 0); @@ -1082,12 +1098,11 @@ void sqlite3GenerateConstraintChecks( } if( isUpdate ){ - sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol+1)); - sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol+1)); - jumpInst1 = sqlite3VdbeAddOp2(v, OP_Eq, 0, 0); + sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-1); + sqlite3VdbeAddOp1(v, OP_SCopy, regRowid); + j2 = sqlite3VdbeAddOp2(v, OP_Eq, 0, 0); } - sqlite3VdbeAddOp1(v, OP_SCopy, -nCol); - jumpInst2 = sqlite3VdbeAddOp2(v, OP_NotExists, base, 0); + j3 = sqlite3VdbeAddOp3(v, OP_NotExists, base, 0, regRowid); switch( onError ){ default: { onError = OE_Abort; @@ -1103,7 +1118,7 @@ void sqlite3GenerateConstraintChecks( case OE_Replace: { sqlite3GenerateRowIndexDelete(v, pTab, base, 0); if( isUpdate ){ - sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol+hasTwoRowids)); + sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids); sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0); } seenReplace = 1; @@ -1116,10 +1131,10 @@ void sqlite3GenerateConstraintChecks( break; } } - sqlite3VdbeJumpHere(v, jumpInst2); + sqlite3VdbeJumpHere(v, j3); if( isUpdate ){ - sqlite3VdbeJumpHere(v, jumpInst1); - sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol+1)); + sqlite3VdbeJumpHere(v, j2); + sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-1); sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0); } } @@ -1128,22 +1143,20 @@ void sqlite3GenerateConstraintChecks( ** index and making sure that duplicate entries do not already exist. ** Add the new records to the indices as we go. */ - extra = -1; for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){ - if( aIdxUsed && aIdxUsed[iCur]==0 ) continue; /* Skip unused indices */ - extra++; + if( aRegIdx[iCur]==0 ) continue; /* Skip unused indices */ /* Create a key for accessing the index entry */ - sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol+extra)); + sqlite3VdbeAddOp1(v, OP_SCopy, regRowid); for(i=0; inColumn; i++){ int idx = pIdx->aiColumn[i]; if( idx==pTab->iPKey ){ - sqlite3VdbeAddOp1(v, OP_SCopy, -(i+extra+nCol+1)); + sqlite3VdbeAddOp1(v, OP_SCopy, regRowid); }else{ - sqlite3VdbeAddOp1(v, OP_SCopy, -(i+extra+nCol-idx)); + sqlite3VdbeAddOp1(v, OP_SCopy, regData+idx); } } - jumpInst1 = sqlite3VdbeAddOp2(v, OP_MakeIdxRec, pIdx->nColumn, 0); + j2 = sqlite3VdbeAddOp3(v, OP_MakeIdxRec, pIdx->nColumn, 0, aRegIdx[iCur]); sqlite3IndexAffinityStr(v, pIdx); /* Find out what action to take in case there is an indexing conflict */ @@ -1161,8 +1174,9 @@ void sqlite3GenerateConstraintChecks( /* Check to see if the new index entry will be unique */ - sqlite3VdbeAddOp1(v, OP_SCopy, -(extra+nCol+1+hasTwoRowids)); - jumpInst2 = sqlite3VdbeAddOp2(v, OP_IsUnique, base+iCur+1, 0); + sqlite3VdbeAddOp1(v, OP_SCopy, aRegIdx[iCur]); + sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids); + j3 = sqlite3VdbeAddOp2(v, OP_IsUnique, base+iCur+1, 0); /* Generate code that executes if the new index entry is not unique */ assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail @@ -1199,7 +1213,7 @@ void sqlite3GenerateConstraintChecks( } case OE_Ignore: { assert( seenReplace==0 ); - sqlite3VdbeAddOp2(v, OP_Pop, nCol+extra+3+hasTwoRowids, 0); + sqlite3VdbeAddOp2(v, OP_Pop, nCol+3+hasTwoRowids, 0); sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); break; } @@ -1207,17 +1221,18 @@ void sqlite3GenerateConstraintChecks( int iRowid = sqlite3StackToReg(pParse, 1); sqlite3GenerateRowDelete(pParse->db, v, pTab, base, iRowid, 0); if( isUpdate ){ - sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol+extra+1+hasTwoRowids)); + sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids); sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0); } seenReplace = 1; break; } } + sqlite3VdbeJumpHere(v, j3); + sqlite3VdbeAddOp1(v, OP_Pop, 1); #if NULL_DISTINCT_FOR_UNIQUE - sqlite3VdbeJumpHere(v, jumpInst1); + sqlite3VdbeJumpHere(v, j2); #endif - sqlite3VdbeJumpHere(v, jumpInst2); } } @@ -1235,7 +1250,7 @@ void sqlite3CompleteInsertion( Parse *pParse, /* The parser context */ Table *pTab, /* the table into which we are inserting */ int base, /* Index of a read/write cursor pointing at pTab */ - char *aIdxUsed, /* Which indices are used. NULL means all are used */ + int *aRegIdx, /* Register used by each index. 0 for unused indices */ int rowidChng, /* True if the record number will change */ int isUpdate, /* True for UPDATE, False for INSERT */ int newIdx, /* Index of NEW table for triggers. -1 if none */ @@ -1252,8 +1267,8 @@ void sqlite3CompleteInsertion( assert( pTab->pSelect==0 ); /* This table is not a VIEW */ for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){} for(i=nIdx-1; i>=0; i--){ - if( aIdxUsed && aIdxUsed[i]==0 ) continue; - sqlite3VdbeAddOp2(v, OP_IdxInsert, base+i+1, 0); + if( aRegIdx[i]==0 ) continue; + sqlite3VdbeAddOp2(v, OP_IdxInsert, base+i+1, aRegIdx[i]); } sqlite3VdbeAddOp2(v, OP_MakeRecord, pTab->nCol, 0); sqlite3TableAffinityStr(v, pTab); @@ -1287,8 +1302,10 @@ void sqlite3CompleteInsertion( ** Generate code that will open cursors for a table and for all ** indices of that table. The "base" parameter is the cursor number used ** for the table. Indices are opened on subsequent cursors. +** +** Return the number of indices on the table. */ -void sqlite3OpenTableAndIndices( +int sqlite3OpenTableAndIndices( Parse *pParse, /* Parsing context */ Table *pTab, /* Table to be opened */ int base, /* Cursor number assigned to the table */ @@ -1299,7 +1316,7 @@ void sqlite3OpenTableAndIndices( Index *pIdx; Vdbe *v; - if( IsVirtual(pTab) ) return; + if( IsVirtual(pTab) ) return 0; iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); v = sqlite3GetVdbe(pParse); assert( v!=0 ); @@ -1314,6 +1331,7 @@ void sqlite3OpenTableAndIndices( if( pParse->nTab<=base+i ){ pParse->nTab = base+i; } + return i-1; } @@ -1614,7 +1632,7 @@ static int xferOptimization( VdbeComment((v, "%s", pDestIdx->zName)); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, 0); - sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, 1); + sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, 0, 1); sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); sqlite3VdbeJumpHere(v, addr1); } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index d5c02e74df..b4e236cb7e 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.641 2008/01/06 00:25:22 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.642 2008/01/08 02:57:56 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1389,7 +1389,7 @@ struct Parse { int nTab; /* Number of previously allocated VDBE cursors */ int nMem; /* Number of memory cells used so far */ int nSet; /* Number of sets used so far */ - int ckOffset; /* Stack offset to data used by CHECK constraints */ + int ckBase; /* Base register of data during check constraints */ u32 writeMask; /* Start a write transaction on these databases */ u32 cookieMask; /* Bitmask of schema verified databases */ int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */ @@ -1774,11 +1774,11 @@ int sqlite3ExprIsConstantOrFunction(Expr*); int sqlite3ExprIsInteger(Expr*, int*); int sqlite3IsRowid(const char*); void sqlite3GenerateRowDelete(sqlite3*, Vdbe*, Table*, int, int, int); -void sqlite3GenerateRowIndexDelete(Vdbe*, Table*, int, char*); +void sqlite3GenerateRowIndexDelete(Vdbe*, Table*, int, int*); void sqlite3GenerateIndexKey(Vdbe*, Index*, int); -void sqlite3GenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int); -void sqlite3CompleteInsertion(Parse*, Table*, int, char*, int, int, int, int); -void sqlite3OpenTableAndIndices(Parse*, Table*, int, int); +void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int*,int,int,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*); void sqlite3TokenCopy(sqlite3*,Token*, Token*); diff --git a/src/update.c b/src/update.c index d31d0b93eb..afb5e89add 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.162 2008/01/06 00:25:22 drh Exp $ +** $Id: update.c,v 1.163 2008/01/08 02:57:56 drh Exp $ */ #include "sqliteInt.h" @@ -90,11 +90,9 @@ void sqlite3Update( Vdbe *v; /* The virtual database engine */ Index *pIdx; /* For looping over indices */ int nIdx; /* Number of indices that need updating */ - int nIdxTotal; /* Total number of indices */ int iCur; /* VDBE Cursor number of pTab */ sqlite3 *db; /* The database structure */ - Index **apIdx = 0; /* An array of indices that need updating too */ - char *aIdxUsed = 0; /* aIdxUsed[i]==1 if the i-th index is used */ + int *aRegIdx = 0; /* One register assigned to each index to be updated */ int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the ** an expression for the i-th column of the table. ** aXRef[i]==-1 if the i-th column is not changed. */ @@ -227,40 +225,30 @@ void sqlite3Update( #endif } - /* Allocate memory for the array apIdx[] and fill it with pointers to every - ** index that needs to be updated. Indices only need updating if their - ** key includes one of the columns named in pChanges or if the record - ** number of the original table entry is changing. + /* Allocate memory for the array aRegIdx[]. There is one entry in the + ** array for each index associated with table being updated. Fill in + ** the value with a register number for indices that are to be used + ** and with zero for unused indices. */ - for(nIdx=nIdxTotal=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdxTotal++){ - if( chngRowid ){ - i = 0; - }else { - for(i=0; inColumn; i++){ - if( aXRef[pIdx->aiColumn[i]]>=0 ) break; - } - } - if( inColumn ) nIdx++; - } - if( nIdxTotal>0 ){ - apIdx = sqlite3DbMallocRaw(db, sizeof(Index*) * nIdx + nIdxTotal ); - if( apIdx==0 ) goto update_cleanup; - aIdxUsed = (char*)&apIdx[nIdx]; + for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){} + if( nIdx>0 ){ + aRegIdx = sqlite3DbMallocRaw(db, sizeof(Index*) * nIdx ); + if( aRegIdx==0 ) goto update_cleanup; } - for(nIdx=j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ + for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ + int reg; if( chngRowid ){ - i = 0; + reg = ++pParse->nMem; }else{ + reg = 0; for(i=0; inColumn; i++){ - if( aXRef[pIdx->aiColumn[i]]>=0 ) break; + if( aXRef[pIdx->aiColumn[i]]>=0 ){ + reg = ++pParse->nMem; + break; + } } } - if( inColumn ){ - apIdx[nIdx++] = pIdx; - aIdxUsed[j] = 1; - }else{ - aIdxUsed[j] = 0; - } + aRegIdx[j] = reg; } /* Begin generating code. @@ -380,7 +368,7 @@ void sqlite3Update( } } for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ - if( openAll || aIdxUsed[i] ){ + if( openAll || aRegIdx[i]>0 ){ KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); sqlite3VdbeAddOp4(v, OP_OpenWrite, iCur+i+1, pIdx->tnum, iDb, (char*)pKey, P4_KEYINFO_HANDOFF); @@ -486,12 +474,12 @@ void sqlite3Update( /* Do constraint checks */ - sqlite3GenerateConstraintChecks(pParse, pTab, iCur, aIdxUsed, chngRowid, 1, + sqlite3GenerateConstraintChecks(pParse, pTab, iCur, aRegIdx, chngRowid, 1, onError, addr); /* Delete the old indices for the current record. */ - sqlite3GenerateRowIndexDelete(v, pTab, iCur, aIdxUsed); + sqlite3GenerateRowIndexDelete(v, pTab, iCur, aRegIdx); /* If changing the record number, delete the old record. */ @@ -501,7 +489,7 @@ void sqlite3Update( /* Create the new index entries and the new record. */ - sqlite3CompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRowid, 1, -1, 0); + sqlite3CompleteInsertion(pParse, pTab, iCur, aRegIdx, chngRowid, 1, -1, 0); } /* Increment the row counter @@ -526,7 +514,7 @@ void sqlite3Update( /* Close all tables */ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ - if( openAll || aIdxUsed[i] ){ + if( openAll || aRegIdx[i]>0 ){ sqlite3VdbeAddOp2(v, OP_Close, iCur+i+1, 0); } } @@ -549,7 +537,7 @@ void sqlite3Update( update_cleanup: sqlite3AuthContextPop(&sContext); - sqlite3_free(apIdx); + sqlite3_free(aRegIdx); sqlite3_free(aXRef); sqlite3SrcListDelete(pTabList); sqlite3ExprListDelete(pChanges); diff --git a/src/vdbe.c b/src/vdbe.c index 58b1b1454f..7ac12ffeae 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.687 2008/01/07 19:20:25 drh Exp $ +** $Id: vdbe.c,v 1.688 2008/01/08 02:57:56 drh Exp $ */ #include "sqliteInt.h" #include @@ -717,6 +717,26 @@ int sqlite3VdbeExec( pOut = &p->aMem[pOp->p2]; } } + }else if( (opProperty & OPFLG_IN2)!=0 ){ + assert( pOp->p2>=0 ); + if( pOp->p2==0 ){ + pIn2 = pTos; + nPop = 1; + }else{ + assert( pOp->p2<=p->nMem ); + pIn2 = &p->aMem[pOp->p2]; + REGISTER_TRACE(pOp->p2, pIn2); + } + }else if( (opProperty & OPFLG_IN3)!=0 ){ + assert( pOp->p3>=0 ); + if( pOp->p3==0 ){ + pIn3 = pTos; + nPop = 1; + }else{ + assert( pOp->p3<=p->nMem ); + pIn3 = &p->aMem[pOp->p3]; + REGISTER_TRACE(pOp->p3, pIn3); + } } switch( pOp->opcode ){ @@ -4166,67 +4186,60 @@ case OP_Next: { /* no-push, jump */ break; } -/* Opcode: IdxInsert P1 P2 * +/* Opcode: IdxInsert P1 P2 P3 ** -** The top of the stack holds a SQL index key made using either the -** MakeIdxRec or MakeRecord instructions. This opcode writes that key +** Register P2 holds a SQL index key made using the +** MakeIdxRec instructions. This opcode writes that key ** into the index P1. Data for the entry is nil. ** -** P2 is a flag that provides a hint to the b-tree layer that this +** P3 is a flag that provides a hint to the b-tree layer that this ** insert is likely to be an append. ** ** This instruction only works for indices. The equivalent instruction ** for tables is OP_Insert. */ -case OP_IdxInsert: { /* no-push */ +case OP_IdxInsert: { /* no-push, in2 */ int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; - assert( pTos>=p->aStack ); assert( i>=0 && inCursor ); assert( p->apCsr[i]!=0 ); - assert( pTos->flags & MEM_Blob ); + assert( pIn2->flags & MEM_Blob ); if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ assert( pC->isTable==0 ); - rc = ExpandBlob(pTos); + rc = ExpandBlob(pIn2); if( rc==SQLITE_OK ){ - int nKey = pTos->n; - const char *zKey = pTos->z; - rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0, 0, pOp->p2); + int nKey = pIn2->n; + const char *zKey = pIn2->z; + rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0, 0, pOp->p3); assert( pC->deferredMoveto==0 ); pC->cacheStatus = CACHE_STALE; } } - Release(pTos); - pTos--; break; } -/* Opcode: IdxDelete P1 * * +/* Opcode: IdxDelete P1 P2 * ** -** The top of the stack is an index key built using the either the -** MakeIdxRec or MakeRecord opcodes. -** This opcode removes that entry from the index. +** The content of register P2 is an index key built using the either the +** MakeIdxRec opcode. Removes that entry from the index. */ -case OP_IdxDelete: { /* no-push */ +case OP_IdxDelete: { /* no-push, in2 */ int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; - assert( pTos>=p->aStack ); - assert( pTos->flags & MEM_Blob ); + assert( pIn2->flags & MEM_Blob ); assert( i>=0 && inCursor ); assert( p->apCsr[i]!=0 ); if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ int res; - rc = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, 0, &res); + rc = sqlite3BtreeMoveto(pCrsr, pIn2->z, pIn2->n, 0, &res); if( rc==SQLITE_OK && res==0 ){ rc = sqlite3BtreeDelete(pCrsr); } assert( pC->deferredMoveto==0 ); pC->cacheStatus = CACHE_STALE; } - Release(pTos); - pTos--; break; } diff --git a/src/vdbeaux.c b/src/vdbeaux.c index e6d489f08f..391b0d0dca 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -821,12 +821,14 @@ int sqlite3VdbeList( pMem++; pMem->flags = MEM_Null; /* Comment */ +#ifdef SQLITE_DEBUG if( pOp->zComment ){ pMem->flags = MEM_Str|MEM_Term; pMem->z = pOp->zComment; pMem->n = strlen(pMem->z); pMem->enc = SQLITE_UTF8; } +#endif } p->nResColumn = 8 - 5*(p->explain-1); diff --git a/src/vdbemem.c b/src/vdbemem.c index 9da14dd326..18a29ab3e9 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -529,7 +529,7 @@ int sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){ } pFrom->flags = MEM_Null; pFrom->xDel = 0; - if( pTo->flags & MEM_Ephem ){ + if( 0 /* pTo->flags & MEM_Ephem */ ){ rc = sqlite3VdbeMemMakeWriteable(pTo); }else{ rc = SQLITE_OK;