From: dan Date: Tue, 26 May 2015 11:53:14 +0000 (+0000) Subject: Fix a problem with ignoring UNIQUE constraints on WITHOUT ROWID tables rendered redun... X-Git-Tag: version-3.8.11~215 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c5b735851391c25a1902a4b1e9732d0d124f8917;p=thirdparty%2Fsqlite.git Fix a problem with ignoring UNIQUE constraints on WITHOUT ROWID tables rendered redundant by the PRIMARY KEY. FossilOrigin-Name: 3b936913f3dc2cae4c94f983f28d85b136a44c9f --- diff --git a/manifest b/manifest index 478a7ce194..86465add84 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Silence\sharmless\scompiler\swarnings\swhen\sbuilding\sthe\scommand\sline\sutilities\swith\sMSVC. -D 2015-05-26T03:31:46.981 +C Fix\sa\sproblem\swith\signoring\sUNIQUE\sconstraints\son\sWITHOUT\sROWID\stables\srendered\sredundant\sby\sthe\sPRIMARY\sKEY. +D 2015-05-26T11:53:14.886 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 69b596e4be75a16f4e55587f29db66497b207fad F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -195,7 +195,7 @@ F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79 F src/btree.c a7d627f89e8382cea8645cc2eec6927b203fdb31 F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1 F src/btreeInt.h 973a22a6fd61350b454ad614832b1f0a5e25a1e4 -F src/build.c d5d9090788118178190c5724c19f93953b8c7a4e +F src/build.c 9552e7490b0310a8c73fcf3a0c36e7624789d8df F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 F src/complete.c a5cf5b4b56390cfb7b8636e8f7ddef90258dd575 F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b @@ -255,7 +255,7 @@ F src/shell.c 07dda7cd692911d2f22269953418d049f2e2c0ee F src/sqlite.h.in 4d0ecd8e1e0272d9a2742b39602f5e4fad8d3246 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 2ebeb634e751a61a6f0eebfa0f4669f46a42f6cd -F src/sqliteInt.h 88738d94a343000e7a5c0e295d111c4cfccb18b0 +F src/sqliteInt.h 26484793b2f8017960b30ae2d0cbc7512eff5b17 F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179 F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e @@ -1215,7 +1215,7 @@ F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d F test/with1.test a86bf7f9288ba759a25ee57221d3bffaca36032a F test/with2.test ee227a663586aa09771cafd4fa269c5217eaf775 F test/withM.test e97f2a8c506ab3ea9eab94e6f6072f6cc924c991 -F test/without_rowid1.test 7862e605753c8d25329f665fa09072e842183151 +F test/without_rowid1.test 4cda656cb4a452296e0d8d8623513f4be80c6d86 F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99 F test/without_rowid3.test 1081aabf60a1e1123b7f9a8f6ae19954351843b0 F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a @@ -1279,7 +1279,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P eda2a437506f148bcb5bb33baa64b5ad8ae73ada -R 729e132ed27defff17edf873b9ea2761 -U mistachkin -Z 455a04fccd298870eb1e19dc1cb5545d +P d26060c468cc6997e9933d9623a47fcc7d86c2da +R 5fc589e99d7c4f392d71685f4b89ca0e +U dan +Z 34e0e604424e8529b6d35704e87be1e0 diff --git a/manifest.uuid b/manifest.uuid index 4edb632337..49abbeb288 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d26060c468cc6997e9933d9623a47fcc7d86c2da \ No newline at end of file +3b936913f3dc2cae4c94f983f28d85b136a44c9f \ No newline at end of file diff --git a/src/build.c b/src/build.c index 44d75e9557..1cf427b033 100644 --- a/src/build.c +++ b/src/build.c @@ -1325,14 +1325,11 @@ void sqlite3AddPrimaryKey( "INTEGER PRIMARY KEY"); #endif }else{ - Vdbe *v = pParse->pVdbe; Index *p; - if( v ) pParse->addrSkipPK = sqlite3VdbeAddOp0(v, OP_Noop); p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0); if( p ){ p->idxType = SQLITE_IDXTYPE_PRIMARYKEY; - if( v ) sqlite3VdbeJumpHere(v, pParse->addrSkipPK); } pList = 0; } @@ -1685,14 +1682,6 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ sqlite3VdbeGetOp(v, pParse->addrCrTab)->opcode = OP_CreateIndex; } - /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master - ** table entry. - */ - if( pParse->addrSkipPK ){ - assert( v ); - sqlite3VdbeGetOp(v, pParse->addrSkipPK)->opcode = OP_Goto; - } - /* Locate the PRIMARY KEY index. Or, if this table was originally ** an INTEGER PRIMARY KEY table, create a new PRIMARY KEY index. */ @@ -1710,6 +1699,16 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ pTab->iPKey = -1; }else{ pPk = sqlite3PrimaryKeyIndex(pTab); + + /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master + ** table entry. This is only required if currently generating VDBE + ** code for a CREATE TABLE (not when parsing one as part of reading + ** a database schema). */ + if( v ){ + assert( db->init.busy==0 ); + sqlite3VdbeGetOp(v, pPk->tnum)->opcode = OP_Goto; + } + /* ** Remove all redundant columns from the PRIMARY KEY. For example, change ** "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)". Later @@ -3250,10 +3249,15 @@ Index *sqlite3CreateIndex( v = sqlite3GetVdbe(pParse); if( v==0 ) goto exit_create_index; - - /* Create the rootpage for the index - */ sqlite3BeginWriteOperation(pParse, 1, iDb); + + /* Create the rootpage for the index using CreateIndex. But before + ** doing so, code a Noop instruction and store its address in + ** Index.tnum. This is required in case this index is actually a + ** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In + ** that case the convertToWithoutRowidTable() routine will replace + ** the Noop with a Goto to jump over the VDBE code generated below. */ + pIndex->tnum = sqlite3VdbeAddOp0(v, OP_Noop); sqlite3VdbeAddOp2(v, OP_CreateIndex, iDb, iMem); /* Gather the complete text of the CREATE INDEX statement into @@ -3293,6 +3297,8 @@ Index *sqlite3CreateIndex( sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName)); sqlite3VdbeAddOp1(v, OP_Expire, 0); } + + sqlite3VdbeJumpHere(v, pIndex->tnum); } /* When adding an index to the list of indices for a table, make diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 586d4d07e4..cba17d711a 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1811,6 +1811,14 @@ struct UnpackedRecord { ** and the value of Index.onError indicate the which conflict resolution ** algorithm to employ whenever an attempt is made to insert a non-unique ** element. +** +** While parsing a CREATE TABLE or CREATE INDEX statement in order to +** generate VDBE code (as opposed to parsing one read from an sqlite_master +** table as part of parsing an existing database schema), transient instances +** of this structure may be created. In this case the Index.tnum variable is +** used to store the address of a VDBE instruction, not a database page +** number (it cannot - the database page is not allocated until the VDBE +** program is executed). See convertToWithoutRowidTable() for details. */ struct Index { char *zName; /* Name of this index */ @@ -2639,7 +2647,6 @@ struct Parse { Parse *pToplevel; /* Parse structure for main program (or NULL) */ Table *pTriggerTab; /* Table triggers are being coded for */ int addrCrTab; /* Address of OP_CreateTable opcode on CREATE TABLE */ - int addrSkipPK; /* Address of instruction to skip PRIMARY KEY index */ u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */ u32 oldmask; /* Mask of old.* columns referenced */ u32 newmask; /* Mask of new.* columns referenced */ diff --git a/test/without_rowid1.test b/test/without_rowid1.test index 9d7a6430fe..b746cca277 100644 --- a/test/without_rowid1.test +++ b/test/without_rowid1.test @@ -277,5 +277,37 @@ foreach {tn cnt where eqp} $queries { do_eqp_test 5.7.$tn.2 "SELECT count(*) FROM t46 WHERE $where" $eqp } +#------------------------------------------------------------------------- +# Check that redundant UNIQUE constraints do not cause a problem. +# +do_execsql_test 6.0 { + CREATE TABLE t47(a, b UNIQUE PRIMARY KEY) WITHOUT ROWID; + CREATE INDEX i47 ON t47(a); + INSERT INTO t47 VALUES(1, 2); + INSERT INTO t47 VALUES(2, 4); + INSERT INTO t47 VALUES(3, 6); + INSERT INTO t47 VALUES(4, 8); + + VACUUM; + PRAGMA integrity_check; + SELECT name FROM sqlite_master WHERE tbl_name = 't47'; +} {ok t47 i47} + +do_execsql_test 6.1 { + CREATE TABLE t48( + a UNIQUE UNIQUE, + b UNIQUE, + PRIMARY KEY(a), + UNIQUE(a) + ) WITHOUT ROWID; + INSERT INTO t48 VALUES('a', 'b'), ('c', 'd'), ('e', 'f'); + VACUUM; + PRAGMA integrity_check; + SELECT name FROM sqlite_master WHERE tbl_name = 't48'; +} { + ok t48 sqlite_autoindex_t48_2 +} + + finish_test