mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-27 20:41:58 +03:00
Get writes working on the sqlite_dbpage virtual table. Add a few test cases.
FossilOrigin-Name: a8b264d811e5bcb7e3ae8a12bf5b6830a9d1adff1f59436dda9e886f97da242f
This commit is contained in:
16
manifest
16
manifest
@ -1,5 +1,5 @@
|
|||||||
C Initial\simplementation\sof\sthe\s"sqlite_dbpage"\svirtual\stable.\s\sCurrently\nit\sis\sread-only\sand\shas\sa\splace-holder\sxBestIndex.
|
C Get\swrites\sworking\son\sthe\ssqlite_dbpage\svirtual\stable.\s\sAdd\sa\sfew\stest\scases.
|
||||||
D 2017-10-11T13:48:11.877
|
D 2017-10-11T15:02:53.047
|
||||||
F Makefile.in f7cba589198b8663d8a43f25ad001cf44fdac4fcd6216325f05775924a7af2f9
|
F Makefile.in f7cba589198b8663d8a43f25ad001cf44fdac4fcd6216325f05775924a7af2f9
|
||||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||||
F Makefile.msc 1224c8773fc7f89c57e83c7b452291d239aa2cff4af50a204c84129e295cc37d
|
F Makefile.msc 1224c8773fc7f89c57e83c7b452291d239aa2cff4af50a204c84129e295cc37d
|
||||||
@ -409,7 +409,7 @@ F src/callback.c 28a8ede982fde4129b828350f78f2c01fe7d12c74d1a0a05d7108ab36f30868
|
|||||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||||
F src/ctime.c ff1be3eed7bdd75aaca61ca8dc848f7c9f850ef2fb9cb56f2734e922a098f9c0
|
F src/ctime.c ff1be3eed7bdd75aaca61ca8dc848f7c9f850ef2fb9cb56f2734e922a098f9c0
|
||||||
F src/date.c 48f743d88bbe88f848532d333cca84f26e52a4f217e86f86be7fc1b919c33d74
|
F src/date.c 48f743d88bbe88f848532d333cca84f26e52a4f217e86f86be7fc1b919c33d74
|
||||||
F src/dbpage.c f274a9b7bb680cc2952ee78883d67e133be0ef6065317813586a5f723af35ad5
|
F src/dbpage.c c625a0bd605d4cea9a3258b8db49a5474a04976e95a9fe380cdaf74e8eb6736d
|
||||||
F src/dbstat.c 7a4ba8518b6369ef3600c49cf9c918ad979acba610b2aebef1b656d649b96720
|
F src/dbstat.c 7a4ba8518b6369ef3600c49cf9c918ad979acba610b2aebef1b656d649b96720
|
||||||
F src/delete.c 21a5f1812fdb599e9f7afb9f650bdabab60a3afd51d7e94e539c982f647b0023
|
F src/delete.c 21a5f1812fdb599e9f7afb9f650bdabab60a3afd51d7e94e539c982f647b0023
|
||||||
F src/expr.c 4d2d0aafd945424f638ee03e11330f03288ccf616e025498f3c8602d01609a0a
|
F src/expr.c 4d2d0aafd945424f638ee03e11330f03288ccf616e025498f3c8602d01609a0a
|
||||||
@ -709,6 +709,7 @@ F test/cursorhint2.test 8457e93d97f665f23f97cdbc8477d16e3480331b
|
|||||||
F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373
|
F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373
|
||||||
F test/date2.test 74c234bece1b016e94dd4ef9c8cc7a199a8806c0e2291cab7ba64bace6350b10
|
F test/date2.test 74c234bece1b016e94dd4ef9c8cc7a199a8806c0e2291cab7ba64bace6350b10
|
||||||
F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
|
F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
|
||||||
|
F test/dbpage.test 9cf4dc92a4de67c81e5c32b24e3fbb8c4757e4b642694a219b3090a4f9277a4d
|
||||||
F test/dbstatus.test 73149851b3aff14fc6db478e58f9083a66422cf5
|
F test/dbstatus.test 73149851b3aff14fc6db478e58f9083a66422cf5
|
||||||
F test/dbstatus2.test e93ab03bfae6d62d4d935f20de928c19ca0ed0ab
|
F test/dbstatus2.test e93ab03bfae6d62d4d935f20de928c19ca0ed0ab
|
||||||
F test/default.test 0cb49b1c315a0d81c81d775e407f66906a2a604d
|
F test/default.test 0cb49b1c315a0d81c81d775e407f66906a2a604d
|
||||||
@ -1657,10 +1658,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 0245adffc6f9b580217e0d2feb396d6895e54cdc25f5dfc9c8f4090b919e9e49
|
P c2c1d656e3f52465192c2a697a976cd1837ccc4e10708a2377cff8bf6eaa7d49
|
||||||
R 9d91f38d6de2e0aabd371a2c4dbcd832
|
R 92490bca397034b7f3fba4e951f0781d
|
||||||
T *branch * dbpage
|
|
||||||
T *sym-dbpage *
|
|
||||||
T -sym-trunk *
|
|
||||||
U drh
|
U drh
|
||||||
Z 95e75b385006fb35e51e104eb16c88ba
|
Z ddf133cf759c24442aeeb91134927fef
|
||||||
|
@ -1 +1 @@
|
|||||||
c2c1d656e3f52465192c2a697a976cd1837ccc4e10708a2377cff8bf6eaa7d49
|
a8b264d811e5bcb7e3ae8a12bf5b6830a9d1adff1f59436dda9e886f97da242f
|
106
src/dbpage.c
106
src/dbpage.c
@ -16,6 +16,19 @@
|
|||||||
** pages of the database file. The pager interface is used so that
|
** pages of the database file. The pager interface is used so that
|
||||||
** uncommitted changes and changes recorded in the WAL file are correctly
|
** uncommitted changes and changes recorded in the WAL file are correctly
|
||||||
** retrieved.
|
** retrieved.
|
||||||
|
**
|
||||||
|
** Usage example:
|
||||||
|
**
|
||||||
|
** SELECT data FROM sqlite_dbpage('aux1') WHERE pgno=123;
|
||||||
|
**
|
||||||
|
** This is an eponymous virtual table so it does not need to be created before
|
||||||
|
** use. The optional argument to the sqlite_dbpage() table name is the
|
||||||
|
** schema for the database file that is to be read. The default schema is
|
||||||
|
** "main".
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sqliteInt.h" /* Requires access to internal data structures */
|
#include "sqliteInt.h" /* Requires access to internal data structures */
|
||||||
@ -28,6 +41,7 @@ typedef struct DbpageCursor DbpageCursor;
|
|||||||
struct DbpageCursor {
|
struct DbpageCursor {
|
||||||
sqlite3_vtab_cursor base; /* Base class. Must be first */
|
sqlite3_vtab_cursor base; /* Base class. Must be first */
|
||||||
int pgno; /* Current page number */
|
int pgno; /* Current page number */
|
||||||
|
int mxPgno; /* Last page to visit on this scan */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DbpageTable {
|
struct DbpageTable {
|
||||||
@ -65,7 +79,7 @@ static int dbpageConnect(
|
|||||||
iDb = 0;
|
iDb = 0;
|
||||||
}
|
}
|
||||||
rc = sqlite3_declare_vtab(db,
|
rc = sqlite3_declare_vtab(db,
|
||||||
"CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB)");
|
"CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable));
|
pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable));
|
||||||
if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
|
if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
|
||||||
@ -99,7 +113,26 @@ static int dbpageDisconnect(sqlite3_vtab *pVtab){
|
|||||||
** 1 pgno=?1
|
** 1 pgno=?1
|
||||||
*/
|
*/
|
||||||
static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
||||||
|
int i;
|
||||||
pIdxInfo->estimatedCost = 1.0e6; /* Initial cost estimate */
|
pIdxInfo->estimatedCost = 1.0e6; /* Initial cost estimate */
|
||||||
|
for(i=0; i<pIdxInfo->nConstraint; i++){
|
||||||
|
struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
|
||||||
|
if( p->usable && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
|
||||||
|
pIdxInfo->estimatedRows = 1;
|
||||||
|
pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
|
||||||
|
pIdxInfo->estimatedCost = 1.0;
|
||||||
|
pIdxInfo->idxNum = 1;
|
||||||
|
pIdxInfo->aConstraintUsage[i].argvIndex = 1;
|
||||||
|
pIdxInfo->aConstraintUsage[i].omit = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( pIdxInfo->nOrderBy>=1
|
||||||
|
&& pIdxInfo->aOrderBy[0].iColumn<=0
|
||||||
|
&& pIdxInfo->aOrderBy[0].desc==0
|
||||||
|
){
|
||||||
|
pIdxInfo->orderByConsumed = 1;
|
||||||
|
}
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,8 +176,7 @@ static int dbpageNext(sqlite3_vtab_cursor *pCursor){
|
|||||||
|
|
||||||
static int dbpageEof(sqlite3_vtab_cursor *pCursor){
|
static int dbpageEof(sqlite3_vtab_cursor *pCursor){
|
||||||
DbpageCursor *pCsr = (DbpageCursor *)pCursor;
|
DbpageCursor *pCsr = (DbpageCursor *)pCursor;
|
||||||
DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
|
return pCsr->pgno > pCsr->mxPgno;
|
||||||
return pCsr->pgno >= pTab->nPage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dbpageFilter(
|
static int dbpageFilter(
|
||||||
@ -157,13 +189,20 @@ static int dbpageFilter(
|
|||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
|
Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
|
||||||
|
|
||||||
if( idxNum==1 ){
|
|
||||||
pCsr->pgno = sqlite3_value_int(argv[0]);
|
|
||||||
}else{
|
|
||||||
pCsr->pgno = 0;
|
|
||||||
}
|
|
||||||
pTab->szPage = sqlite3BtreeGetPageSize(pBt);
|
pTab->szPage = sqlite3BtreeGetPageSize(pBt);
|
||||||
pTab->nPage = sqlite3BtreeLastPage(pBt);
|
pTab->nPage = sqlite3BtreeLastPage(pBt);
|
||||||
|
if( idxNum==1 ){
|
||||||
|
pCsr->pgno = sqlite3_value_int(argv[0]);
|
||||||
|
if( pCsr->pgno<1 || pCsr->pgno>pTab->nPage ){
|
||||||
|
pCsr->pgno = 1;
|
||||||
|
pCsr->mxPgno = 0;
|
||||||
|
}else{
|
||||||
|
pCsr->mxPgno = pCsr->pgno;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
pCsr->pgno = 1;
|
||||||
|
pCsr->mxPgno = pTab->nPage;
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,6 +244,55 @@ static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
|
|||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dbpageUpdate(
|
||||||
|
sqlite3_vtab *pVtab,
|
||||||
|
int argc,
|
||||||
|
sqlite3_value **argv,
|
||||||
|
sqlite_int64 *pRowid
|
||||||
|
){
|
||||||
|
DbpageTable *pTab = (DbpageTable *)pVtab;
|
||||||
|
int pgno;
|
||||||
|
DbPage *pDbPage = 0;
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
char *zErr = 0;
|
||||||
|
|
||||||
|
if( argc==1 ){
|
||||||
|
zErr = "cannot delete";
|
||||||
|
goto update_fail;
|
||||||
|
}
|
||||||
|
pgno = sqlite3_value_int(argv[0]);
|
||||||
|
if( pgno<1 || pgno>pTab->nPage ){
|
||||||
|
zErr = "bad page number";
|
||||||
|
goto update_fail;
|
||||||
|
}
|
||||||
|
if( sqlite3_value_int(argv[1])!=pgno ){
|
||||||
|
zErr = "cannot insert";
|
||||||
|
goto update_fail;
|
||||||
|
}
|
||||||
|
if( sqlite3_value_type(argv[3])!=SQLITE_BLOB
|
||||||
|
|| sqlite3_value_bytes(argv[3])!=pTab->szPage
|
||||||
|
){
|
||||||
|
zErr = "bad page value";
|
||||||
|
goto update_fail;
|
||||||
|
}
|
||||||
|
rc = sqlite3PagerGet(pTab->pPager, pgno, (DbPage**)&pDbPage, 0);
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
rc = sqlite3PagerWrite(pDbPage);
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
memcpy(sqlite3PagerGetData(pDbPage),
|
||||||
|
sqlite3_value_blob(argv[3]),
|
||||||
|
pTab->szPage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sqlite3PagerUnref(pDbPage);
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
update_fail:
|
||||||
|
sqlite3_free(pVtab->zErrMsg);
|
||||||
|
pVtab->zErrMsg = sqlite3_mprintf("%s", zErr);
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Invoke this routine to register the "dbpage" virtual table module
|
** Invoke this routine to register the "dbpage" virtual table module
|
||||||
*/
|
*/
|
||||||
@ -223,7 +311,7 @@ int sqlite3DbpageRegister(sqlite3 *db){
|
|||||||
dbpageEof, /* xEof - check for end of scan */
|
dbpageEof, /* xEof - check for end of scan */
|
||||||
dbpageColumn, /* xColumn - read data */
|
dbpageColumn, /* xColumn - read data */
|
||||||
dbpageRowid, /* xRowid - read data */
|
dbpageRowid, /* xRowid - read data */
|
||||||
0, /* xUpdate */
|
dbpageUpdate, /* xUpdate */
|
||||||
0, /* xBegin */
|
0, /* xBegin */
|
||||||
0, /* xSync */
|
0, /* xSync */
|
||||||
0, /* xCommit */
|
0, /* xCommit */
|
||||||
|
69
test/dbpage.test
Normal file
69
test/dbpage.test
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
# 2017-10-11
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
#***********************************************************************
|
||||||
|
# This file implements regression tests for SQLite library. The
|
||||||
|
# focus of this file is testing the sqlite_dbpage virtual table.
|
||||||
|
#
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
set testprefix dbpage
|
||||||
|
|
||||||
|
ifcapable !vtab||!compound {
|
||||||
|
finish_test
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 100 {
|
||||||
|
PRAGMA page_size=4096;
|
||||||
|
PRAGMA journal_mode=WAL;
|
||||||
|
CREATE TABLE t1(a,b);
|
||||||
|
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
|
||||||
|
INSERT INTO t1(a,b) SELECT x, printf('%d-x%.*c',x,x,'x') FROM c;
|
||||||
|
PRAGMA integrity_check;
|
||||||
|
} {wal ok}
|
||||||
|
do_execsql_test 110 {
|
||||||
|
SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage('main') ORDER BY pgno;
|
||||||
|
} {1 X'53514C6974' 2 X'0500000001' 3 X'0D0000004E' 4 X'0D00000016'}
|
||||||
|
do_execsql_test 120 {
|
||||||
|
SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage WHERE pgno=2;
|
||||||
|
} {2 X'0500000001'}
|
||||||
|
do_execsql_test 130 {
|
||||||
|
SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage WHERE pgno=4;
|
||||||
|
} {4 X'0D00000016'}
|
||||||
|
do_execsql_test 140 {
|
||||||
|
SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage WHERE pgno=5;
|
||||||
|
} {}
|
||||||
|
do_execsql_test 150 {
|
||||||
|
SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage WHERE pgno=0;
|
||||||
|
} {}
|
||||||
|
|
||||||
|
do_execsql_test 200 {
|
||||||
|
CREATE TEMP TABLE saved_content(x);
|
||||||
|
INSERT INTO saved_content(x) SELECT data FROM sqlite_dbpage WHERE pgno=4;
|
||||||
|
UPDATE sqlite_dbpage SET data=zeroblob(4096) WHERE pgno=4;
|
||||||
|
} {}
|
||||||
|
do_catchsql_test 210 {
|
||||||
|
PRAGMA integrity_check;
|
||||||
|
} {1 {database disk image is malformed}}
|
||||||
|
do_execsql_test 220 {
|
||||||
|
SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage('main') ORDER BY pgno;
|
||||||
|
} {1 X'53514C6974' 2 X'0500000001' 3 X'0D0000004E' 4 X'0000000000'}
|
||||||
|
do_execsql_test 230 {
|
||||||
|
UPDATE sqlite_dbpage SET data=(SELECT x FROM saved_content) WHERE pgno=4;
|
||||||
|
} {}
|
||||||
|
do_catchsql_test 230 {
|
||||||
|
PRAGMA integrity_check;
|
||||||
|
} {0 ok}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
finish_test
|
Reference in New Issue
Block a user