diff --git a/manifest b/manifest index 9d280e1849..6a9c5d36ba 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\sVDBE\scomments\son\sthe\sconstraint\schecker.\s\sFix\sa\smissing\swrite\nlock\sin\sthe\sUPDATE\slogic. -D 2013-11-01T14:03:20.023 +C Change\sthe\sinterface\sto\ssqlite3GenerateConstraintChecks()\sfor\simproved\slucidity\nand\sto\sfix\sissues\sin\sdealing\swith\sUPDATEs\sfor\sWITHOUT\sROWID\stables.\s\sMake\ssure\niDataCur\sand\siIdxCur\sare\sinitialized\swhen\sprocessing\sDELETEs\sof\sa\sVIEW.\nUPDATE\sprocessing\sdistinguishes\sbetween\schanges\sto\sROWID\sand\sPRIMARY\sKEY. +D 2013-11-01T17:08:56.112 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 0522b53cdc1fcfc18f3a98e0246add129136c654 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -173,7 +173,7 @@ F src/callback.c f99a8957ba2adf369645fac0db09ad8adcf1caa2 F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c ea4b7f3623a0fcb1146e7f245d7410033e86859c F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 -F src/delete.c df1775ee33f40bc8feb37b2bfb59d792ff496359 +F src/delete.c c58e07fb07878c4b4c4b106cee7f2799a48351f8 F src/expr.c ecc2b98eb75fe5533cfdfcca6b04cfe5f0c6001f F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 628f81177299660a86e40359b3689b81f517e125 @@ -182,7 +182,7 @@ F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759 F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4 F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c da74aded06680ff30a87065df70fda16af3ecda3 +F src/insert.c 4694b23067650659f822d989426116808c0c8e05 F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12 F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b @@ -223,7 +223,7 @@ F src/shell.c d5eebdc6034014103de2b9d58e1d3f6f7de0fb50 F src/sqlite.h.in 547a44dd4ff4d975e92a645ea2d609e543a83d0f F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc -F src/sqliteInt.h 69c16a6a7f45fbe5d0293b753fe8022bef6b1f09 +F src/sqliteInt.h bc4588b0d2eac8429d102609af6cfad583bfb41f F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -275,7 +275,7 @@ F src/test_vfstrace.c 34b544e80ba7fb77be15395a609c669df2e660a2 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/tokenize.c 70061085a51f2f4fc15ece94f32c03bcb78e63b2 F src/trigger.c 53d6b5d50b3b23d4fcd0a36504feb5cff9aed716 -F src/update.c fff9ac57e36e54ac939e22aac077326224759372 +F src/update.c 94d63d3e06b09df3618655a841dc95d5b9466dc6 F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269 F src/util.c 2fa6c821d28bbdbeec1b2a7b091a281c9ef8f918 F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 @@ -1076,7 +1076,7 @@ F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31 F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361 F test/win32longpath.test e2aafc07e6990fe86c69be22a3d1a0e210cd329b -F test/without_rowid1.test e4f023e49a57c90f6d25afd4b3e8b0305ad06e44 +F test/without_rowid1.test ad5764bbe2784a91f7106143e7d1bd8ccfb61ffd F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688 F test/zerodamage.test 209d7ed441f44cc5299e4ebffbef06fd5aabfefd F tool/build-all-msvc.bat 38623a30fd58288fda5cc7f7df2682aaab75c9d5 x @@ -1128,7 +1128,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff -P 5c0eaea6a26b5c3310d96b3c896ac3068a3ebad1 -R 91e4e19c708f99c7ec09052b49466395 +P 3bed599e74d354bf1513e4fb0e8665376ba44d0b +R 67b4771869ffd7159304bf29f7d68635 U drh -Z 7a82973f52b628c87c749d18c8301e86 +Z f06e68ba1ad92e0ce7abe5fdcd557daa diff --git a/manifest.uuid b/manifest.uuid index cbe70d3dff..765f0dea3a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3bed599e74d354bf1513e4fb0e8665376ba44d0b \ No newline at end of file +c525ac5630d6bcd51842cfc84f2c2c50be9cec1c \ No newline at end of file diff --git a/src/delete.c b/src/delete.c index 55688409b8..5d7078a4bb 100644 --- a/src/delete.c +++ b/src/delete.c @@ -324,6 +324,7 @@ void sqlite3DeleteFrom( #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) if( isView ){ sqlite3MaterializeView(pParse, pTab, pWhere, iTabCur); + iDataCur = iIdxCur = iTabCur; } #endif diff --git a/src/insert.c b/src/insert.c index 3c9402ddd3..e4f8ead585 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1039,8 +1039,8 @@ void sqlite3Insert( #endif { int isReplace; /* Set to true if constraints may cause a replace */ - sqlite3GenerateConstraintChecks(pParse, pTab, iDataCur, iIdxCur, - regIns, aRegIdx, ipkColumn>=0, 0, onError, endOfLoop, &isReplace + sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur, + regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace ); sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0); sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur, @@ -1134,22 +1134,22 @@ insert_cleanup: ** contain the content of the first table column. The third register will ** contain the content of the second table column. And so forth. ** -** 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. +** The regOldData parameter is similar to regNewData except that it contains +** the data prior to an UPDATE rather than afterwards. regOldData is zero +** for an INSERT. This routine can distinguish between UPDATE and INSERT by +** checking regOldData for zero. ** -** 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. +** For an UPDATE, the pkChng boolean is true if the true primary key (the +** rowid for a normal table or the PRIMARY KEY for a WITHOUT ROWID table) +** might be modified by the UPDATE. If pkChng is false, then the key of +** the iDataCur content table is guaranteed to be unchanged by the UPDATE. +** +** For an INSERT, the pkChng boolean 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. ** ** The code generated by this routine will store new index entries into ** registers identified by aRegIdx[]. No index entry is created for @@ -1208,30 +1208,30 @@ insert_cleanup: void sqlite3GenerateConstraintChecks( Parse *pParse, /* The parser context */ Table *pTab, /* The table being inserted or updated */ + int *aRegIdx, /* Use register aRegIdx[i] for index i. 0 for unused */ 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 regOldData, /* Previous content. 0 for INSERTs */ + u8 pkChng, /* Non-zero if the rowid or PRIMARY KEY changed */ + u8 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 */ Index *pIdx; /* Pointer to one of the indices */ Index *pPk = 0; /* The PRIMARY KEY index */ sqlite3 *db; /* Database connection */ + int i; /* loop counter */ + int ix; /* Index loop counter */ + int nCol; /* Number of columns */ + int onError; /* Conflict resolution strategy */ + int j1; /* Addresss of jump instruction */ int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */ - int regOldData; /* Previous rowid and table data */ int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */ + u8 isUpdate; - regOldData = (pkChng && isUpdate) ? pkChng : regNewData; + isUpdate = regOldData!=0; db = pParse->db; v = sqlite3GetVdbe(pParse); assert( v!=0 ); @@ -1328,16 +1328,13 @@ void sqlite3GenerateConstraintChecks( } #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, then obviously - ** it is OK for the previous rowid to exist in that case. - ** - ** This block only runs for tables that have a rowid. + /* If rowid is changing, make sure the new rowid does not previously + ** exist in the table. */ if( pkChng && pPk==0 ){ int addrRowidOk = sqlite3VdbeMakeLabel(v); + /* Figure out what action to take in case of a rowid collision */ onError = pTab->keyConf; if( overrideError!=OE_Default ){ onError = overrideError; @@ -1346,9 +1343,17 @@ void sqlite3GenerateConstraintChecks( } if( isUpdate ){ + /* pkChng!=0 does not mean that the rowid has change, only that + ** it might have changed. Skip the conflict logic below if the rowid + ** is unchanged. */ sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRowidOk, regOldData); } + + /* Check to see if the new rowid already exists in the table. Skip + ** the following conflict logic if it does not. */ sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData); + + /* Generate code that deals with a rowid collision */ switch( onError ){ default: { onError = OE_Abort; @@ -1411,6 +1416,9 @@ void sqlite3GenerateConstraintChecks( /* 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. + ** + ** This loop also handles the case of the PRIMARY KEY index for a + ** WITHOUT ROWID table. */ for(ix=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, ix++){ int regIdx; /* Range of registers hold conent for pIdx */ @@ -1422,6 +1430,7 @@ void sqlite3GenerateConstraintChecks( iThisCur = iIdxCur+ix; addrUniqueOk = sqlite3VdbeMakeLabel(v); + /* Skip partial indices for which the WHERE clause is not true */ if( pIdx->pPartIdxWhere ){ sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]); pParse->ckBase = regNewData+1; @@ -1431,7 +1440,8 @@ void sqlite3GenerateConstraintChecks( } /* Create a record for this index entry as it should appear after - ** the insert or update. */ + ** the insert or update. Store that record in the aRegIdx[ix] register + */ regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn); for(i=0; inColumn; i++){ int iField = pIdx->aiColumn[i]; @@ -1449,6 +1459,12 @@ void sqlite3GenerateConstraintChecks( VdbeComment((v, "for %s", pIdx->zName)); sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn); + /* In an UPDATE operation, if this index is the PRIMARY KEY index + ** of a WITHOUT ROWID table and there has been no change the + ** primary key, then no collision is possible. The collision detection + ** logic below can all be skipped. */ + if( isUpdate && pPk && pkChng==0 ) continue; + /* Find out what action to take in case there is a uniqueness conflict */ onError = pIdx->onError; if( onError==OE_None ){ @@ -1470,11 +1486,15 @@ void sqlite3GenerateConstraintChecks( regR = sqlite3GetTempRange(pParse, nPkField); sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk, regIdx, pIdx->nKeyCol); + + /* Generate code to handle collisions */ if( HasRowid(pTab) ){ sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR); /* Conflict only if the rowid of the existing index entry ** is different from old-rowid */ - sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData); + if( isUpdate ){ + sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData); + } }else{ int x; /* Extract the PRIMARY KEY from the end of the index entry and diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 07d0f3bdf7..97b75f16b2 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2922,8 +2922,8 @@ int sqlite3IsRowid(const char*); void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8); void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*); int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*); -void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int,int, - int*,int,int,int,int,int*); +void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int, + u8,u8,int,int*); void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int); int sqlite3OpenTableAndIndices(Parse*, Table*, int, int, int*, int*); void sqlite3BeginWriteOperation(Parse*, int, int); diff --git a/src/update.c b/src/update.c index 9efb7349d7..a631101698 100644 --- a/src/update.c +++ b/src/update.c @@ -108,7 +108,9 @@ void sqlite3Update( int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the ** an expression for the i-th column of the table. ** aXRef[i]==-1 if the i-th column is not changed. */ - int chngPk; /* True if the rowid or PRIMARY KEY is changed */ + u8 chngPk; /* PRIMARY KEY changed in a WITHOUT ROWID table */ + u8 chngRowid; /* Rowid changed in a normal table */ + u8 chngKey; /* Either chngPk or chngRowid */ Expr *pRowidExpr = 0; /* Expression defining the new record number */ int openAll = 0; /* True if all indices need to be opened */ AuthContext sContext; /* The authorization context */ @@ -201,11 +203,9 @@ void sqlite3Update( ** of the UPDATE statement. Also find the column index ** for each column to be updated in the pChanges array. For each ** column to be updated, make sure we have authorization to change - ** that column. Set chngPk if the iDataCur key changes. Note that - ** for WITHOUT ROWID columns, the iDataCur key contains all columns of - ** the table and so it will always change. + ** that column. */ - chngPk = (pPk!=0); + chngRowid = chngPk = 0; for(i=0; inExpr; i++){ if( sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){ goto update_cleanup; @@ -213,8 +213,10 @@ void sqlite3Update( for(j=0; jnCol; j++){ if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){ if( j==pTab->iPKey ){ - chngPk = 1; + chngRowid = 1; pRowidExpr = pChanges->a[i].pExpr; + }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){ + chngPk = 1; } aXRef[j] = i; break; @@ -223,7 +225,7 @@ void sqlite3Update( if( j>=pTab->nCol ){ if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zName) ){ j = -1; - chngPk = 1; + chngRowid = 1; pRowidExpr = pChanges->a[i].pExpr; }else{ sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName); @@ -245,8 +247,12 @@ void sqlite3Update( } #endif } + assert( (chngRowid & chngPk)==0 ); + assert( chngRowid==0 || chngRowid==1 ); + assert( chngPk==0 || chngPk==1 ); + chngKey = chngRowid + chngPk; - hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngPk); + hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngKey); /* Allocate memory for the array aRegIdx[]. There is one entry in the ** array for each index associated with table being updated. Fill in @@ -259,11 +265,11 @@ void sqlite3Update( } for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int reg; - if( hasFK || chngPk || pIdx->pPartIdxWhere ){ + if( chngKey || hasFK || pIdx->pPartIdxWhere || pIdx==pPk ){ reg = ++pParse->nMem; }else{ reg = 0; - for(i=0; inColumn; i++){ + for(i=0; inKeyCol; i++){ if( aXRef[pIdx->aiColumn[i]]>=0 ){ reg = ++pParse->nMem; break; @@ -293,11 +299,11 @@ void sqlite3Update( /* Allocate required registers. */ regRowSet = ++pParse->nMem; regOldRowid = regNewRowid = ++pParse->nMem; - if( pTrigger || hasFK ){ + if( chngPk || pTrigger || hasFK ){ regOld = pParse->nMem + 1; pParse->nMem += pTab->nCol; } - if( chngPk || pTrigger || hasFK ){ + if( chngKey || pTrigger || hasFK ){ regNewRowid = ++pParse->nMem; } regNew = pParse->nMem + 1; @@ -432,27 +438,30 @@ void sqlite3Update( ** contain the new value. If the record number is not being modified, ** then regNewRowid is the same register as regOldRowid, which is ** already populated. */ - assert( chngPk || pTrigger || hasFK || regOldRowid==regNewRowid ); - if( chngPk && pPk==0 ){ + assert( chngKey || pTrigger || hasFK || regOldRowid==regNewRowid ); + if( chngRowid ){ sqlite3ExprCode(pParse, pRowidExpr, regNewRowid); sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid); } - /* If there are triggers on this table, populate an array of registers - ** with the required old.* column data. */ - if( hasFK || pTrigger ){ + /* Compute the old pre-UPDATE content of the row being changed, if that + ** information is needed */ + if( chngPk || hasFK || pTrigger ){ u32 oldmask = (hasFK ? sqlite3FkOldmask(pParse, pTab) : 0); oldmask |= sqlite3TriggerColmask(pParse, pTrigger, pChanges, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onError ); for(i=0; inCol; i++){ - if( aXRef[i]<0 || oldmask==0xffffffff || (i<32 && (oldmask & (1<aCol[i].colFlags & COLFLAG_PRIMKEY)!=0) + ){ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regOld+i); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, regOld+i); } } - if( chngPk==0 ){ + if( chngRowid==0 && pPk==0 ){ sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid); } } @@ -509,7 +518,11 @@ void sqlite3Update( ** is deleted or renamed by a BEFORE trigger - is left undefined in the ** documentation. */ - sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addr, regOldRowid); + if( pPk ){ + sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey, 0); + }else{ + sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addr, regOldRowid); + } /* If it did not delete it, the row-trigger may still have modified ** some of the columns of the row being updated. Load the values for @@ -527,12 +540,13 @@ void sqlite3Update( int j1; /* Address of jump instruction */ /* Do constraint checks. */ - sqlite3GenerateConstraintChecks(pParse, pTab, iDataCur, iIdxCur, - regNewRowid, aRegIdx, (chngPk?regOldRowid:0), 1, onError, addr, 0); + assert( regOldRowid>0 ); + sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur, + regNewRowid, regOldRowid, chngKey, onError, addr, 0); /* Do FK constraint checks. */ if( hasFK ){ - sqlite3FkCheck(pParse, pTab, regOldRowid, 0, aXRef, chngPk); + sqlite3FkCheck(pParse, pTab, regOldRowid, 0, aXRef, chngKey); } /* Delete the index entries associated with the current record. */ @@ -544,7 +558,7 @@ void sqlite3Update( sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx); /* If changing the record number, delete the old record. */ - if( hasFK || chngPk ){ + if( hasFK || chngKey || pPk!=0 ){ sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, 0); } if( sqlite3VdbeCurrentAddr(v)==j1+1 ){ @@ -554,7 +568,7 @@ void sqlite3Update( } if( hasFK ){ - sqlite3FkCheck(pParse, pTab, 0, regNewRowid, aXRef, chngPk); + sqlite3FkCheck(pParse, pTab, 0, regNewRowid, aXRef, chngKey); } /* Insert the new index entries and the new record. */ @@ -565,7 +579,7 @@ void sqlite3Update( ** handle rows (possibly in other tables) that refer via a foreign key ** to the row just updated. */ if( hasFK ){ - sqlite3FkActions(pParse, pTab, pChanges, regOldRowid, aXRef, chngPk); + sqlite3FkActions(pParse, pTab, pChanges, regOldRowid, aXRef, chngKey); } } diff --git a/test/without_rowid1.test b/test/without_rowid1.test index 2dc20ca94a..86117e7683 100644 --- a/test/without_rowid1.test +++ b/test/without_rowid1.test @@ -61,4 +61,15 @@ do_execsql_test without_rowid1-1.22 { SELECT *, '|' FROM t1 ORDER BY c, a; } {arctic sleep ammonia helena | journal sherman ammonia helena | dynamic phone flipper harvard | journal sherman gamma patriot |} +do_execsql_test without_rowid1-1.23 { + SELECT *, '|' FROM t1 ORDER BY b, d; +} {dynamic phone flipper harvard | journal sherman ammonia helena | journal sherman gamma patriot | arctic sleep ammonia helena |} + +# UPDATE statements. +# +do_execsql_test without_rowid1-1.31 { + UPDATE t1 SET d=3.1415926 WHERE a='journal'; + SELECT *, '|' FROM t1 ORDER BY c, a; +} {arctic sleep ammonia helena | journal sherman ammonia 3.1415926 | dynamic phone flipper harvard | journal sherman gamma 3.1415926 |} + finish_test