1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-08 03:22:21 +03:00

Progress toward registerification of the constraint checking logic for

INSERT and UPDATE. (CVS 4693)

FossilOrigin-Name: b9bf509e39f5ac38c2149d2a648f68e5df5ae9e3
This commit is contained in:
drh
2008-01-08 02:57:55 +00:00
parent 6a288a33f9
commit aa9b8963b5
10 changed files with 162 additions and 166 deletions

View File

@@ -1,5 +1,5 @@
C Registerify\sthe\sAUTOINCREMENT\sprocessing\sand\sthe\sOP_IsNull\sand\sOP_NotNull\noperators.\s(CVS\s4692) C Progress\stoward\sregisterification\sof\sthe\sconstraint\schecking\slogic\sfor\nINSERT\sand\sUPDATE.\s(CVS\s4693)
D 2008-01-07T19:20:25 D 2008-01-08T02:57:56
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
@@ -90,13 +90,13 @@ F src/build.c 22b50a462d7b2be82e29071069d1c3daf29e953f
F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0 F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131 F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6 F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6
F src/delete.c 09c7b312a061d08df8a95b1f75cb10c6af14114a F src/delete.c d78e46b259a94a5f98a1bceee206c5fd21276ae7
F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
F src/expr.c f84b4901dff3bacd08ece3f0de09318a5a298121 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 9c1a6501d79c9c4e674e0e2c3bc4a5207f9b3b95 F src/insert.c 3a45102002b611aa1707bb6c6c5c148547d2630a
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 95cdddce11ee871fad1d91d6b6e405969dcc405f F src/sqliteInt.h 964754dcd508ddf0dd0b326072ad80678452e5c2
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,18 +164,18 @@ 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 38e9e4c27896df2d189927e3b483cadf5641f47c F src/update.c acd1c38dbbf253183fe2a8e5be0b3f3fee59be15
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
F src/vdbe.c 3d849013558e52b2c85134fc6ed655d6dc00ace7 F src/vdbe.c e71595acce83c585c31ac0551cee1c8cf9540fd2
F src/vdbe.h bb128757b84280504a1243c450fd13ead248ede5 F src/vdbe.h bb128757b84280504a1243c450fd13ead248ede5
F src/vdbeInt.h 31bd686595356284d5484592e2dc6e58025aa346 F src/vdbeInt.h 31bd686595356284d5484592e2dc6e58025aa346
F src/vdbeapi.c f14174843bf4be2c9afdf2ef48b61e7c3ac62d7c F src/vdbeapi.c f14174843bf4be2c9afdf2ef48b61e7c3ac62d7c
F src/vdbeaux.c 75b7d3e42c94310f28f6f7d3e08b69797fbe8a78 F src/vdbeaux.c b6241be0277795ecd902743366434704f03b7636
F src/vdbeblob.c b90f7494c408d47ce6835000b01e40b371e27baf F src/vdbeblob.c b90f7494c408d47ce6835000b01e40b371e27baf
F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6 F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
F src/vdbemem.c 123994fcd344993d2fb050a83b91b341bbbd08b4 F src/vdbemem.c a94f3e9e85578ba457133ad3446fc6114a03ec5a
F src/vtab.c 03014b2bfa8096ecac5fcdc80d34cd76e06af52a F src/vtab.c 03014b2bfa8096ecac5fcdc80d34cd76e06af52a
F src/where.c 306fafa709ced14b1c816d38b96a8f4446ec1eeb F src/where.c 306fafa709ced14b1c816d38b96a8f4446ec1eeb
F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617 F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617
@@ -604,7 +604,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 38020592f15c072e0d221ae2e0df13508ac4bd49 P aa48867cfa04da265b906e5b583bc7ac6b6a1157
R dde2d5dbca593f8bc201758cd5d40a3d R af4f73c6bffdbedd3861a3c5eb6d920e
U drh U drh
Z 07f47472df3751ae71471b817e3e70f7 Z 313f66697e8ae592eab31fdd061363d6

View File

@@ -1 +1 @@
aa48867cfa04da265b906e5b583bc7ac6b6a1157 b9bf509e39f5ac38c2149d2a648f68e5df5ae9e3

View File

@@ -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
** in order to generate code for DELETE FROM statements. ** 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" #include "sqliteInt.h"
@@ -492,13 +492,13 @@ void sqlite3GenerateRowIndexDelete(
Vdbe *v, /* Generate code into this VDBE */ Vdbe *v, /* Generate code into this VDBE */
Table *pTab, /* Table containing the row to be deleted */ Table *pTab, /* Table containing the row to be deleted */
int iCur, /* Cursor number for the table */ 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; int i;
Index *pIdx; Index *pIdx;
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ 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); sqlite3GenerateIndexKey(v, pIdx, iCur);
sqlite3VdbeAddOp1(v, OP_IdxDelete, iCur+i); sqlite3VdbeAddOp1(v, OP_IdxDelete, iCur+i);
} }

View File

@@ -12,7 +12,7 @@
** This file contains routines used for analyzing expressions and ** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite. ** 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 "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@@ -1944,15 +1944,12 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
Vdbe *v = pParse->pVdbe; Vdbe *v = pParse->pVdbe;
int op; int op;
int inReg = 0; int inReg = 0;
int stackChng = 0;
int origTarget = target; int origTarget = target;
assert( v!=0 || pParse->db->mallocFailed ); assert( v!=0 || pParse->db->mallocFailed );
if( v==0 ) return 0; if( v==0 ) return 0;
if( target<0 ){ if( target<0 ){
target = ++pParse->nMem; target = ++pParse->nMem;
}else if( target==0 ){
stackChng = 1;
} }
if( pExpr==0 ){ if( pExpr==0 ){
@@ -1979,9 +1976,8 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
case TK_COLUMN: { case TK_COLUMN: {
if( pExpr->iTable<0 ){ if( pExpr->iTable<0 ){
/* This only happens when coding check constraints */ /* This only happens when coding check constraints */
assert( pParse->ckOffset>0 ); assert( pParse->ckBase>0 );
sqlite3VdbeAddOp1(v, OP_SCopy, -(pParse->ckOffset-pExpr->iColumn-1)); inReg = pExpr->iColumn + pParse->ckBase;
/* inReg = -(pParse->ckOffset-pExpr->iColumn-1); */
}else{ }else{
sqlite3ExprCodeGetColumn(v, pExpr->pTab, sqlite3ExprCodeGetColumn(v, pExpr->pTab,
pExpr->iColumn, pExpr->iTable, target); 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_ToInt || aff!=SQLITE_AFF_INTEGER );
assert( to_op==OP_ToReal || aff!=SQLITE_AFF_REAL ); assert( to_op==OP_ToReal || aff!=SQLITE_AFF_REAL );
sqlite3VdbeAddOp1(v, to_op, target); sqlite3VdbeAddOp1(v, to_op, target);
stackChng = 0;
inReg = target; inReg = target;
break; break;
} }
@@ -2072,7 +2067,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
sqlite3ExprCode(pParse, pExpr->pLeft, 0); sqlite3ExprCode(pParse, pExpr->pLeft, 0);
sqlite3ExprCode(pParse, pExpr->pRight, 0); sqlite3ExprCode(pParse, pExpr->pRight, 0);
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, 0, 0); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, 0, 0);
stackChng = -1;
break; break;
} }
case TK_AND: case TK_AND:
@@ -2099,12 +2093,9 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
assert( TK_LSHIFT==OP_ShiftLeft ); assert( TK_LSHIFT==OP_ShiftLeft );
assert( TK_RSHIFT==OP_ShiftRight ); assert( TK_RSHIFT==OP_ShiftRight );
assert( TK_CONCAT==OP_Concat ); assert( TK_CONCAT==OP_Concat );
r1 = sqlite3ExprCode(pParse, pExpr->pLeft, 0); r1 = sqlite3ExprCode(pParse, pExpr->pLeft, -1);
r2 = sqlite3ExprCode(pParse, pExpr->pRight, 0); r2 = sqlite3ExprCode(pParse, pExpr->pRight, -1);
sqlite3VdbeAddOp3(v, op, r2, r1, target); sqlite3VdbeAddOp3(v, op, r2, r1, target);
if( r1==0 ) stackChng--;
if( r2==0 ) stackChng--;
if( target==0 ) stackChng++;
inReg = target; inReg = target;
break; break;
} }
@@ -2129,7 +2120,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
assert( TK_NOT==OP_Not ); assert( TK_NOT==OP_Not );
sqlite3ExprCode(pParse, pExpr->pLeft, 0); sqlite3ExprCode(pParse, pExpr->pLeft, 0);
sqlite3VdbeAddOp0(v, op); sqlite3VdbeAddOp0(v, op);
stackChng = 0;
break; break;
} }
case TK_ISNULL: case TK_ISNULL:
@@ -2142,7 +2132,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
addr = sqlite3VdbeAddOp0(v, op); addr = sqlite3VdbeAddOp0(v, op);
sqlite3VdbeAddOp2(v, OP_AddImm, target, -1); sqlite3VdbeAddOp2(v, OP_AddImm, target, -1);
sqlite3VdbeJumpHere(v, addr); sqlite3VdbeJumpHere(v, addr);
stackChng = 0;
inReg = target; inReg = target;
break; break;
} }
@@ -2207,7 +2196,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
} }
sqlite3VdbeAddOp4(v, OP_Function, constMask, nExpr, 0, sqlite3VdbeAddOp4(v, OP_Function, constMask, nExpr, 0,
(char*)pDef, P4_FUNCDEF); (char*)pDef, P4_FUNCDEF);
stackChng = 1-nExpr;
break; break;
} }
#ifndef SQLITE_OMIT_SUBQUERY #ifndef SQLITE_OMIT_SUBQUERY
@@ -2224,7 +2212,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
case TK_IN: { case TK_IN: {
int j1, j2, j3, j4, j5; int j1, j2, j3, j4, j5;
char affinity; char affinity;
int ckOffset = pParse->ckOffset;
int eType; int eType;
eType = sqlite3FindInIndex(pParse, pExpr, 0); eType = sqlite3FindInIndex(pParse, pExpr, 0);
@@ -2236,7 +2223,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
affinity = comparisonAffinity(pExpr); affinity = comparisonAffinity(pExpr);
sqlite3VdbeAddOp1(v, OP_Integer, 1); sqlite3VdbeAddOp1(v, OP_Integer, 1);
pParse->ckOffset = (ckOffset ? (ckOffset+1) : 0);
/* Code the <expr> from "<expr> IN (...)". The temporary table /* Code the <expr> from "<expr> IN (...)". The temporary table
** pExpr->iTable contains the values that make up the (...) set. ** 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: { case TK_UPLUS: {
inReg = sqlite3ExprCode(pParse, pExpr->pLeft, origTarget); inReg = sqlite3ExprCode(pParse, pExpr->pLeft, origTarget);
stackChng = 0;
break; break;
} }
case TK_CASE: { case TK_CASE: {
@@ -2349,7 +2334,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->trigStack->ignoreJump); sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->trigStack->ignoreJump);
VdbeComment((v, "raise(IGNORE)")); VdbeComment((v, "raise(IGNORE)"));
} }
stackChng = 0;
break; break;
} }
#endif #endif
@@ -2360,11 +2344,6 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
}else{ }else{
target = inReg; target = inReg;
} }
stackChng = 0;
}
if( pParse->ckOffset ){
pParse->ckOffset += stackChng;
assert( pParse->ckOffset );
} }
return target; return target;
} }
@@ -2443,7 +2422,6 @@ int sqlite3ExprCodeExprList(
void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
Vdbe *v = pParse->pVdbe; Vdbe *v = pParse->pVdbe;
int op = 0; int op = 0;
int ckOffset = pParse->ckOffset;
if( v==0 || pExpr==0 ) return; if( v==0 || pExpr==0 ) return;
op = pExpr->op; op = pExpr->op;
switch( op ){ switch( op ){
@@ -2518,7 +2496,6 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
break; 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){ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
Vdbe *v = pParse->pVdbe; Vdbe *v = pParse->pVdbe;
int op = 0; int op = 0;
int ckOffset = pParse->ckOffset;
if( v==0 || pExpr==0 ) return; if( v==0 || pExpr==0 ) return;
/* The value of pExpr->op and op are related as follows: /* 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; break;
} }
} }
pParse->ckOffset = ckOffset;
} }
/* /*

View File

@@ -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.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" #include "sqliteInt.h"
@@ -373,6 +373,7 @@ void sqlite3Insert(
int regRowid; /* registers holding insert rowid */ int regRowid; /* registers holding insert rowid */
int regData; /* register holding first column to insert */ int regData; /* register holding first column to insert */
int regRecord; /* Holds the assemblied row record */ int regRecord; /* Holds the assemblied row record */
int *aRegIdx = 0; /* One register allocated to each index */
#ifndef SQLITE_OMIT_TRIGGER #ifndef SQLITE_OMIT_TRIGGER
@@ -631,8 +632,18 @@ void sqlite3Insert(
/* If this is not a view, open the table and and all indices */ /* If this is not a view, open the table and and all indices */
if( !isView ){ if( !isView ){
int nIdx;
int i;
base = pParse->nTab; 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; i<nIdx; i++){
aRegIdx[i] = ++pParse->nMem;
}
} }
/* If the data source is a temporary table, then we have to create /* If the data source is a temporary table, then we have to create
@@ -830,9 +841,9 @@ void sqlite3Insert(
#endif #endif
{ {
sqlite3RegToStack(pParse, regIns, pTab->nCol+1); sqlite3RegToStack(pParse, regIns, pTab->nCol+1);
sqlite3GenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0, sqlite3GenerateConstraintChecks(pParse, pTab, base, aRegIdx, keyColumn>=0,
0, onError, endOfLoop); 0, onError, endOfLoop);
sqlite3CompleteInsertion(pParse, pTab, base, 0,0,0, sqlite3CompleteInsertion(pParse, pTab, base, aRegIdx,0,0,
(triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1, (triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1,
appendFlag); appendFlag);
} }
@@ -895,6 +906,7 @@ insert_cleanup:
sqlite3ExprListDelete(pList); sqlite3ExprListDelete(pList);
sqlite3SelectDelete(pSelect); sqlite3SelectDelete(pSelect);
sqlite3IdListDelete(pColumn); sqlite3IdListDelete(pColumn);
sqlite3_free(aRegIdx);
} }
/* /*
@@ -919,11 +931,11 @@ insert_cleanup:
** 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.
** **
** The code generated by this routine pushes additional entries onto ** The code generated by this routine store new index entries into
** the stack which are the keys for new index entries for the new record. ** registers identified by aRegIdx[]. No index entry is created for
** The order of index keys is the same as the order of the indices on ** indices where aRegIdx[i]==0. The order of indices in aRegIdx[] is
** the pTable->pIndex list. A key is only created for index i if ** the same as the order of indices on the linked list of indices
** aIdxUsed!=0 and aIdxUsed[i]!=0. ** attached to the table.
** **
** This routine also generates code to check constraints. NOT NULL, ** This routine also generates code to check constraints. NOT NULL,
** CHECK, and UNIQUE constraints are all checked. If a constraint fails, ** 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 ** cursor number "base". 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 base+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 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 ** If the isUpdate flag is true, it means that the "base" cursor is
** initially pointing to an entry that is being updated. The isUpdate ** initially pointing to an entry that is being updated. The isUpdate
@@ -980,7 +992,7 @@ 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 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 rowidChng, /* True if the record number 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 */
@@ -990,19 +1002,26 @@ void sqlite3GenerateConstraintChecks(
Vdbe *v; Vdbe *v;
int nCol; int nCol;
int onError; int onError;
int addr; int j1, j2, j3; /* Address of jump instructions */
int extra;
int iCur; int iCur;
Index *pIdx; Index *pIdx;
int seenReplace = 0; int seenReplace = 0;
int jumpInst1=0, jumpInst2;
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;
/* Test all NOT NULL constraints. /* Test all NOT NULL constraints.
*/ */
for(i=0; i<nCol; i++){ for(i=0; i<nCol; i++){
@@ -1019,8 +1038,7 @@ void sqlite3GenerateConstraintChecks(
if( onError==OE_Replace && pTab->aCol[i].pDflt==0 ){ if( onError==OE_Replace && pTab->aCol[i].pDflt==0 ){
onError = OE_Abort; onError = OE_Abort;
} }
sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol-1-i)); j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regData+i);
addr = sqlite3VdbeAddOp0(v, OP_NotNull);
assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
|| onError==OE_Ignore || onError==OE_Replace ); || onError==OE_Ignore || onError==OE_Replace );
switch( onError ){ switch( onError ){
@@ -1041,11 +1059,12 @@ void sqlite3GenerateConstraintChecks(
} }
case OE_Replace: { case OE_Replace: {
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, 0); sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, 0);
sqlite3VdbeAddOp2(v, OP_Copy, 0, regData+i);
sqlite3VdbeAddOp1(v, OP_Push, nCol-i); sqlite3VdbeAddOp1(v, OP_Push, nCol-i);
break; break;
} }
} }
sqlite3VdbeJumpHere(v, addr); sqlite3VdbeJumpHere(v, j1);
} }
/* Test all CHECK constraints /* Test all CHECK constraints
@@ -1053,11 +1072,8 @@ void sqlite3GenerateConstraintChecks(
#ifndef SQLITE_OMIT_CHECK #ifndef SQLITE_OMIT_CHECK
if( pTab->pCheck && (pParse->db->flags & SQLITE_IgnoreChecks)==0 ){ if( pTab->pCheck && (pParse->db->flags & SQLITE_IgnoreChecks)==0 ){
int allOk = sqlite3VdbeMakeLabel(v); int allOk = sqlite3VdbeMakeLabel(v);
assert( pParse->ckOffset==0 ); pParse->ckBase = regData;
pParse->ckOffset = nCol;
sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, 1); sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, 1);
assert( pParse->ckOffset==nCol );
pParse->ckOffset = 0;
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_Pop, nCol+1+hasTwoRowids, 0);
@@ -1082,12 +1098,11 @@ void sqlite3GenerateConstraintChecks(
} }
if( isUpdate ){ if( isUpdate ){
sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol+1)); sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-1);
sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol+1)); sqlite3VdbeAddOp1(v, OP_SCopy, regRowid);
jumpInst1 = sqlite3VdbeAddOp2(v, OP_Eq, 0, 0); j2 = sqlite3VdbeAddOp2(v, OP_Eq, 0, 0);
} }
sqlite3VdbeAddOp1(v, OP_SCopy, -nCol); j3 = sqlite3VdbeAddOp3(v, OP_NotExists, base, 0, regRowid);
jumpInst2 = sqlite3VdbeAddOp2(v, OP_NotExists, base, 0);
switch( onError ){ switch( onError ){
default: { default: {
onError = OE_Abort; onError = OE_Abort;
@@ -1103,7 +1118,7 @@ void sqlite3GenerateConstraintChecks(
case OE_Replace: { case OE_Replace: {
sqlite3GenerateRowIndexDelete(v, pTab, base, 0); sqlite3GenerateRowIndexDelete(v, pTab, base, 0);
if( isUpdate ){ if( isUpdate ){
sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol+hasTwoRowids)); sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids);
sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0); sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0);
} }
seenReplace = 1; seenReplace = 1;
@@ -1116,10 +1131,10 @@ void sqlite3GenerateConstraintChecks(
break; break;
} }
} }
sqlite3VdbeJumpHere(v, jumpInst2); sqlite3VdbeJumpHere(v, j3);
if( isUpdate ){ if( isUpdate ){
sqlite3VdbeJumpHere(v, jumpInst1); sqlite3VdbeJumpHere(v, j2);
sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol+1)); sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-1);
sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0); sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0);
} }
} }
@@ -1128,22 +1143,20 @@ void sqlite3GenerateConstraintChecks(
** index and making sure that duplicate entries do not already exist. ** index and making sure that duplicate entries do not already exist.
** Add the new records to the indices as we go. ** Add the new records to the indices as we go.
*/ */
extra = -1;
for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){ for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){
if( aIdxUsed && aIdxUsed[iCur]==0 ) continue; /* Skip unused indices */ if( aRegIdx[iCur]==0 ) continue; /* Skip unused indices */
extra++;
/* Create a key for accessing the index entry */ /* Create a key for accessing the index entry */
sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol+extra)); sqlite3VdbeAddOp1(v, OP_SCopy, regRowid);
for(i=0; i<pIdx->nColumn; i++){ for(i=0; i<pIdx->nColumn; i++){
int idx = pIdx->aiColumn[i]; int idx = pIdx->aiColumn[i];
if( idx==pTab->iPKey ){ if( idx==pTab->iPKey ){
sqlite3VdbeAddOp1(v, OP_SCopy, -(i+extra+nCol+1)); sqlite3VdbeAddOp1(v, OP_SCopy, regRowid);
}else{ }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); sqlite3IndexAffinityStr(v, pIdx);
/* Find out what action to take in case there is an indexing conflict */ /* 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 */ /* Check to see if the new index entry will be unique */
sqlite3VdbeAddOp1(v, OP_SCopy, -(extra+nCol+1+hasTwoRowids)); sqlite3VdbeAddOp1(v, OP_SCopy, aRegIdx[iCur]);
jumpInst2 = sqlite3VdbeAddOp2(v, OP_IsUnique, base+iCur+1, 0); 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 */ /* 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
@@ -1199,7 +1213,7 @@ void sqlite3GenerateConstraintChecks(
} }
case OE_Ignore: { case OE_Ignore: {
assert( seenReplace==0 ); 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); sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
break; break;
} }
@@ -1207,17 +1221,18 @@ void sqlite3GenerateConstraintChecks(
int iRowid = sqlite3StackToReg(pParse, 1); int iRowid = sqlite3StackToReg(pParse, 1);
sqlite3GenerateRowDelete(pParse->db, v, pTab, base, iRowid, 0); sqlite3GenerateRowDelete(pParse->db, v, pTab, base, iRowid, 0);
if( isUpdate ){ if( isUpdate ){
sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol+extra+1+hasTwoRowids)); sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids);
sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0); sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0);
} }
seenReplace = 1; seenReplace = 1;
break; break;
} }
} }
sqlite3VdbeJumpHere(v, j3);
sqlite3VdbeAddOp1(v, OP_Pop, 1);
#if NULL_DISTINCT_FOR_UNIQUE #if NULL_DISTINCT_FOR_UNIQUE
sqlite3VdbeJumpHere(v, jumpInst1); sqlite3VdbeJumpHere(v, j2);
#endif #endif
sqlite3VdbeJumpHere(v, jumpInst2);
} }
} }
@@ -1235,7 +1250,7 @@ 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 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 rowidChng, /* True if the record number will change */
int isUpdate, /* True for UPDATE, False for INSERT */ int isUpdate, /* True for UPDATE, False for INSERT */
int newIdx, /* Index of NEW table for triggers. -1 if none */ 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 */ assert( pTab->pSelect==0 ); /* This table is not a VIEW */
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( aIdxUsed && aIdxUsed[i]==0 ) continue; if( aRegIdx[i]==0 ) continue;
sqlite3VdbeAddOp2(v, OP_IdxInsert, base+i+1, 0); sqlite3VdbeAddOp2(v, OP_IdxInsert, base+i+1, aRegIdx[i]);
} }
sqlite3VdbeAddOp2(v, OP_MakeRecord, pTab->nCol, 0); sqlite3VdbeAddOp2(v, OP_MakeRecord, pTab->nCol, 0);
sqlite3TableAffinityStr(v, pTab); sqlite3TableAffinityStr(v, pTab);
@@ -1287,8 +1302,10 @@ void sqlite3CompleteInsertion(
** 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 "base" 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.
*/ */
void 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 base, /* Cursor number assigned to the table */
@@ -1299,7 +1316,7 @@ void sqlite3OpenTableAndIndices(
Index *pIdx; Index *pIdx;
Vdbe *v; Vdbe *v;
if( IsVirtual(pTab) ) return; if( IsVirtual(pTab) ) return 0;
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
v = sqlite3GetVdbe(pParse); v = sqlite3GetVdbe(pParse);
assert( v!=0 ); assert( v!=0 );
@@ -1314,6 +1331,7 @@ void sqlite3OpenTableAndIndices(
if( pParse->nTab<=base+i ){ if( pParse->nTab<=base+i ){
pParse->nTab = base+i; pParse->nTab = base+i;
} }
return i-1;
} }
@@ -1614,7 +1632,7 @@ static int xferOptimization(
VdbeComment((v, "%s", pDestIdx->zName)); VdbeComment((v, "%s", pDestIdx->zName));
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0);
sqlite3VdbeAddOp2(v, OP_RowKey, 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); sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1);
sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeJumpHere(v, addr1);
} }

View File

@@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** 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_ #ifndef _SQLITEINT_H_
#define _SQLITEINT_H_ #define _SQLITEINT_H_
@@ -1389,7 +1389,7 @@ struct Parse {
int nTab; /* Number of previously allocated VDBE cursors */ int nTab; /* Number of previously allocated VDBE cursors */
int nMem; /* Number of memory cells used so far */ int nMem; /* Number of memory cells used so far */
int nSet; /* Number of sets 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 writeMask; /* Start a write transaction on these databases */
u32 cookieMask; /* Bitmask of schema verified databases */ u32 cookieMask; /* Bitmask of schema verified databases */
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */ int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
@@ -1774,11 +1774,11 @@ int sqlite3ExprIsConstantOrFunction(Expr*);
int sqlite3ExprIsInteger(Expr*, int*); int sqlite3ExprIsInteger(Expr*, int*);
int sqlite3IsRowid(const char*); 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, char*); void sqlite3GenerateRowIndexDelete(Vdbe*, Table*, int, int*);
void sqlite3GenerateIndexKey(Vdbe*, Index*, int); void sqlite3GenerateIndexKey(Vdbe*, Index*, int);
void sqlite3GenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int); void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int*,int,int,int,int);
void sqlite3CompleteInsertion(Parse*, Table*, int, char*, int, int, int, int); void sqlite3CompleteInsertion(Parse*, Table*, int, int*, int, int, int, int);
void 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*);
void sqlite3TokenCopy(sqlite3*,Token*, Token*); void sqlite3TokenCopy(sqlite3*,Token*, Token*);

View File

@@ -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.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" #include "sqliteInt.h"
@@ -90,11 +90,9 @@ void sqlite3Update(
Vdbe *v; /* The virtual database engine */ Vdbe *v; /* The virtual database engine */
Index *pIdx; /* For looping over indices */ Index *pIdx; /* For looping over indices */
int nIdx; /* Number of indices that need updating */ int nIdx; /* Number of indices that need updating */
int nIdxTotal; /* Total number of indices */
int iCur; /* VDBE Cursor number of pTab */ int iCur; /* VDBE Cursor number of pTab */
sqlite3 *db; /* The database structure */ sqlite3 *db; /* The database structure */
Index **apIdx = 0; /* An array of indices that need updating too */ int *aRegIdx = 0; /* One register assigned to each index to be updated */
char *aIdxUsed = 0; /* aIdxUsed[i]==1 if the i-th index is used */
int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the
** an expression for the i-th column of the table. ** an expression for the i-th column of the table.
** aXRef[i]==-1 if the i-th column is not changed. */ ** aXRef[i]==-1 if the i-th column is not changed. */
@@ -227,40 +225,30 @@ void sqlite3Update(
#endif #endif
} }
/* Allocate memory for the array apIdx[] and fill it with pointers to every /* Allocate memory for the array aRegIdx[]. There is one entry in the
** index that needs to be updated. Indices only need updating if their ** array for each index associated with table being updated. Fill in
** key includes one of the columns named in pChanges or if the record ** the value with a register number for indices that are to be used
** number of the original table entry is changing. ** and with zero for unused indices.
*/ */
for(nIdx=nIdxTotal=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdxTotal++){ 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(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
int reg;
if( chngRowid ){ if( chngRowid ){
i = 0; reg = ++pParse->nMem;
}else { }else{
reg = 0;
for(i=0; i<pIdx->nColumn; i++){ for(i=0; i<pIdx->nColumn; i++){
if( aXRef[pIdx->aiColumn[i]]>=0 ) break; if( aXRef[pIdx->aiColumn[i]]>=0 ){
reg = ++pParse->nMem;
break;
}
} }
} }
if( i<pIdx->nColumn ) nIdx++; aRegIdx[j] = reg;
}
if( nIdxTotal>0 ){
apIdx = sqlite3DbMallocRaw(db, sizeof(Index*) * nIdx + nIdxTotal );
if( apIdx==0 ) goto update_cleanup;
aIdxUsed = (char*)&apIdx[nIdx];
}
for(nIdx=j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
if( chngRowid ){
i = 0;
}else{
for(i=0; i<pIdx->nColumn; i++){
if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
}
}
if( i<pIdx->nColumn ){
apIdx[nIdx++] = pIdx;
aIdxUsed[j] = 1;
}else{
aIdxUsed[j] = 0;
}
} }
/* Begin generating code. /* Begin generating code.
@@ -380,7 +368,7 @@ void sqlite3Update(
} }
} }
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ 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); KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
sqlite3VdbeAddOp4(v, OP_OpenWrite, iCur+i+1, pIdx->tnum, iDb, sqlite3VdbeAddOp4(v, OP_OpenWrite, iCur+i+1, pIdx->tnum, iDb,
(char*)pKey, P4_KEYINFO_HANDOFF); (char*)pKey, P4_KEYINFO_HANDOFF);
@@ -486,12 +474,12 @@ void sqlite3Update(
/* Do constraint checks /* Do constraint checks
*/ */
sqlite3GenerateConstraintChecks(pParse, pTab, iCur, aIdxUsed, chngRowid, 1, sqlite3GenerateConstraintChecks(pParse, pTab, iCur, aRegIdx, chngRowid, 1,
onError, addr); onError, addr);
/* Delete the old indices for the current record. /* 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. /* If changing the record number, delete the old record.
*/ */
@@ -501,7 +489,7 @@ void sqlite3Update(
/* Create the new index entries and the new record. /* 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 /* Increment the row counter
@@ -526,7 +514,7 @@ void sqlite3Update(
/* Close all tables */ /* Close all tables */
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ 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); sqlite3VdbeAddOp2(v, OP_Close, iCur+i+1, 0);
} }
} }
@@ -549,7 +537,7 @@ void sqlite3Update(
update_cleanup: update_cleanup:
sqlite3AuthContextPop(&sContext); sqlite3AuthContextPop(&sContext);
sqlite3_free(apIdx); sqlite3_free(aRegIdx);
sqlite3_free(aXRef); sqlite3_free(aXRef);
sqlite3SrcListDelete(pTabList); sqlite3SrcListDelete(pTabList);
sqlite3ExprListDelete(pChanges); sqlite3ExprListDelete(pChanges);

View File

@@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing ** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code. ** 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 "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@@ -717,6 +717,26 @@ int sqlite3VdbeExec(
pOut = &p->aMem[pOp->p2]; 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 ){ switch( pOp->opcode ){
@@ -4166,67 +4186,60 @@ case OP_Next: { /* no-push, jump */
break; break;
} }
/* Opcode: IdxInsert P1 P2 * /* Opcode: IdxInsert P1 P2 P3
** **
** The top of the stack holds a SQL index key made using either the ** Register P2 holds a SQL index key made using the
** MakeIdxRec or MakeRecord instructions. This opcode writes that key ** MakeIdxRec instructions. This opcode writes that key
** into the index P1. Data for the entry is nil. ** 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. ** insert is likely to be an append.
** **
** This instruction only works for indices. The equivalent instruction ** This instruction only works for indices. The equivalent instruction
** for tables is OP_Insert. ** for tables is OP_Insert.
*/ */
case OP_IdxInsert: { /* no-push */ case OP_IdxInsert: { /* no-push, in2 */
int i = pOp->p1; int i = pOp->p1;
Cursor *pC; Cursor *pC;
BtCursor *pCrsr; BtCursor *pCrsr;
assert( pTos>=p->aStack );
assert( i>=0 && i<p->nCursor ); assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 ); assert( p->apCsr[i]!=0 );
assert( pTos->flags & MEM_Blob ); assert( pIn2->flags & MEM_Blob );
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
assert( pC->isTable==0 ); assert( pC->isTable==0 );
rc = ExpandBlob(pTos); rc = ExpandBlob(pIn2);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
int nKey = pTos->n; int nKey = pIn2->n;
const char *zKey = pTos->z; const char *zKey = pIn2->z;
rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0, 0, pOp->p2); rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0, 0, pOp->p3);
assert( pC->deferredMoveto==0 ); assert( pC->deferredMoveto==0 );
pC->cacheStatus = CACHE_STALE; pC->cacheStatus = CACHE_STALE;
} }
} }
Release(pTos);
pTos--;
break; break;
} }
/* Opcode: IdxDelete P1 * * /* Opcode: IdxDelete P1 P2 *
** **
** The top of the stack is an index key built using the either the ** The content of register P2 is an index key built using the either the
** MakeIdxRec or MakeRecord opcodes. ** MakeIdxRec opcode. Removes that entry from the index.
** This opcode removes that entry from the index.
*/ */
case OP_IdxDelete: { /* no-push */ case OP_IdxDelete: { /* no-push, in2 */
int i = pOp->p1; int i = pOp->p1;
Cursor *pC; Cursor *pC;
BtCursor *pCrsr; BtCursor *pCrsr;
assert( pTos>=p->aStack ); assert( pIn2->flags & MEM_Blob );
assert( pTos->flags & MEM_Blob );
assert( i>=0 && i<p->nCursor ); assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 ); assert( p->apCsr[i]!=0 );
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
int res; 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 ){ if( rc==SQLITE_OK && res==0 ){
rc = sqlite3BtreeDelete(pCrsr); rc = sqlite3BtreeDelete(pCrsr);
} }
assert( pC->deferredMoveto==0 ); assert( pC->deferredMoveto==0 );
pC->cacheStatus = CACHE_STALE; pC->cacheStatus = CACHE_STALE;
} }
Release(pTos);
pTos--;
break; break;
} }

View File

@@ -821,12 +821,14 @@ int sqlite3VdbeList(
pMem++; pMem++;
pMem->flags = MEM_Null; /* Comment */ pMem->flags = MEM_Null; /* Comment */
#ifdef SQLITE_DEBUG
if( pOp->zComment ){ if( pOp->zComment ){
pMem->flags = MEM_Str|MEM_Term; pMem->flags = MEM_Str|MEM_Term;
pMem->z = pOp->zComment; pMem->z = pOp->zComment;
pMem->n = strlen(pMem->z); pMem->n = strlen(pMem->z);
pMem->enc = SQLITE_UTF8; pMem->enc = SQLITE_UTF8;
} }
#endif
} }
p->nResColumn = 8 - 5*(p->explain-1); p->nResColumn = 8 - 5*(p->explain-1);

View File

@@ -529,7 +529,7 @@ int sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){
} }
pFrom->flags = MEM_Null; pFrom->flags = MEM_Null;
pFrom->xDel = 0; pFrom->xDel = 0;
if( pTo->flags & MEM_Ephem ){ if( 0 /* pTo->flags & MEM_Ephem */ ){
rc = sqlite3VdbeMemMakeWriteable(pTo); rc = sqlite3VdbeMemMakeWriteable(pTo);
}else{ }else{
rc = SQLITE_OK; rc = SQLITE_OK;