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:
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user