aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <>2024-09-14 16:39:02 +0000
committerdrh <>2024-09-14 16:39:02 +0000
commitdbff02abc5b4fd9457e7952d714c018386e23cd5 (patch)
tree0b3b523da99b4908fc5b340e4114bc4029b6122e /src
parent99f50dd21949a8fb60a71537447b4ffd1fc0306a (diff)
parent3d56d59adc1e0c60ca752e2dd062e78d3927102e (diff)
downloadsqlite-dbff02abc5b4fd9457e7952d714c018386e23cd5.tar.gz
sqlite-dbff02abc5b4fd9457e7952d714c018386e23cd5.zip
Enhancements to sqlite_dbpage() so that it accepts INSERT statements that can
extend or truncate the database. Add the sqlite3-rsync utility program that make a copy of a live database over SSH. FossilOrigin-Name: b7a8ce4c8c5fc6a3b4744d412d96f99d2452eb4086ad84472511da3b4d6afec6
Diffstat (limited to 'src')
-rw-r--r--src/dbpage.c67
-rw-r--r--src/shell.c.in2
2 files changed, 58 insertions, 11 deletions
diff --git a/src/dbpage.c b/src/dbpage.c
index 9740b418a..42b24f9b8 100644
--- a/src/dbpage.c
+++ b/src/dbpage.c
@@ -28,7 +28,13 @@
**
** 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,18 +347,20 @@ 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;
}else{
const char *zSchema = (const char*)sqlite3_value_text(argv[4]);
- iDb = zSchema ? sqlite3FindDbName(pTab->db, zSchema) : -1;
+ iDb = sqlite3FindDbName(pTab->db, zSchema);
if( iDb<0 ){
zErr = "no such schema";
goto update_fail;
@@ -363,18 +375,31 @@ 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 ){
+ testcase( pTab->aTrunc!=0 );
+ pTab->aTrunc = sqlite3_realloc(pTab->aTrunc, (iDb+1)*sizeof(Pgno));
+ if( pTab->aTrunc ){
+ int j;
+ for(j=pTab->nTrunc; j<iDb; j++) pTab->aTrunc[j] = 0;
+ 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 +423,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 +467,7 @@ int sqlite3DbpageRegister(sqlite3 *db){
dbpageRowid, /* xRowid - read data */
dbpageUpdate, /* xUpdate */
dbpageBegin, /* xBegin */
- 0, /* xSync */
+ dbpageSync, /* xSync */
0, /* xCommit */
0, /* xRollback */
0, /* xFindMethod */
diff --git a/src/shell.c.in b/src/shell.c.in
index 9bc6c2566..2b0e506ed 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -1209,6 +1209,7 @@ INCLUDE test_windirent.c
INCLUDE ../ext/misc/memtrace.c
INCLUDE ../ext/misc/pcachetrace.c
INCLUDE ../ext/misc/shathree.c
+INCLUDE ../ext/misc/sha1.c
INCLUDE ../ext/misc/uint.c
INCLUDE ../ext/misc/decimal.c
INCLUDE ../ext/misc/percentile.c
@@ -5392,6 +5393,7 @@ static void open_db(ShellState *p, int openFlags){
#ifndef SQLITE_OMIT_LOAD_EXTENSION
sqlite3_enable_load_extension(p->db, 1);
#endif
+ sqlite3_sha_init(p->db, 0, 0);
sqlite3_shathree_init(p->db, 0, 0);
sqlite3_uint_init(p->db, 0, 0);
sqlite3_stmtrand_init(p->db, 0, 0);