From: drh Date: Tue, 8 Jan 2008 18:57:50 +0000 (+0000) Subject: Finish registerizing the core logic of INSERT and UPDATE. (CVS 4696) X-Git-Tag: version-3.6.10~1481 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=04adf4161ddfa0df6f167523d1ee6ca47bb26fdd;p=thirdparty%2Fsqlite.git Finish registerizing the core logic of INSERT and UPDATE. (CVS 4696) FossilOrigin-Name: 5fd1036788dbbc48ff1c746d2e1ba12b04a7e58c --- diff --git a/manifest b/manifest index ab75ca1531..b40b7ed61b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\scrash4.test\swith\sadditional\scrash\stesting.\s(CVS\s4695) -D 2008-01-08T16:03:50 +C Finish\sregisterizing\sthe\score\slogic\sof\sINSERT\sand\sUPDATE.\s(CVS\s4696) +D 2008-01-08T18:57:50 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -96,7 +96,7 @@ F src/expr.c 6f2a852227ba2abd5ad0916f539c1f2159da28b4 F src/func.c 996071cf0af9d967e58b69fce1909555059ebc7d F src/hash.c 45a7005aac044b6c86bd7e49c44bc15d30006d6c F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53 -F src/insert.c 3a45102002b611aa1707bb6c6c5c148547d2630a +F src/insert.c e46f25f5262b243b60419f6ca5cc4811bf96eec6 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 964754dcd508ddf0dd0b326072ad80678452e5c2 +F src/sqliteInt.h fd911a263a5b50015afe01be5501bf5b6be913d0 F src/sqliteLimit.h ee4430f88f69bf63527967bb35ca52af7b0ccb1e F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4 F src/tclsqlite.c 9923abeffc9b3d7dad58e92b319661521f60debf @@ -164,7 +164,7 @@ 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 acd1c38dbbf253183fe2a8e5be0b3f3fee59be15 +F src/update.c 89ba318306daa20d901ed698018fe6e3d16b3586 F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736 F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624 F src/vacuum.c 3f34f278809bf3eb0b62ec46ff779e9c385b28f0 @@ -405,7 +405,7 @@ F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47 F test/printf.test 6bf1a86c6a1e45536f72d782bf44c8e3c76510f8 F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301 x F test/ptrchng.test 38ae1806833d72d9a81a6121322e274f24937e18 -F test/quick.test e4aa7c0c4fb6085ad7a3921da98741b5ce824633 +F test/quick.test ab128ce4b4ba34df655291caeaa109695d307d0e F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6 F test/rdonly.test b34db316525440d3b42c32e83942c02c37d28ef0 F test/reindex.test 38b138abe36bf9a08c791ed44d9f76cd6b97b78b @@ -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 3ccce1f58be46787f8a35f0fa6d738ed126c0f07 -R 08ffd7abd6eb20dcba62b11485234765 +P 87b4ac4b73fb84411ced9e9a859dd0e2d211c4b3 +R ea42342909fb8c895292e16f7eae74b2 U drh -Z 5dde2337304e00b23d140f7351ff735d +Z c9e18a2ce9ff1c41852f6d73afcc5930 diff --git a/manifest.uuid b/manifest.uuid index c98ad89974..7428ee3025 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -87b4ac4b73fb84411ced9e9a859dd0e2d211c4b3 \ No newline at end of file +5fd1036788dbbc48ff1c746d2e1ba12b04a7e58c \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index a9ba0ea2ee..26f5408e6a 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.216 2008/01/08 02:57:56 drh Exp $ +** $Id: insert.c,v 1.217 2008/01/08 18:57:50 drh Exp $ */ #include "sqliteInt.h" @@ -351,7 +351,7 @@ void sqlite3Insert( Index *pIdx; /* For looping over indices of the table */ int nColumn; /* Number of columns in the data */ int nHidden = 0; /* Number of hidden columns if TABLE is virtual */ - int base = 0; /* VDBE Cursor number for pTab */ + int baseCur = 0; /* VDBE Cursor number for pTab */ int keyColumn = -1; /* Column that is the INTEGER PRIMARY KEY */ int endOfLoop; /* Label for the end of the insertion loop */ int useTempTable = 0; /* Store SELECT results in intermediate table */ @@ -635,8 +635,8 @@ void sqlite3Insert( int nIdx; int i; - base = pParse->nTab; - nIdx = sqlite3OpenTableAndIndices(pParse, pTab, base, OP_OpenWrite); + baseCur = pParse->nTab; + nIdx = sqlite3OpenTableAndIndices(pParse, pTab, baseCur, OP_OpenWrite); aRegIdx = sqlite3DbMallocZero(db, sizeof(int)*(nIdx+1)); if( aRegIdx==0 ){ goto insert_cleanup; @@ -766,7 +766,7 @@ void sqlite3Insert( if( pOp && pOp->opcode==OP_Null ){ appendFlag = 1; pOp->opcode = OP_NewRowid; - pOp->p1 = base; + pOp->p1 = baseCur; pOp->p2 = regRowid; pOp->p3 = regAutoinc; }else{ @@ -780,13 +780,13 @@ void sqlite3Insert( if( !appendFlag ){ sqlite3VdbeAddOp2(v, OP_IfMemNull, regRowid, sqlite3VdbeCurrentAddr(v)+2); sqlite3VdbeAddOp2(v, OP_Goto, -1, sqlite3VdbeCurrentAddr(v)+2); - sqlite3VdbeAddOp3(v, OP_NewRowid, base, regRowid, regAutoinc); + sqlite3VdbeAddOp3(v, OP_NewRowid, baseCur, regRowid, regAutoinc); sqlite3VdbeAddOp3(v, OP_MustBeInt, 0, 0, regRowid); } }else if( IsVirtual(pTab) ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid); }else{ - sqlite3VdbeAddOp3(v, OP_NewRowid, base, regRowid, regAutoinc); + sqlite3VdbeAddOp3(v, OP_NewRowid, baseCur, regRowid, regAutoinc); appendFlag = 1; } autoIncStep(pParse, regAutoinc, regRowid); @@ -840,12 +840,28 @@ void sqlite3Insert( }else #endif { - sqlite3RegToStack(pParse, regIns, pTab->nCol+1); - sqlite3GenerateConstraintChecks(pParse, pTab, base, aRegIdx, keyColumn>=0, - 0, onError, endOfLoop); - sqlite3CompleteInsertion(pParse, pTab, base, aRegIdx,0,0, - (triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1, - appendFlag); + sqlite3GenerateConstraintChecks( + pParse, + pTab, + baseCur, + regIns, + aRegIdx, + keyColumn>=0, + 0, + onError, + endOfLoop + ); + sqlite3CompleteInsertion( + pParse, + pTab, + baseCur, + regIns, + aRegIdx, + 0, + 0, + (triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1, + appendFlag + ); } } @@ -878,9 +894,9 @@ void sqlite3Insert( if( !IsVirtual(pTab) && !isView ){ /* Close all tables opened */ - sqlite3VdbeAddOp2(v, OP_Close, base, 0); + sqlite3VdbeAddOp2(v, OP_Close, baseCur, 0); for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ - sqlite3VdbeAddOp2(v, OP_Close, idx+base, 0); + sqlite3VdbeAddOp2(v, OP_Close, idx+baseCur, 0); } } @@ -912,8 +928,7 @@ insert_cleanup: /* ** Generate code to do constraint checks prior to an INSERT or an UPDATE. ** -** When this routine is called, the stack contains (from bottom to top) -** the following values: +** The input is a range of consecutive registers as follows: ** ** 1. The rowid of the row to be updated before the update. This ** value is omitted unless we are doing an UPDATE that involves a @@ -927,6 +942,8 @@ insert_cleanup: ** ** N. The data in the last column of the entry after the update. ** +** The regRowid parameter is the index of the register containing (2). +** ** The old rowid shown as entry (1) above is omitted unless both isUpdate ** and rowidChng are 1. isUpdate is true for UPDATEs and false for ** INSERTs and rowidChng is true if the record number is being changed. @@ -977,23 +994,24 @@ insert_cleanup: ** for the constraint is used. ** ** The calling routine must open a read/write cursor for pTab with -** cursor number "base". All indices of pTab must also have open -** read/write cursors with cursor number base+i for the i-th cursor. +** cursor number "baseCur". All indices of pTab must also have open +** read/write cursors with cursor number baseCur+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 aRegIdx[i]==0. ** -** If the isUpdate flag is true, it means that the "base" cursor is +** If the isUpdate flag is true, it means that the "baseCur" cursor is ** initially pointing to an entry that is being updated. The isUpdate -** flag causes extra code to be generated so that the "base" cursor +** flag causes extra code to be generated so that the "baseCur" cursor ** is still pointing at the same entry after the routine returns. -** Without the isUpdate flag, the "base" cursor might be moved. +** Without the isUpdate flag, the "baseCur" cursor might be moved. */ 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 */ + int baseCur, /* Index of a read/write cursor pointing at pTab */ + int regRowid, /* Index of the range of input registers */ int *aRegIdx, /* Register used by each index. 0 for unused indices */ - int rowidChng, /* True if the record number will change */ + int rowidChng, /* True if the rowid will change */ int isUpdate, /* True for UPDATE, False for INSERT */ int overrideError, /* Override onError to this if not OE_Default */ int ignoreDest /* Jump to this label on an OE_Ignore resolution */ @@ -1003,24 +1021,18 @@ void sqlite3GenerateConstraintChecks( int nCol; int onError; int j1, j2, j3; /* Address of jump instructions */ + int regData; /* Register containing first data column */ int iCur; Index *pIdx; int seenReplace = 0; 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; + regData = regRowid + 1; - /* 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. */ @@ -1053,14 +1065,11 @@ void sqlite3GenerateConstraintChecks( break; } case OE_Ignore: { - sqlite3VdbeAddOp2(v, OP_Pop, nCol+1+hasTwoRowids, 0); sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); break; } case OE_Replace: { - sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, 0); - sqlite3VdbeAddOp2(v, OP_Copy, 0, regData+i); - sqlite3VdbeAddOp1(v, OP_Push, nCol-i); + sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regData+i); break; } } @@ -1076,7 +1085,6 @@ void sqlite3GenerateConstraintChecks( sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, 1); onError = overrideError!=OE_Default ? overrideError : OE_Abort; if( onError==OE_Ignore ){ - sqlite3VdbeAddOp2(v, OP_Pop, nCol+1+hasTwoRowids, 0); sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); }else{ sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_CONSTRAINT, onError); @@ -1102,7 +1110,7 @@ void sqlite3GenerateConstraintChecks( sqlite3VdbeAddOp1(v, OP_SCopy, regRowid); j2 = sqlite3VdbeAddOp2(v, OP_Eq, 0, 0); } - j3 = sqlite3VdbeAddOp3(v, OP_NotExists, base, 0, regRowid); + j3 = sqlite3VdbeAddOp3(v, OP_NotExists, baseCur, 0, regRowid); switch( onError ){ default: { onError = OE_Abort; @@ -1116,17 +1124,16 @@ void sqlite3GenerateConstraintChecks( break; } case OE_Replace: { - sqlite3GenerateRowIndexDelete(v, pTab, base, 0); + sqlite3GenerateRowIndexDelete(v, pTab, baseCur, 0); if( isUpdate ){ sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids); - sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0); + sqlite3VdbeAddOp2(v, OP_MoveGe, baseCur, 0); } seenReplace = 1; break; } case OE_Ignore: { assert( seenReplace==0 ); - sqlite3VdbeAddOp2(v, OP_Pop, nCol+1+hasTwoRowids, 0); sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); break; } @@ -1135,7 +1142,7 @@ void sqlite3GenerateConstraintChecks( if( isUpdate ){ sqlite3VdbeJumpHere(v, j2); sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-1); - sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0); + sqlite3VdbeAddOp2(v, OP_MoveGe, baseCur, 0); } } @@ -1176,7 +1183,7 @@ 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 = sqlite3VdbeAddOp2(v, OP_IsUnique, base+iCur+1, 0); + j3 = sqlite3VdbeAddOp2(v, OP_IsUnique, baseCur+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 @@ -1213,16 +1220,16 @@ void sqlite3GenerateConstraintChecks( } case OE_Ignore: { assert( seenReplace==0 ); - sqlite3VdbeAddOp2(v, OP_Pop, nCol+3+hasTwoRowids, 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, base, iRowid, 0); + sqlite3GenerateRowDelete(pParse->db, v, pTab, baseCur, iRowid, 0); if( isUpdate ){ sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids); - sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0); + sqlite3VdbeAddOp2(v, OP_MoveGe, baseCur, 0); } seenReplace = 1; break; @@ -1239,9 +1246,8 @@ void sqlite3GenerateConstraintChecks( /* ** This routine generates code to finish the INSERT or UPDATE operation ** that was started by a prior call to sqlite3GenerateConstraintChecks. -** The stack must contain keys for all active indices followed by data -** and the rowid for the new entry. This routine creates the new -** entries in all indices and in the main table. +** A consecutive range of registers starting at regRowid contains the +** rowid and the content to be inserted. ** ** The arguments to this routine should be the same as the first six ** arguments to sqlite3GenerateConstraintChecks. @@ -1249,7 +1255,8 @@ void sqlite3GenerateConstraintChecks( 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 */ + int baseCur, /* Index of a read/write cursor pointing at pTab */ + int regRowid, /* Range of content */ 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 */ @@ -1261,6 +1268,7 @@ void sqlite3CompleteInsertion( int nIdx; Index *pIdx; int pik_flags; + int regData; v = sqlite3GetVdbe(pParse); assert( v!=0 ); @@ -1268,14 +1276,16 @@ void sqlite3CompleteInsertion( for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){} for(i=nIdx-1; i>=0; i--){ if( aRegIdx[i]==0 ) continue; - sqlite3VdbeAddOp2(v, OP_IdxInsert, base+i+1, aRegIdx[i]); + sqlite3VdbeAddOp2(v, OP_IdxInsert, baseCur+i+1, aRegIdx[i]); } - sqlite3VdbeAddOp2(v, OP_MakeRecord, pTab->nCol, 0); + regData = regRowid + 1; + sqlite3VdbeAddOp1(v, OP_SCopy, regRowid); + sqlite3VdbeAddOp2(v, OP_RegMakeRec, regData, pTab->nCol); sqlite3TableAffinityStr(v, pTab); #ifndef SQLITE_OMIT_TRIGGER if( newIdx>=0 ){ - sqlite3VdbeAddOp1(v, OP_Copy, -1); - sqlite3VdbeAddOp1(v, OP_Copy, -1); + sqlite3VdbeAddOp1(v, OP_SCopy, regRowid); + sqlite3VdbeAddOp1(v, OP_SCopy, -1); sqlite3CodeInsert(pParse, newIdx, 0); } #endif @@ -1288,19 +1298,15 @@ void sqlite3CompleteInsertion( if( appendBias ){ pik_flags |= OPFLAG_APPEND; } - sqlite3CodeInsert(pParse, base, pik_flags); + sqlite3CodeInsert(pParse, baseCur, pik_flags); if( !pParse->nested ){ sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC); } - - if( isUpdate && rowidChng ){ - sqlite3VdbeAddOp2(v, OP_Pop, 1, 0); - } } /* ** Generate code that will open cursors for a table and for all -** indices of that table. The "base" parameter is the cursor number used +** indices of that table. The "baseCur" parameter is the cursor number used ** for the table. Indices are opened on subsequent cursors. ** ** Return the number of indices on the table. @@ -1308,7 +1314,7 @@ void sqlite3CompleteInsertion( int sqlite3OpenTableAndIndices( Parse *pParse, /* Parsing context */ Table *pTab, /* Table to be opened */ - int base, /* Cursor number assigned to the table */ + int baseCur, /* Cursor number assigned to the table */ int op /* OP_OpenRead or OP_OpenWrite */ ){ int i; @@ -1320,16 +1326,16 @@ int sqlite3OpenTableAndIndices( iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); v = sqlite3GetVdbe(pParse); assert( v!=0 ); - sqlite3OpenTable(pParse, base, iDb, pTab, op); + sqlite3OpenTable(pParse, baseCur, iDb, pTab, op); for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); assert( pIdx->pSchema==pTab->pSchema ); - sqlite3VdbeAddOp4(v, op, i+base, pIdx->tnum, iDb, + sqlite3VdbeAddOp4(v, op, i+baseCur, pIdx->tnum, iDb, (char*)pKey, P4_KEYINFO_HANDOFF); VdbeComment((v, "%s", pIdx->zName)); } - if( pParse->nTab<=base+i ){ - pParse->nTab = base+i; + if( pParse->nTab<=baseCur+i ){ + pParse->nTab = baseCur+i; } return i-1; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index b4e236cb7e..ec6da6da53 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.642 2008/01/08 02:57:56 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.643 2008/01/08 18:57:50 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1776,8 +1776,9 @@ int sqlite3IsRowid(const char*); void sqlite3GenerateRowDelete(sqlite3*, Vdbe*, Table*, int, int, int); void sqlite3GenerateRowIndexDelete(Vdbe*, Table*, int, int*); void sqlite3GenerateIndexKey(Vdbe*, Index*, int); -void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int*,int,int,int,int); -void sqlite3CompleteInsertion(Parse*, Table*, int, int*, int, int, int, int); +void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int, + int*,int,int,int,int); +void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*,int,int,int,int); int sqlite3OpenTableAndIndices(Parse*, Table*, int, int); void sqlite3BeginWriteOperation(Parse*, int, int); Expr *sqlite3ExprDup(sqlite3*,Expr*); diff --git a/src/update.c b/src/update.c index afb5e89add..89ececac93 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.163 2008/01/08 02:57:56 drh Exp $ +** $Id: update.c,v 1.164 2008/01/08 18:57:50 drh Exp $ */ #include "sqliteInt.h" @@ -102,9 +102,6 @@ void sqlite3Update( AuthContext sContext; /* The authorization context */ NameContext sNC; /* The name-context to resolve expressions in */ int iDb; /* Database containing the table being updated */ - int memCnt = 0; /* Memory cell used for counting rows changed */ - int mem1; /* Memory address storing the rowid for next row to update */ - int iRowid; /* Memory address storing rowids */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* Trying to update a view */ @@ -120,6 +117,12 @@ void sqlite3Update( int newIdx = -1; /* index of trigger "new" temp table */ int oldIdx = -1; /* index of trigger "old" temp table */ + /* Register Allocations */ + int regRowCount = 0; /* A count of rows changed */ + int regOldRowid; /* The old rowid */ + int regNewRowid; /* The new rowid */ + int regData; /* New data for the row */ + sContext.pParse = 0; db = pParse->db; if( pParse->nErr || db->mallocFailed ){ @@ -251,13 +254,28 @@ void sqlite3Update( aRegIdx[j] = reg; } + /* Allocate a block of register used to store the change record + ** sent to sqlite3GenerateConstraintChecks(). There are either + ** one or two registers for holding the rowid. One rowid register + ** is used if chngRowid is false and two are used if chngRowid is + ** true. Following these are pTab->nCol register holding column + ** data. + */ + regOldRowid = regNewRowid = pParse->nMem + 1; + pParse->nMem += pTab->nCol + 1; + if( chngRowid ){ + regNewRowid++; + pParse->nMem++; + } + regData = regNewRowid+1; + + /* Begin generating code. */ v = sqlite3GetVdbe(pParse); if( v==0 ) goto update_cleanup; if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); sqlite3BeginWriteOperation(pParse, 1, iDb); - mem1 = ++pParse->nMem; #ifndef SQLITE_OMIT_VIRTUALTABLE /* Virtual tables must be handled separately */ @@ -333,9 +351,8 @@ void sqlite3Update( /* Remember the rowid of every item to be updated. */ - iRowid = ++pParse->nMem; - sqlite3VdbeAddOp2(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, iRowid); - sqlite3VdbeAddOp2(v, OP_FifoWrite, iRowid, 0); + sqlite3VdbeAddOp2(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid,iCur,regOldRowid); + sqlite3VdbeAddOp2(v, OP_FifoWrite, regOldRowid, 0); /* End the database scan loop. */ @@ -344,8 +361,8 @@ void sqlite3Update( /* Initialize the count of updated rows */ if( db->flags & SQLITE_CountRows && !pParse->trigStack ){ - memCnt = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Integer, 0, memCnt); + regRowCount = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount); } if( !isView && !IsVirtual(pTab) ){ @@ -383,13 +400,13 @@ void sqlite3Update( } /* Top of the update loop */ - addr = sqlite3VdbeAddOp2(v, OP_FifoRead, iRowid, 0); + addr = sqlite3VdbeAddOp2(v, OP_FifoRead, regOldRowid, 0); sqlite3VdbeAddOp2(v, OP_StackDepth, -1, 0); if( triggers_exist ){ /* Make cursor iCur point to the record that is being updated. */ - sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, iRowid); + sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid); /* Generate the OLD table */ @@ -437,45 +454,44 @@ void sqlite3Update( } if( !isView && !IsVirtual(pTab) ){ - /* Loop over every record that needs updating. We have to load ** the old data for each record to be updated because some columns ** might not change and we will need to copy the old value. ** Also, the old data is needed to delete the old index entries. ** So make the cursor point at the old record. */ - sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, iRowid); - sqlite3VdbeAddOp2(v, OP_SCopy, iRowid, 0); + sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid); /* If the record number will change, push the record number as it ** will be after the update. (The old record number is currently ** on top of the stack.) */ if( chngRowid ){ - sqlite3ExprCode(pParse, pRowidExpr, 0); - sqlite3VdbeAddOp2(v, OP_MustBeInt, 0, 0); + sqlite3ExprCode(pParse, pRowidExpr, regNewRowid); + sqlite3VdbeAddOp3(v, OP_MustBeInt, 0, 0, regNewRowid); } /* Compute new data for this record. */ for(i=0; inCol; i++){ if( i==pTab->iPKey ){ - sqlite3VdbeAddOp2(v, OP_Null, 0, 0); + sqlite3VdbeAddOp2(v, OP_Null, 0, regData+i); continue; } j = aXRef[i]; if( j<0 ){ - sqlite3VdbeAddOp2(v, OP_Column, iCur, i); + sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regData+i); sqlite3ColumnDefault(v, pTab, i); }else{ - sqlite3ExprCode(pParse, pChanges->a[j].pExpr, 0); + sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regData+i); } } /* Do constraint checks */ - sqlite3GenerateConstraintChecks(pParse, pTab, iCur, aRegIdx, chngRowid, 1, - onError, addr); + sqlite3GenerateConstraintChecks(pParse, pTab, iCur, regNewRowid, + aRegIdx, chngRowid, 1, + onError, addr); /* Delete the old indices for the current record. */ @@ -489,13 +505,14 @@ void sqlite3Update( /* Create the new index entries and the new record. */ - sqlite3CompleteInsertion(pParse, pTab, iCur, aRegIdx, chngRowid, 1, -1, 0); + sqlite3CompleteInsertion(pParse, pTab, iCur, regNewRowid, + aRegIdx, chngRowid, 1, -1, 0); } /* Increment the row counter */ if( db->flags & SQLITE_CountRows && !pParse->trigStack){ - sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1); + sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1); } /* If there are triggers, close all the cursors after each iteration @@ -530,7 +547,7 @@ void sqlite3Update( ** invoke the callback function. */ if( db->flags & SQLITE_CountRows && !pParse->trigStack && pParse->nested==0 ){ - sqlite3VdbeAddOp2(v, OP_ResultRow, memCnt, 1); + sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P4_STATIC); } diff --git a/test/quick.test b/test/quick.test index e8aa430f29..732212dc39 100644 --- a/test/quick.test +++ b/test/quick.test @@ -6,7 +6,7 @@ #*********************************************************************** # This file runs all tests. # -# $Id: quick.test,v 1.67 2007/11/26 13:36:00 drh Exp $ +# $Id: quick.test,v 1.68 2008/01/08 18:57:50 drh Exp $ proc lshift {lvar} { upvar $lvar l @@ -48,6 +48,7 @@ set EXCLUDE { crash.test crash2.test crash3.test + crash4.test exclusive3.test fts3.test fuzz.test