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
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
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{
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;
for(i=0; i<pIter->nTblCol; 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;
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;
}
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; i<pIter->nTblCol; 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,
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;
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 ){
if( bRbuRowid ){
zOrder = rbuMPrintf(p, "_rowid_");
}else{
- zOrder = rbuObjIterGetPkList(p, pIter, "");
+ zOrder = rbuObjIterGetPkList(p, pIter, "", ", ", "");
}
}
-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
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
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