mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-08 03:22:21 +03:00
Finish registerizing the core logic of INSERT and UPDATE. (CVS 4696)
FossilOrigin-Name: 5fd1036788dbbc48ff1c746d2e1ba12b04a7e58c
This commit is contained in:
18
manifest
18
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Add\scrash4.test\swith\sadditional\scrash\stesting.\s(CVS\s4695)
|
C Finish\sregisterizing\sthe\score\slogic\sof\sINSERT\sand\sUPDATE.\s(CVS\s4696)
|
||||||
D 2008-01-08T16:03:50
|
D 2008-01-08T18:57:50
|
||||||
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
|
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
|
||||||
F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9
|
F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9
|
||||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||||
@@ -96,7 +96,7 @@ F src/expr.c 6f2a852227ba2abd5ad0916f539c1f2159da28b4
|
|||||||
F src/func.c 996071cf0af9d967e58b69fce1909555059ebc7d
|
F src/func.c 996071cf0af9d967e58b69fce1909555059ebc7d
|
||||||
F src/hash.c 45a7005aac044b6c86bd7e49c44bc15d30006d6c
|
F src/hash.c 45a7005aac044b6c86bd7e49c44bc15d30006d6c
|
||||||
F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53
|
F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53
|
||||||
F src/insert.c 3a45102002b611aa1707bb6c6c5c148547d2630a
|
F src/insert.c e46f25f5262b243b60419f6ca5cc4811bf96eec6
|
||||||
F src/journal.c 807bed7a158979ac8d63953e1774e8d85bff65e2
|
F src/journal.c 807bed7a158979ac8d63953e1774e8d85bff65e2
|
||||||
F src/legacy.c 4ac53191fad2e3c4d59bde1228879b2dc5a96d66
|
F src/legacy.c 4ac53191fad2e3c4d59bde1228879b2dc5a96d66
|
||||||
F src/limits.h 71ab25f17e35e0a9f3f6f234b8ed49cc56731d35
|
F src/limits.h 71ab25f17e35e0a9f3f6f234b8ed49cc56731d35
|
||||||
@@ -136,7 +136,7 @@ F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
|
|||||||
F src/shell.c 5391e889384d2062249f668110d64ed16f601c4b
|
F src/shell.c 5391e889384d2062249f668110d64ed16f601c4b
|
||||||
F src/sqlite.h.in 2a7e3776534bbe6ff2cdc058f3abebe91e7e429f
|
F src/sqlite.h.in 2a7e3776534bbe6ff2cdc058f3abebe91e7e429f
|
||||||
F src/sqlite3ext.h a93f59cdee3638dc0c9c086f80df743a4e68c3cb
|
F src/sqlite3ext.h a93f59cdee3638dc0c9c086f80df743a4e68c3cb
|
||||||
F src/sqliteInt.h 964754dcd508ddf0dd0b326072ad80678452e5c2
|
F src/sqliteInt.h fd911a263a5b50015afe01be5501bf5b6be913d0
|
||||||
F src/sqliteLimit.h ee4430f88f69bf63527967bb35ca52af7b0ccb1e
|
F src/sqliteLimit.h ee4430f88f69bf63527967bb35ca52af7b0ccb1e
|
||||||
F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4
|
F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4
|
||||||
F src/tclsqlite.c 9923abeffc9b3d7dad58e92b319661521f60debf
|
F src/tclsqlite.c 9923abeffc9b3d7dad58e92b319661521f60debf
|
||||||
@@ -164,7 +164,7 @@ F src/test_tclvar.c b2d1115e4d489179d3f029e765211b2ad527ba59
|
|||||||
F src/test_thread.c e297dd41db0b249646e69f97d36ec13e56e8b730
|
F src/test_thread.c e297dd41db0b249646e69f97d36ec13e56e8b730
|
||||||
F src/tokenize.c a4e04438c11fed2c67ec47fe3edbef9cca2d1b48
|
F src/tokenize.c a4e04438c11fed2c67ec47fe3edbef9cca2d1b48
|
||||||
F src/trigger.c 33071215111825634b85567bfc36c14094eebe54
|
F src/trigger.c 33071215111825634b85567bfc36c14094eebe54
|
||||||
F src/update.c acd1c38dbbf253183fe2a8e5be0b3f3fee59be15
|
F src/update.c 89ba318306daa20d901ed698018fe6e3d16b3586
|
||||||
F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736
|
F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736
|
||||||
F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624
|
F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624
|
||||||
F src/vacuum.c 3f34f278809bf3eb0b62ec46ff779e9c385b28f0
|
F src/vacuum.c 3f34f278809bf3eb0b62ec46ff779e9c385b28f0
|
||||||
@@ -405,7 +405,7 @@ F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
|
|||||||
F test/printf.test 6bf1a86c6a1e45536f72d782bf44c8e3c76510f8
|
F test/printf.test 6bf1a86c6a1e45536f72d782bf44c8e3c76510f8
|
||||||
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301 x
|
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301 x
|
||||||
F test/ptrchng.test 38ae1806833d72d9a81a6121322e274f24937e18
|
F test/ptrchng.test 38ae1806833d72d9a81a6121322e274f24937e18
|
||||||
F test/quick.test e4aa7c0c4fb6085ad7a3921da98741b5ce824633
|
F test/quick.test ab128ce4b4ba34df655291caeaa109695d307d0e
|
||||||
F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
|
F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
|
||||||
F test/rdonly.test b34db316525440d3b42c32e83942c02c37d28ef0
|
F test/rdonly.test b34db316525440d3b42c32e83942c02c37d28ef0
|
||||||
F test/reindex.test 38b138abe36bf9a08c791ed44d9f76cd6b97b78b
|
F test/reindex.test 38b138abe36bf9a08c791ed44d9f76cd6b97b78b
|
||||||
@@ -605,7 +605,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
|
|||||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||||
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
||||||
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
||||||
P 3ccce1f58be46787f8a35f0fa6d738ed126c0f07
|
P 87b4ac4b73fb84411ced9e9a859dd0e2d211c4b3
|
||||||
R 08ffd7abd6eb20dcba62b11485234765
|
R ea42342909fb8c895292e16f7eae74b2
|
||||||
U drh
|
U drh
|
||||||
Z 5dde2337304e00b23d140f7351ff735d
|
Z c9e18a2ce9ff1c41852f6d73afcc5930
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
87b4ac4b73fb84411ced9e9a859dd0e2d211c4b3
|
5fd1036788dbbc48ff1c746d2e1ba12b04a7e58c
|
||||||
134
src/insert.c
134
src/insert.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle INSERT statements in SQLite.
|
** 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"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -351,7 +351,7 @@ void sqlite3Insert(
|
|||||||
Index *pIdx; /* For looping over indices of the table */
|
Index *pIdx; /* For looping over indices of the table */
|
||||||
int nColumn; /* Number of columns in the data */
|
int nColumn; /* Number of columns in the data */
|
||||||
int nHidden = 0; /* Number of hidden columns if TABLE is virtual */
|
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 keyColumn = -1; /* Column that is the INTEGER PRIMARY KEY */
|
||||||
int endOfLoop; /* Label for the end of the insertion loop */
|
int endOfLoop; /* Label for the end of the insertion loop */
|
||||||
int useTempTable = 0; /* Store SELECT results in intermediate table */
|
int useTempTable = 0; /* Store SELECT results in intermediate table */
|
||||||
@@ -635,8 +635,8 @@ void sqlite3Insert(
|
|||||||
int nIdx;
|
int nIdx;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
base = pParse->nTab;
|
baseCur = pParse->nTab;
|
||||||
nIdx = sqlite3OpenTableAndIndices(pParse, pTab, base, OP_OpenWrite);
|
nIdx = sqlite3OpenTableAndIndices(pParse, pTab, baseCur, OP_OpenWrite);
|
||||||
aRegIdx = sqlite3DbMallocZero(db, sizeof(int)*(nIdx+1));
|
aRegIdx = sqlite3DbMallocZero(db, sizeof(int)*(nIdx+1));
|
||||||
if( aRegIdx==0 ){
|
if( aRegIdx==0 ){
|
||||||
goto insert_cleanup;
|
goto insert_cleanup;
|
||||||
@@ -766,7 +766,7 @@ void sqlite3Insert(
|
|||||||
if( pOp && pOp->opcode==OP_Null ){
|
if( pOp && pOp->opcode==OP_Null ){
|
||||||
appendFlag = 1;
|
appendFlag = 1;
|
||||||
pOp->opcode = OP_NewRowid;
|
pOp->opcode = OP_NewRowid;
|
||||||
pOp->p1 = base;
|
pOp->p1 = baseCur;
|
||||||
pOp->p2 = regRowid;
|
pOp->p2 = regRowid;
|
||||||
pOp->p3 = regAutoinc;
|
pOp->p3 = regAutoinc;
|
||||||
}else{
|
}else{
|
||||||
@@ -780,13 +780,13 @@ void sqlite3Insert(
|
|||||||
if( !appendFlag ){
|
if( !appendFlag ){
|
||||||
sqlite3VdbeAddOp2(v, OP_IfMemNull, regRowid, sqlite3VdbeCurrentAddr(v)+2);
|
sqlite3VdbeAddOp2(v, OP_IfMemNull, regRowid, sqlite3VdbeCurrentAddr(v)+2);
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, -1, 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);
|
sqlite3VdbeAddOp3(v, OP_MustBeInt, 0, 0, regRowid);
|
||||||
}
|
}
|
||||||
}else if( IsVirtual(pTab) ){
|
}else if( IsVirtual(pTab) ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid);
|
sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid);
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeAddOp3(v, OP_NewRowid, base, regRowid, regAutoinc);
|
sqlite3VdbeAddOp3(v, OP_NewRowid, baseCur, regRowid, regAutoinc);
|
||||||
appendFlag = 1;
|
appendFlag = 1;
|
||||||
}
|
}
|
||||||
autoIncStep(pParse, regAutoinc, regRowid);
|
autoIncStep(pParse, regAutoinc, regRowid);
|
||||||
@@ -840,12 +840,28 @@ void sqlite3Insert(
|
|||||||
}else
|
}else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
sqlite3RegToStack(pParse, regIns, pTab->nCol+1);
|
sqlite3GenerateConstraintChecks(
|
||||||
sqlite3GenerateConstraintChecks(pParse, pTab, base, aRegIdx, keyColumn>=0,
|
pParse,
|
||||||
0, onError, endOfLoop);
|
pTab,
|
||||||
sqlite3CompleteInsertion(pParse, pTab, base, aRegIdx,0,0,
|
baseCur,
|
||||||
|
regIns,
|
||||||
|
aRegIdx,
|
||||||
|
keyColumn>=0,
|
||||||
|
0,
|
||||||
|
onError,
|
||||||
|
endOfLoop
|
||||||
|
);
|
||||||
|
sqlite3CompleteInsertion(
|
||||||
|
pParse,
|
||||||
|
pTab,
|
||||||
|
baseCur,
|
||||||
|
regIns,
|
||||||
|
aRegIdx,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
(triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1,
|
(triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1,
|
||||||
appendFlag);
|
appendFlag
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -878,9 +894,9 @@ void sqlite3Insert(
|
|||||||
|
|
||||||
if( !IsVirtual(pTab) && !isView ){
|
if( !IsVirtual(pTab) && !isView ){
|
||||||
/* Close all tables opened */
|
/* 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++){
|
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.
|
** 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 input is a range of consecutive registers as follows:
|
||||||
** the following values:
|
|
||||||
**
|
**
|
||||||
** 1. The rowid of the row to be updated before the update. This
|
** 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
|
** 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.
|
** 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
|
** 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
|
** and rowidChng are 1. isUpdate is true for UPDATEs and false for
|
||||||
** INSERTs and rowidChng is true if the record number is being changed.
|
** INSERTs and rowidChng is true if the record number is being changed.
|
||||||
@@ -977,23 +994,24 @@ insert_cleanup:
|
|||||||
** for the constraint is used.
|
** for the constraint is used.
|
||||||
**
|
**
|
||||||
** The calling routine must open a read/write cursor for pTab with
|
** The calling routine must open a read/write cursor for pTab with
|
||||||
** cursor number "base". All indices of pTab must also have open
|
** cursor number "baseCur". All indices of pTab must also have open
|
||||||
** read/write cursors with cursor number base+i for the i-th cursor.
|
** read/write cursors with cursor number baseCur+i for the i-th cursor.
|
||||||
** Except, if there is no possibility of a REPLACE action then
|
** Except, if there is no possibility of a REPLACE action then
|
||||||
** cursors do not need to be open for indices where aRegIdx[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
|
** If the isUpdate flag is true, it means that the "baseCur" cursor is
|
||||||
** initially pointing to an entry that is being updated. The isUpdate
|
** 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.
|
** 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(
|
void sqlite3GenerateConstraintChecks(
|
||||||
Parse *pParse, /* The parser context */
|
Parse *pParse, /* The parser context */
|
||||||
Table *pTab, /* the table into which we are inserting */
|
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 *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 isUpdate, /* True for UPDATE, False for INSERT */
|
||||||
int overrideError, /* Override onError to this if not OE_Default */
|
int overrideError, /* Override onError to this if not OE_Default */
|
||||||
int ignoreDest /* Jump to this label on an OE_Ignore resolution */
|
int ignoreDest /* Jump to this label on an OE_Ignore resolution */
|
||||||
@@ -1003,25 +1021,19 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
int nCol;
|
int nCol;
|
||||||
int onError;
|
int onError;
|
||||||
int j1, j2, j3; /* Address of jump instructions */
|
int j1, j2, j3; /* Address of jump instructions */
|
||||||
|
int regData; /* Register containing first data column */
|
||||||
int iCur;
|
int iCur;
|
||||||
Index *pIdx;
|
Index *pIdx;
|
||||||
int seenReplace = 0;
|
int seenReplace = 0;
|
||||||
int hasTwoRowids = (isUpdate && rowidChng);
|
int hasTwoRowids = (isUpdate && rowidChng);
|
||||||
|
|
||||||
int regRowid, regData;
|
|
||||||
|
|
||||||
v = sqlite3GetVdbe(pParse);
|
v = sqlite3GetVdbe(pParse);
|
||||||
assert( v!=0 );
|
assert( v!=0 );
|
||||||
assert( pTab->pSelect==0 ); /* This table is not a VIEW */
|
assert( pTab->pSelect==0 ); /* This table is not a VIEW */
|
||||||
nCol = pTab->nCol;
|
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;
|
regData = regRowid + 1;
|
||||||
|
|
||||||
|
|
||||||
/* Test all NOT NULL constraints.
|
/* Test all NOT NULL constraints.
|
||||||
*/
|
*/
|
||||||
for(i=0; i<nCol; i++){
|
for(i=0; i<nCol; i++){
|
||||||
@@ -1053,14 +1065,11 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OE_Ignore: {
|
case OE_Ignore: {
|
||||||
sqlite3VdbeAddOp2(v, OP_Pop, nCol+1+hasTwoRowids, 0);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OE_Replace: {
|
case OE_Replace: {
|
||||||
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, 0);
|
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regData+i);
|
||||||
sqlite3VdbeAddOp2(v, OP_Copy, 0, regData+i);
|
|
||||||
sqlite3VdbeAddOp1(v, OP_Push, nCol-i);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1076,7 +1085,6 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, 1);
|
sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, 1);
|
||||||
onError = overrideError!=OE_Default ? overrideError : OE_Abort;
|
onError = overrideError!=OE_Default ? overrideError : OE_Abort;
|
||||||
if( onError==OE_Ignore ){
|
if( onError==OE_Ignore ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Pop, nCol+1+hasTwoRowids, 0);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_CONSTRAINT, onError);
|
sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_CONSTRAINT, onError);
|
||||||
@@ -1102,7 +1110,7 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
sqlite3VdbeAddOp1(v, OP_SCopy, regRowid);
|
sqlite3VdbeAddOp1(v, OP_SCopy, regRowid);
|
||||||
j2 = sqlite3VdbeAddOp2(v, OP_Eq, 0, 0);
|
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 ){
|
switch( onError ){
|
||||||
default: {
|
default: {
|
||||||
onError = OE_Abort;
|
onError = OE_Abort;
|
||||||
@@ -1116,17 +1124,16 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OE_Replace: {
|
case OE_Replace: {
|
||||||
sqlite3GenerateRowIndexDelete(v, pTab, base, 0);
|
sqlite3GenerateRowIndexDelete(v, pTab, baseCur, 0);
|
||||||
if( isUpdate ){
|
if( isUpdate ){
|
||||||
sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids);
|
sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids);
|
||||||
sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0);
|
sqlite3VdbeAddOp2(v, OP_MoveGe, baseCur, 0);
|
||||||
}
|
}
|
||||||
seenReplace = 1;
|
seenReplace = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OE_Ignore: {
|
case OE_Ignore: {
|
||||||
assert( seenReplace==0 );
|
assert( seenReplace==0 );
|
||||||
sqlite3VdbeAddOp2(v, OP_Pop, nCol+1+hasTwoRowids, 0);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1135,7 +1142,7 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
if( isUpdate ){
|
if( isUpdate ){
|
||||||
sqlite3VdbeJumpHere(v, j2);
|
sqlite3VdbeJumpHere(v, j2);
|
||||||
sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-1);
|
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 */
|
/* Check to see if the new index entry will be unique */
|
||||||
sqlite3VdbeAddOp1(v, OP_SCopy, aRegIdx[iCur]);
|
sqlite3VdbeAddOp1(v, OP_SCopy, aRegIdx[iCur]);
|
||||||
sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids);
|
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 */
|
/* Generate code that executes if the new index entry is not unique */
|
||||||
assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
|
assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
|
||||||
@@ -1213,16 +1220,16 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
}
|
}
|
||||||
case OE_Ignore: {
|
case OE_Ignore: {
|
||||||
assert( seenReplace==0 );
|
assert( seenReplace==0 );
|
||||||
sqlite3VdbeAddOp2(v, OP_Pop, nCol+3+hasTwoRowids, 0);
|
sqlite3VdbeAddOp1(v, OP_Pop, 2+hasTwoRowids);
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OE_Replace: {
|
case OE_Replace: {
|
||||||
int iRowid = sqlite3StackToReg(pParse, 1);
|
int iRowid = sqlite3StackToReg(pParse, 1);
|
||||||
sqlite3GenerateRowDelete(pParse->db, v, pTab, base, iRowid, 0);
|
sqlite3GenerateRowDelete(pParse->db, v, pTab, baseCur, iRowid, 0);
|
||||||
if( isUpdate ){
|
if( isUpdate ){
|
||||||
sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids);
|
sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids);
|
||||||
sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0);
|
sqlite3VdbeAddOp2(v, OP_MoveGe, baseCur, 0);
|
||||||
}
|
}
|
||||||
seenReplace = 1;
|
seenReplace = 1;
|
||||||
break;
|
break;
|
||||||
@@ -1239,9 +1246,8 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
/*
|
/*
|
||||||
** This routine generates code to finish the INSERT or UPDATE operation
|
** This routine generates code to finish the INSERT or UPDATE operation
|
||||||
** that was started by a prior call to sqlite3GenerateConstraintChecks.
|
** that was started by a prior call to sqlite3GenerateConstraintChecks.
|
||||||
** The stack must contain keys for all active indices followed by data
|
** A consecutive range of registers starting at regRowid contains the
|
||||||
** and the rowid for the new entry. This routine creates the new
|
** rowid and the content to be inserted.
|
||||||
** entries in all indices and in the main table.
|
|
||||||
**
|
**
|
||||||
** The arguments to this routine should be the same as the first six
|
** The arguments to this routine should be the same as the first six
|
||||||
** arguments to sqlite3GenerateConstraintChecks.
|
** arguments to sqlite3GenerateConstraintChecks.
|
||||||
@@ -1249,7 +1255,8 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
void sqlite3CompleteInsertion(
|
void sqlite3CompleteInsertion(
|
||||||
Parse *pParse, /* The parser context */
|
Parse *pParse, /* The parser context */
|
||||||
Table *pTab, /* the table into which we are inserting */
|
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 *aRegIdx, /* Register used by each index. 0 for unused indices */
|
||||||
int rowidChng, /* True if the record number will change */
|
int rowidChng, /* True if the record number will change */
|
||||||
int isUpdate, /* True for UPDATE, False for INSERT */
|
int isUpdate, /* True for UPDATE, False for INSERT */
|
||||||
@@ -1261,6 +1268,7 @@ void sqlite3CompleteInsertion(
|
|||||||
int nIdx;
|
int nIdx;
|
||||||
Index *pIdx;
|
Index *pIdx;
|
||||||
int pik_flags;
|
int pik_flags;
|
||||||
|
int regData;
|
||||||
|
|
||||||
v = sqlite3GetVdbe(pParse);
|
v = sqlite3GetVdbe(pParse);
|
||||||
assert( v!=0 );
|
assert( v!=0 );
|
||||||
@@ -1268,14 +1276,16 @@ void sqlite3CompleteInsertion(
|
|||||||
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){}
|
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){}
|
||||||
for(i=nIdx-1; i>=0; i--){
|
for(i=nIdx-1; i>=0; i--){
|
||||||
if( aRegIdx[i]==0 ) continue;
|
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);
|
sqlite3TableAffinityStr(v, pTab);
|
||||||
#ifndef SQLITE_OMIT_TRIGGER
|
#ifndef SQLITE_OMIT_TRIGGER
|
||||||
if( newIdx>=0 ){
|
if( newIdx>=0 ){
|
||||||
sqlite3VdbeAddOp1(v, OP_Copy, -1);
|
sqlite3VdbeAddOp1(v, OP_SCopy, regRowid);
|
||||||
sqlite3VdbeAddOp1(v, OP_Copy, -1);
|
sqlite3VdbeAddOp1(v, OP_SCopy, -1);
|
||||||
sqlite3CodeInsert(pParse, newIdx, 0);
|
sqlite3CodeInsert(pParse, newIdx, 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -1288,19 +1298,15 @@ void sqlite3CompleteInsertion(
|
|||||||
if( appendBias ){
|
if( appendBias ){
|
||||||
pik_flags |= OPFLAG_APPEND;
|
pik_flags |= OPFLAG_APPEND;
|
||||||
}
|
}
|
||||||
sqlite3CodeInsert(pParse, base, pik_flags);
|
sqlite3CodeInsert(pParse, baseCur, pik_flags);
|
||||||
if( !pParse->nested ){
|
if( !pParse->nested ){
|
||||||
sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
|
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
|
** 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.
|
** for the table. Indices are opened on subsequent cursors.
|
||||||
**
|
**
|
||||||
** Return the number of indices on the table.
|
** Return the number of indices on the table.
|
||||||
@@ -1308,7 +1314,7 @@ void sqlite3CompleteInsertion(
|
|||||||
int sqlite3OpenTableAndIndices(
|
int sqlite3OpenTableAndIndices(
|
||||||
Parse *pParse, /* Parsing context */
|
Parse *pParse, /* Parsing context */
|
||||||
Table *pTab, /* Table to be opened */
|
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 op /* OP_OpenRead or OP_OpenWrite */
|
||||||
){
|
){
|
||||||
int i;
|
int i;
|
||||||
@@ -1320,16 +1326,16 @@ int sqlite3OpenTableAndIndices(
|
|||||||
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||||
v = sqlite3GetVdbe(pParse);
|
v = sqlite3GetVdbe(pParse);
|
||||||
assert( v!=0 );
|
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++){
|
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||||
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
|
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
|
||||||
assert( pIdx->pSchema==pTab->pSchema );
|
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);
|
(char*)pKey, P4_KEYINFO_HANDOFF);
|
||||||
VdbeComment((v, "%s", pIdx->zName));
|
VdbeComment((v, "%s", pIdx->zName));
|
||||||
}
|
}
|
||||||
if( pParse->nTab<=base+i ){
|
if( pParse->nTab<=baseCur+i ){
|
||||||
pParse->nTab = base+i;
|
pParse->nTab = baseCur+i;
|
||||||
}
|
}
|
||||||
return i-1;
|
return i-1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** 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_
|
#ifndef _SQLITEINT_H_
|
||||||
#define _SQLITEINT_H_
|
#define _SQLITEINT_H_
|
||||||
@@ -1776,8 +1776,9 @@ int sqlite3IsRowid(const char*);
|
|||||||
void sqlite3GenerateRowDelete(sqlite3*, Vdbe*, Table*, int, int, int);
|
void sqlite3GenerateRowDelete(sqlite3*, Vdbe*, Table*, int, int, int);
|
||||||
void sqlite3GenerateRowIndexDelete(Vdbe*, Table*, int, int*);
|
void sqlite3GenerateRowIndexDelete(Vdbe*, Table*, int, int*);
|
||||||
void sqlite3GenerateIndexKey(Vdbe*, Index*, int);
|
void sqlite3GenerateIndexKey(Vdbe*, Index*, int);
|
||||||
void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int*,int,int,int,int);
|
void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int,
|
||||||
void sqlite3CompleteInsertion(Parse*, Table*, int, int*, int, int, int, int);
|
int*,int,int,int,int);
|
||||||
|
void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*,int,int,int,int);
|
||||||
int sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
|
int sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
|
||||||
void sqlite3BeginWriteOperation(Parse*, int, int);
|
void sqlite3BeginWriteOperation(Parse*, int, int);
|
||||||
Expr *sqlite3ExprDup(sqlite3*,Expr*);
|
Expr *sqlite3ExprDup(sqlite3*,Expr*);
|
||||||
|
|||||||
65
src/update.c
65
src/update.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle UPDATE statements.
|
** 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"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -102,9 +102,6 @@ void sqlite3Update(
|
|||||||
AuthContext sContext; /* The authorization context */
|
AuthContext sContext; /* The authorization context */
|
||||||
NameContext sNC; /* The name-context to resolve expressions in */
|
NameContext sNC; /* The name-context to resolve expressions in */
|
||||||
int iDb; /* Database containing the table being updated */
|
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
|
#ifndef SQLITE_OMIT_TRIGGER
|
||||||
int isView; /* Trying to update a view */
|
int isView; /* Trying to update a view */
|
||||||
@@ -120,6 +117,12 @@ void sqlite3Update(
|
|||||||
int newIdx = -1; /* index of trigger "new" temp table */
|
int newIdx = -1; /* index of trigger "new" temp table */
|
||||||
int oldIdx = -1; /* index of trigger "old" 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;
|
sContext.pParse = 0;
|
||||||
db = pParse->db;
|
db = pParse->db;
|
||||||
if( pParse->nErr || db->mallocFailed ){
|
if( pParse->nErr || db->mallocFailed ){
|
||||||
@@ -251,13 +254,28 @@ void sqlite3Update(
|
|||||||
aRegIdx[j] = reg;
|
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.
|
/* Begin generating code.
|
||||||
*/
|
*/
|
||||||
v = sqlite3GetVdbe(pParse);
|
v = sqlite3GetVdbe(pParse);
|
||||||
if( v==0 ) goto update_cleanup;
|
if( v==0 ) goto update_cleanup;
|
||||||
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
||||||
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
||||||
mem1 = ++pParse->nMem;
|
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
/* Virtual tables must be handled separately */
|
/* Virtual tables must be handled separately */
|
||||||
@@ -333,9 +351,8 @@ void sqlite3Update(
|
|||||||
|
|
||||||
/* Remember the rowid of every item to be updated.
|
/* Remember the rowid of every item to be updated.
|
||||||
*/
|
*/
|
||||||
iRowid = ++pParse->nMem;
|
sqlite3VdbeAddOp2(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid,iCur,regOldRowid);
|
||||||
sqlite3VdbeAddOp2(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, iRowid);
|
sqlite3VdbeAddOp2(v, OP_FifoWrite, regOldRowid, 0);
|
||||||
sqlite3VdbeAddOp2(v, OP_FifoWrite, iRowid, 0);
|
|
||||||
|
|
||||||
/* End the database scan loop.
|
/* End the database scan loop.
|
||||||
*/
|
*/
|
||||||
@@ -344,8 +361,8 @@ void sqlite3Update(
|
|||||||
/* Initialize the count of updated rows
|
/* Initialize the count of updated rows
|
||||||
*/
|
*/
|
||||||
if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
|
if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
|
||||||
memCnt = ++pParse->nMem;
|
regRowCount = ++pParse->nMem;
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, memCnt);
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !isView && !IsVirtual(pTab) ){
|
if( !isView && !IsVirtual(pTab) ){
|
||||||
@@ -383,13 +400,13 @@ void sqlite3Update(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Top of the update loop */
|
/* 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);
|
sqlite3VdbeAddOp2(v, OP_StackDepth, -1, 0);
|
||||||
|
|
||||||
if( triggers_exist ){
|
if( triggers_exist ){
|
||||||
/* Make cursor iCur point to the record that is being updated.
|
/* 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
|
/* Generate the OLD table
|
||||||
*/
|
*/
|
||||||
@@ -437,44 +454,43 @@ void sqlite3Update(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( !isView && !IsVirtual(pTab) ){
|
if( !isView && !IsVirtual(pTab) ){
|
||||||
|
|
||||||
/* Loop over every record that needs updating. We have to load
|
/* Loop over every record that needs updating. We have to load
|
||||||
** the old data for each record to be updated because some columns
|
** the old data for each record to be updated because some columns
|
||||||
** might not change and we will need to copy the old value.
|
** might not change and we will need to copy the old value.
|
||||||
** Also, the old data is needed to delete the old index entries.
|
** Also, the old data is needed to delete the old index entries.
|
||||||
** So make the cursor point at the old record.
|
** So make the cursor point at the old record.
|
||||||
*/
|
*/
|
||||||
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, iRowid);
|
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid);
|
||||||
sqlite3VdbeAddOp2(v, OP_SCopy, iRowid, 0);
|
|
||||||
|
|
||||||
/* If the record number will change, push the record number as it
|
/* If the record number will change, push the record number as it
|
||||||
** will be after the update. (The old record number is currently
|
** will be after the update. (The old record number is currently
|
||||||
** on top of the stack.)
|
** on top of the stack.)
|
||||||
*/
|
*/
|
||||||
if( chngRowid ){
|
if( chngRowid ){
|
||||||
sqlite3ExprCode(pParse, pRowidExpr, 0);
|
sqlite3ExprCode(pParse, pRowidExpr, regNewRowid);
|
||||||
sqlite3VdbeAddOp2(v, OP_MustBeInt, 0, 0);
|
sqlite3VdbeAddOp3(v, OP_MustBeInt, 0, 0, regNewRowid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute new data for this record.
|
/* Compute new data for this record.
|
||||||
*/
|
*/
|
||||||
for(i=0; i<pTab->nCol; i++){
|
for(i=0; i<pTab->nCol; i++){
|
||||||
if( i==pTab->iPKey ){
|
if( i==pTab->iPKey ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
|
sqlite3VdbeAddOp2(v, OP_Null, 0, regData+i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
j = aXRef[i];
|
j = aXRef[i];
|
||||||
if( j<0 ){
|
if( j<0 ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Column, iCur, i);
|
sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regData+i);
|
||||||
sqlite3ColumnDefault(v, pTab, i);
|
sqlite3ColumnDefault(v, pTab, i);
|
||||||
}else{
|
}else{
|
||||||
sqlite3ExprCode(pParse, pChanges->a[j].pExpr, 0);
|
sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regData+i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do constraint checks
|
/* Do constraint checks
|
||||||
*/
|
*/
|
||||||
sqlite3GenerateConstraintChecks(pParse, pTab, iCur, aRegIdx, chngRowid, 1,
|
sqlite3GenerateConstraintChecks(pParse, pTab, iCur, regNewRowid,
|
||||||
|
aRegIdx, chngRowid, 1,
|
||||||
onError, addr);
|
onError, addr);
|
||||||
|
|
||||||
/* Delete the old indices for the current record.
|
/* Delete the old indices for the current record.
|
||||||
@@ -489,13 +505,14 @@ void sqlite3Update(
|
|||||||
|
|
||||||
/* Create the new index entries and the new record.
|
/* 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
|
/* Increment the row counter
|
||||||
*/
|
*/
|
||||||
if( db->flags & SQLITE_CountRows && !pParse->trigStack){
|
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
|
/* If there are triggers, close all the cursors after each iteration
|
||||||
@@ -530,7 +547,7 @@ void sqlite3Update(
|
|||||||
** invoke the callback function.
|
** invoke the callback function.
|
||||||
*/
|
*/
|
||||||
if( db->flags & SQLITE_CountRows && !pParse->trigStack && pParse->nested==0 ){
|
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);
|
sqlite3VdbeSetNumCols(v, 1);
|
||||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P4_STATIC);
|
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P4_STATIC);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#***********************************************************************
|
#***********************************************************************
|
||||||
# This file runs all tests.
|
# 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} {
|
proc lshift {lvar} {
|
||||||
upvar $lvar l
|
upvar $lvar l
|
||||||
@@ -48,6 +48,7 @@ set EXCLUDE {
|
|||||||
crash.test
|
crash.test
|
||||||
crash2.test
|
crash2.test
|
||||||
crash3.test
|
crash3.test
|
||||||
|
crash4.test
|
||||||
exclusive3.test
|
exclusive3.test
|
||||||
fts3.test
|
fts3.test
|
||||||
fuzz.test
|
fuzz.test
|
||||||
|
|||||||
Reference in New Issue
Block a user