]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the ability for sqlite_dbpage to truncate the database file by writing
authordrh <>
Tue, 10 Sep 2024 12:09:03 +0000 (12:09 +0000)
committerdrh <>
Tue, 10 Sep 2024 12:09:03 +0000 (12:09 +0000)
a NULL page.  Experimental.

FossilOrigin-Name: eb3c89ee2e4c5425be75deaf46a06a9cd8b210c695b918dd63a78f930c6e6b63

manifest
manifest.uuid
src/dbpage.c

index c5f3a5e79e57f91b6d435c739cca30c1d1b8c808..fc47d2846abc57cf24cdb8de0dffb3b9da7cc513 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Generalize\sthe\ssqlite3_dbpage\svirtual\stable\sso\sthat\sit\sis\sable\sto\swrite\nnew\spages\sonto\sthe\send\sof\sthe\sdatabase\sfile\susing\sINSERT.
-D 2024-09-09T18:45:58.205
+C Add\sthe\sability\sfor\ssqlite_dbpage\sto\struncate\sthe\sdatabase\sfile\sby\swriting\na\sNULL\spage.\s\sExperimental.
+D 2024-09-10T12:09:03.839
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -714,7 +714,7 @@ F src/callback.c db3a45e376deff6a16c0058163fe0ae2b73a2945f3f408ca32cf74960b28d49
 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
 F src/ctime.c b224d3db0f28c4a5f1407c50107a0a8133bd244ff3c7f6f8cedeb896a8cf1b64
 F src/date.c 89ce1ff20512a7fa5070ba6e7dd5c171148ca7d580955795bf97c79c2456144a
-F src/dbpage.c f8c93e845d1093554247c1e757cb443fc48ffbcb112cecfdebeca4b6aa6e5c6e
+F src/dbpage.c 3c437630c2933b9eefca915d191f8dea9da135195593bb17f553be58ffcd3634
 F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c
 F src/delete.c 444c4d1eaac40103461e3b6f0881846dd3aafc1cec1dd169d3482fa331667da7
 F src/expr.c 6d5f2c38fe3ec06a7eac599dac822788b36064124e20112a844e9cd5156cb239
@@ -2212,8 +2212,11 @@ F vsixtest/vsixtest.tcl 6195aba1f12a5e10efc2b8c0009532167be5e301abe5b31385638080
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 123cb1f579daec3ed092fe9dd1bc0d3250f2b56d4cda1efa92af139029e112e2
-R 3c119894ad399726f0c98d7eab61a4dc
+P fe0d67e72d4228661c021f227bfc0d5ddb1b726db0f36c7221ead8dd8bd1dc73
+R fb6f94f4d85e2b2f81d969e85d52cc7e
+T *branch * dbpage
+T *sym-dbpage *
+T -sym-trunk *
 U drh
-Z 54e5dc5728a062a0fc19b7e3f1b82dff
+Z 44b34a478a24f6c5d7a75b5688f34391
 # Remove this line to create a well-formed Fossil manifest.
index 49f91d3e2ec19a0cf97963763610cd69d0e94d97..653a750d5223f76baeda19f93f9de604e21c5459 100644 (file)
@@ -1 +1 @@
-fe0d67e72d4228661c021f227bfc0d5ddb1b726db0f36c7221ead8dd8bd1dc73
+eb3c89ee2e4c5425be75deaf46a06a9cd8b210c695b918dd63a78f930c6e6b63
index 9740b418a386cf06546a894015ac4e761bf136d7..4da81f8ca1b484de4145d33e8f5a5a1e84a1d001 100644 (file)
 **
 ** The data field of sqlite_dbpage table can be updated.  The new
 ** value must be a BLOB which is the correct page size, otherwise the
-** update fails.  Rows may not be deleted or inserted.
+** update fails.  INSERT operations also work, and operate as if they
+** where REPLACE.  The size of the database can be extended by INSERT-ing
+** new pages on the end.
+**
+** Rows may not be deleted.  However, doing an INSERT to page number N
+** with NULL page data causes the N-th page and all subsequent pages to be
+** deleted and the database to be truncated.
 */
 
 #include "sqliteInt.h"   /* Requires access to internal data structures */
@@ -51,6 +57,8 @@ struct DbpageCursor {
 struct DbpageTable {
   sqlite3_vtab base;              /* Base class.  Must be first */
   sqlite3 *db;                    /* The database */
+  int nTrunc;                     /* Entries in aTrunc[] */
+  Pgno *aTrunc;                   /* Truncation size for each database */
 };
 
 /* Columns */
@@ -59,7 +67,6 @@ struct DbpageTable {
 #define DBPAGE_COLUMN_SCHEMA  2
 
 
-
 /*
 ** Connect to or create a dbpagevfs virtual table.
 */
@@ -100,6 +107,8 @@ static int dbpageConnect(
 ** Disconnect from or destroy a dbpagevfs virtual table.
 */
 static int dbpageDisconnect(sqlite3_vtab *pVtab){
+  DbpageTable *pTab = (DbpageTable *)pVtab;
+  sqlite3_free(pTab->aTrunc);
   sqlite3_free(pVtab);
   return SQLITE_OK;
 }
@@ -325,6 +334,7 @@ static int dbpageUpdate(
   Btree *pBt;
   Pager *pPager;
   int szPage;
+  int isInsert;
 
   (void)pRowid;
   if( pTab->db->flags & SQLITE_Defensive ){
@@ -337,12 +347,14 @@ static int dbpageUpdate(
   }
   if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
     pgno = (Pgno)sqlite3_value_int(argv[2]);
+    isInsert = 1;
   }else{
     pgno = sqlite3_value_int(argv[0]);
     if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){
       zErr = "cannot insert";
       goto update_fail;
     }
+    isInsert = 0;
   }
   if( sqlite3_value_type(argv[4])==SQLITE_NULL ){
     iDb = 0;
@@ -363,18 +375,28 @@ static int dbpageUpdate(
   if( sqlite3_value_type(argv[3])!=SQLITE_BLOB 
    || sqlite3_value_bytes(argv[3])!=szPage
   ){
-    zErr = "bad page value";
-    goto update_fail;
+    if( sqlite3_value_type(argv[3])==SQLITE_NULL && isInsert ){
+      if( iDb>=pTab->nTrunc ){
+        pTab->aTrunc = sqlite3_realloc(pTab->aTrunc, (iDb+1)*sizeof(Pgno));
+        if( pTab->aTrunc ){
+          pTab->nTrunc = iDb+1;
+        }else{
+          return SQLITE_NOMEM;
+        }
+      }
+      pTab->aTrunc[iDb] = pgno;
+    }else{
+      zErr = "bad page value";
+      goto update_fail;
+    }
   }
   pPager = sqlite3BtreePager(pBt);
   rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0);
   if( rc==SQLITE_OK ){
     const void *pData = sqlite3_value_blob(argv[3]);
-    assert( pData!=0 || pTab->db->mallocFailed );
-    if( pData
-     && (rc = sqlite3PagerWrite(pDbPage))==SQLITE_OK
-    ){
-      memcpy(sqlite3PagerGetData(pDbPage), pData, szPage);
+    if( (rc = sqlite3PagerWrite(pDbPage))==SQLITE_OK && pData ){
+      unsigned char *aPage = sqlite3PagerGetData(pDbPage);
+      memcpy(aPage, pData, szPage);
     }
   }
   sqlite3PagerUnref(pDbPage);
@@ -398,6 +420,26 @@ static int dbpageBegin(sqlite3_vtab *pVtab){
     Btree *pBt = db->aDb[i].pBt;
     if( pBt ) (void)sqlite3BtreeBeginTrans(pBt, 1, 0);
   }
+  if( pTab->nTrunc>0 ){
+    memset(pTab->aTrunc, 0, sizeof(pTab->aTrunc[0])*pTab->nTrunc);
+  }
+  return SQLITE_OK;
+}
+
+/* Invoke sqlite3PagerTruncate() as necessary, just prior to COMMIT
+*/
+static int dbpageSync(sqlite3_vtab *pVtab){
+  int iDb;
+  DbpageTable *pTab = (DbpageTable *)pVtab;
+
+  for(iDb=0; iDb<pTab->nTrunc; iDb++){
+    if( pTab->aTrunc[iDb]>0 ){
+      Btree *pBt = pTab->db->aDb[iDb].pBt;
+      Pager *pPager = sqlite3BtreePager(pBt);
+      sqlite3PagerTruncateImage(pPager, pTab->aTrunc[iDb]);
+      pTab->aTrunc[iDb] = 0;
+    }
+  }
   return SQLITE_OK;
 }
 
@@ -422,7 +464,7 @@ int sqlite3DbpageRegister(sqlite3 *db){
     dbpageRowid,                  /* xRowid - read data */
     dbpageUpdate,                 /* xUpdate */
     dbpageBegin,                  /* xBegin */
-    0,                            /* xSync */
+    dbpageSync,                   /* xSync */
     0,                            /* xCommit */
     0,                            /* xRollback */
     0,                            /* xFindMethod */