]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Ensure that the correct number of columns in a UNIQUE index are checked for
authordrh <drh@noemail.net>
Wed, 30 Jul 2014 13:56:48 +0000 (13:56 +0000)
committerdrh <drh@noemail.net>
Wed, 30 Jul 2014 13:56:48 +0000 (13:56 +0000)
uniqueness, regardless of whether or not the original table has a ROWID or
if the columns are NOT NULL, etc.  Ticket [9a6daf340df99ba93c].

FossilOrigin-Name: 6b785e92f279cb65746834d5cd25594fd3333342

manifest
manifest.uuid
src/build.c
src/vdbe.c
src/vdbesort.c
test/unique2.test [new file with mode: 0644]

index 36b66e55d7ca497da2489ababd6663049c6ad2d7..551a1332b7040f3dd7ecb263823a4a5717639693 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Enhancements\sand\supdates\sto\sthe\sWin32\smutex\ssubsystem.
-D 2014-07-29T19:54:03.929
+C Ensure\sthat\sthe\scorrect\snumber\sof\scolumns\sin\sa\sUNIQUE\sindex\sare\schecked\sfor\nuniqueness,\sregardless\sof\swhether\sor\snot\sthe\soriginal\stable\shas\sa\sROWID\sor\nif\sthe\scolumns\sare\sNOT\sNULL,\setc.\s\sTicket\s[9a6daf340df99ba93c].
+D 2014-07-30T13:56:48.415
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -170,7 +170,7 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
 F src/btree.c b5531339cd826af46b9621e4a9323971a9380e12
 F src/btree.h 4245a349bfe09611d7ff887dbc3a80cee8b7955a
 F src/btreeInt.h cf180d86b2e9e418f638d65baa425c4c69c0e0e3
-F src/build.c 48f400fa14fd6add244b954ce7e223ce7ccacf0b
+F src/build.c 7ba21d8f0f5f1e8b5a0ed21aab9be2b39d1af516
 F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98
 F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
 F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a
@@ -283,14 +283,14 @@ F src/update.c 01564b3c430f6c7b0a35afaf7aba7987206fa3a5
 F src/utf.c a0314e637768a030e6e84a957d0c4f6ba910cc05
 F src/util.c 3076bdd51cdbf60a6e2e57fada745be37133c73e
 F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
-F src/vdbe.c b127f05ff110c1f640b5aff98fa57d5028c8f2ee
+F src/vdbe.c f87f77b0049cbef1fa68b331c3551d82b4d9fba4
 F src/vdbe.h c63fad052c9e7388d551e556e119c0bcf6bebdf8
 F src/vdbeInt.h f5513f2b5ac1e2c5128996c7ea23add256a301df
 F src/vdbeapi.c 24e40422382beb774daab11fe9fe9d37e8a04949
 F src/vdbeaux.c ac063f36c929f88bf6cecdbcc413000e272265bb
 F src/vdbeblob.c 9205ce9d3b064d9600f8418a897fc88b5687d9ac
 F src/vdbemem.c d90a1e8acf8b63dc9d14cbbea12bfec6cec31394
-F src/vdbesort.c 44441d73b08b3a638dcdb725afffb87c6574ad27
+F src/vdbesort.c f7f5563bf7d4695ca8f3203f3bf9de96d04ed0b3
 F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
 F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
 F src/wal.c 264df50a1b33124130b23180ded2e2c5663c652a
@@ -1041,6 +1041,7 @@ F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
 F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
 F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a
 F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264
+F test/unique2.test 41e7f83c6827605991160a31380148a9fc5f1339
 F test/unixexcl.test cd6c765f75e50e8e2c2ba763149e5d340ea19825
 F test/unordered.test ca7adce0419e4ca0c50f039885e76ed2c531eda8
 F test/update.test 1b6c488a8f993d090b7ee9ad0e234faa161b3aeb
@@ -1184,7 +1185,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 8b651d4d6cde7efbc0cc7155948f477477be100e 08c9a4ea6353900095a471365a8611a443f5f399
-R b75cbb8ba71bd17b820832cbd89e629a
-U mistachkin
-Z f55203ab4632e071cc6adc34ad558bc2
+P ca9868cdae19045dc522490b34dee0f14d928ebe
+R aa3d0aadabff4023861d0c947293977e
+U drh
+Z 0e144877cde1d96e38c3dc4f9894f6d4
index 2526bc68aaffb3ad0f74faae7c64ef251051d811..194b99221e4a89d359d8e3cbfd372bc6793246ef 100644 (file)
@@ -1 +1 @@
-ca9868cdae19045dc522490b34dee0f14d928ebe
\ No newline at end of file
+6b785e92f279cb65746834d5cd25594fd3333342
\ No newline at end of file
index 27c9671da6ebff42ee8146cbc2bae10d6024bc76..384802c5336af31028be2b94f647263889deeb8b 100644 (file)
@@ -2712,7 +2712,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
     sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
     addr2 = sqlite3VdbeCurrentAddr(v);
     sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord,
-                         pKey->nField - pIndex->nKeyCol); VdbeCoverage(v);
+                         pIndex->nKeyCol); VdbeCoverage(v);
     sqlite3UniqueConstraint(pParse, OE_Abort, pIndex);
   }else{
     addr2 = sqlite3VdbeCurrentAddr(v);
index a00a1da836f43bc2310660b1536be51ad71b11db..52f0f3aa749517c4d56b750515926332ec2d4d1f 100644 (file)
@@ -4271,12 +4271,12 @@ case OP_ResetCount: {
 }
 
 /* Opcode: SorterCompare P1 P2 P3 P4
-** Synopsis:  if key(P1)!=rtrim(r[P3],P4) goto P2
+** Synopsis:  if key(P1)!=trim(r[P3],P4) goto P2
 **
 ** P1 is a sorter cursor. This instruction compares a prefix of the
 ** the record blob in register P3 against a prefix of the entry that 
-** the sorter cursor currently points to.  The final P4 fields of both
-** the P3 and sorter record are ignored.
+** the sorter cursor currently points to.  Only the first P4 fields
+** of r[P3] and the sorter record are compared.
 **
 ** If either P3 or the sorter contains a NULL in one of their significant
 ** fields (not counting the P4 fields at the end which are ignored) then
@@ -4288,14 +4288,14 @@ case OP_ResetCount: {
 case OP_SorterCompare: {
   VdbeCursor *pC;
   int res;
-  int nIgnore;
+  int nKeyCol;
 
   pC = p->apCsr[pOp->p1];
   assert( isSorter(pC) );
   assert( pOp->p4type==P4_INT32 );
   pIn3 = &aMem[pOp->p3];
-  nIgnore = pOp->p4.i;
-  rc = sqlite3VdbeSorterCompare(pC, pIn3, nIgnore, &res);
+  nKeyCol = pOp->p4.i;
+  rc = sqlite3VdbeSorterCompare(pC, pIn3, nKeyCol, &res);
   VdbeBranchTaken(res!=0,2);
   if( res ){
     pc = pOp->p2-1;
index d3690244c40f003d4ba08b5dfd4d3e8723d727e8..6a5855f2efef1efa67ce9e9756f601c48bc1ede1 100644 (file)
@@ -385,7 +385,7 @@ static int vdbeSorterIterInit(
 */
 static void vdbeSorterCompare(
   const VdbeCursor *pCsr,         /* Cursor object (for pKeyInfo) */
-  int nIgnore,                    /* Ignore the last nIgnore fields */
+  int nKeyCol,                    /* Num of columns. 0 means "all" */
   const void *pKey1, int nKey1,   /* Left side of comparison */
   const void *pKey2, int nKey2,   /* Right side of comparison */
   int *pRes                       /* OUT: Result of comparison */
@@ -399,10 +399,9 @@ static void vdbeSorterCompare(
     sqlite3VdbeRecordUnpack(pKeyInfo, nKey2, pKey2, r2);
   }
 
-  if( nIgnore ){
-    r2->nField = pKeyInfo->nField - nIgnore;
-    assert( r2->nField>0 );
-    for(i=0; i<r2->nField; i++){
+  if( nKeyCol ){
+    r2->nField = nKeyCol;
+    for(i=0; i<nKeyCol; i++){
       if( r2->aMem[i].flags & MEM_Null ){
         *pRes = -1;
         return;
@@ -1084,13 +1083,13 @@ int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){
 int sqlite3VdbeSorterCompare(
   const VdbeCursor *pCsr,         /* Sorter cursor */
   Mem *pVal,                      /* Value to compare to current sorter key */
-  int nIgnore,                    /* Ignore this many fields at the end */
+  int nKeyCol,                    /* Only compare this many fields */
   int *pRes                       /* OUT: Result of comparison */
 ){
   VdbeSorter *pSorter = pCsr->pSorter;
   void *pKey; int nKey;           /* Sorter key to compare pVal with */
 
   pKey = vdbeSorterRowkey(pSorter, &nKey);
-  vdbeSorterCompare(pCsr, nIgnore, pVal->z, pVal->n, pKey, nKey, pRes);
+  vdbeSorterCompare(pCsr, nKeyCol, pVal->z, pVal->n, pKey, nKey, pRes);
   return SQLITE_OK;
 }
diff --git a/test/unique2.test b/test/unique2.test
new file mode 100644 (file)
index 0000000..6a320d4
--- /dev/null
@@ -0,0 +1,78 @@
+# 2014-07-30
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.  The
+# focus of this file is testing the CREATE UNIQUE INDEX statement
+# to verify that ticket 9a6daf340df99ba93c53bcf8fa83d9f28040d2a8
+# has been fixed:
+#
+#  drh added on 2014-07-30 12:33:04:
+#
+#  The CREATE UNIQUE INDEX on the third line below does not fail even
+#  though the x column values are not all unique.
+#
+#     CREATE TABLE t1(x NOT NULL);
+#     INSERT INTO t1 VALUES(1),(2),(2),(3);
+#     CREATE UNIQUE INDEX t1x ON t1(x);
+#
+# If the index is created before the INSERT, then uniqueness is enforced
+# at the point of the INSERT. Note that the NOT NULL on the indexed column
+# seems to be required in order to exhibit this bug.
+#
+# "PRAGMA integrity_check" does not detect the resulting malformed database.
+# That might be considered a separate issue.
+#
+# Bisecting shows that this problem was introduced by the addition of
+#  WITHOUT ROWID support in version 3.8.2, specifically in check-in
+# [c80e229dd9c1230] on 2013-11-07. This problem was reported on the mailing
+# list by Pavel Pimenov.  and primary keys, and the UNIQUE constraint
+# on table columns
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+foreach {id sql} {
+   1 {CREATE TABLE t1(x TEXT PRIMARY KEY, y NOT NULL) WITHOUT ROWID}
+   2 {CREATE TABLE t1(x TEXT PRIMARY KEY, y NOT NULL)}
+   3 {CREATE TABLE t1(x TEXT PRIMARY KEY, y) WITHOUT ROWID}
+   4 {CREATE TABLE t1(x TEXT PRIMARY KEY, y)}
+} {
+  do_test $id.1 {
+    db eval {DROP TABLE IF EXISTS t1}
+    db eval $sql
+    db eval {INSERT INTO t1(x,y) VALUES(1,1),(2,2),(3,2),(4,3)}
+  } {}
+  do_test $id.2 {
+    catchsql {CREATE UNIQUE INDEX t1y ON t1(y)}
+  } {1 {UNIQUE constraint failed: t1.y}}
+}
+
+foreach {id sql} {
+   5 {CREATE TABLE t1(w,x,y NOT NULL,z NOT NULL,PRIMARY KEY(w,x)) WITHOUT ROWID}
+   6 {CREATE TABLE t1(w,x,y NOT NULL,z NOT NULL,PRIMARY KEY(w,x))}
+   7 {CREATE TABLE t1(w,x,y NOT NULL,z,PRIMARY KEY(w,x)) WITHOUT ROWID}
+   8 {CREATE TABLE t1(w,x,y NOT NULL,z,PRIMARY KEY(w,x))}
+   9 {CREATE TABLE t1(w,x,y,z NOT NULL,PRIMARY KEY(w,x)) WITHOUT ROWID}
+  10 {CREATE TABLE t1(w,x,y,z NOT NULL,PRIMARY KEY(w,x))}
+  11 {CREATE TABLE t1(w,x,y,z,PRIMARY KEY(w,x)) WITHOUT ROWID}
+  12 {CREATE TABLE t1(w,x,y,z,PRIMARY KEY(w,x))}
+} {
+  do_test $id.1 {
+    db eval {DROP TABLE IF EXISTS t1}
+    db eval $sql
+    db eval {INSERT INTO t1(w,x,y,z) VALUES(1,2,3,4),(2,3,3,4)}
+  } {}
+  do_test $id.2 {
+    catchsql {CREATE UNIQUE INDEX t1yz ON t1(y,z)}
+  } {1 {UNIQUE constraint failed: t1.y, t1.z}}
+}
+
+finish_test