--- /dev/null
+# 2022 November 07
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+#
+
+source [file join [file dirname [info script]] rbu_common.tcl]
+set ::testprefix rburename
+
+
+do_execsql_test 1.0 {
+ CREATE TABLE t1(a, b);
+ INSERT INTO t1 VALUES(1, 2);
+ INSERT INTO t1 VALUES(3, 4);
+ INSERT INTO t1 VALUES(5, 6);
+}
+
+forcedelete test.db-vacuum
+
+proc my_rename {old new} {
+ lappend ::my_rename_calls [list [file tail $old] [file tail $new]]
+ file rename $old $new
+}
+
+do_test 1.1 {
+ sqlite3rbu_vacuum rbu test.db
+ rbu rename_handler my_rename
+ while {[rbu step]=="SQLITE_OK"} {}
+ rbu close
+} SQLITE_DONE
+
+do_test 1.2 {
+ set ::my_rename_calls
+} {{test.db-oal test.db-wal}}
+
+proc my_rename {old new} {
+ error "something went wrong"
+}
+
+do_test 1.3 {
+ sqlite3rbu_vacuum rbu test.db
+ rbu rename_handler my_rename
+ while {[rbu step]=="SQLITE_OK"} {}
+ list [catch { rbu close } msg] $msg
+} {1 SQLITE_IOERR}
+
+finish_test
int nPagePerSector; /* Pages per sector for pTargetFd */
i64 iOalSz;
i64 nPhaseOneStep;
+ void *pRenameArg;
+ int (*xRename)(void*, const char*, const char*);
/* The following state variables are used as part of the incremental
** checkpoint stage (eStage==RBU_STAGE_CKPT). See comments surrounding
}
if( p->rc==SQLITE_OK ){
-#if defined(_WIN32_WCE)
- {
- LPWSTR zWideOal;
- LPWSTR zWideWal;
-
- zWideOal = rbuWinUtf8ToUnicode(zOal);
- if( zWideOal ){
- zWideWal = rbuWinUtf8ToUnicode(zWal);
- if( zWideWal ){
- if( MoveFileW(zWideOal, zWideWal) ){
- p->rc = SQLITE_OK;
- }else{
- p->rc = SQLITE_IOERR;
- }
- sqlite3_free(zWideWal);
- }else{
- p->rc = SQLITE_IOERR_NOMEM;
- }
- sqlite3_free(zWideOal);
- }else{
- p->rc = SQLITE_IOERR_NOMEM;
- }
- }
-#else
- p->rc = rename(zOal, zWal) ? SQLITE_IOERR : SQLITE_OK;
-#endif
+ p->rc = p->xRename(p->pRenameArg, zOal, zWal);
}
if( p->rc!=SQLITE_OK
/* Create the custom VFS. */
memset(p, 0, sizeof(sqlite3rbu));
+ sqlite3rbu_rename_handler(p, 0, 0);
rbuCreateVfs(p);
/* Open the target, RBU and state databases */
return rc;
}
+/*
+** Default xRename callback for RBU.
+*/
+static int xDefaultRename(void *pArg, const char *zOld, const char *zNew){
+ int rc = SQLITE_OK;
+#if defined(_WIN32_WCE)
+ {
+ LPWSTR zWideOld;
+ LPWSTR zWideNew;
+
+ zWideOld = rbuWinUtf8ToUnicode(zOld);
+ if( zWideOld ){
+ zWideNew = rbuWinUtf8ToUnicode(zNew);
+ if( zWideNew ){
+ if( MoveFileW(zWideOld, zWideNew) ){
+ rc = SQLITE_OK;
+ }else{
+ rc = SQLITE_IOERR;
+ }
+ sqlite3_free(zWideNew);
+ }else{
+ rc = SQLITE_IOERR_NOMEM;
+ }
+ sqlite3_free(zWideOld);
+ }else{
+ rc = SQLITE_IOERR_NOMEM;
+ }
+ }
+#else
+ rc = rename(zOld, zNew) ? SQLITE_IOERR : SQLITE_OK;
+#endif
+ return rc;
+}
+
+void sqlite3rbu_rename_handler(
+ sqlite3rbu *pRbu,
+ void *pArg,
+ int (*xRename)(void *pArg, const char *zOld, const char *zNew)
+){
+ if( xRename ){
+ pRbu->xRename = xRename;
+ pRbu->pRenameArg = pArg;
+ }else{
+ pRbu->xRename = xDefaultRename;
+ pRbu->pRenameArg = 0;
+ }
+}
+
/**************************************************************************
** Beginning of RBU VFS shim methods. The VFS shim modifies the behaviour
** of a standard VFS in the following ways:
SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu);
+/*
+** As part of applying an RBU update or performing an RBU vacuum operation,
+** the system must at one point move the *-oal file to the equivalent *-wal
+** path. Normally, it does this by invoking POSIX function rename(2) directly.
+** Except on WINCE platforms, where it uses win32 API MoveFileW(). This
+** function may be used to register a callback that the RBU module will invoke
+** instead of one of these APIs.
+**
+** If a callback is registered with an RBU handle, it invokes it instead
+** of rename(2) when it needs to move a file within the file-system. The
+** first argument passed to the xRename() callback is a copy of the second
+** argument (pArg) passed to this function. The second is the full path
+** to the file to move and the third the full path to which it should be
+** moved. The callback function should return SQLITE_OK to indicate
+** success. If an error occurs, it should return an SQLite error code.
+** In this case the RBU operation will be abandoned and the error returned
+** to the RBU user.
+**
+** Passing a NULL pointer in place of the xRename argument to this function
+** restores the default behaviour.
+*/
+SQLITE_API void sqlite3rbu_rename_handler(
+ sqlite3rbu *pRbu,
+ void *pArg,
+ int (*xRename)(void *pArg, const char *zOld, const char *zNew)
+);
+
+
/*
** Create an RBU VFS named zName that accesses the underlying file-system
** via existing VFS zParent. Or, if the zParent parameter is passed NULL,
# endif
#endif
#include <assert.h>
+#include <string.h>
+
+typedef struct TestRbu TestRbu;
+struct TestRbu {
+ sqlite3rbu *pRbu;
+ Tcl_Interp *interp;
+ Tcl_Obj *xRename;
+};
/* From main.c */
extern const char *sqlite3ErrName(int);
Tcl_DecrRefCount(pScript);
}
+static int xRenameCallback(void *pArg, const char *zOld, const char *zNew){
+ int rc = SQLITE_OK;
+ TestRbu *pTest = (TestRbu*)pArg;
+ Tcl_Obj *pEval = Tcl_DuplicateObj(pTest->xRename);
+
+ Tcl_IncrRefCount(pEval);
+ Tcl_ListObjAppendElement(pTest->interp, pEval, Tcl_NewStringObj(zOld, -1));
+ Tcl_ListObjAppendElement(pTest->interp, pEval, Tcl_NewStringObj(zNew, -1));
+
+ rc = Tcl_EvalObjEx(pTest->interp, pEval, TCL_GLOBAL_ONLY);
+ Tcl_DecrRefCount(pEval);
+
+ return rc ? SQLITE_IOERR : SQLITE_OK;
+}
static int SQLITE_TCLAPI test_sqlite3rbu_cmd(
ClientData clientData,
Tcl_Obj *CONST objv[]
){
int ret = TCL_OK;
- sqlite3rbu *pRbu = (sqlite3rbu*)clientData;
+ TestRbu *pTest = (TestRbu*)clientData;
+ sqlite3rbu *pRbu = pTest->pRbu;
struct RbuCmd {
const char *zName;
int nArg;
{"temp_size_limit", 3, "LIMIT"}, /* 10 */
{"temp_size", 2, ""}, /* 11 */
{"dbRbu_eval", 3, "SQL"}, /* 12 */
+ {"rename_handler", 3, "SCRIPT"},/* 13 */
{0,0,0}
};
int iCmd;
}
ret = TCL_ERROR;
}
+ if( pTest->xRename ) Tcl_DecrRefCount(pTest->xRename);
+ ckfree(pTest);
break;
}
break;
}
+ case 13: /* rename_handler */ {
+ Tcl_Obj *pScript = objv[2];
+ assert( !sqlite3_stricmp(aCmd[13].zName, "rename_handler") );
+ if( Tcl_GetCharLength(pScript)==0 ){
+ sqlite3rbu_rename_handler(pRbu, 0, 0);
+ }else{
+ pTest->xRename = Tcl_DuplicateObj(pScript);
+ Tcl_IncrRefCount(pTest->xRename);
+ sqlite3rbu_rename_handler(pRbu, pTest, xRenameCallback);
+ }
+ break;
+ }
+
default: /* seems unlikely */
assert( !"cannot happen" );
break;
return ret;
}
+static void createRbuWrapper(
+ Tcl_Interp *interp,
+ const char *zCmd,
+ sqlite3rbu *pRbu
+){
+ TestRbu *pTest = (TestRbu*)ckalloc(sizeof(TestRbu));
+ memset(pTest, 0, sizeof(TestRbu));
+ pTest->pRbu = pRbu;
+ pTest->interp = interp;
+ Tcl_CreateObjCommand(interp, zCmd, test_sqlite3rbu_cmd, (ClientData)pTest, 0);
+}
+
/*
** Tclcmd: sqlite3rbu CMD <target-db> <rbu-db> ?<state-db>?
*/
if( objc==5 ) zStateDb = Tcl_GetString(objv[4]);
pRbu = sqlite3rbu_open(zTarget, zRbu, zStateDb);
- Tcl_CreateObjCommand(interp, zCmd, test_sqlite3rbu_cmd, (ClientData)pRbu, 0);
+ createRbuWrapper(interp, zCmd, pRbu);
Tcl_SetObjResult(interp, objv[1]);
return TCL_OK;
}
if( zStateDb && zStateDb[0]=='\0' ) zStateDb = 0;
pRbu = sqlite3rbu_vacuum(zTarget, zStateDb);
- Tcl_CreateObjCommand(interp, zCmd, test_sqlite3rbu_cmd, (ClientData)pRbu, 0);
+ createRbuWrapper(interp, zCmd, pRbu);
Tcl_SetObjResult(interp, objv[1]);
return TCL_OK;
}
-C Minor\sdoc\supdates\sin\sspeed-check.sh.\sNo\scode\schanges.
-D 2022-11-07T17:21:53.311
+C Add\sthe\ssqlite3rbu_rename_handler()\sAPI.\sTo\soverride\sthe\sdefault\sroutine\sthat\sRBU\suses\sto\srename\sfiles.
+D 2022-11-07T18:00:18.684
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F ext/rbu/rbumulti.test 5fb139058f37ddc5a113c5b93238de915b769b7792de41b44c983bc7c18cf5b9
F ext/rbu/rbupartial.test f25df014b8dbe3c5345851fba6e66f79ab237f57dc201b2d5f0dbae658ae5a4c
F ext/rbu/rbuprogress.test 857cf1f8166c83ef977edb9ef4fc42d80f71fbd798652b46ae2f3a7031870f8d
+F ext/rbu/rburename.test a9b4aea612352b74c45de1757edd2ecb2079348b1d4cc734572dc29e55b1b376
F ext/rbu/rburesume.test dbdc4ca504e9c76375a69e5f0d91205db967dcc509a5166ca80231f8fda49eb1
F ext/rbu/rbusave.test f4190a1a86fccf84f723af5c93813365ae33feda35845ba107b59683d1cdd926
F ext/rbu/rbusplit.test b37e7b40b38760881dc9c854bd40b4744c6b6cd74990754eca3bda0f407051e8
F ext/rbu/rbuvacuum2.test 886add83fd74bcb02e6dd016ae5b585367bd58c5d0694c9d9ca7bdb1d1f578c2
F ext/rbu/rbuvacuum3.test 8addd82e4b83b4c93fa47428eae4fd0dbf410f8512c186f38e348feb49ba03dc
F ext/rbu/rbuvacuum4.test a78898e438a44803eb2bc897ba3323373c9f277418e2d6d76e90f2f1dbccfd10
-F ext/rbu/sqlite3rbu.c 8737cabdfbee84bb25a7851ecef8b1312be332761238da9be6ddb10c62ad4291
-F ext/rbu/sqlite3rbu.h 1dc88ab7bd32d0f15890ea08d23476c4198d3da3056985403991f8c9cd389812
-F ext/rbu/test_rbu.c 03f6f177096a5f822d68d8e4069ad8907fe572c62ff2d19b141f59742821828a
+F ext/rbu/sqlite3rbu.c 90b6b5be1cb6cbd9b7a7dc0c0641d5be63cf00cf9ec8c3b57d27217d28530ea9
+F ext/rbu/sqlite3rbu.h 02d981e2d39c151391759e1a400e29c7388730812957ac3db8dad7f6c9f9cfc8
+F ext/rbu/test_rbu.c ee6ede75147bc081fe9bc3931e6b206277418d14d3fbceea6fdc6216d9b47055
F ext/recover/dbdata.c 1d5353d3af247c4e0656f8f88a80564aa840644c1177212dd11a186dce4ab213
F ext/recover/recover1.test 02004eb8f9ec2825ba77e24742c18e45162cb21d27e76a3a435b83a759a1131a
F ext/recover/recover_common.tcl a61306c1eb45c0c3fc45652c35b2d4ec19729e340bdf65a272ce4c229cefd85a
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P e377c0a1ef030395293c5f24d7cb8e5b36ce972e9fac31b99c8425075486a46a
-R f5acca92b76100558a23567d01b4e532
-U stephan
-Z f9eb95c0c00a0b5ae6e90e4af7b92086
+P d2ed4116fbf1de3c840f84e05db6f29f7b489518ac07d56f61df153deab6bf6b
+R 883198cf0956cf3ea945ee8907257d82
+U dan
+Z f0f97d889869754ab1656f4d9587d370
# Remove this line to create a well-formed Fossil manifest.
-d2ed4116fbf1de3c840f84e05db6f29f7b489518ac07d56f61df153deab6bf6b
\ No newline at end of file
+ebbb1f88e7b5d6cbe84d400f1a187acedb4c668d0b7e4c63bf1496e57da9b8ad
\ No newline at end of file