From a05a722f2373f8ec849c1e0ed26708583fb43bf4 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 19 Jan 2008 03:35:58 +0000 Subject: [PATCH] Cleanup and simplification of constraint processing. Simplifications to the VM for better test coverage. (CVS 4729) FossilOrigin-Name: d9ebe9d78c558af050c44ac4437ce0ef8193a4a8 --- manifest | 20 ++-- manifest.uuid | 2 +- src/insert.c | 82 ++++++++-------- src/select.c | 9 +- src/update.c | 5 +- src/vdbe.c | 265 ++++++++++++++++++++++---------------------------- src/vdbemem.c | 6 +- 7 files changed, 176 insertions(+), 213 deletions(-) diff --git a/manifest b/manifest index 8061f8a6db..49aa4ce22d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\stest\sinstrumentation\sproblems\son\sshared_err.test.\s(CVS\s4728) -D 2008-01-18T17:03:33 +C Cleanup\sand\ssimplification\sof\sconstraint\sprocessing.\s\sSimplifications\nto\sthe\sVM\sfor\sbetter\stest\scoverage.\s(CVS\s4729) +D 2008-01-19T03:35:59 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -96,7 +96,7 @@ F src/expr.c 9ac9177466b17b57e814f0beabc9e7bba88f8e38 F src/func.c 996071cf0af9d967e58b69fce1909555059ebc7d F src/hash.c 45a7005aac044b6c86bd7e49c44bc15d30006d6c F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53 -F src/insert.c ed16eaf9391929e29fdbfa589db09b7224b31905 +F src/insert.c 969b543eedaeb3ec4cd52cd6931db94da67388c3 F src/journal.c 807bed7a158979ac8d63953e1774e8d85bff65e2 F src/legacy.c 4ac53191fad2e3c4d59bde1228879b2dc5a96d66 F src/limits.h 71ab25f17e35e0a9f3f6f234b8ed49cc56731d35 @@ -131,7 +131,7 @@ F src/pragma.c 155315ee3e6a861a0060ba4d184dfffd08ebbc03 F src/prepare.c c31a879d6795f4765fd0b113675c6debbc96b7fd F src/printf.c eb27822ba2eec669161409ca31279a24c26ac910 F src/random.c 02ef38b469237482f1ea14a78b2087cfbaec48bd -F src/select.c d9a394a2566849f9f7b03e2da3fd3ed4a91611eb +F src/select.c 9fb094cc0c8acdcbf3581fdfc4490e997b5d1d1e F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c 0691a3d52dc37cf6ac2f74838e5ff8ae1055ac9b F src/sqlite.h.in 2a7e3776534bbe6ff2cdc058f3abebe91e7e429f @@ -164,18 +164,18 @@ F src/test_tclvar.c b2d1115e4d489179d3f029e765211b2ad527ba59 F src/test_thread.c e297dd41db0b249646e69f97d36ec13e56e8b730 F src/tokenize.c a4e04438c11fed2c67ec47fe3edbef9cca2d1b48 F src/trigger.c 9bd3b6fa0beff4a02d262c96466f752ec15a7fc3 -F src/update.c 2513c6120f9510ae782446a2b839931e994b75dd +F src/update.c 31edd9c9764e80753930bd5f9b43e0edb404636f F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736 F src/util.c deda8c5a400530e1c27c03619cc4cd1a06fc5281 F src/vacuum.c 3f34f278809bf3eb0b62ec46ff779e9c385b28f0 -F src/vdbe.c 3734b4b4fc34e46be4542593f9907a8a4d31c3d4 +F src/vdbe.c 986d1b4034e271c67f8cab0e03a5e459cb288ad7 F src/vdbe.h 58a7d931ffb704e034b2a725981cfa5bd406fad9 F src/vdbeInt.h 835e6f0337ce89d705ef9a162338788808adc4b7 F src/vdbeapi.c cb8c427a3ab646490c83204a98e94eff03ee2e89 F src/vdbeaux.c 0d2a9730195d40f7d1156731bc69f240927255c5 F src/vdbeblob.c e386d49d8354aa5a58f0a7f2794303442c149120 F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6 -F src/vdbemem.c 666a1d7b9d48ce6b1f6eb5e454693e0da08f6187 +F src/vdbemem.c e15122efe8868e400c2aba8ea101588944e83317 F src/vtab.c 9924e37cf7f5c527aeabb5da025874af505fb91d F src/where.c 0cc6052f73aef0d2ce59505d7ae06d6fbf696025 F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617 @@ -607,7 +607,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P 42d8a377551baef01fb4e80f35fc12f9454a3cd4 -R 53a68cbdb5a0c09e7f3102caf81464df +P 5aef5b0dd8e44a56f84fbc6f843016bca5101987 +R 07faac02e9ea2890001493a3c96130c4 U drh -Z f8720638d058f6048f391f0665e9a25c +Z 11b35796b0f55998b3b3bad35c703ebb diff --git a/manifest.uuid b/manifest.uuid index 4212cb612b..0cef15c101 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5aef5b0dd8e44a56f84fbc6f843016bca5101987 \ No newline at end of file +d9ebe9d78c558af050c44ac4437ce0ef8193a4a8 \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index e62e623fbc..6136454ab1 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.225 2008/01/17 16:22:15 drh Exp $ +** $Id: insert.c,v 1.226 2008/01/19 03:35:59 drh Exp $ */ #include "sqliteInt.h" @@ -943,7 +943,7 @@ insert_cleanup: ** ** 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 -** change to the record number. (Or writing to a virtual table.) +** change to the record number or writing to a virtual table. ** ** 2. The rowid of the row after the update. ** @@ -957,7 +957,10 @@ insert_cleanup: ** ** 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. +** INSERTs. RowidChng means that the new rowid is explicitly specified by +** the update or insert statement. If rowidChng is false, it means that +** the rowid is computed automatically in an insert or that the rowid value +** is not modified by the update. ** ** The code generated by this routine store new index entries into ** registers identified by aRegIdx[]. No index entry is created for @@ -1009,12 +1012,6 @@ insert_cleanup: ** 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 "baseCur" cursor is -** initially pointing to an entry that is being updated. The isUpdate -** 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 "baseCur" cursor might be moved. */ void sqlite3GenerateConstraintChecks( Parse *pParse, /* The parser context */ @@ -1022,7 +1019,7 @@ void sqlite3GenerateConstraintChecks( 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 rowid will change */ + int rowidChng, /* True if the rowid might collide with existing entry */ 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 */ @@ -1031,7 +1028,7 @@ void sqlite3GenerateConstraintChecks( Vdbe *v; int nCol; int onError; - int j1, j2, j3; /* Address of jump instructions */ + int j1, j2, j3; /* Addresses of jump instructions */ int regData; /* Register containing first data column */ int iCur; Index *pIdx; @@ -1116,41 +1113,41 @@ void sqlite3GenerateConstraintChecks( onError = OE_Abort; } - if( isUpdate ){ - j2 = sqlite3VdbeAddOp3(v, OP_Eq, regRowid, 0, regRowid-1); - } - j3 = sqlite3VdbeAddOp3(v, OP_NotExists, baseCur, 0, regRowid); - switch( onError ){ - default: { - onError = OE_Abort; - /* Fall thru into the next case */ + if( onError==OE_Replace && pTab->pIndex==0 ){ + seenReplace = 1; + }else{ + if( isUpdate ){ + j2 = sqlite3VdbeAddOp3(v, OP_Eq, regRowid, 0, regRowid-1); } - case OE_Rollback: - case OE_Abort: - case OE_Fail: { - sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, - "PRIMARY KEY must be unique", P4_STATIC); - break; - } - case OE_Replace: { - sqlite3GenerateRowIndexDelete(pParse, pTab, baseCur, 0); - if( isUpdate ){ - sqlite3VdbeAddOp3(v, OP_MoveGe, baseCur, 0, regRowid-hasTwoRowids); + j3 = sqlite3VdbeAddOp3(v, OP_NotExists, baseCur, 0, regRowid); + switch( onError ){ + default: { + onError = OE_Abort; + /* Fall thru into the next case */ + } + case OE_Rollback: + case OE_Abort: + case OE_Fail: { + sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, + "PRIMARY KEY must be unique", P4_STATIC); + break; + } + case OE_Replace: { + sqlite3GenerateRowIndexDelete(pParse, pTab, baseCur, 0); + seenReplace = 1; + break; + } + case OE_Ignore: { + assert( seenReplace==0 ); + sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); + break; } - seenReplace = 1; - break; } - case OE_Ignore: { - assert( seenReplace==0 ); - sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); - break; + sqlite3VdbeJumpHere(v, j3); + if( isUpdate ){ + sqlite3VdbeJumpHere(v, j2); } } - sqlite3VdbeJumpHere(v, j3); - if( isUpdate ){ - sqlite3VdbeJumpHere(v, j2); - sqlite3VdbeAddOp3(v, OP_MoveGe, baseCur, 0, regRowid-1); - } } /* Test all UNIQUE constraints by creating entries for each UNIQUE @@ -1239,9 +1236,6 @@ void sqlite3GenerateConstraintChecks( } case OE_Replace: { sqlite3GenerateRowDelete(pParse, pTab, baseCur, regR, 0); - if( isUpdate ){ - sqlite3VdbeAddOp3(v, OP_MoveGe, baseCur, 0, regRowid-hasTwoRowids); - } seenReplace = 1; break; } diff --git a/src/select.c b/src/select.c index 55334a08aa..5579a81be8 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.405 2008/01/17 17:15:56 drh Exp $ +** $Id: select.c,v 1.406 2008/01/19 03:35:59 drh Exp $ */ #include "sqliteInt.h" @@ -602,12 +602,11 @@ static int selectInnerLoop( ** the temporary table iParm. */ case SRT_Except: { - int addr, r1; + int r1; r1 = sqlite3GetTempReg(pParse); - addr = sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nColumn, r1); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nColumn, r1); sqlite3VdbeChangeP4(v, -1, aff, P4_STATIC); - sqlite3VdbeAddOp3(v, OP_NotFound, iParm, addr+3, r1); - sqlite3VdbeAddOp1(v, OP_Delete, iParm); + sqlite3VdbeAddOp2(v, OP_IdxDelete, iParm, r1); sqlite3ReleaseTempReg(pParse, r1); break; } diff --git a/src/update.c b/src/update.c index b769d2f1f6..fb45563ac4 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.169 2008/01/17 16:22:15 drh Exp $ +** $Id: update.c,v 1.170 2008/01/19 03:35:59 drh Exp $ */ #include "sqliteInt.h" @@ -102,6 +102,7 @@ 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 j1; /* Addresses of jump instructions */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* Trying to update a view */ @@ -504,6 +505,7 @@ void sqlite3Update( /* Delete the old indices for the current record. */ + j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regOldRowid); sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, aRegIdx); /* If changing the record number, delete the old record. @@ -511,6 +513,7 @@ void sqlite3Update( if( chngRowid ){ sqlite3VdbeAddOp2(v, OP_Delete, iCur, 0); } + sqlite3VdbeJumpHere(v, j1); /* Create the new index entries and the new record. */ diff --git a/src/vdbe.c b/src/vdbe.c index f7293e1b2a..76c505e15d 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.699 2008/01/18 14:08:25 drh Exp $ +** $Id: vdbe.c,v 1.700 2008/01/19 03:35:59 drh Exp $ */ #include "sqliteInt.h" #include @@ -595,7 +595,7 @@ int sqlite3VdbeExec( if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; if( prc!=0 ){ rc = SQLITE_INTERRUPT; - goto vdbe_halt; + goto vdbe_error_halt; } nProgressOps = 0; } @@ -950,7 +950,6 @@ case OP_SCopy: { if( pOp->opcode==OP_Move ){ rc = sqlite3VdbeMemMove(pOut, pIn1); }else{ - Release(pOut); sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); if( pOp->opcode==OP_Copy ){ Deephemeralize(pOut); @@ -1074,10 +1073,8 @@ case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ int flags; flags = pIn1->flags | pIn2->flags; - if( (flags & MEM_Null)!=0 ){ - Release(pOut); - pOut->flags = MEM_Null; - }else if( (pIn1->flags & pIn2->flags & MEM_Int)==MEM_Int ){ + if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null; + if( (pIn1->flags & pIn2->flags & MEM_Int)==MEM_Int ){ i64 a, b; a = pIn1->u.i; b = pIn2->u.i; @@ -1086,7 +1083,7 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ case OP_Subtract: b -= a; break; case OP_Multiply: b *= a; break; case OP_Divide: { - if( a==0 ) goto divide_by_zero; + if( a==0 ) goto arithmetic_result_is_null; /* Dividing the largest possible negative 64-bit integer (1<<63) by ** -1 returns an integer to large to store in a 64-bit data-type. On ** some architectures, the value overflows to (1<<63). On others, @@ -1099,7 +1096,7 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ break; } default: { - if( a==0 ) goto divide_by_zero; + if( a==0 ) goto arithmetic_result_is_null; if( a==-1 ) a = 1; b %= a; break; @@ -1117,21 +1114,21 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ case OP_Subtract: b -= a; break; case OP_Multiply: b *= a; break; case OP_Divide: { - if( a==0.0 ) goto divide_by_zero; + if( a==0.0 ) goto arithmetic_result_is_null; b /= a; break; } default: { i64 ia = (i64)a; i64 ib = (i64)b; - if( ia==0 ) goto divide_by_zero; + if( ia==0 ) goto arithmetic_result_is_null; if( ia==-1 ) ia = 1; b = ib % ia; break; } } if( sqlite3_isnan(b) ){ - goto divide_by_zero; + goto arithmetic_result_is_null; } Release(pOut); pOut->r = b; @@ -1142,9 +1139,8 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ } break; -divide_by_zero: - Release(pOut); - pOut->flags = MEM_Null; +arithmetic_result_is_null: + sqlite3VdbeMemSetNull(pOut); break; } @@ -1295,8 +1291,7 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */ i64 a, b; if( (pIn1->flags | pIn2->flags) & MEM_Null ){ - Release(pOut); - pOut->flags = MEM_Null; + sqlite3VdbeMemSetNull(pOut); break; } a = sqlite3VdbeIntValue(pIn2); @@ -1305,8 +1300,8 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */ case OP_BitAnd: a &= b; break; case OP_BitOr: a |= b; break; case OP_ShiftLeft: a <<= b; break; - case OP_ShiftRight: a >>= b; break; - default: /* CANT HAPPEN */ break; + default: assert( pOp->opcode==OP_ShiftRight ); + a >>= b; break; } Release(pOut); pOut->u.i = a; @@ -1880,7 +1875,8 @@ case OP_Column: { sqlite3BtreeDataSize(pCrsr, &payloadSize); } nField = pC->nField; - }else if( pC->pseudoTable ){ + }else{ + assert( pC->pseudoTable ); /* The record is the sole entry of a pseudo-table */ payloadSize = pC->nData; zRec = pC->pData; @@ -1888,11 +1884,6 @@ case OP_Column: { assert( payloadSize==0 || zRec!=0 ); nField = pC->nField; pCrsr = 0; - }else{ - zRec = 0; - payloadSize = 0; - pCrsr = 0; - nField = 0; } /* If payloadSize is 0, then just store a NULL */ @@ -1909,7 +1900,7 @@ case OP_Column: { /* Read and parse the table header. Store the results of the parse ** into the record header cache fields of the cursor. */ - if( pC && pC->cacheStatus==p->cacheCtr ){ + if( pC->cacheStatus==p->cacheCtr ){ aType = pC->aType; aOffset = pC->aOffset; }else{ @@ -2125,7 +2116,7 @@ case OP_MakeRecord: { applyAffinity(pRec, zAffinity[pRec-pData0], encoding); } if( pRec->flags&MEM_Zero && pRec->n>0 ){ - ExpandBlob(pRec); + sqlite3VdbeMemExpandBlob(pRec); } serial_type = sqlite3VdbeSerialType(pRec, file_format); len = sqlite3VdbeSerialTypeLen(serial_type); @@ -2209,10 +2200,12 @@ case OP_MakeRecord: { ** has an index of 1. */ case OP_Statement: { - int i = pOp->p1; - Btree *pBt; - if( i>=0 && inDb && (pBt = db->aDb[i].pBt)!=0 - && (db->autoCommit==0 || db->activeVdbeCnt>1) ){ + if( db->autoCommit==0 || db->activeVdbeCnt>1 ){ + int i = pOp->p1; + Btree *pBt; + assert( i>=0 && inDb ); + assert( db->aDb[i].pBt!=0 ); + pBt = db->aDb[i].pBt; assert( sqlite3BtreeIsInTrans(pBt) ); assert( (p->btreeMask & (1<nullRow = 1; - if( pX==0 ) break; /* We always provide a key comparison function. If the table being ** opened is of type INTKEY, the comparision function will be ignored. */ rc = sqlite3BtreeCursor(pX, p2, wrFlag, @@ -2691,10 +2683,9 @@ case OP_OpenPseudo: { */ case OP_Close: { int i = pOp->p1; - if( i>=0 && inCursor ){ - sqlite3VdbeFreeCursor(p, p->apCsr[i]); - p->apCsr[i] = 0; - } + assert( i>=0 && inCursor ); + sqlite3VdbeFreeCursor(p, p->apCsr[i]); + p->apCsr[i] = 0; break; } @@ -3223,73 +3214,71 @@ case OP_Insert: { Mem *pData = &p->aMem[pOp->p2]; Mem *pKey = &p->aMem[pOp->p3]; + i64 iKey; /* The integer ROWID or key for the record to be inserted */ int i = pOp->p1; Cursor *pC; assert( i>=0 && inCursor ); - assert( p->apCsr[i]!=0 ); + pC = p->apCsr[i]; + assert( pC!=0 ); + assert( pC->pCursor!=0 || pC->pseudoTable ); + assert( pKey->flags & MEM_Int ); + assert( pC->isTable ); REGISTER_TRACE(pOp->p2, pData); REGISTER_TRACE(pOp->p3, pKey); - if( ((pC = p->apCsr[i])->pCursor!=0 || pC->pseudoTable) ){ - i64 iKey; /* The integer ROWID or key for the record to be inserted */ - assert( pKey->flags & MEM_Int ); - assert( pC->isTable ); - iKey = intToKey(pKey->u.i); - - if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; - if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = pKey->u.i; - if( pC->nextRowidValid && pKey->u.i>=pC->nextRowid ){ - pC->nextRowidValid = 0; - } - if( pData->flags & MEM_Null ){ - pData->z = 0; - pData->n = 0; - }else{ - assert( pData->flags & (MEM_Blob|MEM_Str) ); - } - if( pC->pseudoTable ){ - sqlite3_free(pC->pData); - pC->iKey = iKey; - pC->nData = pData->n; - if( pData->flags & MEM_Dyn ){ - pC->pData = pData->z; - pData->flags &= ~MEM_Dyn; - pData->flags |= MEM_Ephem; - }else{ - pC->pData = sqlite3_malloc( pC->nData+2 ); - if( !pC->pData ) goto no_mem; - memcpy(pC->pData, pData->z, pC->nData); - pC->pData[pC->nData] = 0; - pC->pData[pC->nData+1] = 0; - } - pC->nullRow = 0; - }else{ - int nZero; - if( pData->flags & MEM_Zero ){ - nZero = pData->u.i; - }else{ - nZero = 0; - } - rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey, - pData->z, pData->n, nZero, - pOp->p5 & OPFLAG_APPEND); - } - - pC->rowidIsValid = 0; - pC->deferredMoveto = 0; - pC->cacheStatus = CACHE_STALE; - - /* Invoke the update-hook if required. */ - if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){ - const char *zDb = db->aDb[pC->iDb].zName; - const char *zTbl = pOp->p4.z; - int op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT); - assert( pC->isTable ); - db->xUpdateCallback(db->pUpdateArg, op, zDb, zTbl, iKey); - assert( pC->iDb>=0 ); - } + iKey = intToKey(pKey->u.i); + if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; + if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = pKey->u.i; + if( pC->nextRowidValid && pKey->u.i>=pC->nextRowid ){ + pC->nextRowidValid = 0; } + if( pData->flags & MEM_Null ){ + pData->z = 0; + pData->n = 0; + }else{ + assert( pData->flags & (MEM_Blob|MEM_Str) ); + } + if( pC->pseudoTable ){ + sqlite3_free(pC->pData); + pC->iKey = iKey; + pC->nData = pData->n; + if( pData->flags & MEM_Dyn ){ + pC->pData = pData->z; + pData->flags &= ~MEM_Dyn; + pData->flags |= MEM_Ephem; + }else{ + pC->pData = sqlite3_malloc( pC->nData+2 ); + if( !pC->pData ) goto no_mem; + memcpy(pC->pData, pData->z, pC->nData); + pC->pData[pC->nData] = 0; + pC->pData[pC->nData+1] = 0; + } + pC->nullRow = 0; + }else{ + int nZero; + if( pData->flags & MEM_Zero ){ + nZero = pData->u.i; + }else{ + nZero = 0; + } + rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey, + pData->z, pData->n, nZero, + pOp->p5 & OPFLAG_APPEND); + } + + pC->rowidIsValid = 0; + pC->deferredMoveto = 0; + pC->cacheStatus = CACHE_STALE; + /* Invoke the update-hook if required. */ + if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){ + const char *zDb = db->aDb[pC->iDb].zName; + const char *zTbl = pOp->p4.z; + int op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT); + assert( pC->isTable ); + db->xUpdateCallback(db->pUpdateArg, op, zDb, zTbl, iKey); + assert( pC->iDb>=0 ); + } break; } @@ -3403,10 +3392,7 @@ case OP_RowData: { /* out2-prerelease */ BtCursor *pCrsr = pC->pCursor; rc = sqlite3VdbeCursorMoveto(pC); if( rc ) goto abort_due_to_error; - if( pC->nullRow ){ - pOut->flags = MEM_Null; - break; - }else if( pC->isIndex ){ + if( pC->isIndex ){ i64 n64; assert( !pC->isTable ); sqlite3BtreeKeySize(pCrsr, &n64); @@ -3436,13 +3422,12 @@ case OP_RowData: { /* out2-prerelease */ }else{ rc = sqlite3BtreeData(pCrsr, 0, n, pOut->z); } - }else if( pC->pseudoTable ){ + }else{ + assert( pC->pseudoTable ); pOut->n = pC->nData; assert( pC->nData<=SQLITE_MAX_LENGTH ); pOut->z = pC->pData; pOut->flags = MEM_Blob|MEM_Ephem; - }else{ - pOut->flags = MEM_Null; } pOut->enc = SQLITE_UTF8; /* In case the blob is ever cast to text */ UPDATE_MAX_BLOBSIZE(pOut); @@ -3468,7 +3453,7 @@ case OP_Rowid: { /* out2-prerelease */ v = pC->lastRowid; }else if( pC->pseudoTable ){ v = keyToInt(pC->iKey); - }else if( pC->nullRow || pC->pCursor==0 ){ + }else if( pC->nullRow ){ /* Leave the rowid set to a NULL */ break; }else{ @@ -3511,21 +3496,19 @@ case OP_Last: { /* jump */ int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; + int res; assert( i>=0 && inCursor ); pC = p->apCsr[i]; assert( pC!=0 ); - if( (pCrsr = pC->pCursor)!=0 ){ - int res; - rc = sqlite3BtreeLast(pCrsr, &res); - pC->nullRow = res; - pC->deferredMoveto = 0; - pC->cacheStatus = CACHE_STALE; - if( res && pOp->p2>0 ){ - pc = pOp->p2 - 1; - } - }else{ - pC->nullRow = 0; + pCrsr = pC->pCursor; + assert( pCrsr!=0 ); + rc = sqlite3BtreeLast(pCrsr, &res); + pC->nullRow = res; + pC->deferredMoveto = 0; + pC->cacheStatus = CACHE_STALE; + if( res && pOp->p2>0 ){ + pc = pOp->p2 - 1; } break; } @@ -3576,7 +3559,8 @@ case OP_Rewind: { /* jump */ res = 1; } pC->nullRow = res; - if( res && pOp->p2>0 ){ + assert( pOp->p2>0 && pOp->p2nOp ); + if( res ){ pc = pOp->p2 - 1; } break; @@ -3722,17 +3706,6 @@ case OP_IdxRowid: { /* out2-prerelease */ break; } -/* Opcode: IdxGT P1 P2 P3 * * -** -** The value in register P3 is an index entry that omits the ROWID. Compare -** the value in register P3 against the index that P1 is currently pointing to. -** Ignore the ROWID on the P1 index. -** -** The P3 value might have fewer columns that P1 index. -** -** If the P1 index entry is greater than the value in register P3 -** then jump to P2. Otherwise fall through to the next instruction. -*/ /* Opcode: IdxGE P1 P2 P3 * P5 ** ** The value in register P3 is an index entry that omits the ROWID. Compare @@ -3764,7 +3737,6 @@ case OP_IdxRowid: { /* out2-prerelease */ ** like IdxLE. */ case OP_IdxLT: /* jump, in3 */ -case OP_IdxGT: /* jump, in3 */ case OP_IdxGE: { /* jump, in3 */ int i= pOp->p1; Cursor *pC; @@ -3777,8 +3749,8 @@ case OP_IdxGE: { /* jump, in3 */ assert( pIn3->flags & MEM_Blob ); /* Created using OP_MakeRecord */ assert( pC->deferredMoveto==0 ); ExpandBlob(pIn3); - *pC->pIncrKey = pOp->p5!=0; - assert( pOp->opcode!=OP_IdxGT || pOp->p5==0 ); + assert( pOp->p5==0 || pOp->p5==1 ); + *pC->pIncrKey = pOp->p5; rc = sqlite3VdbeIdxKeyCompare(pC, pIn3->n, (u8*)pIn3->z, &res); *pC->pIncrKey = 0; if( rc!=SQLITE_OK ){ @@ -3786,7 +3758,8 @@ case OP_IdxGE: { /* jump, in3 */ } if( pOp->opcode==OP_IdxLT ){ res = -res; - }else if( pOp->opcode==OP_IdxGE ){ + }else{ + assert( pOp->opcode==OP_IdxGE ); res++; } if( res>0 ){ @@ -4056,10 +4029,9 @@ case OP_IntegrityCk: { z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot, pnErr->u.i, &nErr); pnErr->u.i -= nErr; - Release(pIn1); + sqlite3VdbeMemSetNull(pIn1); if( nErr==0 ){ assert( z==0 ); - pIn1->flags = MEM_Null; }else{ pIn1->z = z; pIn1->n = strlen(z); @@ -4790,15 +4762,13 @@ default: { #endif /* NDEBUG */ } /* The end of the for(;;) loop the loops through opcodes */ - /* If we reach this point, it means that execution is finished. + /* If we reach this point, it means that execution is finished with + ** an error of some kind. */ -vdbe_halt: - if( rc ){ - p->rc = rc; - rc = SQLITE_ERROR; - }else{ - rc = SQLITE_DONE; - } +vdbe_error_halt: + assert( rc ); + p->rc = rc; + rc = SQLITE_ERROR; sqlite3VdbeHalt(p); /* This is the only way out of this procedure. We have to @@ -4814,7 +4784,7 @@ vdbe_return: too_big: sqlite3SetString(&p->zErrMsg, "string or blob too big", (char*)0); rc = SQLITE_TOOBIG; - goto vdbe_halt; + goto vdbe_error_halt; /* Jump to here if a malloc() fails. */ @@ -4822,7 +4792,7 @@ no_mem: db->mallocFailed = 1; sqlite3SetString(&p->zErrMsg, "out of memory", (char*)0); rc = SQLITE_NOMEM; - goto vdbe_halt; + goto vdbe_error_halt; /* Jump to here for an SQLITE_MISUSE error. */ @@ -4834,11 +4804,10 @@ abort_due_to_misuse: ** should hold the error number. */ abort_due_to_error: - if( p->zErrMsg==0 ){ - if( db->mallocFailed ) rc = SQLITE_NOMEM; - sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(rc), (char*)0); - } - goto vdbe_halt; + assert( p->zErrMsg==0 ); + if( db->mallocFailed ) rc = SQLITE_NOMEM; + sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(rc), (char*)0); + goto vdbe_error_halt; /* Jump to here if the sqlite3_interrupt() API sets the interrupt ** flag. @@ -4852,5 +4821,5 @@ abort_due_to_interrupt: } p->rc = rc; sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(rc), (char*)0); - goto vdbe_halt; + goto vdbe_error_halt; } diff --git a/src/vdbemem.c b/src/vdbemem.c index 2d9a943a44..4da350e73b 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -508,11 +508,12 @@ int sqlite3VdbeMemTooBig(Mem *p){ /* ** Make an shallow copy of pFrom into pTo. Prior contents of -** pTo are overwritten. The pFrom->z field is not duplicated. If +** pTo are freed. The pFrom->z field is not duplicated. If ** pFrom->z is used, then pTo->z points to the same thing as pFrom->z ** and flags gets srcType (either MEM_Ephem or MEM_Static). */ void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ + sqlite3VdbeMemRelease(pTo); memcpy(pTo, pFrom, sizeof(*pFrom)-sizeof(pFrom->zShort)); pTo->xDel = 0; if( pTo->flags & (MEM_Str|MEM_Blob) ){ @@ -528,9 +529,6 @@ void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ */ int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ int rc; - if( pTo->flags & MEM_Dyn ){ - sqlite3VdbeMemRelease(pTo); - } sqlite3VdbeMemShallowCopy(pTo, pFrom, MEM_Ephem); if( pTo->flags & MEM_Ephem ){ rc = sqlite3VdbeMemMakeWriteable(pTo);