1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-11 01:42:22 +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

@@ -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);
}