From: drh Date: Wed, 4 Jun 2003 12:23:30 +0000 (+0000) Subject: Avoid corrupting indices when doing a REPLACE on a table with an X-Git-Tag: version-3.6.10~5069 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5383ae5c128d6c2917ebed60bcb568777f850f91;p=thirdparty%2Fsqlite.git Avoid corrupting indices when doing a REPLACE on a table with an INTEGER PRIMARY KEY that also has another index. Ticket #334. (CVS 999) FossilOrigin-Name: e813faae0e4086571d13c769f793add7f1f979af --- diff --git a/manifest b/manifest index 2492b32749..af58a13bf3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Additional\stesting\sof\sthe\sATTACH\scommand\swith\sbug\sfixes\sfor\sthe\snew\sproblems\nthat\sthe\stests\sfound.\s(CVS\s998) -D 2003-06-03T01:47:11 +C Avoid\scorrupting\sindices\swhen\sdoing\sa\sREPLACE\son\sa\stable\swith\san\nINTEGER\sPRIMARY\sKEY\sthat\salso\shas\sanother\sindex.\s\sTicket\s#334.\s(CVS\s999) +D 2003-06-04T12:23:31 F Makefile.in 1ff85c27d4350c74118341024e8a4fb2a04a3a43 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -32,7 +32,7 @@ F src/expr.c ebdb0f3ee039c8030de25935ce2df030966540a6 F src/func.c 33bbce6acaf9578ac99aa1f689968ccaf2ce43a2 F src/hash.c 058f077c1f36f266581aa16f907a3903abf64aa3 F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8 -F src/insert.c e34301f41a69cf59c4d75962b2ca5e1af427b5f0 +F src/insert.c 6a61c6d1ef17396d0e87e555806653fddab0b084 F src/main.c 945f9b6855007b28a6c910584d1ca5adff92d821 F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565 F src/os.c 080238f03015057879cdf53bc4af9e497f2ba724 @@ -83,7 +83,7 @@ F test/format3.test b05cb2968841553698290f2833f72894f156024e F test/func.test 000515779001ac6899eec4b54e65c6e2501279d4 F test/in.test 22de8a3eb27265aab723adc513bea0e76bef70c6 F test/index.test 90ef4c426865f15937858bd433cc82b9c11af913 -F test/insert.test 5697ba098e4d8a6f0151f281b7e39dec9c439e05 +F test/insert.test e73709f2fee30e003ce131e7ca66ad3dcfac662a F test/insert2.test c288375a64dad3295044714f0dfed4a193cf067f F test/intpkey.test 39f49fd993350f7f3ab255e5cfbf9a09d8f8800e F test/ioerr.test 5dbaf09f96b56ee01cf3edd762b96eb4ad2c9ca4 @@ -165,7 +165,7 @@ F www/speed.tcl cb4c10a722614aea76d2c51f32ee43400d5951be F www/sqlite.tcl 4bd1729e320f5fa9125f0022b281fbe839192125 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 -P daf7b94017f03638da1ef65830f3762be030b93c -R 64dc9487d2ea82a1f70ee389c18ab473 +P 3e8889d7ce5e99fc855526fc1bb62ddbe282bfc5 +R 9165bb0816719b739dc59ff58a777b66 U drh -Z 95bab4cd51ed3d170690377c2faf1c26 +Z 94bfab46c8d22deaac737964000d29aa diff --git a/manifest.uuid b/manifest.uuid index d8d624a765..790a33f06d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3e8889d7ce5e99fc855526fc1bb62ddbe282bfc5 \ No newline at end of file +e813faae0e4086571d13c769f793add7f1f979af \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index 53178374e6..98fc76cff9 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.86 2003/06/01 01:10:33 drh Exp $ +** $Id: insert.c,v 1.87 2003/06/04 12:23:31 drh Exp $ */ #include "sqliteInt.h" @@ -715,10 +715,8 @@ void sqliteGenerateConstraintChecks( /* 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. - ** Also, if the conflict resolution policy is REPLACE, then we - ** can skip this test. */ - if( /* (recnoChng || !isUpdate) && pTab->iPKey>=0 */ recnoChng ){ + if( recnoChng ){ onError = pTab->keyConf; if( overrideError!=OE_Default ){ onError = overrideError; @@ -728,40 +726,48 @@ void sqliteGenerateConstraintChecks( onError = OE_Abort; } - if( onError!=OE_Replace ){ - if( isUpdate ){ - sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1); - sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1); - jumpInst1 = sqliteVdbeAddOp(v, OP_Eq, 0, 0); + if( isUpdate ){ + sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1); + sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1); + jumpInst1 = sqliteVdbeAddOp(v, OP_Eq, 0, 0); + } + sqliteVdbeAddOp(v, OP_Dup, nCol, 1); + jumpInst2 = sqliteVdbeAddOp(v, OP_NotExists, base, 0); + switch( onError ){ + default: { + onError = OE_Abort; + /* Fall thru into the next case */ } - sqliteVdbeAddOp(v, OP_Dup, nCol, 1); - jumpInst2 = sqliteVdbeAddOp(v, OP_NotExists, base, 0); - switch( onError ){ - default: { - onError = OE_Abort; - /* Fall thru into the next case */ - } - case OE_Rollback: - case OE_Abort: - case OE_Fail: { - sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError); - sqliteVdbeChangeP3(v, -1, "PRIMARY KEY must be unique", P3_STATIC); - break; - } - case OE_Ignore: { - sqliteVdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0); - sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest); - break; + case OE_Rollback: + case OE_Abort: + case OE_Fail: { + sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError); + sqliteVdbeChangeP3(v, -1, "PRIMARY KEY must be unique", P3_STATIC); + break; + } + case OE_Replace: { + sqliteGenerateRowIndexDelete(pParse->db, v, pTab, base, 0); + if( isUpdate ){ + sqliteVdbeAddOp(v, OP_Dup, nCol+extra+1+hasTwoRecnos, 1); + sqliteVdbeAddOp(v, OP_MoveTo, base, 0); } + seenReplace = 1; + break; } - contAddr = sqliteVdbeCurrentAddr(v); - sqliteVdbeChangeP2(v, jumpInst2, contAddr); - if( isUpdate ){ - sqliteVdbeChangeP2(v, jumpInst1, contAddr); - sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1); - sqliteVdbeAddOp(v, OP_MoveTo, base, 0); + case OE_Ignore: { + assert( seenReplace==0 ); + sqliteVdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0); + sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest); + break; } } + contAddr = sqliteVdbeCurrentAddr(v); + sqliteVdbeChangeP2(v, jumpInst2, contAddr); + if( isUpdate ){ + sqliteVdbeChangeP2(v, jumpInst1, contAddr); + sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1); + sqliteVdbeAddOp(v, OP_MoveTo, base, 0); + } } /* Test all UNIQUE constraints by creating entries for each UNIQUE @@ -796,6 +802,11 @@ void sqliteGenerateConstraintChecks( }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 */ sqliteVdbeAddOp(v, OP_Dup, extra+nCol+1+hasTwoRecnos, 1); diff --git a/test/insert.test b/test/insert.test index f551e4e4ae..4dbe19191a 100644 --- a/test/insert.test +++ b/test/insert.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the INSERT statement. # -# $Id: insert.test,v 1.12 2003/04/03 01:50:48 drh Exp $ +# $Id: insert.test,v 1.13 2003/06/04 12:23:32 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -253,5 +253,21 @@ do_test insert-5.7 { expr {[lsearch $x OpenTemp]>0} } {0} +# Ticket #334: REPLACE statement corrupting indices. +# +do_test insert-6.1 { + execsql { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE); + INSERT INTO t1 VALUES(1,2); + INSERT INTO t1 VALUES(2,3); + SELECT b FROM t1 WHERE b=2; + } +} {2} +do_test insert-6.2 { + execsql { + REPLACE INTO t1 VALUES(1,4); + SELECT b FROM t1 WHERE b=2; + } +} {} finish_test