]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Bug fixes in the INSERT constraint checker. Refactor the Rowid handling logic
authordrh <drh@noemail.net>
Mon, 4 Nov 2013 21:44:54 +0000 (21:44 +0000)
committerdrh <drh@noemail.net>
Mon, 4 Nov 2013 21:44:54 +0000 (21:44 +0000)
for ANALYZE with STAT3/4.

FossilOrigin-Name: 1ea43c0f236792a3bc13e1cb330f5ff3402c2851

manifest
manifest.uuid
src/analyze.c
src/insert.c
src/pragma.c

index ad2634b5b1bbe242c10ca1dc1c7d653d05490662..fadb82468de7e9a30fbcf75bc58358327a7ce2e2 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sanother\stest\scase\sfile\sfor\sWITHOUT\sROWID\sand\sfix\sthe\sbugs\sthat\sthe\snew\s\ntest\sfile\suncovered.
-D 2013-11-04T18:34:46.599
+C Bug\sfixes\sin\sthe\sINSERT\sconstraint\schecker.\s\sRefactor\sthe\sRowid\shandling\slogic\nfor\sANALYZE\swith\sSTAT3/4.
+D 2013-11-04T21:44:54.263
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 0522b53cdc1fcfc18f3a98e0246add129136c654
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -159,7 +159,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
 F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
 F src/alter.c 2af0330bb1b601af7a7789bf7229675fd772a083
-F src/analyze.c b583d62c9b74d887864eaa594d629c0b33bea4a5
+F src/analyze.c 0727d84692bdad3bada987950fd714445cca225c
 F src/attach.c 0a17c9364895316ca4f52d06a97a72c0af1ae8b3
 F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
 F src/backup.c 2f1987981139bd2f6d8c728d64bf09fb387443c3
@@ -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 faa58c9978001f67b3fcb4e0fb588c7852c05483
+F src/insert.c b89a81a5c4cfc5cf83f29751e07b45527af27dc2
 F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
 F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
 F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
@@ -212,7 +212,7 @@ F src/parse.y 073a8294e1826f1b1656e84806b77e4199f4bb57
 F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
 F src/pcache1.c a467393909a4ed7ca9de066d85ba5c5b04a5be63
-F src/pragma.c 8d67f2e7a73b8260cfed328eb024fb16c20e0f16
+F src/pragma.c ac43f31b04afd586f7d4a7535f6c4b07b329a1de
 F src/prepare.c fa6988589f39af8504a61731614cd4f6ae71554f
 F src/printf.c da9119eb31a187a4b99f60aa4a225141c0ebb74b
 F src/random.c 0b2dbc37fdfbfa6bd455b091dfcef5bdb32dba68
@@ -1131,7 +1131,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 89098e6d18dacd1554cf4471b5f035db85d1f327
-R 4fbdd86f5ad03355f6f11feb2ddb3d95
+P bc2a06eb8e57573d08e77800a7937eee5af3f035
+R c6a00a38efed0dd468c88c1afd0d6407
 U drh
-Z 1acf97ed6e77633885d90ac086f2b0ff
+Z 16670a36629db5e8da9906d68f8a996e
index 479d71aef009a5d6a91c1fd19dcbb72f5abd1e8a..34757248352a8ca628ce6a8e6c4315aeb4cfe4b6 100644 (file)
@@ -1 +1 @@
-bc2a06eb8e57573d08e77800a7937eee5af3f035
\ No newline at end of file
+1ea43c0f236792a3bc13e1cb330f5ff3402c2851
\ No newline at end of file
index a71231eb5e9269a336a9d01c05963cca14aabf35..0e5869427e681bc7800f1b83fbd80c88984123df 100644 (file)
@@ -268,9 +268,11 @@ struct Stat4Sample {
   tRowcnt *anDLt;                 /* sqlite_stat4.nDLt */
 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
   tRowcnt *anLt;                  /* sqlite_stat4.nLt */
-  i64 iRowid;                     /* Rowid in main table of the key */
+  union {
+    i64 iRowid;                     /* Rowid in main table of the key */
+    u8 *aRowid;                     /* Key for WITHOUT ROWID tables */
+  } u;
   u32 nRowid;                     /* Sizeof aRowid[] */
-  u8 *aRowid;                     /* Key for WITHOUT ROWID tables */
   u8 isPSample;                   /* True if a periodic sample */
   int iCol;                       /* If !isPSample, the reason for inclusion */
   u32 iHash;                      /* Tiebreaker hash */
@@ -295,22 +297,57 @@ struct Stat4Accum {
 */
 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
 static void sampleClear(sqlite3 *db, Stat4Sample *p){
-  sqlite3DbFree(db, p->aRowid);
-  p->aRowid = 0;
+  assert( db!=0 );
+  if( p->nRowid ){
+    sqlite3DbFree(db, p->u.aRowid);
+    p->nRowid = 0;
+  }
+}
+#endif
+
+/* Initialize the BLOB value of a ROWID
+*/
+#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){
+  assert( db!=0 );
+  if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
+  p->u.aRowid = sqlite3DbMallocRaw(db, n);
+  if( p->u.aRowid ){
+    p->nRowid = n;
+    memcpy(p->u.aRowid, pData, n);
+  }else{
+    p->nRowid = 0;
+  }
+}
+#endif
+
+/* Initialize the INTEGER value of a ROWID.
+*/
+#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+static void sampleSetRowidInt64(sqlite3 *db, Stat4Sample *p, i64 iRowid){
+  assert( db!=0 );
+  if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
   p->nRowid = 0;
+  p->u.iRowid = iRowid;
 }
 #endif
 
-/* Make a copy of the Stat4Sample.aRowid field.
+
+/*
+** Copy the contents of object (*pFrom) into (*pTo).
 */
 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
-static void sampleDup(sqlite3 *db, Stat4Sample *p){
-  if( p->aRowid ){
-    u8 *aCopy = sqlite3DbMallocRaw(db, p->nRowid);
-    if( aCopy ){
-      memcpy(aCopy, p->aRowid, p->nRowid);
-      p->aRowid = aCopy;
-    }
+static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
+  pTo->isPSample = pFrom->isPSample;
+  pTo->iCol = pFrom->iCol;
+  pTo->iHash = pFrom->iHash;
+  memcpy(pTo->anEq, pFrom->anEq, sizeof(tRowcnt)*p->nCol);
+  memcpy(pTo->anLt, pFrom->anLt, sizeof(tRowcnt)*p->nCol);
+  memcpy(pTo->anDLt, pFrom->anDLt, sizeof(tRowcnt)*p->nCol);
+  if( pFrom->nRowid ){
+    sampleSetRowid(p->db, pTo, pFrom->nRowid, pFrom->u.aRowid);
+  }else{
+    sampleSetRowidInt64(p->db, pTo, pFrom->u.iRowid);
   }
 }
 #endif
@@ -324,6 +361,7 @@ static void stat4Destructor(void *pOld){
   int i;
   for(i=0; i<p->nCol; i++) sampleClear(p->db, p->aBest+i);
   for(i=0; i<p->mxSample; i++) sampleClear(p->db, p->a+i);
+  sampleClear(p->db, &p->current);
 #endif
   sqlite3DbFree(p->db, p);
 }
@@ -483,23 +521,6 @@ static int sampleIsBetter(
 #endif
 }
 
-/*
-** Copy the contents of object (*pFrom) into (*pTo).
-*/
-static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
-  pTo->iRowid = pFrom->iRowid;
-  pTo->isPSample = pFrom->isPSample;
-  pTo->iCol = pFrom->iCol;
-  pTo->iHash = pFrom->iHash;
-  sampleClear(p->db, pTo);
-  pTo->nRowid = pFrom->nRowid;
-  pTo->aRowid = pFrom->aRowid;
-  sampleDup(p->db, pTo);
-  memcpy(pTo->anEq, pFrom->anEq, sizeof(tRowcnt)*p->nCol);
-  memcpy(pTo->anLt, pFrom->anLt, sizeof(tRowcnt)*p->nCol);
-  memcpy(pTo->anDLt, pFrom->anDLt, sizeof(tRowcnt)*p->nCol);
-}
-
 /*
 ** Copy the contents of sample *pNew into the p->a[] array. If necessary,
 ** remove the least desirable sample from p->a[] to make room.
@@ -545,6 +566,7 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
     tRowcnt *anEq = pMin->anEq;
     tRowcnt *anLt = pMin->anLt;
     tRowcnt *anDLt = pMin->anDLt;
+    sampleClear(p->db, pMin);
     memmove(pMin, &pMin[1], sizeof(p->a[0])*(p->nSample-p->iMin-1));
     pSample = &p->a[p->nSample-1];
     pSample->anEq = anEq;
@@ -694,13 +716,10 @@ static void statPush(
   p->nRow++;
 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
   if( sqlite3_value_type(argv[2])==SQLITE_INTEGER ){
-    p->current.iRowid = sqlite3_value_int64(argv[2]);
-    p->current.aRowid = 0;
-    p->current.nRowid = 0;
+    sampleSetRowidInt64(p->db, &p->current, sqlite3_value_int64(argv[2]));
   }else{
-    p->current.iRowid = 0;
-    p->current.nRowid = sqlite3_value_bytes(argv[2]);
-    p->current.aRowid = (u8*)sqlite3_value_blob(argv[2]);
+    sampleSetRowid(p->db, &p->current, sqlite3_value_bytes(argv[2]),
+                                       sqlite3_value_blob(argv[2]));
   }
   p->current.iHash = p->iPrn = p->iPrn*1103515245 + 12345;
 #endif
@@ -827,9 +846,10 @@ static void statGet(
     if( p->iGet<p->nSample ){
       Stat4Sample *pS = p->a + p->iGet;
       if( pS->nRowid==0 ){
-        sqlite3_result_int64(context, pS->iRowid);
+        sqlite3_result_int64(context, pS->u.iRowid);
       }else{
-        sqlite3_result_blob(context, pS->aRowid, pS->nRowid, SQLITE_STATIC);
+        sqlite3_result_blob(context, pS->u.aRowid, pS->nRowid,
+                            SQLITE_TRANSIENT);
       }
     }
   }else{
index 3cc88f96f66e3a1c9e39428b0ece12fe2103fe11..a6cab3e899493210944f4e95a398899a0fee7edb 100644 (file)
@@ -1463,7 +1463,10 @@ void sqlite3GenerateConstraintChecks(
     ** 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;
+    if( isUpdate && pPk && pkChng==0 ){
+      sqlite3VdbeResolveLabel(v, addrUniqueOk);
+      continue;
+    }
 
     /* Find out what action to take in case there is a uniqueness conflict */
     onError = pIdx->onError;
@@ -1498,38 +1501,40 @@ void sqlite3GenerateConstraintChecks(
     }else{
       int x;
       /* Extract the PRIMARY KEY from the end of the index entry and
-      ** store it in register regR..regR+nPk-1 */
-      for(i=0; i<pPk->nKeyCol; i++){
-        x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
-        sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
-        VdbeComment((v, "%s.%s", pTab->zName,
-                     pTab->aCol[pPk->aiColumn[i]].zName));
+      ** store it in registers regR..regR+nPk-1 */
+      if( isUpdate || onError==OE_Replace ){
+        for(i=0; i<pPk->nKeyCol; i++){
+          x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
+          sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
+          VdbeComment((v, "%s.%s", pTab->zName,
+                       pTab->aCol[pPk->aiColumn[i]].zName));
+        }
       }
-      if( pIdx->autoIndex==2 ){
-        /* For a PRIMARY KEY index on a WITHOUT ROWID table, always conflict
-        ** on an INSERT.  On an UPDATE, only conflict if the PRIMARY KEY
-        ** has changed. */
-        if( isUpdate ){
+      if( isUpdate ){
+        if( pIdx->autoIndex==2 ){
+          /* For a PRIMARY KEY index on a WITHOUT ROWID table, always conflict
+          ** on an INSERT.  On an UPDATE, only conflict if the PRIMARY KEY
+          ** has changed. */
           int addrPkConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
           for(i=0; i<pPk->nKeyCol-1; i++){
             x = pPk->aiColumn[i];
             sqlite3VdbeAddOp3(v, OP_Ne, regOldData+1+x,
-                              addrPkConflict, regIdx+x);
+                              addrPkConflict, regIdx+i);
           }
           x = pPk->aiColumn[i];
           sqlite3VdbeAddOp3(v, OP_Eq, regOldData+1+x, addrUniqueOk, regIdx+i);
+        }else{
+          /* For a UNIQUE index on a WITHOUT ROWID table, conflict only if the
+          ** PRIMARY KEY value of the match is different from the old
+          ** PRIMARY KEY value from before the update. */
+          int addrConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
+          for(i=0; i<pPk->nKeyCol-1; i++){
+            sqlite3VdbeAddOp3(v, OP_Ne, regOldData+pPk->aiColumn[i]+1,
+                              addrConflict, regR+i);
+          }
+          sqlite3VdbeAddOp3(v, OP_Eq, regOldData+pPk->aiColumn[i]+1,
+                            addrUniqueOk, regR+i);
         }
-      }else{
-        /* For a UNIQUE index on a WITHOUT ROWID table, conflict only if the
-        ** PRIMARY KEY value of the match is different from the old PRIMARY KEY
-        ** value from before the update. */
-        int addrConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
-        for(i=0; i<pPk->nKeyCol-1; i++){
-          sqlite3VdbeAddOp3(v, OP_Ne,
-                           regOldData+pPk->aiColumn[i]+1, addrConflict, regR+i);
-        }
-        sqlite3VdbeAddOp3(v, OP_Eq,
-                          regOldData+pPk->aiColumn[i]+1, addrUniqueOk, regR+i);
       }
     }
     sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
@@ -1827,8 +1832,8 @@ static int xferOptimization(
   int iDbSrc;                      /* The database of pSrc */
   int iSrc, iDest;                 /* Cursors from source and destination */
   int addr1, addr2;                /* Loop addresses */
-  int emptyDestTest;               /* Address of test for empty pDest */
-  int emptySrcTest;                /* Address of test for empty pSrc */
+  int emptyDestTest = 0;           /* Address of test for empty pDest */
+  int emptySrcTest = 0;            /* Address of test for empty pSrc */
   Vdbe *v;                         /* The VDBE we are building */
   KeyInfo *pKey;                   /* Key information for an index */
   int regAutoinc;                  /* Memory register used by AUTOINC */
@@ -2026,6 +2031,9 @@ static int xferOptimization(
     sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1);
     sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
     sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
+  }else{
+    sqlite3TableLock(pParse, iDbDest, pDest->tnum, 1, pDest->zName);
+    sqlite3TableLock(pParse, iDbSrc, pSrc->tnum, 0, pSrc->zName);
   }
   for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
     for(pSrcIdx=pSrc->pIndex; ALWAYS(pSrcIdx); pSrcIdx=pSrcIdx->pNext){
index 3871ad02a6d70e47edb356cc71fe4fec1a864aec..948d96056c78623c4535c9aeafc5e954243b1b14 100644 (file)
@@ -1903,7 +1903,7 @@ void sqlite3Pragma(
           r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3);
           sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1);  /* increment entry count */
           jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, 0, r1,
-                                      pIdx->nKeyCol+1);
+                                      pIdx->nColumn);
           sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
           sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, "row ", P4_STATIC);
           sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);