]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Get VACUUM and the xfer optimization working with WITHOUT ROWID.
authordrh <drh@noemail.net>
Wed, 23 Oct 2013 16:03:07 +0000 (16:03 +0000)
committerdrh <drh@noemail.net>
Wed, 23 Oct 2013 16:03:07 +0000 (16:03 +0000)
FossilOrigin-Name: 579815fff1737552d2077255862b8f4fd220927c

manifest
manifest.uuid
src/insert.c
src/vacuum.c

index c1c11d5c270a41b8b73e740f37e730f018704db1..6e44f92311693dd0add70b08891ffe6f8bd66974 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Some\sinserts\sand\squeries\sworking\sfor\smulti-column\sprimary\skeys\nand\sWITHOUT\sROWID.
-D 2013-10-23T13:30:58.697
+C Get\sVACUUM\sand\sthe\sxfer\soptimization\sworking\swith\sWITHOUT\sROWID.
+D 2013-10-23T16:03:07.935
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 0522b53cdc1fcfc18f3a98e0246add129136c654
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -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 f95fb9bf2ca2ed222e30087ebfbc41cdcaf45b4e
+F src/insert.c 288b90185e7c01777e14b117f85414a658ee7cdb
 F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
 F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
 F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
@@ -278,7 +278,7 @@ F src/trigger.c ba0a883cd536b7dfdd4df3733001f5372a4299da
 F src/update.c 2bb5a267796e6d0177ef5689487c3688de5c309e
 F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
 F src/util.c 2fa6c821d28bbdbeec1b2a7b091a281c9ef8f918
-F src/vacuum.c f313bc97123a4dd4bfd3f50a00c4d44c08a5b1b7
+F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
 F src/vdbe.c 9970b726e045a4098b41009ab35d3528cef7c79e
 F src/vdbe.h 4f554b5627f26710c4c36d919110a3fc611ca5c4
 F src/vdbeInt.h ff57f67aee1ba26a3a47e786533dab155ab6dad6
@@ -1127,7 +1127,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 3f8016dee24213ec83a02d71ad2698789cc3a818
-R 8d5debd82aac9a40f36ea419916ec920
+P b21d831b2aa55507dd9def2acb02cdbffddf10d1
+R 6a806e8a94192c315a83eec413a16607
 U drh
-Z d4d1d21b1888e64aec811a14e29e0bcc
+Z 8ef207bba4cb227da6d5c01b961429c0
index 29c46281e22348403c9b5371b447d6285814b716..fe1ecadff7bcd43278f327168115b5c0bb7b82a9 100644 (file)
@@ -1 +1 @@
-b21d831b2aa55507dd9def2acb02cdbffddf10d1
\ No newline at end of file
+579815fff1737552d2077255862b8f4fd220927c
\ No newline at end of file
index 0c654d3dc4aa2bf3bdac7c4f1e8a28462f37232e..01156fc5d89281f58b0089f5e64ab9e07a5935cd 100644 (file)
@@ -1774,6 +1774,9 @@ static int xferOptimization(
   if( pSrc==pDest ){
     return 0;   /* tab1 and tab2 may not be the same table */
   }
+  if( HasRowid(pDest)!=HasRowid(pSrc) ){
+    return 0;   /* source and destination must both be WITHOUT ROWID or not */
+  }
 #ifndef SQLITE_OMIT_VIRTUALTABLE
   if( pSrc->tabFlags & TF_Virtual ){
     return 0;   /* tab2 must not be a virtual table */
@@ -1788,6 +1791,9 @@ static int xferOptimization(
   if( pDest->iPKey!=pSrc->iPKey ){
     return 0;   /* Both tables must have the same INTEGER PRIMARY KEY */
   }
+  if( HasRowid(pDest)!=HasRowid(pSrc) ){
+    return 0;   /* source and destination must both be WITHOUT ROWID or not */
+  }
   for(i=0; i<pDest->nCol; i++){
     if( pDest->aCol[i].affinity!=pSrc->aCol[i].affinity ){
       return 0;    /* Affinity must be the same on all columns */
@@ -1844,60 +1850,62 @@ static int xferOptimization(
   iSrc = pParse->nTab++;
   iDest = pParse->nTab++;
   regAutoinc = autoIncBegin(pParse, iDbDest, pDest);
-  sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
-  if( (pDest->iPKey<0 && pDest->pIndex!=0)          /* (1) */
-   || destHasUniqueIdx                              /* (2) */
-   || (onError!=OE_Abort && onError!=OE_Rollback)   /* (3) */
-  ){
-    /* In some circumstances, we are able to run the xfer optimization
-    ** only if the destination table is initially empty.  This code makes
-    ** that determination.  Conditions under which the destination must
-    ** be empty:
-    **
-    ** (1) There is no INTEGER PRIMARY KEY but there are indices.
-    **     (If the destination is not initially empty, the rowid fields
-    **     of index entries might need to change.)
-    **
-    ** (2) The destination has a unique index.  (The xfer optimization 
-    **     is unable to test uniqueness.)
-    **
-    ** (3) onError is something other than OE_Abort and OE_Rollback.
-    */
-    addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iDest, 0);
-    emptyDestTest = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
-    sqlite3VdbeJumpHere(v, addr1);
-  }else{
-    emptyDestTest = 0;
-  }
-  sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead);
-  emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0);
   regData = sqlite3GetTempReg(pParse);
   regRowid = sqlite3GetTempReg(pParse);
-  if( pDest->iPKey>=0 ){
-    addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
-    addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
-    sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_PRIMARYKEY,
-        onError, "PRIMARY KEY must be unique", P4_STATIC);
-    sqlite3VdbeJumpHere(v, addr2);
-    autoIncStep(pParse, regAutoinc, regRowid);
-  }else if( pDest->pIndex==0 ){
-    addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid);
-  }else{
-    addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
-    assert( (pDest->tabFlags & TF_Autoincrement)==0 );
-  }
-  sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData);
-  sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid);
-  sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
-  sqlite3VdbeChangeP4(v, -1, pDest->zName, 0);
-  sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1);
+  if( HasRowid(pSrc) ){
+    sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
+    if( (pDest->iPKey<0 && pDest->pIndex!=0)          /* (1) */
+     || destHasUniqueIdx                              /* (2) */
+     || (onError!=OE_Abort && onError!=OE_Rollback)   /* (3) */
+    ){
+      /* In some circumstances, we are able to run the xfer optimization
+      ** only if the destination table is initially empty.  This code makes
+      ** that determination.  Conditions under which the destination must
+      ** be empty:
+      **
+      ** (1) There is no INTEGER PRIMARY KEY but there are indices.
+      **     (If the destination is not initially empty, the rowid fields
+      **     of index entries might need to change.)
+      **
+      ** (2) The destination has a unique index.  (The xfer optimization 
+      **     is unable to test uniqueness.)
+      **
+      ** (3) onError is something other than OE_Abort and OE_Rollback.
+      */
+      addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iDest, 0);
+      emptyDestTest = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
+      sqlite3VdbeJumpHere(v, addr1);
+    }else{
+      emptyDestTest = 0;
+    }
+    sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead);
+    emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0);
+    if( pDest->iPKey>=0 ){
+      addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
+      addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
+      sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_PRIMARYKEY,
+          onError, "PRIMARY KEY must be unique", P4_STATIC);
+      sqlite3VdbeJumpHere(v, addr2);
+      autoIncStep(pParse, regAutoinc, regRowid);
+    }else if( pDest->pIndex==0 ){
+      addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid);
+    }else{
+      addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
+      assert( (pDest->tabFlags & TF_Autoincrement)==0 );
+    }
+    sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData);
+    sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid);
+    sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
+    sqlite3VdbeChangeP4(v, -1, pDest->zName, 0);
+    sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1);
+    sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
+    sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
+  }
   for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
     for(pSrcIdx=pSrc->pIndex; ALWAYS(pSrcIdx); pSrcIdx=pSrcIdx->pNext){
       if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
     }
     assert( pSrcIdx );
-    sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
-    sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
     pKey = sqlite3IndexKeyinfo(pParse, pSrcIdx);
     sqlite3VdbeAddOp4(v, OP_OpenRead, iSrc, pSrcIdx->tnum, iDbSrc,
                       (char*)pKey, P4_KEYINFO_HANDOFF);
@@ -1912,12 +1920,12 @@ static int xferOptimization(
     sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1);
     sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1);
     sqlite3VdbeJumpHere(v, addr1);
+    sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
+    sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
   }
   sqlite3VdbeJumpHere(v, emptySrcTest);
   sqlite3ReleaseTempReg(pParse, regRowid);
   sqlite3ReleaseTempReg(pParse, regData);
-  sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
-  sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
   if( emptyDestTest ){
     sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_OK, 0);
     sqlite3VdbeJumpHere(v, emptyDestTest);
index 5d41d93e0dce400bfc3e5bf598dfc8cfadfc65b0..936a44a7fe1b7f237bc8b6aca1c4221f57f4dfe7 100644 (file)
@@ -234,7 +234,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
   rc = execExecSql(db, pzErrMsg,
       "SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14) "
       "  FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
-      "   AND rootpage>0"
+      "   AND coalesce(rootpage,1)>0"
   );
   if( rc!=SQLITE_OK ) goto end_of_vacuum;
   rc = execExecSql(db, pzErrMsg,
@@ -255,7 +255,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
       "|| ' SELECT * FROM main.' || quote(name) || ';'"
       "FROM main.sqlite_master "
       "WHERE type = 'table' AND name!='sqlite_sequence' "
-      "  AND rootpage>0"
+      "  AND coalesce(rootpage,1)>0"
   );
   if( rc!=SQLITE_OK ) goto end_of_vacuum;