mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-24 22:22:08 +03:00
Improved comments and variable names in infrastructure routines of UPDATE,
DELETE, and INSERT. FossilOrigin-Name: ad90e762e51384ac7c311f08a641419f03f6d3f0
This commit is contained in:
18
manifest
18
manifest
@ -1,5 +1,5 @@
|
||||
C Moving\sUPDATE\stowards\sthe\siDataCur/iIdxCur\srepresentation.\s\sStill\snot\sworking\nfor\sWITHOUT\sROWID,\sthough.
|
||||
D 2013-10-31T12:13:37.732
|
||||
C Improved\scomments\sand\svariable\snames\sin\sinfrastructure\sroutines\sof\sUPDATE,\nDELETE,\sand\sINSERT.
|
||||
D 2013-10-31T15:37:49.070
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 0522b53cdc1fcfc18f3a98e0246add129136c654
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -173,7 +173,7 @@ F src/callback.c f99a8957ba2adf369645fac0db09ad8adcf1caa2
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c ea4b7f3623a0fcb1146e7f245d7410033e86859c
|
||||
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
|
||||
F src/delete.c d50cc704030139e19f2e9d5ac7a49db04dfe08a9
|
||||
F src/delete.c 0e10849258efbdab48b8679de19edd661859dc7d
|
||||
F src/expr.c 3180b6332072b263f845592e72e92971af562ab0
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 628f81177299660a86e40359b3689b81f517e125
|
||||
@ -182,7 +182,7 @@ F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759
|
||||
F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
|
||||
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c e8f0691953194cf1df85b463fed8b75b0dedf7d9
|
||||
F src/insert.c 64eb6bf8eda1bbe003cc38394d721b4810f65182
|
||||
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
|
||||
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
|
||||
@ -212,7 +212,7 @@ F src/parse.y 073a8294e1826f1b1656e84806b77e4199f4bb57
|
||||
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
|
||||
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
|
||||
F src/pcache1.c a467393909a4ed7ca9de066d85ba5c5b04a5be63
|
||||
F src/pragma.c 74dec25a3f0d3e5da796345a0ca817cb445e9d2a
|
||||
F src/pragma.c ff1a98998d2038bc9c770326986b7c4728de4973
|
||||
F src/prepare.c f47ba2bba7ac5650881ab6c41f6d33a6de1a8d52
|
||||
F src/printf.c da9119eb31a187a4b99f60aa4a225141c0ebb74b
|
||||
F src/random.c 0b2dbc37fdfbfa6bd455b091dfcef5bdb32dba68
|
||||
@ -1076,7 +1076,7 @@ F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
|
||||
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
|
||||
F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
|
||||
F test/win32longpath.test e2aafc07e6990fe86c69be22a3d1a0e210cd329b
|
||||
F test/without_rowid1.test fb3ceaa20bda4e0338f594696a49014c3cbeb30c
|
||||
F test/without_rowid1.test e4f023e49a57c90f6d25afd4b3e8b0305ad06e44
|
||||
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
|
||||
F test/zerodamage.test 209d7ed441f44cc5299e4ebffbef06fd5aabfefd
|
||||
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.sh d1a6de74685f360ab718efda6265994b99bbea01
|
||||
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
||||
P 1adfca6019847d37dee4a297669f29d5ca184066
|
||||
R 925135441c339dd20ca1becb38d6fbf2
|
||||
P deacbd21b50cc8c63a1572d14a4bbc7af4052d37
|
||||
R 868cea4e5c536af4b28fd795ccabbf1e
|
||||
U drh
|
||||
Z 72a84fe0a8232f3d99ba9db66435b958
|
||||
Z 77c0455bfaa16e77ab3ac24edbdbd46c
|
||||
|
@ -1 +1 @@
|
||||
deacbd21b50cc8c63a1572d14a4bbc7af4052d37
|
||||
ad90e762e51384ac7c311f08a641419f03f6d3f0
|
51
src/delete.c
51
src/delete.c
@ -523,24 +523,21 @@ delete_from_cleanup:
|
||||
|
||||
/*
|
||||
** 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.
|
||||
** These are the requirements:
|
||||
** Preconditions:
|
||||
**
|
||||
** 1. iDataCur is an open cursor on the btree that is the primary data
|
||||
** repository for the table. This will be either the table itself,
|
||||
** 1. iDataCur is an open cursor on the btree that is the canonical data
|
||||
** 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
|
||||
** of a WITHOUT ROWID table.
|
||||
** of a WITHOUT ROWID table.)
|
||||
**
|
||||
** 2. Read/write cursors for all indices of pTab must be open as
|
||||
** cursor number iIdxCur+i for the i-th index.
|
||||
**
|
||||
** 3. The primary key for the row to be deleted must be stored in a
|
||||
** 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(
|
||||
Parse *pParse, /* Parsing context */
|
||||
@ -560,7 +557,7 @@ void sqlite3GenerateRowDelete(
|
||||
|
||||
/* Vdbe is guaranteed to have been allocated by this stage. */
|
||||
assert( v );
|
||||
VdbeModuleComment((v, "BEGIN: GenerateRowDelete(%d,%d,%d,%d)",
|
||||
VdbeModuleComment((v, "BEGIN: GenRowDel(%d,%d,%d,%d)",
|
||||
iDataCur, iIdxCur, iPk, (int)nPk));
|
||||
|
||||
/* 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
|
||||
** RAISE(IGNORE) exception. */
|
||||
sqlite3VdbeResolveLabel(v, iLabel);
|
||||
VdbeModuleComment((v, "END: GenerateRowDelete()"));
|
||||
VdbeModuleComment((v, "END: GenRowDel()"));
|
||||
}
|
||||
|
||||
/*
|
||||
** 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.
|
||||
** These are the requirements:
|
||||
** Preconditions:
|
||||
**
|
||||
** 1. A read/write cursor "iDataCur" pointing to canonical storage
|
||||
** tree for the table pTab, which will be either the table itself
|
||||
** 1. A read/write cursor "iDataCur" must be open on the canonical storage
|
||||
** btree for the table pTab. (This will be either the table itself
|
||||
** 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
|
||||
** 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
|
||||
** deleted.
|
||||
** 3. The "iDataCur" cursor must be already be positioned on the row
|
||||
** that is to be deleted.
|
||||
*/
|
||||
void sqlite3GenerateRowIndexDelete(
|
||||
Parse *pParse, /* Parsing and code generating context */
|
||||
@ -664,15 +661,17 @@ void sqlite3GenerateRowIndexDelete(
|
||||
int iIdxCur, /* First index cursor */
|
||||
int *aRegIdx /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */
|
||||
){
|
||||
int i;
|
||||
Index *pIdx;
|
||||
int r1;
|
||||
int iPartIdxLabel;
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
Index *pPk;
|
||||
int i; /* Index loop counter */
|
||||
int r1; /* Register holding an index key */
|
||||
int iPartIdxLabel; /* Jump destination for skipping partial index entries */
|
||||
Index *pIdx; /* Current index */
|
||||
Vdbe *v; /* The prepared statement under construction */
|
||||
Index *pPk; /* PRIMARY KEY index, or NULL for rowid tables */
|
||||
|
||||
v = pParse->pVdbe;
|
||||
pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
|
||||
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( pIdx==pPk ) continue;
|
||||
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1, &iPartIdxLabel);
|
||||
|
203
src/insert.c
203
src/insert.c
@ -1123,36 +1123,47 @@ insert_cleanup:
|
||||
#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 WITHOUT ROWID tables.
|
||||
** For an UPDATE (isUpdate!=0), if pkChng is non-zero then it contains
|
||||
** 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...
|
||||
**
|
||||
** 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
|
||||
** The code generated by this routine will store new index entries into
|
||||
** registers identified by aRegIdx[]. No index entry is created for
|
||||
** 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
|
||||
** 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,
|
||||
** CHECK, and UNIQUE constraints are all checked. If a constraint fails,
|
||||
@ -1162,22 +1173,23 @@ insert_cleanup:
|
||||
** Constraint type Action What Happens
|
||||
** --------------- ---------- ----------------------------------------
|
||||
** 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.
|
||||
**
|
||||
** any ABORT Back out changes from the current command
|
||||
** only (do not do a complete rollback) then
|
||||
** cause sqlite3_exec() to return immediately
|
||||
** cause sqlite3_step() to return immediately
|
||||
** 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
|
||||
** 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
|
||||
** the stack and there is an immediate jump
|
||||
** to label ignoreDest.
|
||||
** any IGNORE The attempt in insert or update the current
|
||||
** row is skipped, without throwing an error.
|
||||
** Processing continues with the next row.
|
||||
** (There is an immediate jump to ignoreDest.)
|
||||
**
|
||||
** NOT NULL REPLACE The NULL value is replace by the default
|
||||
** value for that column. If the default value
|
||||
@ -1192,50 +1204,44 @@ insert_cleanup:
|
||||
** Or if overrideError==OE_Default, then the pParse->onError parameter
|
||||
** is used. Or if pParse->onError==OE_Default then the onError value
|
||||
** 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(
|
||||
Parse *pParse, /* The parser context */
|
||||
Table *pTab, /* the table into which we are inserting */
|
||||
int iDataCur, /* Cursor of the canonical data tree */
|
||||
int iIdxCur, /* First index cursor */
|
||||
int regRowid, /* First register in a range holding values to insert */
|
||||
int *aRegIdx, /* Register used by each index. 0 for unused indices */
|
||||
int pkChng, /* Non-zero if the rowid or PRIMARY KEY changed */
|
||||
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 */
|
||||
int *pbMayReplace /* OUT: Set to true if constraint may cause a replace */
|
||||
Parse *pParse, /* The parser context */
|
||||
Table *pTab, /* The table being inserted or updated */
|
||||
int iDataCur, /* Canonical data cursor (main table or PK index) */
|
||||
int iIdxCur, /* First index cursor */
|
||||
int regNewData, /* First register in a range holding values to insert */
|
||||
int *aRegIdx, /* Register used by each index. 0 for unused indices */
|
||||
int pkChng, /* Non-zero if the rowid or PRIMARY KEY changed */
|
||||
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 */
|
||||
int *pbMayReplace /* OUT: Set to true if constraint may cause a replace */
|
||||
){
|
||||
int i; /* loop counter */
|
||||
Vdbe *v; /* VDBE under constrution */
|
||||
int nCol; /* Number of columns */
|
||||
int onError; /* Conflict resolution strategy */
|
||||
int j1; /* Addresss of jump instruction */
|
||||
int ix; /* Index loop counter */
|
||||
int regData; /* Register containing first data column */
|
||||
int i; /* loop counter */
|
||||
Vdbe *v; /* VDBE under constrution */
|
||||
int nCol; /* Number of columns */
|
||||
int onError; /* Conflict resolution strategy */
|
||||
int j1; /* Addresss of jump instruction */
|
||||
int ix; /* Index loop counter */
|
||||
Index *pIdx; /* Pointer to one of the indices */
|
||||
Index *pPk = 0; /* The PRIMARY KEY index */
|
||||
sqlite3 *db; /* Database connection */
|
||||
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 */
|
||||
|
||||
regOldPk = (pkChng && isUpdate) ? pkChng : regRowid;
|
||||
regOldData = (pkChng && isUpdate) ? pkChng : regNewData;
|
||||
db = pParse->db;
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
assert( v!=0 );
|
||||
assert( pTab->pSelect==0 ); /* This table is not a VIEW */
|
||||
nCol = pTab->nCol;
|
||||
regData = regRowid + 1;
|
||||
|
||||
/* For WITHOUT ROWID tables, we'll need to know the Index and the cursor
|
||||
** number for the PRIMARY KEY index */
|
||||
|
||||
/* pPk is the PRIMARY KEY index for WITHOUT ROWID tables and NULL for
|
||||
** 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) ){
|
||||
pPk = 0;
|
||||
nPkField = 1;
|
||||
@ -1246,7 +1252,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
|
||||
/* Record that this module has started */
|
||||
VdbeModuleComment((v, "BEGIN: GenCnstCks(%d,%d,%d,%d,%d)",
|
||||
iDataCur, iIdxCur, regRowid, pkChng, regOldPk));
|
||||
iDataCur, iIdxCur, regNewData, regOldData, pkChng));
|
||||
|
||||
/* Test all NOT NULL constraints.
|
||||
*/
|
||||
@ -1274,20 +1280,20 @@ void sqlite3GenerateConstraintChecks(
|
||||
case OE_Fail: {
|
||||
char *zMsg;
|
||||
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",
|
||||
pTab->zName, pTab->aCol[i].zName);
|
||||
sqlite3VdbeChangeP4(v, -1, zMsg, P4_DYNAMIC);
|
||||
break;
|
||||
}
|
||||
case OE_Ignore: {
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regData+i, ignoreDest);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regNewData+1+i, ignoreDest);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert( onError==OE_Replace );
|
||||
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regData+i);
|
||||
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regData+i);
|
||||
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regNewData+1+i);
|
||||
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regNewData+1+i);
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
break;
|
||||
}
|
||||
@ -1299,7 +1305,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
|
||||
ExprList *pCheck = pTab->pCheck;
|
||||
pParse->ckBase = regData;
|
||||
pParse->ckBase = regNewData+1;
|
||||
onError = overrideError!=OE_Default ? overrideError : OE_Abort;
|
||||
for(i=0; i<pCheck->nExpr; i++){
|
||||
int allOk = sqlite3VdbeMakeLabel(v);
|
||||
@ -1324,7 +1330,8 @@ void sqlite3GenerateConstraintChecks(
|
||||
|
||||
/* If there is an INTEGER PRIMARY KEY, make sure the primary key
|
||||
** 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.
|
||||
*/
|
||||
@ -1339,9 +1346,9 @@ void sqlite3GenerateConstraintChecks(
|
||||
}
|
||||
|
||||
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 ){
|
||||
default: {
|
||||
onError = OE_Abort;
|
||||
@ -1384,7 +1391,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
|
||||
sqlite3MultiWrite(pParse);
|
||||
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
|
||||
regRowid, 1, 0, OE_Replace);
|
||||
regNewData, 1, 0, OE_Replace);
|
||||
}else if( pTab->pIndex ){
|
||||
sqlite3MultiWrite(pParse);
|
||||
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, 0);
|
||||
@ -1406,37 +1413,41 @@ void sqlite3GenerateConstraintChecks(
|
||||
** Compute the revised record entries for indices as we go.
|
||||
*/
|
||||
for(ix=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, ix++){
|
||||
int regIdx;
|
||||
int regR;
|
||||
int iThisCur = iIdxCur+ix;
|
||||
int addrUniqueOk = sqlite3VdbeMakeLabel(v);
|
||||
int regIdx; /* Range of registers hold conent for pIdx */
|
||||
int regR; /* Range of registers holding conflicting PK */
|
||||
int iThisCur; /* Cursor for this UNIQUE index */
|
||||
int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */
|
||||
|
||||
if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */
|
||||
iThisCur = iIdxCur+ix;
|
||||
addrUniqueOk = sqlite3VdbeMakeLabel(v);
|
||||
|
||||
if( pIdx->pPartIdxWhere ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]);
|
||||
pParse->ckBase = regData;
|
||||
pParse->ckBase = regNewData+1;
|
||||
sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrUniqueOk,
|
||||
SQLITE_JUMPIFNULL);
|
||||
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);
|
||||
for(i=0; i<pIdx->nColumn; i++){
|
||||
i16 iField = pIdx->aiColumn[i];
|
||||
int iField = pIdx->aiColumn[i];
|
||||
if( iField<0 || iField==pTab->iPKey ){
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i);
|
||||
iField = regNewData;
|
||||
}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]);
|
||||
sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), P4_TRANSIENT);
|
||||
VdbeComment((v, "for %s", pIdx->zName));
|
||||
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;
|
||||
if( onError==OE_None ){
|
||||
sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
|
||||
@ -1458,10 +1469,10 @@ void sqlite3GenerateConstraintChecks(
|
||||
sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
|
||||
regIdx, pIdx->nKeyCol);
|
||||
if( HasRowid(pTab) ){
|
||||
sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
|
||||
/* Conflict only if the rowid of the existing index entry
|
||||
** is different from old-rowid */
|
||||
sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
|
||||
sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldPk);
|
||||
sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData);
|
||||
}else{
|
||||
/* Extract the PRIMARY KEY from the end of the index entry and
|
||||
** store it in register regR..regR+nPk-1 */
|
||||
@ -1478,10 +1489,10 @@ void sqlite3GenerateConstraintChecks(
|
||||
if( isUpdate ){
|
||||
int addrPkConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
|
||||
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);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_Eq, regOldPk+pPk->aiColumn[i]+1,
|
||||
sqlite3VdbeAddOp3(v, OP_Eq, regOldData+pPk->aiColumn[i]+1,
|
||||
addrUniqueOk, regIdx+i);
|
||||
}
|
||||
}else{
|
||||
@ -1492,10 +1503,10 @@ void sqlite3GenerateConstraintChecks(
|
||||
assert( pIdx->nKeyCol + pPk->nKeyCol == pIdx->nColumn );
|
||||
for(i=0; i<pPk->nKeyCol-1; i++){
|
||||
sqlite3VdbeAddOp3(v, OP_Ne,
|
||||
regOldPk+pPk->aiColumn[i], addrConflict, regR+i);
|
||||
regOldData+pPk->aiColumn[i]+1, addrConflict, regR+i);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_Eq,
|
||||
regOldPk+pPk->aiColumn[i], addrUniqueOk, regR+i);
|
||||
regOldData+pPk->aiColumn[i]+1, addrUniqueOk, regR+i);
|
||||
}
|
||||
}
|
||||
sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
|
||||
@ -1560,7 +1571,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
/*
|
||||
** This routine generates code to finish the INSERT or UPDATE operation
|
||||
** 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.
|
||||
**
|
||||
** 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 */
|
||||
int iDataCur, /* Cursor of the canonical data source */
|
||||
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 isUpdate, /* True for UPDATE, False for INSERT */
|
||||
int appendBias, /* True if this is likely to be an append */
|
||||
int useSeekResult /* True to set the USESEEKRESULT flag on OP_[Idx]Insert */
|
||||
){
|
||||
int i;
|
||||
Vdbe *v;
|
||||
Index *pIdx;
|
||||
u8 pik_flags;
|
||||
int regData;
|
||||
int regRec;
|
||||
Vdbe *v; /* Prepared statements under construction */
|
||||
Index *pIdx; /* An index being inserted or updated */
|
||||
u8 pik_flags; /* flag values passed to the btree insert */
|
||||
int regData; /* Content registers (after the rowid) */
|
||||
int regRec; /* Register holding assemblied record for the table */
|
||||
int i; /* Loop counter */
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
assert( v!=0 );
|
||||
@ -1598,7 +1609,7 @@ void sqlite3CompleteInsertion(
|
||||
}
|
||||
}
|
||||
if( !HasRowid(pTab) ) return;
|
||||
regData = regRowid + 1;
|
||||
regData = regNewData + 1;
|
||||
regRec = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec);
|
||||
sqlite3TableAffinityStr(v, pTab);
|
||||
@ -1615,7 +1626,7 @@ void sqlite3CompleteInsertion(
|
||||
if( useSeekResult ){
|
||||
pik_flags |= OPFLAG_USESEEKRESULT;
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, regRec, regRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, regRec, regNewData);
|
||||
if( !pParse->nested ){
|
||||
sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
|
||||
}
|
||||
|
@ -1917,7 +1917,7 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeJumpHere(v, jmp2);
|
||||
sqlite3VdbeResolveLabel(v, jmp3);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Next, 1, loopTop);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop);
|
||||
sqlite3VdbeJumpHere(v, loopTop-1);
|
||||
#ifndef SQLITE_OMIT_BTREECOUNT
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0,
|
||||
|
@ -59,6 +59,6 @@ do_test without_rowid1-1.21 {
|
||||
do_execsql_test without_rowid1-1.22 {
|
||||
REPLACE INTO t1 VALUES('dynamic','phone','flipper','harvard');
|
||||
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
|
||||
|
Reference in New Issue
Block a user