From: drh Date: Sat, 8 Dec 2018 00:43:08 +0000 (+0000) Subject: Allow the INTO clause of VACUUM to be a text-valued expression. X-Git-Tag: version-3.27.0~312^2~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2f6239ed4e7d8e152de77d00aae4678d62d7e4f3;p=thirdparty%2Fsqlite.git Allow the INTO clause of VACUUM to be a text-valued expression. FossilOrigin-Name: af172b53b46759f491f522356e14c5e2374d3f25ec70fbc1e100cadded8f9b22 --- diff --git a/manifest b/manifest index 635f30acfa..52fef86043 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 4f71499d96..d2641d7679 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -92f70e0fa3c9de7fde046f11cc0a7c2800511bb5ace8e68c845133931607616e \ No newline at end of file +af172b53b46759f491f522356e14c5e2374d3f25ec70fbc1e100cadded8f9b22 \ No newline at end of file diff --git a/src/parse.y b/src/parse.y index dbbd40775e..3f9384c86c 100644 --- a/src/parse.y +++ b/src/parse.y @@ -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 diff --git a/src/sqliteInt.h b/src/sqliteInt.h index e175de9518..0412a33523 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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); diff --git a/src/vacuum.c b/src/vacuum.c index a28541cc58..b4041b6d97 100644 --- a/src/vacuum.c +++ b/src/vacuum.c @@ -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; ireadOnly==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; } diff --git a/test/vacuum-into.test b/test/vacuum-into.test index f04c0becac..cb91abc5d9 100644 --- a/test/vacuum-into.test +++ b/test/vacuum-into.test @@ -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