Continue working to get UPDATE operational for WITHOUT ROWID tables.
Fix PRAGMA integrity_check so that it works on WITHOUT ROWID tables.
FossilOrigin-Name: 0d4fea7462c0f61cd1c736cbcd7bea5ec2034d54
diff --git a/src/insert.c b/src/insert.c
index b79a729..752d401 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -1159,6 +1159,40 @@
return regPk;
}
+/*
+** Locate the "principle btree" for a table. This is the table itself for
+** ordinary tables, but for WITHOUT ROWID tables, the principle btree is the
+** PRIMARY KEY index.
+**
+** Inputs are pTab and baseCur. The *ppPk is written with a pointer to the
+** PRIMARY KEY index for WITHOUT ROWID tables or with NULL for ordinary
+** tables. The *piPkCur is written with the cursor to use, assuming that the
+** table cursor is baseCur and that index cursors are consecutively numbered
+** thereafter.
+*/
+void sqlite3PrincipleBtree(
+ Table *pTab, /* The main Table object */
+ int baseCur, /* VDBE cursor for main table. */
+ Index **ppPk, /* Write PRIMARY KEY index of WITHOUT ROWID tables here */
+ int *piPkCur /* Either baseCur or the cursor for *ppPk */
+){
+ int pkCur;
+ Index *pPk;
+ if( !HasRowid(pTab) ){
+ pkCur = baseCur+1;
+ pPk = pTab->pIndex;
+ while( ALWAYS(pPk) && pPk->autoIndex!=2 ){
+ pPk=pPk->pNext;
+ pkCur++;
+ }
+ }else{
+ pkCur = baseCur;
+ pPk = 0;
+ }
+ *ppPk = pPk;
+ *piPkCur = pkCur;
+}
+
/*
** Generate code to do constraint checks prior to an INSERT or an UPDATE.
@@ -1263,6 +1297,7 @@
int regOldPk; /* Previous rowid or PRIMARY KEY value */
int regNewPk = 0; /* New PRIMARY KEY value */
int pkCur = 0; /* Cursor used by the PRIMARY KEY */
+ int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
regOldPk = (pkChng && isUpdate) ? pkChng : regRowid;
db = pParse->db;
@@ -1271,20 +1306,15 @@
assert( pTab->pSelect==0 ); /* This table is not a VIEW */
nCol = pTab->nCol;
regData = regRowid + 1;
- VdbeModuleComment((v, "BEGIN: GenerateConstraintChecks(%d,%d,%d)",
- baseCur, regRowid, pkChng));
/* For WITHOUT ROWID tables, we'll need to know the Index and the cursor
** number for the PRIMARY KEY index */
- if( !HasRowid(pTab) ){
- assert( pkChng==0 || isUpdate!=0 );
- pkCur = baseCur+1;
- pPk = pTab->pIndex;
- while( ALWAYS(pPk) && pPk->autoIndex!=2 ){
- pPk=pPk->pNext;
- pkCur++;
- }
- }
+ sqlite3PrincipleBtree(pTab, baseCur, &pPk, &pkCur);
+ nPkField = pPk ? pPk->nKeyCol : 1;
+
+ /* Record that this module has started */
+ VdbeModuleComment((v, "BEGIN: GenCnstCks(%d,%d,%d,%d,%d)",
+ baseCur, regRowid, pkChng, regOldPk, pkCur));
/* Test all NOT NULL constraints.
*/
@@ -1366,7 +1396,7 @@
**
** This block only runs for tables that have a rowid.
*/
- if( pkChng && pkCur==0 ){
+ if( pkChng && pPk==0 ){
int addrRowidOk = sqlite3VdbeMakeLabel(v);
onError = pTab->keyConf;
@@ -1492,7 +1522,7 @@
}
/* Check to see if the new index entry will be unique */
- regR = sqlite3GetTempReg(pParse);
+ regR = sqlite3GetTempRange(pParse, nPkField);
sqlite3VdbeAddOp4Int(v, OP_NoConflict, idxCur, addrUniqueOk,
regIdx, pIdx->nKeyCol);
#if 0
@@ -1510,13 +1540,15 @@
** if the PRIMARY KEY has changed. If the PRIMARY KEY is unchanged,
** then the matching entry is just the original row that is being
** modified. */
- int addrPkConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
- for(i=0; i<pPk->nKeyCol-1; i++){
- sqlite3VdbeAddOp3(v, OP_Ne,
- regOldPk+pPk->aiColumn[i], addrPkConflict, regIdx+i);
+ if( onError!=OE_Replace ){
+ int addrPkConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
+ for(i=0; i<pPk->nKeyCol-1; i++){
+ sqlite3VdbeAddOp3(v, OP_Ne, regOldPk+pPk->aiColumn[i]+1,
+ addrPkConflict, regIdx+i);
+ }
+ sqlite3VdbeAddOp3(v, OP_Eq, regOldPk+pPk->aiColumn[i]+1,
+ addrUniqueOk, regIdx+i);
}
- sqlite3VdbeAddOp3(v, OP_Eq,
- regOldPk+pPk->aiColumn[i], addrUniqueOk, regIdx+i);
}else{
/* For a UNIQUE index on a WITHOUT ROWID table, conflict only if the
** PRIMARY KEY value of the match is different from the old PRIMARY KEY
@@ -1524,13 +1556,13 @@
int addrConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol*2;
assert( pIdx->nKeyCol + pPk->nKeyCol == pIdx->nColumn );
for(i=0; i<pPk->nKeyCol-1; i++){
- sqlite3VdbeAddOp3(v, OP_Column, idxCur, pIdx->nKeyCol+i, regR);
+ sqlite3VdbeAddOp3(v, OP_Column, idxCur, pIdx->nKeyCol+i, regR+i);
sqlite3VdbeAddOp3(v, OP_Ne,
- regOldPk+pPk->aiColumn[i], addrConflict, regR);
+ regOldPk+pPk->aiColumn[i], addrConflict, regR+i);
}
- sqlite3VdbeAddOp3(v, OP_Column, idxCur, pIdx->nKeyCol+i, regR);
+ sqlite3VdbeAddOp3(v, OP_Column, idxCur, pIdx->nKeyCol+i, regR+i);
sqlite3VdbeAddOp3(v, OP_Eq,
- regOldPk+pPk->aiColumn[i], addrUniqueOk, regR);
+ regOldPk+pPk->aiColumn[i], addrUniqueOk, regR+i);
}
sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
@@ -1575,9 +1607,13 @@
if( db->flags&SQLITE_RecTriggers ){
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
}
- sqlite3GenerateRowDelete(
- pParse, pTab, pTrigger, baseCur, regR, 0, 0, OE_Replace
- );
+ if( pIdx==pPk ){
+ /*sqlite3VdbeAddOp3(v, OP_IdxDelete, pkCur, regIdx, pIdx->nColumn);*/
+ sqlite3VdbeAddOp1(v, OP_Delete, pkCur);
+ }else{
+ sqlite3GenerateRowDelete(pParse, pTab, pTrigger, baseCur,
+ regR, nPkField, 0, OE_Replace);
+ }
seenReplace = 1;
break;
}
@@ -1589,7 +1625,7 @@
if( pbMayReplace ){
*pbMayReplace = seenReplace;
}
- VdbeModuleComment((v, "END: GenerateConstraintChecks()"));
+ VdbeModuleComment((v, "END: GenCnstCks()"));
}
/*
@@ -1679,7 +1715,11 @@
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
v = sqlite3GetVdbe(pParse);
assert( v!=0 );
- sqlite3OpenTable(pParse, baseCur, iDb, pTab, op);
+ if( pkCur<0 ){
+ sqlite3OpenTable(pParse, baseCur, iDb, pTab, op);
+ }else{
+ sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
+ }
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
int iCur = (pkCur>=0 && pIdx->autoIndex==2) ? pkCur : i+baseCur;