]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Allow the INTO clause of VACUUM to be a text-valued expression.
authordrh <drh@noemail.net>
Sat, 8 Dec 2018 00:43:08 +0000 (00:43 +0000)
committerdrh <drh@noemail.net>
Sat, 8 Dec 2018 00:43:08 +0000 (00:43 +0000)
FossilOrigin-Name: af172b53b46759f491f522356e14c5e2374d3f25ec70fbc1e100cadded8f9b22

manifest
manifest.uuid
src/parse.y
src/sqliteInt.h
src/vacuum.c
src/vdbe.c
test/vacuum-into.test

index 635f30acfac1df09bfe7fbe40145bbed9689fab0..52fef86043ecbe71b24795e2a29b1621f91e2696 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Do\snot\sallow\sVACUUM\sINTO\sinto\sa\sfile\sthat\salready\sexists.
-D 2018-12-07T23:48:41.554
+C Allow\sthe\sINTO\sclause\sof\sVACUUM\sto\sbe\sa\stext-valued\sexpression.
+D 2018-12-08T00:43:08.028
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F Makefile.in 68d0ba0f0b533d5bc84c78c13a6ce84ee81183a67014caa47a969e67f028fa1c
@@ -496,7 +496,7 @@ F src/os_win.c 85d9e532d0444ab6c16d7431490c2e279e282aa0917b0e988996b1ae0de5c5a0
 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
 F src/pager.c 75e0f3cfa3962c714f519f8a3d1e67ecca1c91de0e010a036b988e40ce9e4c73
 F src/pager.h 217921e81eb5fe455caa5cda96061959706bcdd29ddb57166198645ef7822ac3
-F src/parse.y 3bf1b720e70a3cfb08f491913f61b181d71576879146d68ee845f6d77c6bdc70
+F src/parse.y a3c0db595bc642c6ee1d72869842f7f5b0b6ebeb91c21d0a7cba631d27e7afbd
 F src/pcache.c 696a01f1a6370c1b50a09c15972bc3bee3333f8fcd1f2da8e9a76b1b062c59ee
 F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
 F src/pcache1.c ad0ffc5b35b0280d045ac569d34d4b842e3e6a4a118f6396b320987a0957afcc
@@ -512,7 +512,7 @@ F src/shell.c.in 1f0819e69fb1ebd2eb44695530dc43936608bf9b752981a0ffd4e2e4a9e3883
 F src/sqlite.h.in 908ec406feefc4c7e1486a2e3dc30a8bfb51c5a345a8e8130ac201962db171c4
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 960f1b86c3610fa23cb6a267572a97dcf286e77aa0dd3b9b23292ffaa1ea8683
-F src/sqliteInt.h fa86b5689fae6d3b446fcae0430e4d1f3757bf5e72d0ca2e34d1287a2c3643f2
+F src/sqliteInt.h 70ce5e14c887554d3c51f2045f5a95b6e83de745d7f6448e79e49fdd8dfc2d5c
 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
 F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
 F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
@@ -577,8 +577,8 @@ F src/update.c 1816d56c1bca1ba4e0ef98cac2f49be62858e9df1dc08844c7067eb41cc44274
 F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4
 F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
 F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
-F src/vacuum.c 5d49497308883e608bb420c112e87c10417b576af2a6d1dd0dba62d4a494ffd7
-F src/vdbe.c 872bdd34338548242b36df18c49c90b34689e41c0b4e5c197e83bb82a38ce8dd
+F src/vacuum.c 3ffe64ecfc94b7528c5d7bdb1c3a19d72fec63f2aa846e3b90f8de5dbbddf5aa
+F src/vdbe.c 55bafc424748d9ed505ab2680736e51d1bb05c01e9885cbb3b287b51dc8b47ec
 F src/vdbe.h d82f323d581b36b8e147d650257ef34e0e93790039b6cbda45c321c275f7595e
 F src/vdbeInt.h 73f5051923f3f29779bfc374c0c68e23b8e5e3792def2e33e51b427edb890abd
 F src/vdbeapi.c 9709452bee82963e1f7f1f5d0c71db823d553f8dbb2c47a911c4983d537a1947
@@ -1562,7 +1562,7 @@ F test/uri.test 3481026f00ade6dfe8adb7acb6e1e47b04369568
 F test/uri2.test 9d3ba7a53ee167572d53a298ee4a5d38ec4a8fb7
 F test/userauth01.test e740a2697a7b40d7c5003a7d7edaee16acd349a9
 F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
-F test/vacuum-into.test dab9e498ea303f27370e71eb7e9a3369eb71ae90f4ea1afa741a1347ece39f5d
+F test/vacuum-into.test 181a8ae8c2479d88ebc118076e8cfbc062ad8f8a51b56a139bd12870a8a84c34
 F test/vacuum.test ce91c39f7f91a4273bf620efad21086b5aa6ef1d
 F test/vacuum2.test aa048abee196c16c9ba308465494009057b79f9b
 F test/vacuum3.test 77ecdd54592b45a0bcb133339f99f1ae0ae94d0d
@@ -1783,7 +1783,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 93d92a0a5d21a1856316c0205ecaa253691b6e5349b552d43027005676d14820
-R 4b91cbcd00a28fb8ade4cd8b52c5b6e4
+P 92f70e0fa3c9de7fde046f11cc0a7c2800511bb5ace8e68c845133931607616e
+R f797d08299c49f27762cbb498a2316b3
 U drh
-Z b3677de0205f375bf2be187f033f6ce8
+Z 0107ff29eb1054c07981156ef518bc62
index 4f71499d9692edb7b7ed1ce9185e51e79d67cfc2..d2641d767951352a6becd936f95fe7a7a7daf84e 100644 (file)
@@ -1 +1 @@
-92f70e0fa3c9de7fde046f11cc0a7c2800511bb5ace8e68c845133931607616e
\ No newline at end of file
+af172b53b46759f491f522356e14c5e2374d3f25ec70fbc1e100cadded8f9b22
\ No newline at end of file
index dbbd40775ed828e8a4185a226307da54c6e5de12..3f9384c86cfef75f1c30eb026d3965fe6d405aeb 100644 (file)
@@ -1367,11 +1367,12 @@ cmd ::= DROP INDEX ifexists(E) fullname(X).   {sqlite3DropIndex(pParse, X, E);}
 //
 %ifndef SQLITE_OMIT_VACUUM
 %ifndef SQLITE_OMIT_ATTACH
-%type vinto {Token}
-cmd ::= VACUUM vinto(Y).                {sqlite3Vacuum(pParse,0,&Y);}
-cmd ::= VACUUM nm(X) vinto(Y).          {sqlite3Vacuum(pParse,&X,&Y);}
-vinto(A) ::= INTO nm(X).                {A = X;}
-vinto(A) ::= .                          {A.z = 0;}
+%type vinto {Expr*}
+%destructor vinto {sqlite3ExprDelete(pParse->db, $$);}
+cmd ::= VACUUM vinto(Y).                {sqlite3Vacuum(pParse,0,Y);}
+cmd ::= VACUUM nm(X) vinto(Y).          {sqlite3Vacuum(pParse,&X,Y);}
+vinto(A) ::= INTO expr(X).              {A = X;}
+vinto(A) ::= .                          {A = 0;}
 %endif  SQLITE_OMIT_ATTACH
 %endif  SQLITE_OMIT_VACUUM
 
index e175de95184aee27ad52bbbaede742c5d796c121..0412a33523531bee16f2cca9ad2998a2d7b1e57a 100644 (file)
@@ -3985,8 +3985,8 @@ Table *sqlite3LocateTableItem(Parse*,u32 flags,struct SrcList_item *);
 Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
 void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
 void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
-void sqlite3Vacuum(Parse*,Token*,Token*);
-int sqlite3RunVacuum(char**, sqlite3*, int, const char*);
+void sqlite3Vacuum(Parse*,Token*,Expr*);
+int sqlite3RunVacuum(char**, sqlite3*, int, sqlite3_value*);
 char *sqlite3NameFromToken(sqlite3*, Token*);
 int sqlite3ExprCompare(Parse*,Expr*, Expr*, int);
 int sqlite3ExprCompareSkip(Expr*, Expr*, int);
index a28541cc58c79bc4c0b2be57abc324bc72d6b671..b4041b6d973419aa7ed7cf60a249049d3dd64812 100644 (file)
@@ -102,17 +102,16 @@ static int execSqlF(sqlite3 *db, char **pzErrMsg, const char *zSql, ...){
 ** transient would cause the database file to appear to be deleted
 ** following reboot.
 */
-void sqlite3Vacuum(Parse *pParse, Token *pNm, Token *pInto){
+void sqlite3Vacuum(Parse *pParse, Token *pNm, Expr *pInto){
   Vdbe *v = sqlite3GetVdbe(pParse);
   int iDb = 0;
-  assert( pInto!=0 );
-  if( v==0 ) return;
+  if( v==0 ) goto build_vacuum_end;
   if( pNm ){
 #ifndef SQLITE_BUG_COMPATIBLE_20160819
     /* Default behavior:  Report an error if the argument to VACUUM is
     ** not recognized */
     iDb = sqlite3TwoPartName(pParse, pNm, pNm, &pNm);
-    if( iDb<0 ) return;
+    if( iDb<0 ) goto build_vacuum_end;
 #else
     /* When SQLITE_BUG_COMPATIBLE_20160819 is defined, unrecognized arguments
     ** to VACUUM are silently ignored.  This is a back-out of a bug fix that
@@ -124,20 +123,28 @@ void sqlite3Vacuum(Parse *pParse, Token *pNm, Token *pInto){
 #endif
   }
   if( iDb!=1 ){
-    sqlite3VdbeAddOp1(v, OP_Vacuum, iDb);
-    sqlite3VdbeUsesBtree(v, iDb);
-    if( pInto->z ){
-      char *zName = sqlite3NameFromToken(pParse->db, pInto);
-      sqlite3VdbeChangeP4(v, -1, zName, P4_DYNAMIC);
+    int iIntoReg = 0;
+    if( pInto ){
+      iIntoReg = ++pParse->nMem;
+      sqlite3ExprCode(pParse, pInto, iIntoReg);
     }
+    sqlite3VdbeAddOp2(v, OP_Vacuum, iDb, iIntoReg);
+    sqlite3VdbeUsesBtree(v, iDb);
   }
+build_vacuum_end:
+  sqlite3ExprDelete(pParse->db, pInto);
   return;
 }
 
 /*
 ** This routine implements the OP_Vacuum opcode of the VDBE.
 */
-int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb, const char *zOut){
+int sqlite3RunVacuum(
+  char **pzErrMsg,        /* Write error message here */
+  sqlite3 *db,            /* Database connection */
+  int iDb,                /* Which attached DB to vacuum */
+  sqlite3_value *pOut     /* Write results here, if not NULL */
+){
   int rc = SQLITE_OK;     /* Return code from service routines */
   Btree *pMain;           /* The database being vacuumed */
   Btree *pTemp;           /* The temporary database we vacuum into */
@@ -151,6 +158,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb, const char *zOut){
   int nRes;               /* Bytes of reserved space at the end of each page */
   int nDb;                /* Number of attached databases */
   const char *zDbMain;    /* Schema name of database to vacuum */
+  const char *zOut;       /* Name of output file */
 
   if( !db->autoCommit ){
     sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
@@ -160,6 +168,15 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb, const char *zOut){
     sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress");
     return SQLITE_ERROR;
   }
+  if( pOut ){
+    if( sqlite3_value_type(pOut)!=SQLITE_TEXT ){
+      sqlite3SetString(pzErrMsg, db, "non-text filename");
+      return SQLITE_ERROR;
+    }
+    zOut = (const char*)sqlite3_value_text(pOut);
+  }else{
+    zOut = "";
+  }
 
   /* Save the current value of the database flags so that it can be 
   ** restored before returning. Then set the writable-schema flag, and
@@ -194,13 +211,13 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb, const char *zOut){
   ** to write the journal header file.
   */
   nDb = db->nDb;
-  rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut ? zOut : "");
+  rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut);
   if( rc!=SQLITE_OK ) goto end_of_vacuum;
   assert( (db->nDb-1)==nDb );
   pDb = &db->aDb[nDb];
   assert( strcmp(pDb->zDbSName,"vacuum_db")==0 );
   pTemp = pDb->pBt;
-  if( zOut!=0 ){
+  if( pOut ){
     sqlite3_file *id = sqlite3PagerFile(sqlite3BtreePager(pTemp));
     i64 sz = 0;
     if( id->pMethods!=0 && (sqlite3OsFileSize(id, &sz)!=SQLITE_OK || sz>0) ){
@@ -232,7 +249,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb, const char *zOut){
   */
   rc = execSql(db, pzErrMsg, "BEGIN");
   if( rc!=SQLITE_OK ) goto end_of_vacuum;
-  rc = sqlite3BtreeBeginTrans(pMain, zOut==0 ? 2 : 0, 0);
+  rc = sqlite3BtreeBeginTrans(pMain, pOut==0 ? 2 : 0, 0);
   if( rc!=SQLITE_OK ) goto end_of_vacuum;
 
   /* Do not attempt to change the page size for a WAL database */
@@ -327,7 +344,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb, const char *zOut){
     };
 
     assert( 1==sqlite3BtreeIsInTrans(pTemp) );
-    assert( zOut!=0 || 1==sqlite3BtreeIsInTrans(pMain) );
+    assert( pOut!=0 || 1==sqlite3BtreeIsInTrans(pMain) );
 
     /* Copy Btree meta values */
     for(i=0; i<ArraySize(aCopy); i+=2){
@@ -338,23 +355,21 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb, const char *zOut){
       if( NEVER(rc!=SQLITE_OK) ) goto end_of_vacuum;
     }
 
-    if( zOut==0 ){
+    if( pOut==0 ){
       rc = sqlite3BtreeCopyFile(pMain, pTemp);
-    }else{
-      rc = sqlite3BtreeCommit(pMain);
     }
     if( rc!=SQLITE_OK ) goto end_of_vacuum;
     rc = sqlite3BtreeCommit(pTemp);
     if( rc!=SQLITE_OK ) goto end_of_vacuum;
 #ifndef SQLITE_OMIT_AUTOVACUUM
-    if( zOut==0 ){
+    if( pOut==0 ){
       sqlite3BtreeSetAutoVacuum(pMain, sqlite3BtreeGetAutoVacuum(pTemp));
     }
 #endif
   }
 
   assert( rc==SQLITE_OK );
-  if( zOut==0 ){
+  if( pOut==0 ){
     rc = sqlite3BtreeSetPageSize(pMain, sqlite3BtreeGetPageSize(pTemp), nRes,1);
   }
 
index 179189eea7660bb2a7b08b01308391eb55678ed2..ebd599342a242a457b2efbf0956f31ab76c48836 100644 (file)
@@ -6684,18 +6684,19 @@ case OP_JournalMode: {    /* out2 */
 #endif /* SQLITE_OMIT_PRAGMA */
 
 #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
-/* Opcode: Vacuum P1 * * P4 *
+/* Opcode: Vacuum P1 P2 * * *
 **
 ** Vacuum the entire database P1.  P1 is 0 for "main", and 2 or more
 ** for an attached database.  The "temp" database may not be vacuumed.
 **
-** If P4 is not a NULL pointer, then it is a UTF8 string which is the
-** name of a file into which to write the result of the vacuum.  When
-** P4 is NULL, the result of vacuum overwrites the original database.
+** If P2 is not zero, then it is a register holding a string which is
+** the file into which the result of vacuum should be written.  When
+** P2 is zero, the vacuum overwrites the original database.
 */
 case OP_Vacuum: {
   assert( p->readOnly==0 );
-  rc = sqlite3RunVacuum(&p->zErrMsg, db, pOp->p1, pOp->p4.z);
+  rc = sqlite3RunVacuum(&p->zErrMsg, db, pOp->p1,
+                        pOp->p2 ? &aMem[pOp->p2] : 0);
   if( rc ) goto abort_due_to_error;
   break;
 }
index f04c0becaca587db090908743a2554f85222d3c0..cb91abc5d974ac0184e083f4991848c57481b67e 100644 (file)
@@ -55,4 +55,15 @@ do_catchsql_test vacuum-into-200 {
   VACUUM main INTO ':memory:';
 } {0 {}}
 
+# The INTO argument can be an arbitrary expression.
+#
+do_execsql_test vacuum-into-300 {
+  CREATE TABLE t2(name TEXT);
+  INSERT INTO t2 VALUES(':memory:');
+  VACUUM main INTO (SELECT name FROM t2);
+} {}
+do_catchsql_test vacuum-into-310 {
+  VACUUM INTO null;
+} {1 {non-text filename}}
+
 finish_test