/ Check-in [c525ac56]
Login

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

Overview
Comment:Change the interface to sqlite3GenerateConstraintChecks() for improved lucidity and to fix issues in dealing with UPDATEs for WITHOUT ROWID tables. Make sure iDataCur and iIdxCur are initialized when processing DELETEs of a VIEW. UPDATE processing distinguishes between changes to ROWID and PRIMARY KEY.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | omit-rowid
Files: files | file ages | folders
SHA1: c525ac5630d6bcd51842cfc84f2c2c50be9cec1c
User & Date: drh 2013-11-01 17:08:56
Context
2013-11-01
17:21
Merge all changes from trunk, and disable a pair of corruption tests that are no longer valid since sqlite_master.rootpage can now be NULL for tables. check-in: dd5d57b9 user: drh tags: omit-rowid
17:08
Change the interface to sqlite3GenerateConstraintChecks() for improved lucidity and to fix issues in dealing with UPDATEs for WITHOUT ROWID tables. Make sure iDataCur and iIdxCur are initialized when processing DELETEs of a VIEW. UPDATE processing distinguishes between changes to ROWID and PRIMARY KEY. check-in: c525ac56 user: drh tags: omit-rowid
14:03
Improved VDBE comments on the constraint checker. Fix a missing write lock in the UPDATE logic. check-in: 3bed599e user: drh tags: omit-rowid
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/delete.c.

   320    320   
   321    321     /* If we are trying to delete from a view, realize that view into
   322    322     ** a ephemeral table.
   323    323     */
   324    324   #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
   325    325     if( isView ){
   326    326       sqlite3MaterializeView(pParse, pTab, pWhere, iTabCur);
          327  +    iDataCur = iIdxCur = iTabCur;
   327    328     }
   328    329   #endif
   329    330   
   330    331     /* Resolve the column names in the WHERE clause.
   331    332     */
   332    333     memset(&sNC, 0, sizeof(sNC));
   333    334     sNC.pParse = pParse;

Changes to src/insert.c.

  1035   1035         sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, pVTab, P4_VTAB);
  1036   1036         sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError);
  1037   1037         sqlite3MayAbort(pParse);
  1038   1038       }else
  1039   1039   #endif
  1040   1040       {
  1041   1041         int isReplace;    /* Set to true if constraints may cause a replace */
  1042         -      sqlite3GenerateConstraintChecks(pParse, pTab, iDataCur, iIdxCur,
  1043         -          regIns, aRegIdx, ipkColumn>=0, 0, onError, endOfLoop, &isReplace
         1042  +      sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
         1043  +          regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace
  1044   1044         );
  1045   1045         sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
  1046   1046         sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur,
  1047   1047                                  regIns, aRegIdx, 0, appendFlag, isReplace==0);
  1048   1048       }
  1049   1049     }
  1050   1050   
................................................................................
  1130   1130   ** the data to be inserted or the data after the update.  There will be
  1131   1131   ** pTab->nCol+1 registers in this range.  The first register (the one
  1132   1132   ** that regNewData points to) will contain the new rowid, or NULL in the
  1133   1133   ** case of a WITHOUT ROWID table.  The second register in the range will
  1134   1134   ** contain the content of the first table column.  The third register will
  1135   1135   ** contain the content of the second table column.  And so forth.
  1136   1136   **
  1137         -** For an UPDATE (isUpdate!=0), if pkChng is non-zero then it contains
  1138         -** the address of a range of registers containing the rowid and table
  1139         -** data from before the change.  In other words, pkChng is like 
  1140         -** regNewData except that it describes the row before the update rather
  1141         -** than afterwards.  If pkChng is zero, that means that the rowid does 
  1142         -** not change (for a normal rowid table) or the PRIMARY KEY does not
  1143         -** change (for a WITHOUT ROWID table) in which case the old data is
  1144         -** not needed.
         1137  +** The regOldData parameter is similar to regNewData except that it contains
         1138  +** the data prior to an UPDATE rather than afterwards.  regOldData is zero
         1139  +** for an INSERT.  This routine can distinguish between UPDATE and INSERT by
         1140  +** checking regOldData for zero.
  1145   1141   **
  1146         -** For an INSERT (isUpdate==0), pkChng is just a boolean that indicates
  1147         -** whether or not the rowid was explicitly specified as part of the
  1148         -** INSERT statement.  If pkChng is zero, it means that the either rowid
  1149         -** is computed automatically or that the table is a WITHOUT ROWID table
  1150         -** and has no rowid.  On an INSERT, pkChng will only be true if the
  1151         -** INSERT statement provides an integer value for either the rowid
  1152         -** column or its INTEGER PRIMARY KEY alias.
         1142  +** For an UPDATE, the pkChng boolean is true if the true primary key (the
         1143  +** rowid for a normal table or the PRIMARY KEY for a WITHOUT ROWID table)
         1144  +** might be modified by the UPDATE.  If pkChng is false, then the key of
         1145  +** the iDataCur content table is guaranteed to be unchanged by the UPDATE.
         1146  +**
         1147  +** For an INSERT, the pkChng boolean indicates whether or not the rowid
         1148  +** was explicitly specified as part of the INSERT statement.  If pkChng
         1149  +** is zero, it means that the either rowid is computed automatically or
         1150  +** that the table is a WITHOUT ROWID table and has no rowid.  On an INSERT,
         1151  +** pkChng will only be true if the INSERT statement provides an integer
         1152  +** value for either the rowid column or its INTEGER PRIMARY KEY alias.
  1153   1153   **
  1154   1154   ** The code generated by this routine will store new index entries into
  1155   1155   ** registers identified by aRegIdx[].  No index entry is created for
  1156   1156   ** indices where aRegIdx[i]==0.  The order of indices in aRegIdx[] is
  1157   1157   ** the same as the order of indices on the linked list of indices
  1158   1158   ** at pTab->pIndex.
  1159   1159   **
................................................................................
  1204   1204   ** Or if overrideError==OE_Default, then the pParse->onError parameter
  1205   1205   ** is used.  Or if pParse->onError==OE_Default then the onError value
  1206   1206   ** for the constraint is used.
  1207   1207   */
  1208   1208   void sqlite3GenerateConstraintChecks(
  1209   1209     Parse *pParse,       /* The parser context */
  1210   1210     Table *pTab,         /* The table being inserted or updated */
         1211  +  int *aRegIdx,        /* Use register aRegIdx[i] for index i.  0 for unused */
  1211   1212     int iDataCur,        /* Canonical data cursor (main table or PK index) */
  1212   1213     int iIdxCur,         /* First index cursor */
  1213   1214     int regNewData,      /* First register in a range holding values to insert */
  1214         -  int *aRegIdx,        /* Register used by each index.  0 for unused indices */
  1215         -  int pkChng,          /* Non-zero if the rowid or PRIMARY KEY changed */
  1216         -  int isUpdate,        /* True for UPDATE, False for INSERT */
  1217         -  int overrideError,   /* Override onError to this if not OE_Default */
         1215  +  int regOldData,      /* Previous content.  0 for INSERTs */
         1216  +  u8 pkChng,           /* Non-zero if the rowid or PRIMARY KEY changed */
         1217  +  u8 overrideError,    /* Override onError to this if not OE_Default */
  1218   1218     int ignoreDest,      /* Jump to this label on an OE_Ignore resolution */
  1219   1219     int *pbMayReplace    /* OUT: Set to true if constraint may cause a replace */
  1220   1220   ){
  1221         -  int i;               /* loop counter */
  1222   1221     Vdbe *v;             /* VDBE under constrution */
  1223         -  int nCol;            /* Number of columns */
  1224         -  int onError;         /* Conflict resolution strategy */
  1225         -  int j1;              /* Addresss of jump instruction */
  1226         -  int ix;              /* Index loop counter */
  1227   1222     Index *pIdx;         /* Pointer to one of the indices */
  1228   1223     Index *pPk = 0;      /* The PRIMARY KEY index */
  1229   1224     sqlite3 *db;         /* Database connection */
         1225  +  int i;               /* loop counter */
         1226  +  int ix;              /* Index loop counter */
         1227  +  int nCol;            /* Number of columns */
         1228  +  int onError;         /* Conflict resolution strategy */
         1229  +  int j1;              /* Addresss of jump instruction */
  1230   1230     int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
  1231         -  int regOldData;      /* Previous rowid and table data */
  1232   1231     int nPkField;        /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
         1232  +  u8 isUpdate;
  1233   1233   
  1234         -  regOldData = (pkChng && isUpdate) ? pkChng : regNewData;
         1234  +  isUpdate = regOldData!=0;
  1235   1235     db = pParse->db;
  1236   1236     v = sqlite3GetVdbe(pParse);
  1237   1237     assert( v!=0 );
  1238   1238     assert( pTab->pSelect==0 );  /* This table is not a VIEW */
  1239   1239     nCol = pTab->nCol;
  1240   1240     
  1241   1241     /* pPk is the PRIMARY KEY index for WITHOUT ROWID tables and NULL for
................................................................................
  1324   1324                                 onError, zConsName, P4_DYNAMIC);
  1325   1325         }
  1326   1326         sqlite3VdbeResolveLabel(v, allOk);
  1327   1327       }
  1328   1328     }
  1329   1329   #endif /* !defined(SQLITE_OMIT_CHECK) */
  1330   1330   
  1331         -  /* If there is an INTEGER PRIMARY KEY, make sure the primary key
  1332         -  ** of the new record does not previously exist.  Except, if this
  1333         -  ** is an UPDATE and the primary key is not changing, then obviously
  1334         -  ** it is OK for the previous rowid to exist in that case.
  1335         -  **
  1336         -  ** This block only runs for tables that have a rowid.
         1331  +  /* If rowid is changing, make sure the new rowid does not previously
         1332  +  ** exist in the table.
  1337   1333     */
  1338   1334     if( pkChng && pPk==0 ){
  1339   1335       int addrRowidOk = sqlite3VdbeMakeLabel(v);
  1340   1336   
         1337  +    /* Figure out what action to take in case of a rowid collision */
  1341   1338       onError = pTab->keyConf;
  1342   1339       if( overrideError!=OE_Default ){
  1343   1340         onError = overrideError;
  1344   1341       }else if( onError==OE_Default ){
  1345   1342         onError = OE_Abort;
  1346   1343       }
  1347   1344   
  1348   1345       if( isUpdate ){
         1346  +      /* pkChng!=0 does not mean that the rowid has change, only that
         1347  +      ** it might have changed.  Skip the conflict logic below if the rowid
         1348  +      ** is unchanged. */
  1349   1349         sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRowidOk, regOldData);
  1350   1350       }
         1351  +
         1352  +    /* Check to see if the new rowid already exists in the table.  Skip
         1353  +    ** the following conflict logic if it does not. */
  1351   1354       sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData);
         1355  +
         1356  +    /* Generate code that deals with a rowid collision */
  1352   1357       switch( onError ){
  1353   1358         default: {
  1354   1359           onError = OE_Abort;
  1355   1360           /* Fall thru into the next case */
  1356   1361         }
  1357   1362         case OE_Rollback:
  1358   1363         case OE_Abort:
................................................................................
  1407   1412       }
  1408   1413       sqlite3VdbeResolveLabel(v, addrRowidOk);
  1409   1414     }
  1410   1415   
  1411   1416     /* Test all UNIQUE constraints by creating entries for each UNIQUE
  1412   1417     ** index and making sure that duplicate entries do not already exist.
  1413   1418     ** Compute the revised record entries for indices as we go.
         1419  +  **
         1420  +  ** This loop also handles the case of the PRIMARY KEY index for a
         1421  +  ** WITHOUT ROWID table.
  1414   1422     */
  1415   1423     for(ix=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, ix++){
  1416   1424       int regIdx;          /* Range of registers hold conent for pIdx */
  1417   1425       int regR;            /* Range of registers holding conflicting PK */
  1418   1426       int iThisCur;        /* Cursor for this UNIQUE index */
  1419   1427       int addrUniqueOk;    /* Jump here if the UNIQUE constraint is satisfied */
  1420   1428   
  1421   1429       if( aRegIdx[ix]==0 ) continue;  /* Skip indices that do not change */
  1422   1430       iThisCur = iIdxCur+ix;
  1423   1431       addrUniqueOk = sqlite3VdbeMakeLabel(v);
  1424   1432   
         1433  +    /* Skip partial indices for which the WHERE clause is not true */
  1425   1434       if( pIdx->pPartIdxWhere ){
  1426   1435         sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]);
  1427   1436         pParse->ckBase = regNewData+1;
  1428   1437         sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrUniqueOk,
  1429   1438                            SQLITE_JUMPIFNULL);
  1430   1439         pParse->ckBase = 0;
  1431   1440       }
  1432   1441   
  1433   1442       /* Create a record for this index entry as it should appear after
  1434         -    ** the insert or update. */
         1443  +    ** the insert or update.  Store that record in the aRegIdx[ix] register
         1444  +    */
  1435   1445       regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn);
  1436   1446       for(i=0; i<pIdx->nColumn; i++){
  1437   1447         int iField = pIdx->aiColumn[i];
  1438   1448         int x;
  1439   1449         if( iField<0 || iField==pTab->iPKey ){
  1440   1450           x = regNewData;
  1441   1451         }else{
................................................................................
  1444   1454         sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i);
  1445   1455         VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName));
  1446   1456       }
  1447   1457       sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
  1448   1458       sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), P4_TRANSIENT);
  1449   1459       VdbeComment((v, "for %s", pIdx->zName));
  1450   1460       sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn);
         1461  +
         1462  +    /* In an UPDATE operation, if this index is the PRIMARY KEY index 
         1463  +    ** of a WITHOUT ROWID table and there has been no change the
         1464  +    ** primary key, then no collision is possible.  The collision detection
         1465  +    ** logic below can all be skipped. */
         1466  +    if( isUpdate && pPk && pkChng==0 ) continue;
  1451   1467   
  1452   1468       /* Find out what action to take in case there is a uniqueness conflict */
  1453   1469       onError = pIdx->onError;
  1454   1470       if( onError==OE_None ){ 
  1455   1471         sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
  1456   1472         sqlite3VdbeResolveLabel(v, addrUniqueOk);
  1457   1473         continue;  /* pIdx is not a UNIQUE index */
................................................................................
  1466   1482         else if( onError==OE_Fail ) onError = OE_Abort;
  1467   1483       }
  1468   1484       
  1469   1485       /* Check to see if the new index entry will be unique */
  1470   1486       regR = sqlite3GetTempRange(pParse, nPkField);
  1471   1487       sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
  1472   1488                            regIdx, pIdx->nKeyCol);
         1489  +
         1490  +    /* Generate code to handle collisions */
  1473   1491       if( HasRowid(pTab) ){
  1474   1492         sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
  1475   1493         /* Conflict only if the rowid of the existing index entry
  1476   1494         ** is different from old-rowid */
  1477         -      sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData);
         1495  +      if( isUpdate ){
         1496  +        sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData);
         1497  +      }
  1478   1498       }else{
  1479   1499         int x;
  1480   1500         /* Extract the PRIMARY KEY from the end of the index entry and
  1481   1501         ** store it in register regR..regR+nPk-1 */
  1482   1502         for(i=0; i<pPk->nKeyCol; i++){
  1483   1503           x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
  1484   1504           sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);

Changes to src/sqliteInt.h.

  2918   2918   int sqlite3ExprCanBeNull(const Expr*);
  2919   2919   void sqlite3ExprCodeIsNullJump(Vdbe*, const Expr*, int, int);
  2920   2920   int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
  2921   2921   int sqlite3IsRowid(const char*);
  2922   2922   void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8);
  2923   2923   void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*);
  2924   2924   int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*);
  2925         -void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int,int,
  2926         -                                     int*,int,int,int,int,int*);
         2925  +void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int,
         2926  +                                     u8,u8,int,int*);
  2927   2927   void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int);
  2928   2928   int sqlite3OpenTableAndIndices(Parse*, Table*, int, int, int*, int*);
  2929   2929   void sqlite3BeginWriteOperation(Parse*, int, int);
  2930   2930   void sqlite3MultiWrite(Parse*);
  2931   2931   void sqlite3MayAbort(Parse*);
  2932   2932   void sqlite3HaltConstraint(Parse*, int, int, char*, int);
  2933   2933   Expr *sqlite3ExprDup(sqlite3*,Expr*,int);

Changes to src/update.c.

   104    104     int iDataCur;          /* Cursor for the canonical data btree */
   105    105     int iIdxCur;           /* Cursor for the first index */
   106    106     sqlite3 *db;           /* The database structure */
   107    107     int *aRegIdx = 0;      /* One register assigned to each index to be updated */
   108    108     int *aXRef = 0;        /* aXRef[i] is the index in pChanges->a[] of the
   109    109                            ** an expression for the i-th column of the table.
   110    110                            ** aXRef[i]==-1 if the i-th column is not changed. */
   111         -  int chngPk;            /* True if the rowid or PRIMARY KEY is changed */
          111  +  u8 chngPk;             /* PRIMARY KEY changed in a WITHOUT ROWID table */
          112  +  u8 chngRowid;          /* Rowid changed in a normal table */
          113  +  u8 chngKey;            /* Either chngPk or chngRowid */
   112    114     Expr *pRowidExpr = 0;  /* Expression defining the new record number */
   113    115     int openAll = 0;       /* True if all indices need to be opened */
   114    116     AuthContext sContext;  /* The authorization context */
   115    117     NameContext sNC;       /* The name-context to resolve expressions in */
   116    118     int iDb;               /* Database containing the table being updated */
   117    119     int okOnePass;         /* True for one-pass algorithm without the FIFO */
   118    120     int hasFK;             /* True if foreign key processing is required */
................................................................................
   197    199     sNC.pParse = pParse;
   198    200     sNC.pSrcList = pTabList;
   199    201   
   200    202     /* Resolve the column names in all the expressions of the
   201    203     ** of the UPDATE statement.  Also find the column index
   202    204     ** for each column to be updated in the pChanges array.  For each
   203    205     ** column to be updated, make sure we have authorization to change
   204         -  ** that column.  Set chngPk if the iDataCur key changes.  Note that
   205         -  ** for WITHOUT ROWID columns, the iDataCur key contains all columns of
   206         -  ** the table and so it will always change.
          206  +  ** that column.
   207    207     */
   208         -  chngPk = (pPk!=0);
          208  +  chngRowid = chngPk = 0;
   209    209     for(i=0; i<pChanges->nExpr; i++){
   210    210       if( sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){
   211    211         goto update_cleanup;
   212    212       }
   213    213       for(j=0; j<pTab->nCol; j++){
   214    214         if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){
   215    215           if( j==pTab->iPKey ){
   216         -          chngPk = 1;
          216  +          chngRowid = 1;
   217    217             pRowidExpr = pChanges->a[i].pExpr;
          218  +        }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){
          219  +          chngPk = 1;
   218    220           }
   219    221           aXRef[j] = i;
   220    222           break;
   221    223         }
   222    224       }
   223    225       if( j>=pTab->nCol ){
   224    226         if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zName) ){
   225    227           j = -1;
   226         -        chngPk = 1;
          228  +        chngRowid = 1;
   227    229           pRowidExpr = pChanges->a[i].pExpr;
   228    230         }else{
   229    231           sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName);
   230    232           pParse->checkSchema = 1;
   231    233           goto update_cleanup;
   232    234         }
   233    235       }
................................................................................
   241    243           goto update_cleanup;
   242    244         }else if( rc==SQLITE_IGNORE ){
   243    245           aXRef[j] = -1;
   244    246         }
   245    247       }
   246    248   #endif
   247    249     }
          250  +  assert( (chngRowid & chngPk)==0 );
          251  +  assert( chngRowid==0 || chngRowid==1 );
          252  +  assert( chngPk==0 || chngPk==1 );
          253  +  chngKey = chngRowid + chngPk;
   248    254   
   249         -  hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngPk);
          255  +  hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngKey);
   250    256   
   251    257     /* Allocate memory for the array aRegIdx[].  There is one entry in the
   252    258     ** array for each index associated with table being updated.  Fill in
   253    259     ** the value with a register number for indices that are to be used
   254    260     ** and with zero for unused indices.
   255    261     */
   256    262     if( nIdx>0 ){
   257    263       aRegIdx = sqlite3DbMallocRaw(db, sizeof(Index*) * nIdx );
   258    264       if( aRegIdx==0 ) goto update_cleanup;
   259    265     }
   260    266     for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
   261    267       int reg;
   262         -    if( hasFK || chngPk || pIdx->pPartIdxWhere ){
          268  +    if( chngKey || hasFK || pIdx->pPartIdxWhere || pIdx==pPk ){
   263    269         reg = ++pParse->nMem;
   264    270       }else{
   265    271         reg = 0;
   266         -      for(i=0; i<pIdx->nColumn; i++){
          272  +      for(i=0; i<pIdx->nKeyCol; i++){
   267    273           if( aXRef[pIdx->aiColumn[i]]>=0 ){
   268    274             reg = ++pParse->nMem;
   269    275             break;
   270    276           }
   271    277         }
   272    278       }
   273    279       aRegIdx[j] = reg;
................................................................................
   289    295       goto update_cleanup;
   290    296     }
   291    297   #endif
   292    298   
   293    299     /* Allocate required registers. */
   294    300     regRowSet = ++pParse->nMem;
   295    301     regOldRowid = regNewRowid = ++pParse->nMem;
   296         -  if( pTrigger || hasFK ){
          302  +  if( chngPk || pTrigger || hasFK ){
   297    303       regOld = pParse->nMem + 1;
   298    304       pParse->nMem += pTab->nCol;
   299    305     }
   300         -  if( chngPk || pTrigger || hasFK ){
          306  +  if( chngKey || pTrigger || hasFK ){
   301    307       regNewRowid = ++pParse->nMem;
   302    308     }
   303    309     regNew = pParse->nMem + 1;
   304    310     pParse->nMem += pTab->nCol;
   305    311   
   306    312     /* Start the view context. */
   307    313     if( isView ){
................................................................................
   428    434       sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addr, regOldRowid);
   429    435     }
   430    436   
   431    437     /* If the record number will change, set register regNewRowid to
   432    438     ** contain the new value. If the record number is not being modified,
   433    439     ** then regNewRowid is the same register as regOldRowid, which is
   434    440     ** already populated.  */
   435         -  assert( chngPk || pTrigger || hasFK || regOldRowid==regNewRowid );
   436         -  if( chngPk && pPk==0 ){
          441  +  assert( chngKey || pTrigger || hasFK || regOldRowid==regNewRowid );
          442  +  if( chngRowid ){
   437    443       sqlite3ExprCode(pParse, pRowidExpr, regNewRowid);
   438    444       sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid);
   439    445     }
   440    446   
   441         -  /* If there are triggers on this table, populate an array of registers 
   442         -  ** with the required old.* column data.  */
   443         -  if( hasFK || pTrigger ){
          447  +  /* Compute the old pre-UPDATE content of the row being changed, if that
          448  +  ** information is needed */
          449  +  if( chngPk || hasFK || pTrigger ){
   444    450       u32 oldmask = (hasFK ? sqlite3FkOldmask(pParse, pTab) : 0);
   445    451       oldmask |= sqlite3TriggerColmask(pParse, 
   446    452           pTrigger, pChanges, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onError
   447    453       );
   448    454       for(i=0; i<pTab->nCol; i++){
   449         -      if( aXRef[i]<0 || oldmask==0xffffffff || (i<32 && (oldmask & (1<<i))) ){
          455  +      if( oldmask==0xffffffff
          456  +       || (i<32 && (oldmask & (1<<i)))
          457  +       || (chngPk && (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0)
          458  +      ){
   450    459           sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regOld+i);
   451    460         }else{
   452    461           sqlite3VdbeAddOp2(v, OP_Null, 0, regOld+i);
   453    462         }
   454    463       }
   455         -    if( chngPk==0 ){
          464  +    if( chngRowid==0 && pPk==0 ){
   456    465         sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid);
   457    466       }
   458    467     }
   459    468   
   460    469     /* Populate the array of registers beginning at regNew with the new
   461    470     ** row data. This array is used to check constaints, create the new
   462    471     ** table and index records, and as the values for any new.* references
................................................................................
   505    514   
   506    515       /* The row-trigger may have deleted the row being updated. In this
   507    516       ** case, jump to the next row. No updates or AFTER triggers are 
   508    517       ** required. This behavior - what happens when the row being updated
   509    518       ** is deleted or renamed by a BEFORE trigger - is left undefined in the
   510    519       ** documentation.
   511    520       */
   512         -    sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addr, regOldRowid);
          521  +    if( pPk ){
          522  +      sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey, 0);
          523  +    }else{
          524  +      sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addr, regOldRowid);
          525  +    }
   513    526   
   514    527       /* If it did not delete it, the row-trigger may still have modified 
   515    528       ** some of the columns of the row being updated. Load the values for 
   516    529       ** all columns not modified by the update statement into their 
   517    530       ** registers in case this has happened.
   518    531       */
   519    532       for(i=0; i<pTab->nCol; i++){
................................................................................
   523    536       }
   524    537     }
   525    538   
   526    539     if( !isView ){
   527    540       int j1;                       /* Address of jump instruction */
   528    541   
   529    542       /* Do constraint checks. */
   530         -    sqlite3GenerateConstraintChecks(pParse, pTab, iDataCur, iIdxCur,
   531         -        regNewRowid, aRegIdx, (chngPk?regOldRowid:0), 1, onError, addr, 0);
          543  +    assert( regOldRowid>0 );
          544  +    sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
          545  +        regNewRowid, regOldRowid, chngKey, onError, addr, 0);
   532    546   
   533    547       /* Do FK constraint checks. */
   534    548       if( hasFK ){
   535         -      sqlite3FkCheck(pParse, pTab, regOldRowid, 0, aXRef, chngPk);
          549  +      sqlite3FkCheck(pParse, pTab, regOldRowid, 0, aXRef, chngKey);
   536    550       }
   537    551   
   538    552       /* Delete the index entries associated with the current record.  */
   539    553       if( pPk ){
   540    554         j1 = sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, 0, regKey, 0);
   541    555       }else{
   542    556         j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, 0, regOldRowid);
   543    557       }
   544    558       sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx);
   545    559     
   546    560       /* If changing the record number, delete the old record.  */
   547         -    if( hasFK || chngPk ){
          561  +    if( hasFK || chngKey || pPk!=0 ){
   548    562         sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, 0);
   549    563       }
   550    564       if( sqlite3VdbeCurrentAddr(v)==j1+1 ){
   551    565         sqlite3VdbeChangeToNoop(v, j1);
   552    566       }else{
   553    567         sqlite3VdbeJumpHere(v, j1);
   554    568       }
   555    569   
   556    570       if( hasFK ){
   557         -      sqlite3FkCheck(pParse, pTab, 0, regNewRowid, aXRef, chngPk);
          571  +      sqlite3FkCheck(pParse, pTab, 0, regNewRowid, aXRef, chngKey);
   558    572       }
   559    573     
   560    574       /* Insert the new index entries and the new record. */
   561    575       sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur,
   562    576                                regNewRowid, aRegIdx, 1, 0, 0);
   563    577   
   564    578       /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
   565    579       ** handle rows (possibly in other tables) that refer via a foreign key
   566    580       ** to the row just updated. */ 
   567    581       if( hasFK ){
   568         -      sqlite3FkActions(pParse, pTab, pChanges, regOldRowid, aXRef, chngPk);
          582  +      sqlite3FkActions(pParse, pTab, pChanges, regOldRowid, aXRef, chngKey);
   569    583       }
   570    584     }
   571    585   
   572    586     /* Increment the row counter 
   573    587     */
   574    588     if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab){
   575    589       sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);

Changes to test/without_rowid1.test.

    57     57   # REPLACE INTO works, however.
    58     58   #
    59     59   do_execsql_test without_rowid1-1.22 {
    60     60     REPLACE INTO t1 VALUES('dynamic','phone','flipper','harvard');
    61     61     SELECT *, '|' FROM t1 ORDER BY c, a;
    62     62   } {arctic sleep ammonia helena | journal sherman ammonia helena | dynamic phone flipper harvard | journal sherman gamma patriot |}
    63     63   
           64  +do_execsql_test without_rowid1-1.23 {
           65  +  SELECT *, '|' FROM t1 ORDER BY b, d;
           66  +} {dynamic phone flipper harvard | journal sherman ammonia helena | journal sherman gamma patriot | arctic sleep ammonia helena |}
           67  +
           68  +# UPDATE statements.
           69  +#
           70  +do_execsql_test without_rowid1-1.31 {
           71  +  UPDATE t1 SET d=3.1415926 WHERE a='journal';
           72  +  SELECT *, '|' FROM t1 ORDER BY c, a;
           73  +} {arctic sleep ammonia helena | journal sherman ammonia 3.1415926 | dynamic phone flipper harvard | journal sherman gamma 3.1415926 |}
           74  +
    64     75   finish_test