mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-01 06:27:03 +03:00
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
This commit is contained in:
67
src/dbpage.c
67
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 */
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user