1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-27 20:41:58 +03:00

Improved comments and variable names in infrastructure routines of UPDATE,

DELETE, and INSERT.

FossilOrigin-Name: ad90e762e51384ac7c311f08a641419f03f6d3f0
This commit is contained in:
drh
2013-10-31 15:37:49 +00:00
parent 77f64bb7b9
commit 6934fc7b6f
6 changed files with 144 additions and 134 deletions

View File

@ -1,5 +1,5 @@
C Moving\sUPDATE\stowards\sthe\siDataCur/iIdxCur\srepresentation.\s\sStill\snot\sworking\nfor\sWITHOUT\sROWID,\sthough. C Improved\scomments\sand\svariable\snames\sin\sinfrastructure\sroutines\sof\sUPDATE,\nDELETE,\sand\sINSERT.
D 2013-10-31T12:13:37.732 D 2013-10-31T15:37:49.070
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 0522b53cdc1fcfc18f3a98e0246add129136c654 F Makefile.in 0522b53cdc1fcfc18f3a98e0246add129136c654
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -173,7 +173,7 @@ F src/callback.c f99a8957ba2adf369645fac0db09ad8adcf1caa2
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c ea4b7f3623a0fcb1146e7f245d7410033e86859c F src/ctime.c ea4b7f3623a0fcb1146e7f245d7410033e86859c
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
F src/delete.c d50cc704030139e19f2e9d5ac7a49db04dfe08a9 F src/delete.c 0e10849258efbdab48b8679de19edd661859dc7d
F src/expr.c 3180b6332072b263f845592e72e92971af562ab0 F src/expr.c 3180b6332072b263f845592e72e92971af562ab0
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c 628f81177299660a86e40359b3689b81f517e125 F src/fkey.c 628f81177299660a86e40359b3689b81f517e125
@ -182,7 +182,7 @@ F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759
F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4 F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22 F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
F src/insert.c e8f0691953194cf1df85b463fed8b75b0dedf7d9 F src/insert.c 64eb6bf8eda1bbe003cc38394d721b4810f65182
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12 F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
@ -212,7 +212,7 @@ F src/parse.y 073a8294e1826f1b1656e84806b77e4199f4bb57
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
F src/pcache1.c a467393909a4ed7ca9de066d85ba5c5b04a5be63 F src/pcache1.c a467393909a4ed7ca9de066d85ba5c5b04a5be63
F src/pragma.c 74dec25a3f0d3e5da796345a0ca817cb445e9d2a F src/pragma.c ff1a98998d2038bc9c770326986b7c4728de4973
F src/prepare.c f47ba2bba7ac5650881ab6c41f6d33a6de1a8d52 F src/prepare.c f47ba2bba7ac5650881ab6c41f6d33a6de1a8d52
F src/printf.c da9119eb31a187a4b99f60aa4a225141c0ebb74b F src/printf.c da9119eb31a187a4b99f60aa4a225141c0ebb74b
F src/random.c 0b2dbc37fdfbfa6bd455b091dfcef5bdb32dba68 F src/random.c 0b2dbc37fdfbfa6bd455b091dfcef5bdb32dba68
@ -1076,7 +1076,7 @@ F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361 F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
F test/win32longpath.test e2aafc07e6990fe86c69be22a3d1a0e210cd329b F test/win32longpath.test e2aafc07e6990fe86c69be22a3d1a0e210cd329b
F test/without_rowid1.test fb3ceaa20bda4e0338f594696a49014c3cbeb30c F test/without_rowid1.test e4f023e49a57c90f6d25afd4b3e8b0305ad06e44
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688 F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
F test/zerodamage.test 209d7ed441f44cc5299e4ebffbef06fd5aabfefd F test/zerodamage.test 209d7ed441f44cc5299e4ebffbef06fd5aabfefd
F tool/build-all-msvc.bat 38623a30fd58288fda5cc7f7df2682aaab75c9d5 x F tool/build-all-msvc.bat 38623a30fd58288fda5cc7f7df2682aaab75c9d5 x
@ -1128,7 +1128,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
P 1adfca6019847d37dee4a297669f29d5ca184066 P deacbd21b50cc8c63a1572d14a4bbc7af4052d37
R 925135441c339dd20ca1becb38d6fbf2 R 868cea4e5c536af4b28fd795ccabbf1e
U drh U drh
Z 72a84fe0a8232f3d99ba9db66435b958 Z 77c0455bfaa16e77ab3ac24edbdbd46c

View File

@ -1 +1 @@
deacbd21b50cc8c63a1572d14a4bbc7af4052d37 ad90e762e51384ac7c311f08a641419f03f6d3f0

View File

@ -523,24 +523,21 @@ delete_from_cleanup:
/* /*
** This routine generates VDBE code that causes a single row of a ** This routine generates VDBE code that causes a single row of a
** single table to be deleted. ** single table to be deleted. Both the original table entry and
** all indices are removed.
** **
** The VDBE must be in a particular state when this routine is called. ** Preconditions:
** These are the requirements:
** **
** 1. iDataCur is an open cursor on the btree that is the primary data ** 1. iDataCur is an open cursor on the btree that is the canonical data
** repository for the table. This will be either the table itself, ** store for the table. (This will be either the table itself,
** in the case of a rowid table, or the PRIMARY KEY index in the case ** in the case of a rowid table, or the PRIMARY KEY index in the case
** of a WITHOUT ROWID table. ** of a WITHOUT ROWID table.)
** **
** 2. Read/write cursors for all indices of pTab must be open as ** 2. Read/write cursors for all indices of pTab must be open as
** cursor number iIdxCur+i for the i-th index. ** cursor number iIdxCur+i for the i-th index.
** **
** 3. The primary key for the row to be deleted must be stored in a ** 3. The primary key for the row to be deleted must be stored in a
** sequence of nPk memory cells starting at iPk. ** sequence of nPk memory cells starting at iPk.
**
** This routine generates code to remove both the table record and all
** index entries that point to that record.
*/ */
void sqlite3GenerateRowDelete( void sqlite3GenerateRowDelete(
Parse *pParse, /* Parsing context */ Parse *pParse, /* Parsing context */
@ -560,7 +557,7 @@ void sqlite3GenerateRowDelete(
/* Vdbe is guaranteed to have been allocated by this stage. */ /* Vdbe is guaranteed to have been allocated by this stage. */
assert( v ); assert( v );
VdbeModuleComment((v, "BEGIN: GenerateRowDelete(%d,%d,%d,%d)", VdbeModuleComment((v, "BEGIN: GenRowDel(%d,%d,%d,%d)",
iDataCur, iIdxCur, iPk, (int)nPk)); iDataCur, iIdxCur, iPk, (int)nPk));
/* Seek cursor iCur to the row to delete. If this row no longer exists /* Seek cursor iCur to the row to delete. If this row no longer exists
@ -636,26 +633,26 @@ void sqlite3GenerateRowDelete(
** trigger programs were invoked. Or if a trigger program throws a ** trigger programs were invoked. Or if a trigger program throws a
** RAISE(IGNORE) exception. */ ** RAISE(IGNORE) exception. */
sqlite3VdbeResolveLabel(v, iLabel); sqlite3VdbeResolveLabel(v, iLabel);
VdbeModuleComment((v, "END: GenerateRowDelete()")); VdbeModuleComment((v, "END: GenRowDel()"));
} }
/* /*
** This routine generates VDBE code that causes the deletion of all ** This routine generates VDBE code that causes the deletion of all
** index entries associated with a single row of a single table. ** index entries associated with a single row of a single table, pTab
** **
** The VDBE must be in a particular state when this routine is called. ** Preconditions:
** These are the requirements:
** **
** 1. A read/write cursor "iDataCur" pointing to canonical storage ** 1. A read/write cursor "iDataCur" must be open on the canonical storage
** tree for the table pTab, which will be either the table itself ** btree for the table pTab. (This will be either the table itself
** for rowid tables or to the primary key index for WITHOUT ROWID ** for rowid tables or to the primary key index for WITHOUT ROWID
** tables. ** tables.)
** **
** 2. Read/write cursors for all indices of pTab must be open as ** 2. Read/write cursors for all indices of pTab must be open as
** cursor number iIdxCur+i for the i-th index. ** cursor number iIdxCur+i for the i-th index. (The pTab->pIndex
** index is the 0-th index.)
** **
** 3. The "iDataCur" cursor must be pointing to the row that is to be ** 3. The "iDataCur" cursor must be already be positioned on the row
** deleted. ** that is to be deleted.
*/ */
void sqlite3GenerateRowIndexDelete( void sqlite3GenerateRowIndexDelete(
Parse *pParse, /* Parsing and code generating context */ Parse *pParse, /* Parsing and code generating context */
@ -664,15 +661,17 @@ void sqlite3GenerateRowIndexDelete(
int iIdxCur, /* First index cursor */ int iIdxCur, /* First index cursor */
int *aRegIdx /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */ int *aRegIdx /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */
){ ){
int i; int i; /* Index loop counter */
Index *pIdx; int r1; /* Register holding an index key */
int r1; int iPartIdxLabel; /* Jump destination for skipping partial index entries */
int iPartIdxLabel; Index *pIdx; /* Current index */
Vdbe *v = pParse->pVdbe; Vdbe *v; /* The prepared statement under construction */
Index *pPk; Index *pPk; /* PRIMARY KEY index, or NULL for rowid tables */
v = pParse->pVdbe;
pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
assert( iIdxCur+i!=iDataCur || pPk==pIdx );
if( aRegIdx!=0 && aRegIdx[i]==0 ) continue; if( aRegIdx!=0 && aRegIdx[i]==0 ) continue;
if( pIdx==pPk ) continue; if( pIdx==pPk ) continue;
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1, &iPartIdxLabel); r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1, &iPartIdxLabel);

View File

@ -1123,36 +1123,47 @@ insert_cleanup:
#endif #endif
/* /*
** 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
** on table pTab.
** **
** The input is a range of consecutive registers as follows: ** The regNewData parameter is the first register in a range that contains
** the data to be inserted or the data after the update. There will be
** pTab->nCol+1 registers in this range. The first register (the one
** that regNewData points to) will contain the new rowid, or NULL in the
** case of a WITHOUT ROWID table. The second register in the range will
** contain the content of the first table column. The third register will
** contain the content of the second table column. And so forth.
** **
** 1. The rowid of the row after the update, or NULL ** For an UPDATE (isUpdate!=0), if pkChng is non-zero then it contains
** for WITHOUT ROWID tables. ** the address of a range of registers containing the rowid and table
** data from before the change. In other words, pkChng is like
** regNewData except that it describes the row before the update rather
** than afterwards. If pkChng is zero, that means that the rowid does
** not change (for a normal rowid table) or the PRIMARY KEY does not
** change (for a WITHOUT ROWID table) in which case the old data is
** not needed.
** **
** 2. The data in the first column of the entry after the update. ** For an INSERT (isUpdate==0), pkChng is just a boolean that indicates
** whether or not the rowid was explicitly specified as part of the
** INSERT statement. If pkChng is zero, it means that the either rowid
** is computed automatically or that the table is a WITHOUT ROWID table
** and has no rowid. On an INSERT, pkChng will only be true if the
** INSERT statement provides an integer value for either the rowid
** column or its INTEGER PRIMARY KEY alias.
** **
** i. Data from middle columns... ** The code generated by this routine will store new index entries into
**
** N. The data in the last column of the entry after the update.
**
** The regRowid parameter is the index of the register containing (1).
**
** If isUpdate is true and pkChng is non-zero, then pkChng contains
** the address of a range of registers containing the rowid or PRIMARY KEY
** value before the update takes place. isUpdate is true for UPDATEs and
** false for INSERTs. If isUpdate is false then a non-zero pkChng
** indicates that the rowid was explicitly specified as part of the
** INSERT statement. If pkChng is false, it means that the rowid is
** computed automatically in an insert and is therefore guaranteed to
** be unique. The pkChng parameter is always false for inserts
** into a WITHOUT ROWID table.
**
** The code generated by this routine should store new index entries into
** registers identified by aRegIdx[]. No index entry is created for ** registers identified by aRegIdx[]. No index entry is created for
** indices where aRegIdx[i]==0. The order of indices in aRegIdx[] is ** indices where aRegIdx[i]==0. The order of indices in aRegIdx[] is
** the same as the order of indices on the linked list of indices ** the same as the order of indices on the linked list of indices
** attached to the table. ** at pTab->pIndex.
**
** The caller must have already opened writeable cursors on the main
** table and all applicable indices (that is to say, all indices for which
** aRegIdx[] is not zero). iDataCur is the cursor for the main table when
** inserting or updating a rowid table, or the cursor for the PRIMARY KEY
** index when operating on a WITHOUT ROWID table. iIdxCur is the cursor
** for the first index in the pTab->pIndex list. Cursors for other indices
** are at iIdxCur+N for the N-th element of the pTab->pIndex list.
** **
** 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,
@ -1162,22 +1173,23 @@ insert_cleanup:
** Constraint type Action What Happens ** Constraint type Action What Happens
** --------------- ---------- ---------------------------------------- ** --------------- ---------- ----------------------------------------
** any ROLLBACK The current transaction is rolled back and ** any ROLLBACK The current transaction is rolled back and
** sqlite3_exec() returns immediately with a ** sqlite3_step() returns immediately with a
** return code of SQLITE_CONSTRAINT. ** return code of SQLITE_CONSTRAINT.
** **
** any ABORT Back out changes from the current command ** any ABORT Back out changes from the current command
** only (do not do a complete rollback) then ** only (do not do a complete rollback) then
** cause sqlite3_exec() to return immediately ** cause sqlite3_step() to return immediately
** with SQLITE_CONSTRAINT. ** with SQLITE_CONSTRAINT.
** **
** any FAIL Sqlite3_exec() returns immediately with a ** any FAIL Sqlite3_step() returns immediately with a
** return code of SQLITE_CONSTRAINT. The ** return code of SQLITE_CONSTRAINT. The
** transaction is not rolled back and any ** transaction is not rolled back and any
** prior changes are retained. ** changes to prior rows are retained.
** **
** any IGNORE The record number and data is popped from ** any IGNORE The attempt in insert or update the current
** the stack and there is an immediate jump ** row is skipped, without throwing an error.
** to label ignoreDest. ** Processing continues with the next row.
** (There is an immediate jump to ignoreDest.)
** **
** NOT NULL REPLACE The NULL value is replace by the default ** NOT NULL REPLACE The NULL value is replace by the default
** value for that column. If the default value ** value for that column. If the default value
@ -1192,19 +1204,13 @@ insert_cleanup:
** Or if overrideError==OE_Default, then the pParse->onError parameter ** Or if overrideError==OE_Default, then the pParse->onError parameter
** is used. Or if pParse->onError==OE_Default then the onError value ** is used. Or if pParse->onError==OE_Default then the onError value
** for the constraint is used. ** for the constraint is used.
**
** The calling routine must open a read/write cursor for pTab with
** cursor number "baseCur". All indices of pTab must also have open
** read/write cursors with cursor number baseCur+i for the i-th cursor.
** Except, if there is no possibility of a REPLACE action then
** cursors do not need to be open for indices where aRegIdx[i]==0.
*/ */
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 being inserted or updated */
int iDataCur, /* Cursor of the canonical data tree */ int iDataCur, /* Canonical data cursor (main table or PK index) */
int iIdxCur, /* First index cursor */ int iIdxCur, /* First index cursor */
int regRowid, /* First register in a range holding values to insert */ int regNewData, /* First register in a range holding values to insert */
int *aRegIdx, /* Register used by each index. 0 for unused indices */ int *aRegIdx, /* Register used by each index. 0 for unused indices */
int pkChng, /* Non-zero if the rowid or PRIMARY KEY changed */ int pkChng, /* Non-zero if the rowid or PRIMARY KEY changed */
int isUpdate, /* True for UPDATE, False for INSERT */ int isUpdate, /* True for UPDATE, False for INSERT */
@ -1218,24 +1224,24 @@ void sqlite3GenerateConstraintChecks(
int onError; /* Conflict resolution strategy */ int onError; /* Conflict resolution strategy */
int j1; /* Addresss of jump instruction */ int j1; /* Addresss of jump instruction */
int ix; /* Index loop counter */ int ix; /* Index loop counter */
int regData; /* Register containing first data column */
Index *pIdx; /* Pointer to one of the indices */ Index *pIdx; /* Pointer to one of the indices */
Index *pPk = 0; /* The PRIMARY KEY index */ Index *pPk = 0; /* The PRIMARY KEY index */
sqlite3 *db; /* Database connection */ sqlite3 *db; /* Database connection */
int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */ int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
int regOldPk; /* Previous rowid or PRIMARY KEY value */ int regOldData; /* Previous rowid and table data */
int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */ int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
regOldPk = (pkChng && isUpdate) ? pkChng : regRowid; regOldData = (pkChng && isUpdate) ? pkChng : regNewData;
db = pParse->db; db = pParse->db;
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;
regData = regRowid + 1;
/* For WITHOUT ROWID tables, we'll need to know the Index and the cursor /* pPk is the PRIMARY KEY index for WITHOUT ROWID tables and NULL for
** number for the PRIMARY KEY index */ ** normal rowid tables. nPkField is the number of key fields in the
** pPk index or 1 for a rowid table. In other words, nPkField is the
** number of fields in the true primary key of the table. */
if( HasRowid(pTab) ){ if( HasRowid(pTab) ){
pPk = 0; pPk = 0;
nPkField = 1; nPkField = 1;
@ -1246,7 +1252,7 @@ void sqlite3GenerateConstraintChecks(
/* Record that this module has started */ /* Record that this module has started */
VdbeModuleComment((v, "BEGIN: GenCnstCks(%d,%d,%d,%d,%d)", VdbeModuleComment((v, "BEGIN: GenCnstCks(%d,%d,%d,%d,%d)",
iDataCur, iIdxCur, regRowid, pkChng, regOldPk)); iDataCur, iIdxCur, regNewData, regOldData, pkChng));
/* Test all NOT NULL constraints. /* Test all NOT NULL constraints.
*/ */
@ -1274,20 +1280,20 @@ void sqlite3GenerateConstraintChecks(
case OE_Fail: { case OE_Fail: {
char *zMsg; char *zMsg;
sqlite3VdbeAddOp3(v, OP_HaltIfNull, sqlite3VdbeAddOp3(v, OP_HaltIfNull,
SQLITE_CONSTRAINT_NOTNULL, onError, regData+i); SQLITE_CONSTRAINT_NOTNULL, onError, regNewData+1+i);
zMsg = sqlite3MPrintf(db, "%s.%s may not be NULL", zMsg = sqlite3MPrintf(db, "%s.%s may not be NULL",
pTab->zName, pTab->aCol[i].zName); pTab->zName, pTab->aCol[i].zName);
sqlite3VdbeChangeP4(v, -1, zMsg, P4_DYNAMIC); sqlite3VdbeChangeP4(v, -1, zMsg, P4_DYNAMIC);
break; break;
} }
case OE_Ignore: { case OE_Ignore: {
sqlite3VdbeAddOp2(v, OP_IsNull, regData+i, ignoreDest); sqlite3VdbeAddOp2(v, OP_IsNull, regNewData+1+i, ignoreDest);
break; break;
} }
default: { default: {
assert( onError==OE_Replace ); assert( onError==OE_Replace );
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regData+i); j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regNewData+1+i);
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regData+i); sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regNewData+1+i);
sqlite3VdbeJumpHere(v, j1); sqlite3VdbeJumpHere(v, j1);
break; break;
} }
@ -1299,7 +1305,7 @@ void sqlite3GenerateConstraintChecks(
#ifndef SQLITE_OMIT_CHECK #ifndef SQLITE_OMIT_CHECK
if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){ if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
ExprList *pCheck = pTab->pCheck; ExprList *pCheck = pTab->pCheck;
pParse->ckBase = regData; pParse->ckBase = regNewData+1;
onError = overrideError!=OE_Default ? overrideError : OE_Abort; onError = overrideError!=OE_Default ? overrideError : OE_Abort;
for(i=0; i<pCheck->nExpr; i++){ for(i=0; i<pCheck->nExpr; i++){
int allOk = sqlite3VdbeMakeLabel(v); int allOk = sqlite3VdbeMakeLabel(v);
@ -1324,7 +1330,8 @@ void sqlite3GenerateConstraintChecks(
/* If there is an INTEGER PRIMARY KEY, make sure the primary key /* If there is an INTEGER PRIMARY KEY, make sure the primary key
** of the new record does not previously exist. Except, if this ** of the new record does not previously exist. Except, if this
** is an UPDATE and the primary key is not changing, that is OK. ** is an UPDATE and the primary key is not changing, then obviously
** it is OK for the previous rowid to exist in that case.
** **
** This block only runs for tables that have a rowid. ** This block only runs for tables that have a rowid.
*/ */
@ -1339,9 +1346,9 @@ void sqlite3GenerateConstraintChecks(
} }
if( isUpdate ){ if( isUpdate ){
sqlite3VdbeAddOp3(v, OP_Eq, regRowid, addrRowidOk, pkChng); sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRowidOk, regOldData);
} }
sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regRowid); sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData);
switch( onError ){ switch( onError ){
default: { default: {
onError = OE_Abort; onError = OE_Abort;
@ -1384,7 +1391,7 @@ void sqlite3GenerateConstraintChecks(
if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){ if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
sqlite3MultiWrite(pParse); sqlite3MultiWrite(pParse);
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
regRowid, 1, 0, OE_Replace); regNewData, 1, 0, OE_Replace);
}else if( pTab->pIndex ){ }else if( pTab->pIndex ){
sqlite3MultiWrite(pParse); sqlite3MultiWrite(pParse);
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, 0); sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, 0);
@ -1406,37 +1413,41 @@ void sqlite3GenerateConstraintChecks(
** Compute the revised record entries for indices as we go. ** Compute the revised record entries for indices as we go.
*/ */
for(ix=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, ix++){ for(ix=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, ix++){
int regIdx; int regIdx; /* Range of registers hold conent for pIdx */
int regR; int regR; /* Range of registers holding conflicting PK */
int iThisCur = iIdxCur+ix; int iThisCur; /* Cursor for this UNIQUE index */
int addrUniqueOk = sqlite3VdbeMakeLabel(v); int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */
if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */ if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */
iThisCur = iIdxCur+ix;
addrUniqueOk = sqlite3VdbeMakeLabel(v);
if( pIdx->pPartIdxWhere ){ if( pIdx->pPartIdxWhere ){
sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]); sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]);
pParse->ckBase = regData; pParse->ckBase = regNewData+1;
sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrUniqueOk, sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrUniqueOk,
SQLITE_JUMPIFNULL); SQLITE_JUMPIFNULL);
pParse->ckBase = 0; pParse->ckBase = 0;
} }
/* Create a key for accessing the index entry */ /* Create a record for this index entry as it should appear after
** the insert or update. */
regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn); regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn);
for(i=0; i<pIdx->nColumn; i++){ for(i=0; i<pIdx->nColumn; i++){
i16 iField = pIdx->aiColumn[i]; int iField = pIdx->aiColumn[i];
if( iField<0 || iField==pTab->iPKey ){ if( iField<0 || iField==pTab->iPKey ){
sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i); iField = regNewData;
}else{ }else{
sqlite3VdbeAddOp2(v, OP_SCopy, regData+iField, regIdx+i); iField += regNewData + 1;
} }
sqlite3VdbeAddOp2(v, OP_SCopy, iField, regIdx+i);
} }
sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]); sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), P4_TRANSIENT); sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), P4_TRANSIENT);
VdbeComment((v, "for %s", pIdx->zName)); VdbeComment((v, "for %s", pIdx->zName));
sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn); sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn);
/* Find out what action to take in case there is an indexing conflict */ /* Find out what action to take in case there is a uniqueness conflict */
onError = pIdx->onError; onError = pIdx->onError;
if( onError==OE_None ){ if( onError==OE_None ){
sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn); sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
@ -1458,10 +1469,10 @@ void sqlite3GenerateConstraintChecks(
sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk, sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
regIdx, pIdx->nKeyCol); regIdx, pIdx->nKeyCol);
if( HasRowid(pTab) ){ if( HasRowid(pTab) ){
sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
/* Conflict only if the rowid of the existing index entry /* Conflict only if the rowid of the existing index entry
** is different from old-rowid */ ** is different from old-rowid */
sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR); sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData);
sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldPk);
}else{ }else{
/* Extract the PRIMARY KEY from the end of the index entry and /* Extract the PRIMARY KEY from the end of the index entry and
** store it in register regR..regR+nPk-1 */ ** store it in register regR..regR+nPk-1 */
@ -1478,10 +1489,10 @@ void sqlite3GenerateConstraintChecks(
if( isUpdate ){ if( isUpdate ){
int addrPkConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol; int addrPkConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
for(i=0; i<pPk->nKeyCol-1; i++){ for(i=0; i<pPk->nKeyCol-1; i++){
sqlite3VdbeAddOp3(v, OP_Ne, regOldPk+pPk->aiColumn[i]+1, sqlite3VdbeAddOp3(v, OP_Ne, regOldData+pPk->aiColumn[i]+1,
addrPkConflict, regIdx+i); addrPkConflict, regIdx+i);
} }
sqlite3VdbeAddOp3(v, OP_Eq, regOldPk+pPk->aiColumn[i]+1, sqlite3VdbeAddOp3(v, OP_Eq, regOldData+pPk->aiColumn[i]+1,
addrUniqueOk, regIdx+i); addrUniqueOk, regIdx+i);
} }
}else{ }else{
@ -1492,10 +1503,10 @@ void sqlite3GenerateConstraintChecks(
assert( pIdx->nKeyCol + pPk->nKeyCol == pIdx->nColumn ); assert( pIdx->nKeyCol + pPk->nKeyCol == pIdx->nColumn );
for(i=0; i<pPk->nKeyCol-1; i++){ for(i=0; i<pPk->nKeyCol-1; i++){
sqlite3VdbeAddOp3(v, OP_Ne, sqlite3VdbeAddOp3(v, OP_Ne,
regOldPk+pPk->aiColumn[i], addrConflict, regR+i); regOldData+pPk->aiColumn[i]+1, addrConflict, regR+i);
} }
sqlite3VdbeAddOp3(v, OP_Eq, sqlite3VdbeAddOp3(v, OP_Eq,
regOldPk+pPk->aiColumn[i], addrUniqueOk, regR+i); regOldData+pPk->aiColumn[i]+1, addrUniqueOk, regR+i);
} }
} }
sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn); sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
@ -1560,7 +1571,7 @@ 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.
** A consecutive range of registers starting at regRowid contains the ** A consecutive range of registers starting at regNewData contains the
** rowid and the content to be inserted. ** rowid and the content to be inserted.
** **
** 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
@ -1571,18 +1582,18 @@ void sqlite3CompleteInsertion(
Table *pTab, /* the table into which we are inserting */ Table *pTab, /* the table into which we are inserting */
int iDataCur, /* Cursor of the canonical data source */ int iDataCur, /* Cursor of the canonical data source */
int iIdxCur, /* First index cursor */ int iIdxCur, /* First index cursor */
int regRowid, /* Range of content */ int regNewData, /* 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 isUpdate, /* True for UPDATE, False for INSERT */ int isUpdate, /* True for UPDATE, False for INSERT */
int appendBias, /* True if this is likely to be an append */ int appendBias, /* True if this is likely to be an append */
int useSeekResult /* True to set the USESEEKRESULT flag on OP_[Idx]Insert */ int useSeekResult /* True to set the USESEEKRESULT flag on OP_[Idx]Insert */
){ ){
int i; Vdbe *v; /* Prepared statements under construction */
Vdbe *v; Index *pIdx; /* An index being inserted or updated */
Index *pIdx; u8 pik_flags; /* flag values passed to the btree insert */
u8 pik_flags; int regData; /* Content registers (after the rowid) */
int regData; int regRec; /* Register holding assemblied record for the table */
int regRec; int i; /* Loop counter */
v = sqlite3GetVdbe(pParse); v = sqlite3GetVdbe(pParse);
assert( v!=0 ); assert( v!=0 );
@ -1598,7 +1609,7 @@ void sqlite3CompleteInsertion(
} }
} }
if( !HasRowid(pTab) ) return; if( !HasRowid(pTab) ) return;
regData = regRowid + 1; regData = regNewData + 1;
regRec = sqlite3GetTempReg(pParse); regRec = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec); sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec);
sqlite3TableAffinityStr(v, pTab); sqlite3TableAffinityStr(v, pTab);
@ -1615,7 +1626,7 @@ void sqlite3CompleteInsertion(
if( useSeekResult ){ if( useSeekResult ){
pik_flags |= OPFLAG_USESEEKRESULT; pik_flags |= OPFLAG_USESEEKRESULT;
} }
sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, regRec, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, regRec, regNewData);
if( !pParse->nested ){ if( !pParse->nested ){
sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT); sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
} }

View File

@ -1917,7 +1917,7 @@ void sqlite3Pragma(
sqlite3VdbeJumpHere(v, jmp2); sqlite3VdbeJumpHere(v, jmp2);
sqlite3VdbeResolveLabel(v, jmp3); sqlite3VdbeResolveLabel(v, jmp3);
} }
sqlite3VdbeAddOp2(v, OP_Next, 1, loopTop); sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop);
sqlite3VdbeJumpHere(v, loopTop-1); sqlite3VdbeJumpHere(v, loopTop-1);
#ifndef SQLITE_OMIT_BTREECOUNT #ifndef SQLITE_OMIT_BTREECOUNT
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0,

View File

@ -59,6 +59,6 @@ do_test without_rowid1-1.21 {
do_execsql_test without_rowid1-1.22 { do_execsql_test without_rowid1-1.22 {
REPLACE INTO t1 VALUES('dynamic','phone','flipper','harvard'); REPLACE INTO t1 VALUES('dynamic','phone','flipper','harvard');
SELECT *, '|' FROM t1 ORDER BY c, a; SELECT *, '|' FROM t1 ORDER BY c, a;
} {} } {arctic sleep ammonia helena | journal sherman ammonia helena | dynamic phone flipper harvard | journal sherman gamma patriot |}
finish_test finish_test