]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the sqlite3rbu_rename_handler() API. To override the default routine that RBU...
authordan <Dan Kennedy>
Mon, 7 Nov 2022 18:00:18 +0000 (18:00 +0000)
committerdan <Dan Kennedy>
Mon, 7 Nov 2022 18:00:18 +0000 (18:00 +0000)
FossilOrigin-Name: ebbb1f88e7b5d6cbe84d400f1a187acedb4c668d0b7e4c63bf1496e57da9b8ad

ext/rbu/rburename.test [new file with mode: 0644]
ext/rbu/sqlite3rbu.c
ext/rbu/sqlite3rbu.h
ext/rbu/test_rbu.c
manifest
manifest.uuid

diff --git a/ext/rbu/rburename.test b/ext/rbu/rburename.test
new file mode 100644 (file)
index 0000000..2275396
--- /dev/null
@@ -0,0 +1,54 @@
+# 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
index 27a3720daa06c779aa85068ff425cb69bbb6fba4..d79439010fdc20893a48b4f5db0e10eff9d4748a 100644 (file)
@@ -393,6 +393,8 @@ struct sqlite3rbu {
   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
@@ -3241,32 +3243,7 @@ static void rbuMoveOalFile(sqlite3rbu *p){
     }
 
     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 
@@ -4005,6 +3982,7 @@ static sqlite3rbu *openRbuHandle(
 
     /* Create the custom VFS. */
     memset(p, 0, sizeof(sqlite3rbu));
+    sqlite3rbu_rename_handler(p, 0, 0);
     rbuCreateVfs(p);
 
     /* Open the target, RBU and state databases */
@@ -4396,6 +4374,54 @@ int sqlite3rbu_savestate(sqlite3rbu *p){
   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:
index 69d89500a02be2df3bbcafdf0695460c13e2dd05..c819cd3f2ab15a758239461e9f2f5eebcf15d61b 100644 (file)
@@ -544,6 +544,34 @@ SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int*pnTwo);
 
 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, 
index 6d04bfe8ccfa99651ad293877df2da625d490fab..af794d80f8a0b8ac1864de17f043cf7d203ccfca 100644 (file)
 #  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);
@@ -55,6 +63,20 @@ void test_rbu_delta(sqlite3_context *pCtx, int nArg, sqlite3_value **apVal){
   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,
@@ -63,7 +85,8 @@ static int SQLITE_TCLAPI test_sqlite3rbu_cmd(
   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;
@@ -82,6 +105,7 @@ static int SQLITE_TCLAPI test_sqlite3rbu_cmd(
     {"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;
@@ -127,6 +151,8 @@ static int SQLITE_TCLAPI test_sqlite3rbu_cmd(
         }
         ret = TCL_ERROR;
       }
+      if( pTest->xRename ) Tcl_DecrRefCount(pTest->xRename);
+      ckfree(pTest);
       break;
     }
 
@@ -214,6 +240,19 @@ static int SQLITE_TCLAPI test_sqlite3rbu_cmd(
       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;
@@ -222,6 +261,18 @@ static int SQLITE_TCLAPI test_sqlite3rbu_cmd(
   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>?
 */
@@ -247,7 +298,7 @@ static int SQLITE_TCLAPI test_sqlite3rbu(
   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;
 }
@@ -276,7 +327,7 @@ static int SQLITE_TCLAPI test_sqlite3rbu_vacuum(
   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;
 }
index e9cc151f56c10c0b971bad37057dded4e85909e9..b6d5bc0fe841a49a7364318ef79fffac5593a460 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-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
@@ -374,6 +374,7 @@ F ext/rbu/rbumisc.test 329986cf5dd51890c4eb906c2f960ebb773a79a64bed90f506b7c4178
 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
@@ -382,9 +383,9 @@ F ext/rbu/rbuvacuum.test 55e101e90168c2b31df6c9638fe73dc7f7cc666b6142266d1563697
 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
@@ -2054,8 +2055,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 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.
index bc43c26e8ed4eecf50568625b8e0a81b8753f9aa..b211793766ca2838f7210bc36649409b723690f5 100644 (file)
@@ -1 +1 @@
-d2ed4116fbf1de3c840f84e05db6f29f7b489518ac07d56f61df153deab6bf6b
\ No newline at end of file
+ebbb1f88e7b5d6cbe84d400f1a187acedb4c668d0b7e4c63bf1496e57da9b8ad
\ No newline at end of file