From 126537e1dccc5f9006679ebcde202de36a8df636 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 7 May 2019 16:28:50 +0000 Subject: [PATCH] Remove some redundant code from sqlite3rbu.c. Add test cases for RBU vacuum. FossilOrigin-Name: 7b051698d8a763d9db190fd662931266d24a4982f34f100a28641934c222e37b --- ext/rbu/rbuvacuum4.test | 23 ++++++++- ext/rbu/sqlite3rbu.c | 100 ++++++++++++++++++++++++++-------------- manifest | 14 +++--- manifest.uuid | 2 +- 4 files changed, 96 insertions(+), 43 deletions(-) diff --git a/ext/rbu/rbuvacuum4.test b/ext/rbu/rbuvacuum4.test index 751d9e9250..9984c9120a 100644 --- a/ext/rbu/rbuvacuum4.test +++ b/ext/rbu/rbuvacuum4.test @@ -71,6 +71,7 @@ do_execsql_test 4.0 { INSERT INTO x1 VALUES(NULL, 2, 5, NULL); CREATE INDEX x1ad ON x1(d, a); + CREATE INDEX x1null ON x1(d, a) WHERE d>15; } do_rbu_vacuum_test 4.1.1 1 @@ -81,6 +82,26 @@ do_execsql_test 4.2 { do_rbu_vacuum_test 4.1.2 0 -finish_test +#------------------------------------------------------------------------- +reset_db +do_execsql_test 5.0 { + CREATE TABLE "a b c"(a, "b b" PRIMARY KEY, "c c"); + CREATE INDEX abc1 ON "a b c"(a, "c c"); + + INSERT INTO "a b c" VALUES(NULL, 'a', NULL); + INSERT INTO "a b c" VALUES(NULL, 'b', NULL); + INSERT INTO "a b c" VALUES(NULL, 'c', NULL); + + INSERT INTO "a b c" VALUES(1, 2, 3); + INSERT INTO "a b c" VALUES(3, 9, 1); + INSERT INTO "a b c" VALUES('aaa', 'bbb', 'ccc'); + CREATE TABLE x(a); + INSERT INTO x VALUES('a'), ('b'), ('d'); + CREATE UNIQUE INDEX y ON x(a); +} + +do_rbu_vacuum_test 5.1 1 + +finish_test diff --git a/ext/rbu/sqlite3rbu.c b/ext/rbu/sqlite3rbu.c index 37acecff00..0ed2837ca7 100644 --- a/ext/rbu/sqlite3rbu.c +++ b/ext/rbu/sqlite3rbu.c @@ -930,7 +930,8 @@ static void rbuTargetNameFunc( zIn = (const char*)sqlite3_value_text(argv[0]); if( zIn ){ if( rbuIsVacuum(p) ){ - if( argc==1 || 0==sqlite3_value_int(argv[1]) ){ + assert( argc==2 ); + if( 0==sqlite3_value_int(argv[1]) ){ sqlite3_result_text(pCtx, zIn, -1, SQLITE_STATIC); } }else{ @@ -1417,10 +1418,18 @@ static char *rbuObjIterGetCollist( return zList; } +/* +** Return a comma separated list of the quoted PRIMARY KEY column names, +** in order, for the current table. Before each column name, add the text +** zPre. After each column name, add the zPost text. Use zSeparator as +** the separator text (usually ", "). +*/ static char *rbuObjIterGetPkList( sqlite3rbu *p, /* RBU object */ RbuObjIter *pIter, /* Object iterator for column names */ - const char *zExtra + const char *zPre, /* Before each quoted column name */ + const char *zSeparator, /* Separator to use between columns */ + const char *zPost /* After each quoted column name */ ){ int iPk = 1; char *zRet = 0; @@ -1430,8 +1439,9 @@ static char *rbuObjIterGetPkList( for(i=0; inTblCol; i++){ if( (int)pIter->abTblPk[i]==iPk ){ const char *zCol = pIter->azTblCol[i]; - zRet = rbuMPrintf(p, "%z%s\"%w\"%s", zRet, zSep, zCol, zExtra); - zSep = ", "; + zRet = rbuMPrintf(p, "%z%s%s\"%w\"%s", zRet, zSep, zPre, zCol, zPost); + zSep = zSeparator; + break; } } if( i==pIter->nTblCol ) break; @@ -1440,11 +1450,30 @@ static char *rbuObjIterGetPkList( return zRet; } +/* +** This function is called as part of restarting an RBU vacuum within +** stage 1 of the process (while the *-oal file is being built) while +** updating a table (not an index). The table may be a rowid table or +** a WITHOUT ROWID table. It queries the target database to find the +** largest key that has already been written to the target table and +** constructs a WHERE clause that can be used to extract the remaining +** rows from the source table. For a rowid table, the WHERE clause +** is of the form: +** +** "WHERE _rowid_ > ?" +** +** and for WITHOUT ROWID tables: +** +** "WHERE (key1, key2) > (?, ?)" +** +** Instead of "?" placeholders, the actual WHERE clauses created by +** this function contain literal SQL values. +*/ static char *rbuVacuumTableStart( - sqlite3rbu *p, - RbuObjIter *pIter, - int bRowid, - const char *zWrite + sqlite3rbu *p, /* RBU handle */ + RbuObjIter *pIter, /* RBU iterator object */ + int bRowid, /* True for a rowid table */ + const char *zWrite /* Target table name prefix */ ){ sqlite3_stmt *pMax = 0; char *zRet = 0; @@ -1460,28 +1489,9 @@ static char *rbuVacuumTableStart( } rbuFinalize(p, pMax); }else{ - char *zOrder = 0; - char *zSelect = 0; - char *zList = 0; - int iPk = 1; - const char *zSep = ""; - const char *zSep2 = ""; - while( 1 ){ - int i; - for(i=0; inTblCol; i++){ - if( (int)pIter->abTblPk[i]==iPk ){ - const char *zCol = pIter->azTblCol[i]; - zOrder = rbuMPrintf(p, "%z%s\"%w\" DESC", zOrder, zSep, zCol); - zList = rbuMPrintf(p, "%z%s\"%w\"", zList, zSep, zCol); - zSelect = rbuMPrintf(p, "%z%squote(\"%w\")", zSelect, zSep2, zCol); - zSep = ", "; - zSep2 = "||','||"; - break; - } - } - if( i==pIter->nTblCol ) break; - iPk++; - } + char *zOrder = rbuObjIterGetPkList(p, pIter, "", ", ", " DESC"); + char *zSelect = rbuObjIterGetPkList(p, pIter, "quote(", "||','||", ")"); + char *zList = rbuObjIterGetPkList(p, pIter, "", ", ", ""); if( p->rc==SQLITE_OK ){ p->rc = prepareFreeAndCollectError(p->dbMain, &pMax, &p->zErrmsg, @@ -1504,9 +1514,31 @@ static char *rbuVacuumTableStart( return zRet; } +/* +** This function is called as part of restating an RBU vacuum when the +** current operation is writing content to an index. If possible, it +** queries the target index b-tree for the largest key already written to +** it, then composes and returns an expression that can be used in a WHERE +** clause to select the remaining required rows from the source table. +** It is only possible to return such an expression if: +** +** * The index contains no DESC columns, and +** * The last key written to the index before the operation was +** suspended does not contain any NULL values. +** +** The expression is of the form: +** +** (index-field1, index-field2, ...) > (?, ?, ...) +** +** except that the "?" placeholders are replaced with literal values. +** +** If the expression cannot be created, NULL is returned. In this case, +** the caller has to use an OFFSET clause to extract only the required +** rows from the sourct table, just as it does for an RBU update operation. +*/ char *rbuVacuumIndexStart( - sqlite3rbu *p, - RbuObjIter *pIter + sqlite3rbu *p, /* RBU handle */ + RbuObjIter *pIter /* RBU iterator object */ ){ char *zOrder = 0; char *zLhs = 0; @@ -2274,7 +2306,7 @@ static int rbuObjIterPrepareAll( if( p->rc==SQLITE_OK ){ char *zSql; if( rbuIsVacuum(p) ){ - const char *zStart = 0; + char *zStart = 0; if( nOffset ){ zStart = rbuVacuumIndexStart(p, pIter); if( zStart ){ @@ -2435,7 +2467,7 @@ static int rbuObjIterPrepareAll( if( bRbuRowid ){ zOrder = rbuMPrintf(p, "_rowid_"); }else{ - zOrder = rbuObjIterGetPkList(p, pIter, ""); + zOrder = rbuObjIterGetPkList(p, pIter, "", ", ", ""); } } diff --git a/manifest b/manifest index 44ed7b69ca..69f1d68b6d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Optimize\sfurther\scases\sof\srestarting\san\sRBU\svacuum. -D 2019-05-06T20:40:23.801 +C Remove\ssome\sredundant\scode\sfrom\ssqlite3rbu.c.\sAdd\stest\scases\sfor\sRBU\svacuum. +D 2019-05-07T16:28:50.534 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -359,8 +359,8 @@ F ext/rbu/rbutemplimit.test 7f408f49b90fa0a720d7599f3aec74a3c85e6cd78e56fdf726ce F ext/rbu/rbuvacuum.test 55e101e90168c2b31df6c9638fe73dc7f7cc666b6142266d1563697d79f73534 F ext/rbu/rbuvacuum2.test b8e5b51dc8b2c0153373d024c0936be3f66f9234acbd6d0baab0869d56b14e6b F ext/rbu/rbuvacuum3.test 8addd82e4b83b4c93fa47428eae4fd0dbf410f8512c186f38e348feb49ba03dc -F ext/rbu/rbuvacuum4.test fcae689344a28acf1013c9e2563d334f15ef741f5a16396945701ab90799e877 -F ext/rbu/sqlite3rbu.c e2669fb2a716615f38628a0477ecd665a040970501cba2511e9dffe066e2c9c8 +F ext/rbu/rbuvacuum4.test 08abd9e18d8aee5bb812de0d6a928cc8bbacae58ecb1f150637e80f4c93c8afa +F ext/rbu/sqlite3rbu.c ec93d28c5cef16ccef7ed76c2b6c410e8eb078c73705b6e7b683f88f722228f2 F ext/rbu/sqlite3rbu.h 1dc88ab7bd32d0f15890ea08d23476c4198d3da3056985403991f8c9cd389812 F ext/rbu/test_rbu.c 03f6f177096a5f822d68d8e4069ad8907fe572c62ff2d19b141f59742821828a F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15 @@ -1824,7 +1824,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 cdc09867ed6522026ae7bfac1f59cd79b60fba6d07d49b99b030a501a7059ee4 -R aeb9fedb3c4f55c16b474638fcef63d3 +P 6b3261bfa1d762aa29a57244a30cf5e35655f1fe9c30ee682c186dec29d7a2c2 +R 4a715a784b4b470a8ebf2ddbf655a0cc U dan -Z ccdab55de99d2c516e9414504dca1a30 +Z c393b32565e9671e4034603b54f16352 diff --git a/manifest.uuid b/manifest.uuid index 049d28edef..366634c67e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6b3261bfa1d762aa29a57244a30cf5e35655f1fe9c30ee682c186dec29d7a2c2 \ No newline at end of file +7b051698d8a763d9db190fd662931266d24a4982f34f100a28641934c222e37b \ No newline at end of file -- 2.39.5