/ Check-in [141a38a7]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Improved comments on the constraint checking logic.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | omit-rowid
Files: files | file ages | folders
SHA1:141a38a7a636e3e4255b59c27df4a1b3d6f26e97
User & Date: drh 2013-10-29 16:14:35
Context
2013-10-29
20:47
Import the automatic comment generating changes from trunk. check-in: 8bb51da1 user: drh tags: omit-rowid
16:14
Improved comments on the constraint checking logic. check-in: 141a38a7 user: drh tags: omit-rowid
2013-10-28
22:39
Merge recent fixes from trunk. check-in: 9f8191d1 user: drh tags: omit-rowid
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/insert.c.

1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
....
1271
1272
1273
1274
1275
1276
1277

1278
1279
1280
1281
1282
1283
1284
....
1300
1301
1302
1303
1304
1305
1306

1307
1308
1309
1310
1311
1312
1313
....
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
....
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
....
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
**
** 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 or that the rowid value is not 
** modified by an update. 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
** 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.
................................................................................
  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++;
    }
  }
................................................................................
      onError = OE_Abort;
    }
    assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
        || onError==OE_Ignore || onError==OE_Replace );
    switch( onError ){
      case OE_Abort:
        sqlite3MayAbort(pParse);

      case OE_Rollback:
      case OE_Fail: {
        char *zMsg;
        sqlite3VdbeAddOp3(v, OP_HaltIfNull,
                          SQLITE_CONSTRAINT_NOTNULL, onError, regData+i);
        zMsg = sqlite3MPrintf(db, "%s.%s may not be NULL",
                              pTab->zName, pTab->aCol[i].zName);
................................................................................
                              onError, zConsName, P4_DYNAMIC);
      }
      sqlite3VdbeResolveLabel(v, allOk);
    }
  }
#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);
................................................................................
  */
  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;
................................................................................
      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);
      }







|
|







 







>







 







>







 







|







 







|







 







>
>
>
>
>

|
|



|
>
>
>








>
>
>







1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
....
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
....
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
....
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
....
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
....
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
1528
**
** 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
** 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.
................................................................................
  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) ){
    assert( pkChng==0 || isUpdate!=0 );
    pkCur = baseCur+1;
    pPk = pTab->pIndex;
    while( ALWAYS(pPk) && pPk->autoIndex!=2 ){
      pPk=pPk->pNext;
      pkCur++;
    }
  }
................................................................................
      onError = OE_Abort;
    }
    assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
        || onError==OE_Ignore || onError==OE_Replace );
    switch( onError ){
      case OE_Abort:
        sqlite3MayAbort(pParse);
        /* Fall through */
      case OE_Rollback:
      case OE_Fail: {
        char *zMsg;
        sqlite3VdbeAddOp3(v, OP_HaltIfNull,
                          SQLITE_CONSTRAINT_NOTNULL, onError, regData+i);
        zMsg = sqlite3MPrintf(db, "%s.%s may not be NULL",
                              pTab->zName, pTab->aCol[i].zName);
................................................................................
                              onError, zConsName, P4_DYNAMIC);
      }
      sqlite3VdbeResolveLabel(v, allOk);
    }
  }
#endif /* !defined(SQLITE_OMIT_CHECK) */

  /* 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.
  **
  ** This block only runs for tables that have a rowid.
  */
  if( pkChng && pkCur==0 ){
    int addrRowidOk = sqlite3VdbeMakeLabel(v);
................................................................................
  */
  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 indices that do not change */

    if( pIdx->pPartIdxWhere ){
      sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[iCur]);
      pParse->ckBase = regData;
      sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrUniqueOk,
                         SQLITE_JUMPIFNULL);
      pParse->ckBase = 0;
................................................................................
      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 0
    if( !isUpdate ){
      /* A pre-existing row is always a conflict on an insert */
    }else
#endif
    if( HasRowid(pTab) ){
      /* Conflict only if the rowid of the existing index entry
      ** is different from old-rowid */
      sqlite3VdbeAddOp2(v, OP_IdxRowid, idxCur, regR);
      sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldPk);
    }else if( pIdx->autoIndex==2 ){
      /* For PRIMARY KEY index on a WITHOUT ROWID table, conflict only
      ** 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);
      }
      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
      ** value from before the update. */
      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);
      }