4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 ******************************************************************************
13 ** This file contains an implementation of the "sqlite_dbpage" virtual table.
15 ** The sqlite_dbpage virtual table is used to read or write whole raw
16 ** pages of the database file. The pager interface is used so that
17 ** uncommitted changes and changes recorded in the WAL file are correctly
22 ** SELECT data FROM sqlite_dbpage('aux1') WHERE pgno=123;
24 ** This is an eponymous virtual table so it does not need to be created before
25 ** use. The optional argument to the sqlite_dbpage() table name is the
26 ** schema for the database file that is to be read. The default schema is
29 ** The data field of sqlite_dbpage table can be updated. The new
30 ** value must be a BLOB which is the correct page size, otherwise the
31 ** update fails. Rows may not be deleted or inserted.
34 #include "sqliteInt.h" /* Requires access to internal data structures */
35 #if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
36 && !defined(SQLITE_OMIT_VIRTUALTABLE)
38 typedef struct DbpageTable DbpageTable
;
39 typedef struct DbpageCursor DbpageCursor
;
42 sqlite3_vtab_cursor base
; /* Base class. Must be first */
43 int pgno
; /* Current page number */
44 int mxPgno
; /* Last page to visit on this scan */
45 Pager
*pPager
; /* Pager being read/written */
46 DbPage
*pPage1
; /* Page 1 of the database */
47 int iDb
; /* Index of database to analyze */
48 int szPage
; /* Size of each page in bytes */
52 sqlite3_vtab base
; /* Base class. Must be first */
53 sqlite3
*db
; /* The database */
57 #define DBPAGE_COLUMN_PGNO 0
58 #define DBPAGE_COLUMN_DATA 1
59 #define DBPAGE_COLUMN_SCHEMA 2
64 ** Connect to or create a dbpagevfs virtual table.
66 static int dbpageConnect(
69 int argc
, const char *const*argv
,
70 sqlite3_vtab
**ppVtab
,
73 DbpageTable
*pTab
= 0;
80 sqlite3_vtab_config(db
, SQLITE_VTAB_DIRECTONLY
);
81 sqlite3_vtab_config(db
, SQLITE_VTAB_USES_ALL_SCHEMAS
);
82 rc
= sqlite3_declare_vtab(db
,
83 "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
85 pTab
= (DbpageTable
*)sqlite3_malloc64(sizeof(DbpageTable
));
86 if( pTab
==0 ) rc
= SQLITE_NOMEM_BKPT
;
89 assert( rc
==SQLITE_OK
|| pTab
==0 );
91 memset(pTab
, 0, sizeof(DbpageTable
));
95 *ppVtab
= (sqlite3_vtab
*)pTab
;
100 ** Disconnect from or destroy a dbpagevfs virtual table.
102 static int dbpageDisconnect(sqlite3_vtab
*pVtab
){
110 ** 0 schema=main, full table scan
111 ** 1 schema=main, pgno=?1
112 ** 2 schema=?1, full table scan
113 ** 3 schema=?1, pgno=?2
115 static int dbpageBestIndex(sqlite3_vtab
*tab
, sqlite3_index_info
*pIdxInfo
){
120 /* If there is a schema= constraint, it must be honored. Report a
121 ** ridiculously large estimated cost if the schema= constraint is
124 for(i
=0; i
<pIdxInfo
->nConstraint
; i
++){
125 struct sqlite3_index_constraint
*p
= &pIdxInfo
->aConstraint
[i
];
126 if( p
->iColumn
!=DBPAGE_COLUMN_SCHEMA
) continue;
127 if( p
->op
!=SQLITE_INDEX_CONSTRAINT_EQ
) continue;
130 return SQLITE_CONSTRAINT
;
133 pIdxInfo
->aConstraintUsage
[i
].argvIndex
= 1;
134 pIdxInfo
->aConstraintUsage
[i
].omit
= 1;
138 /* If we reach this point, it means that either there is no schema=
139 ** constraint (in which case we use the "main" schema) or else the
140 ** schema constraint was accepted. Lower the estimated cost accordingly
142 pIdxInfo
->estimatedCost
= 1.0e6
;
144 /* Check for constraints against pgno */
145 for(i
=0; i
<pIdxInfo
->nConstraint
; i
++){
146 struct sqlite3_index_constraint
*p
= &pIdxInfo
->aConstraint
[i
];
147 if( p
->usable
&& p
->iColumn
<=0 && p
->op
==SQLITE_INDEX_CONSTRAINT_EQ
){
148 pIdxInfo
->estimatedRows
= 1;
149 pIdxInfo
->idxFlags
= SQLITE_INDEX_SCAN_UNIQUE
;
150 pIdxInfo
->estimatedCost
= 1.0;
151 pIdxInfo
->aConstraintUsage
[i
].argvIndex
= iPlan
? 2 : 1;
152 pIdxInfo
->aConstraintUsage
[i
].omit
= 1;
157 pIdxInfo
->idxNum
= iPlan
;
159 if( pIdxInfo
->nOrderBy
>=1
160 && pIdxInfo
->aOrderBy
[0].iColumn
<=0
161 && pIdxInfo
->aOrderBy
[0].desc
==0
163 pIdxInfo
->orderByConsumed
= 1;
169 ** Open a new dbpagevfs cursor.
171 static int dbpageOpen(sqlite3_vtab
*pVTab
, sqlite3_vtab_cursor
**ppCursor
){
174 pCsr
= (DbpageCursor
*)sqlite3_malloc64(sizeof(DbpageCursor
));
176 return SQLITE_NOMEM_BKPT
;
178 memset(pCsr
, 0, sizeof(DbpageCursor
));
179 pCsr
->base
.pVtab
= pVTab
;
183 *ppCursor
= (sqlite3_vtab_cursor
*)pCsr
;
188 ** Close a dbpagevfs cursor.
190 static int dbpageClose(sqlite3_vtab_cursor
*pCursor
){
191 DbpageCursor
*pCsr
= (DbpageCursor
*)pCursor
;
192 if( pCsr
->pPage1
) sqlite3PagerUnrefPageOne(pCsr
->pPage1
);
198 ** Move a dbpagevfs cursor to the next entry in the file.
200 static int dbpageNext(sqlite3_vtab_cursor
*pCursor
){
202 DbpageCursor
*pCsr
= (DbpageCursor
*)pCursor
;
207 static int dbpageEof(sqlite3_vtab_cursor
*pCursor
){
208 DbpageCursor
*pCsr
= (DbpageCursor
*)pCursor
;
209 return pCsr
->pgno
> pCsr
->mxPgno
;
215 ** 0 schema=main, full table scan
216 ** 1 schema=main, pgno=?1
217 ** 2 schema=?1, full table scan
218 ** 3 schema=?1, pgno=?2
220 ** idxStr is not used
222 static int dbpageFilter(
223 sqlite3_vtab_cursor
*pCursor
,
224 int idxNum
, const char *idxStr
,
225 int argc
, sqlite3_value
**argv
227 DbpageCursor
*pCsr
= (DbpageCursor
*)pCursor
;
228 DbpageTable
*pTab
= (DbpageTable
*)pCursor
->pVtab
;
230 sqlite3
*db
= pTab
->db
;
235 /* Default setting is no rows of result */
242 zSchema
= (const char*)sqlite3_value_text(argv
[0]);
243 pCsr
->iDb
= sqlite3FindDbName(db
, zSchema
);
244 if( pCsr
->iDb
<0 ) return SQLITE_OK
;
248 pBt
= db
->aDb
[pCsr
->iDb
].pBt
;
249 if( NEVER(pBt
==0) ) return SQLITE_OK
;
250 pCsr
->pPager
= sqlite3BtreePager(pBt
);
251 pCsr
->szPage
= sqlite3BtreeGetPageSize(pBt
);
252 pCsr
->mxPgno
= sqlite3BtreeLastPage(pBt
);
254 assert( argc
>(idxNum
>>1) );
255 pCsr
->pgno
= sqlite3_value_int(argv
[idxNum
>>1]);
256 if( pCsr
->pgno
<1 || pCsr
->pgno
>pCsr
->mxPgno
){
260 pCsr
->mxPgno
= pCsr
->pgno
;
263 assert( pCsr
->pgno
==1 );
265 if( pCsr
->pPage1
) sqlite3PagerUnrefPageOne(pCsr
->pPage1
);
266 rc
= sqlite3PagerGet(pCsr
->pPager
, 1, &pCsr
->pPage1
, 0);
270 static int dbpageColumn(
271 sqlite3_vtab_cursor
*pCursor
,
272 sqlite3_context
*ctx
,
275 DbpageCursor
*pCsr
= (DbpageCursor
*)pCursor
;
279 sqlite3_result_int(ctx
, pCsr
->pgno
);
284 if( pCsr
->pgno
==((PENDING_BYTE
/pCsr
->szPage
)+1) ){
285 /* The pending byte page. Assume it is zeroed out. Attempting to
286 ** request this page from the page is an SQLITE_CORRUPT error. */
287 sqlite3_result_zeroblob(ctx
, pCsr
->szPage
);
289 rc
= sqlite3PagerGet(pCsr
->pPager
, pCsr
->pgno
, (DbPage
**)&pDbPage
, 0);
291 sqlite3_result_blob(ctx
, sqlite3PagerGetData(pDbPage
), pCsr
->szPage
,
294 sqlite3PagerUnref(pDbPage
);
298 default: { /* schema */
299 sqlite3
*db
= sqlite3_context_db_handle(ctx
);
300 sqlite3_result_text(ctx
, db
->aDb
[pCsr
->iDb
].zDbSName
, -1, SQLITE_STATIC
);
307 static int dbpageRowid(sqlite3_vtab_cursor
*pCursor
, sqlite_int64
*pRowid
){
308 DbpageCursor
*pCsr
= (DbpageCursor
*)pCursor
;
309 *pRowid
= pCsr
->pgno
;
313 static int dbpageUpdate(
316 sqlite3_value
**argv
,
319 DbpageTable
*pTab
= (DbpageTable
*)pVtab
;
331 if( pTab
->db
->flags
& SQLITE_Defensive
){
336 zErr
= "cannot delete";
339 pgno
= sqlite3_value_int(argv
[0]);
340 if( sqlite3_value_type(argv
[0])==SQLITE_NULL
341 || (Pgno
)sqlite3_value_int(argv
[1])!=pgno
343 zErr
= "cannot insert";
346 zSchema
= (const char*)sqlite3_value_text(argv
[4]);
347 iDb
= ALWAYS(zSchema
) ? sqlite3FindDbName(pTab
->db
, zSchema
) : -1;
349 zErr
= "no such schema";
352 pBt
= pTab
->db
->aDb
[iDb
].pBt
;
353 if( NEVER(pgno
<1) || NEVER(pBt
==0) || NEVER(pgno
>sqlite3BtreeLastPage(pBt
)) ){
354 zErr
= "bad page number";
357 szPage
= sqlite3BtreeGetPageSize(pBt
);
358 if( sqlite3_value_type(argv
[3])!=SQLITE_BLOB
359 || sqlite3_value_bytes(argv
[3])!=szPage
361 zErr
= "bad page value";
364 pPager
= sqlite3BtreePager(pBt
);
365 rc
= sqlite3PagerGet(pPager
, pgno
, (DbPage
**)&pDbPage
, 0);
367 const void *pData
= sqlite3_value_blob(argv
[3]);
368 assert( pData
!=0 || pTab
->db
->mallocFailed
);
370 && (rc
= sqlite3PagerWrite(pDbPage
))==SQLITE_OK
372 memcpy(sqlite3PagerGetData(pDbPage
), pData
, szPage
);
375 sqlite3PagerUnref(pDbPage
);
379 sqlite3_free(pVtab
->zErrMsg
);
380 pVtab
->zErrMsg
= sqlite3_mprintf("%s", zErr
);
384 /* Since we do not know in advance which database files will be
385 ** written by the sqlite_dbpage virtual table, start a write transaction
388 static int dbpageBegin(sqlite3_vtab
*pVtab
){
389 DbpageTable
*pTab
= (DbpageTable
*)pVtab
;
390 sqlite3
*db
= pTab
->db
;
392 for(i
=0; i
<db
->nDb
; i
++){
393 Btree
*pBt
= db
->aDb
[i
].pBt
;
394 if( pBt
) (void)sqlite3BtreeBeginTrans(pBt
, 1, 0);
401 ** Invoke this routine to register the "dbpage" virtual table module
403 int sqlite3DbpageRegister(sqlite3
*db
){
404 static sqlite3_module dbpage_module
= {
406 dbpageConnect
, /* xCreate */
407 dbpageConnect
, /* xConnect */
408 dbpageBestIndex
, /* xBestIndex */
409 dbpageDisconnect
, /* xDisconnect */
410 dbpageDisconnect
, /* xDestroy */
411 dbpageOpen
, /* xOpen - open a cursor */
412 dbpageClose
, /* xClose - close a cursor */
413 dbpageFilter
, /* xFilter - configure scan constraints */
414 dbpageNext
, /* xNext - advance a cursor */
415 dbpageEof
, /* xEof - check for end of scan */
416 dbpageColumn
, /* xColumn - read data */
417 dbpageRowid
, /* xRowid - read data */
418 dbpageUpdate
, /* xUpdate */
419 dbpageBegin
, /* xBegin */
431 return sqlite3_create_module(db
, "sqlite_dbpage", &dbpage_module
, 0);
433 #elif defined(SQLITE_ENABLE_DBPAGE_VTAB)
434 int sqlite3DbpageRegister(sqlite3
*db
){ return SQLITE_OK
; }
435 #endif /* SQLITE_ENABLE_DBSTAT_VTAB */