Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Work on the UPDATE and INSERT logic. This is an incremental check-in so that can switch over to trunk to work on an unrelated issue there. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | omit-rowid |
Files: | files | file ages | folders |
SHA1: |
086ec2a177b24ad90d5d705a99d93aa0 |
User & Date: | drh 2013-10-26 15:40:48.224 |
Context
2013-10-28
| ||
22:39 | Merge recent fixes from trunk. (check-in: 9f8191d1d8 user: drh tags: omit-rowid) | |
2013-10-26
| ||
15:40 | Work on the UPDATE and INSERT logic. This is an incremental check-in so that can switch over to trunk to work on an unrelated issue there. (check-in: 086ec2a177 user: drh tags: omit-rowid) | |
13:36 | Replace the OP_IsUnique opcode with OP_NoConflict. This code simplification might be useful to move onto trunk even if this branch is never merged. (check-in: e6650e16dd user: drh tags: omit-rowid) | |
Changes
Changes to src/insert.c.
︙ | ︙ | |||
1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 | #ifdef pTrigger #undef pTrigger #endif #ifdef tmask #undef tmask #endif /* ** Generate code to do constraint checks prior to an INSERT or an UPDATE. ** ** The input is a range of consecutive registers as follows: ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 | #ifdef pTrigger #undef pTrigger #endif #ifdef tmask #undef tmask #endif /* ** If regFirst is a set of value for a table row in table order and pPk ** is the PRIMARY KEY index for that table, then return the index of the ** first register in a contiguous array of registers that are the primary ** key values for the table row. ** ** For the common cases where the PRIMARY KEY has only a single value or ** where a multi-value PRIMARY KEY is contiguous in table order, this ** routine simply returns a pointer into the regFirst array. But if there ** is a multi-value PRIMARY KEY with the values out-of-order, this routine ** has to generate code that will copy PRIMARY KEY values into newly ** allocated contiguous registers. */ static int sqlite3PrimaryKeyRegisters(Parse *pParse, Index *pPk, int regFirst){ int i; int nKeyCol = pPk->nKeyCol; int regPk; assert( pParse->pVdbe!=0 ); if( nKeyCol==1 ){ return regFirst + pPk->aiColumn[0]; } for(i=1; i<nKeyCol; i++){ if( pPk->aiColumn[i-1]+1!=pPk->aiColumn[i] ) break; } if( i==nKeyCol ){ return regFirst + pPk->aiColumn[0]; } regPk = pParse->nMem+1; pParse->nMem += nKeyCol; for(i=0; i<nKeyCol; i++){ int x = pPk->aiColumn[i]; sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, regFirst+x, regPk+i); } return regPk; } /* ** Generate code to do constraint checks prior to an INSERT or an UPDATE. ** ** The input is a range of consecutive registers as follows: ** ** 1. The rowid of the row after the update, or NULL ** for WITHOUT ROWID tables. ** ** 2. The data in the first column of the entry after the update. ** ** i. Data from middle columns... ** ** N. The data in the last column of the entry after the update. ** |
︙ | ︙ | |||
1203 1204 1205 1206 1207 1208 1209 | */ void sqlite3GenerateConstraintChecks( Parse *pParse, /* The parser context */ Table *pTab, /* the table into which we are inserting */ int baseCur, /* A read/write cursor pointing at pTab */ int regRowid, /* First register in a range holding values to insert */ int *aRegIdx, /* Register used by each index. 0 for unused indices */ | | < > | > > > > > > > > > > > > > > | 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 | */ void sqlite3GenerateConstraintChecks( Parse *pParse, /* The parser context */ Table *pTab, /* the table into which we are inserting */ int baseCur, /* A read/write cursor pointing at pTab */ 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 */ ){ 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 regData; /* Register containing first data column */ int iCur; /* Table cursor number */ 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 regNewPk = 0; /* New PRIMARY KEY value */ int pkCur = 0; /* Cursor used by the PRIMARY KEY */ regOldPk = (pkChng && isUpdate) ? pkChng : regRowid; 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 */ if( !HasRowid(pTab) ){ pkCur = baseCur+1; pPk = pTab->pIndex; while( ALWAYS(pPk) && pPk->autoIndex!=2 ){ pPk=pPk->pNext; pkCur++; } } /* Test all NOT NULL constraints. */ for(i=0; i<nCol; i++){ if( i==pTab->iPKey ){ continue; } |
︙ | ︙ | |||
1305 1306 1307 1308 1309 1310 1311 1312 | } } #endif /* !defined(SQLITE_OMIT_CHECK) */ /* If we have 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. */ | > > | > > | | | | 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 | } } #endif /* !defined(SQLITE_OMIT_CHECK) */ /* If we have 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. ** ** This block only runs for tables that have a rowid. */ if( pkChng && pkCur==0 ){ int addrRowidOk = sqlite3VdbeMakeLabel(v); onError = pTab->keyConf; if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } if( isUpdate ){ sqlite3VdbeAddOp3(v, OP_Eq, regRowid, addrRowidOk, pkChng); } sqlite3VdbeAddOp3(v, OP_NotExists, baseCur, addrRowidOk, regRowid); switch( onError ){ default: { onError = OE_Abort; /* Fall thru into the next case */ } case OE_Rollback: case OE_Abort: |
︙ | ︙ | |||
1375 1376 1377 1378 1379 1380 1381 | } case OE_Ignore: { assert( seenReplace==0 ); sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); break; } } | | < < < | > | | | | | > > > | | > > > > > > > > > > > > > > > > > > > > > | | 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 | } case OE_Ignore: { assert( seenReplace==0 ); sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); break; } } sqlite3VdbeResolveLabel(v, addrRowidOk); } /* Test all UNIQUE constraints by creating entries for each UNIQUE ** index and making sure that duplicate entries do not already exist. ** Compute the revised record entries for indices as we go. */ for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){ int regIdx; int regR; int idxCur = baseCur+iCur+1; int addrUniqueOk = sqlite3VdbeMakeLabel(v); if( aRegIdx[iCur]==0 ) continue; /* Skip unused indices */ if( pIdx->pPartIdxWhere ){ sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[iCur]); pParse->ckBase = regData; sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrUniqueOk, SQLITE_JUMPIFNULL); pParse->ckBase = 0; } /* Create a key for accessing the index entry */ regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn); for(i=0; i<pIdx->nColumn; i++){ i16 idx = pIdx->aiColumn[i]; if( idx<0 || idx==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i); }else{ sqlite3VdbeAddOp2(v, OP_SCopy, regData+idx, regIdx+i); } } sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[iCur]); sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), P4_TRANSIENT); sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn); /* Find out what action to take in case there is an indexing conflict */ onError = pIdx->onError; if( onError==OE_None ){ sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nKeyCol+1); sqlite3VdbeResolveLabel(v, addrUniqueOk); continue; /* pIdx is not a UNIQUE index */ } if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } if( seenReplace ){ if( onError==OE_Ignore ) onError = OE_Replace; else if( onError==OE_Fail ) onError = OE_Abort; } /* Check to see if the new index entry will be unique */ regR = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4Int(v, OP_NoConflict, idxCur, addrUniqueOk, regIdx, pIdx->nKeyCol); if( HasRowid(pTab) ){ /* Conflict only if the rowid of the existing entry with the matching ** key is different from old-rowid */ sqlite3VdbeAddOp2(v, OP_IdxRowid, idxCur, regR); sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldPk); }else if( pIdx->autoIndex==2 ){ /* If there is a matching entry on the PRIMARY KEY index ... */ 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); } sqlite3VdbeAddOp3(v, OP_Eq, regOldPk+pPk->aiColumn[i], addrUniqueOk, regIdx+i); }else{ 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_Ne, regOldPk+pPk->aiColumn[i], addrConflict, regR); } sqlite3VdbeAddOp3(v, OP_Column, idxCur, pIdx->nKeyCol+i, regR); sqlite3VdbeAddOp3(v, OP_Eq, regOldPk+pPk->aiColumn[i], addrUniqueOk, regR); } sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn); /* Generate code that executes if the new index entry is not unique */ assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail || onError==OE_Ignore || onError==OE_Replace ); switch( onError ){ case OE_Rollback: case OE_Abort: |
︙ | ︙ | |||
1487 1488 1489 1490 1491 1492 1493 | sqlite3GenerateRowDelete( pParse, pTab, pTrigger, baseCur, regR, 0, 0, OE_Replace ); seenReplace = 1; break; } } | | | 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 | sqlite3GenerateRowDelete( pParse, pTab, pTrigger, baseCur, regR, 0, 0, OE_Replace ); seenReplace = 1; break; } } sqlite3VdbeResolveLabel(v, addrUniqueOk); sqlite3ReleaseTempReg(pParse, regR); } if( pbMayReplace ){ *pbMayReplace = seenReplace; } } |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
3733 3734 3735 3736 3737 3738 3739 | ** rowid P3 then jump immediately to P2. If P1 does contain a record ** with rowid P3 then leave the cursor pointing at that record and fall ** through to the next instruction. ** ** The OP_NotFound opcode performs the same operation on index btrees ** (with arbitrary multi-value keys). ** | | | 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 | ** rowid P3 then jump immediately to P2. If P1 does contain a record ** with rowid P3 then leave the cursor pointing at that record and fall ** through to the next instruction. ** ** The OP_NotFound opcode performs the same operation on index btrees ** (with arbitrary multi-value keys). ** ** See also: Found, NotFound, NoConflict */ case OP_NotExists: { /* jump, in3 */ VdbeCursor *pC; BtCursor *pCrsr; int res; u64 iKey; |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
78 79 80 81 82 83 84 | sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */ const sqlite3_module *pModule; /* Module for cursor pVtabCursor */ i64 seqCount; /* Sequence counter */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ i64 lastRowid; /* Last rowid from a Next or NextIdx operation */ VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */ | | < | 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */ const sqlite3_module *pModule; /* Module for cursor pVtabCursor */ i64 seqCount; /* Sequence counter */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ i64 lastRowid; /* Last rowid from a Next or NextIdx operation */ VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */ /* Result of last sqlite3BtreeMoveto() done by an OP_NotExists */ int seekResult; /* Cached information about the header for the data record that the ** cursor is currently pointing to. Only valid if cacheStatus matches ** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of ** CACHE_STALE and so setting cacheStatus=CACHE_STALE guarantees that ** the cache is out of date. |
︙ | ︙ |