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;
76 rc
= sqlite3_declare_vtab(db
,
77 "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
79 pTab
= (DbpageTable
*)sqlite3_malloc64(sizeof(DbpageTable
));
80 if( pTab
==0 ) rc
= SQLITE_NOMEM_BKPT
;
83 assert( rc
==SQLITE_OK
|| pTab
==0 );
85 memset(pTab
, 0, sizeof(DbpageTable
));
89 *ppVtab
= (sqlite3_vtab
*)pTab
;
94 ** Disconnect from or destroy a dbpagevfs virtual table.
96 static int dbpageDisconnect(sqlite3_vtab
*pVtab
){
104 ** 0 schema=main, full table scan
105 ** 1 schema=main, pgno=?1
106 ** 2 schema=?1, full table scan
107 ** 3 schema=?1, pgno=?2
109 static int dbpageBestIndex(sqlite3_vtab
*tab
, sqlite3_index_info
*pIdxInfo
){
113 /* If there is a schema= constraint, it must be honored. Report a
114 ** ridiculously large estimated cost if the schema= constraint is
117 for(i
=0; i
<pIdxInfo
->nConstraint
; i
++){
118 struct sqlite3_index_constraint
*p
= &pIdxInfo
->aConstraint
[i
];
119 if( p
->iColumn
!=DBPAGE_COLUMN_SCHEMA
) continue;
120 if( p
->op
!=SQLITE_INDEX_CONSTRAINT_EQ
) continue;
123 return SQLITE_CONSTRAINT
;
126 pIdxInfo
->aConstraintUsage
[i
].argvIndex
= 1;
127 pIdxInfo
->aConstraintUsage
[i
].omit
= 1;
131 /* If we reach this point, it means that either there is no schema=
132 ** constraint (in which case we use the "main" schema) or else the
133 ** schema constraint was accepted. Lower the estimated cost accordingly
135 pIdxInfo
->estimatedCost
= 1.0e6
;
137 /* Check for constraints against pgno */
138 for(i
=0; i
<pIdxInfo
->nConstraint
; i
++){
139 struct sqlite3_index_constraint
*p
= &pIdxInfo
->aConstraint
[i
];
140 if( p
->usable
&& p
->iColumn
<=0 && p
->op
==SQLITE_INDEX_CONSTRAINT_EQ
){
141 pIdxInfo
->estimatedRows
= 1;
142 pIdxInfo
->idxFlags
= SQLITE_INDEX_SCAN_UNIQUE
;
143 pIdxInfo
->estimatedCost
= 1.0;
144 pIdxInfo
->aConstraintUsage
[i
].argvIndex
= iPlan
? 2 : 1;
145 pIdxInfo
->aConstraintUsage
[i
].omit
= 1;
150 pIdxInfo
->idxNum
= iPlan
;
152 if( pIdxInfo
->nOrderBy
>=1
153 && pIdxInfo
->aOrderBy
[0].iColumn
<=0
154 && pIdxInfo
->aOrderBy
[0].desc
==0
156 pIdxInfo
->orderByConsumed
= 1;
162 ** Open a new dbpagevfs cursor.
164 static int dbpageOpen(sqlite3_vtab
*pVTab
, sqlite3_vtab_cursor
**ppCursor
){
167 pCsr
= (DbpageCursor
*)sqlite3_malloc64(sizeof(DbpageCursor
));
169 return SQLITE_NOMEM_BKPT
;
171 memset(pCsr
, 0, sizeof(DbpageCursor
));
172 pCsr
->base
.pVtab
= pVTab
;
176 *ppCursor
= (sqlite3_vtab_cursor
*)pCsr
;
181 ** Close a dbpagevfs cursor.
183 static int dbpageClose(sqlite3_vtab_cursor
*pCursor
){
184 DbpageCursor
*pCsr
= (DbpageCursor
*)pCursor
;
185 if( pCsr
->pPage1
) sqlite3PagerUnrefPageOne(pCsr
->pPage1
);
191 ** Move a dbpagevfs cursor to the next entry in the file.
193 static int dbpageNext(sqlite3_vtab_cursor
*pCursor
){
195 DbpageCursor
*pCsr
= (DbpageCursor
*)pCursor
;
200 static int dbpageEof(sqlite3_vtab_cursor
*pCursor
){
201 DbpageCursor
*pCsr
= (DbpageCursor
*)pCursor
;
202 return pCsr
->pgno
> pCsr
->mxPgno
;
208 ** 0 schema=main, full table scan
209 ** 1 schema=main, pgno=?1
210 ** 2 schema=?1, full table scan
211 ** 3 schema=?1, pgno=?2
213 ** idxStr is not used
215 static int dbpageFilter(
216 sqlite3_vtab_cursor
*pCursor
,
217 int idxNum
, const char *idxStr
,
218 int argc
, sqlite3_value
**argv
220 DbpageCursor
*pCsr
= (DbpageCursor
*)pCursor
;
221 DbpageTable
*pTab
= (DbpageTable
*)pCursor
->pVtab
;
223 sqlite3
*db
= pTab
->db
;
226 /* Default setting is no rows of result */
233 zSchema
= (const char*)sqlite3_value_text(argv
[0]);
234 pCsr
->iDb
= sqlite3FindDbName(db
, zSchema
);
235 if( pCsr
->iDb
<0 ) return SQLITE_OK
;
239 pBt
= db
->aDb
[pCsr
->iDb
].pBt
;
240 if( pBt
==0 ) return SQLITE_OK
;
241 pCsr
->pPager
= sqlite3BtreePager(pBt
);
242 pCsr
->szPage
= sqlite3BtreeGetPageSize(pBt
);
243 pCsr
->mxPgno
= sqlite3BtreeLastPage(pBt
);
245 assert( argc
>(idxNum
>>1) );
246 pCsr
->pgno
= sqlite3_value_int(argv
[idxNum
>>1]);
247 if( pCsr
->pgno
<1 || pCsr
->pgno
>pCsr
->mxPgno
){
251 pCsr
->mxPgno
= pCsr
->pgno
;
254 assert( pCsr
->pgno
==1 );
256 if( pCsr
->pPage1
) sqlite3PagerUnrefPageOne(pCsr
->pPage1
);
257 rc
= sqlite3PagerGet(pCsr
->pPager
, 1, &pCsr
->pPage1
, 0);
261 static int dbpageColumn(
262 sqlite3_vtab_cursor
*pCursor
,
263 sqlite3_context
*ctx
,
266 DbpageCursor
*pCsr
= (DbpageCursor
*)pCursor
;
270 sqlite3_result_int(ctx
, pCsr
->pgno
);
275 rc
= sqlite3PagerGet(pCsr
->pPager
, pCsr
->pgno
, (DbPage
**)&pDbPage
, 0);
277 sqlite3_result_blob(ctx
, sqlite3PagerGetData(pDbPage
), pCsr
->szPage
,
280 sqlite3PagerUnref(pDbPage
);
283 default: { /* schema */
284 sqlite3
*db
= sqlite3_context_db_handle(ctx
);
285 sqlite3_result_text(ctx
, db
->aDb
[pCsr
->iDb
].zDbSName
, -1, SQLITE_STATIC
);
292 static int dbpageRowid(sqlite3_vtab_cursor
*pCursor
, sqlite_int64
*pRowid
){
293 DbpageCursor
*pCsr
= (DbpageCursor
*)pCursor
;
294 *pRowid
= pCsr
->pgno
;
298 static int dbpageUpdate(
301 sqlite3_value
**argv
,
304 DbpageTable
*pTab
= (DbpageTable
*)pVtab
;
315 if( pTab
->db
->flags
& SQLITE_Defensive
){
320 zErr
= "cannot delete";
323 pgno
= sqlite3_value_int(argv
[0]);
324 if( (Pgno
)sqlite3_value_int(argv
[1])!=pgno
){
325 zErr
= "cannot insert";
328 zSchema
= (const char*)sqlite3_value_text(argv
[4]);
329 iDb
= zSchema
? sqlite3FindDbName(pTab
->db
, zSchema
) : -1;
331 zErr
= "no such schema";
334 pBt
= pTab
->db
->aDb
[iDb
].pBt
;
335 if( pgno
<1 || pBt
==0 || pgno
>(int)sqlite3BtreeLastPage(pBt
) ){
336 zErr
= "bad page number";
339 szPage
= sqlite3BtreeGetPageSize(pBt
);
340 if( sqlite3_value_type(argv
[3])!=SQLITE_BLOB
341 || sqlite3_value_bytes(argv
[3])!=szPage
343 zErr
= "bad page value";
346 pPager
= sqlite3BtreePager(pBt
);
347 rc
= sqlite3PagerGet(pPager
, pgno
, (DbPage
**)&pDbPage
, 0);
349 rc
= sqlite3PagerWrite(pDbPage
);
351 memcpy(sqlite3PagerGetData(pDbPage
),
352 sqlite3_value_blob(argv
[3]),
356 sqlite3PagerUnref(pDbPage
);
360 sqlite3_free(pVtab
->zErrMsg
);
361 pVtab
->zErrMsg
= sqlite3_mprintf("%s", zErr
);
365 /* Since we do not know in advance which database files will be
366 ** written by the sqlite_dbpage virtual table, start a write transaction
369 static int dbpageBegin(sqlite3_vtab
*pVtab
){
370 DbpageTable
*pTab
= (DbpageTable
*)pVtab
;
371 sqlite3
*db
= pTab
->db
;
373 for(i
=0; i
<db
->nDb
; i
++){
374 Btree
*pBt
= db
->aDb
[i
].pBt
;
375 if( pBt
) sqlite3BtreeBeginTrans(pBt
, 1, 0);
382 ** Invoke this routine to register the "dbpage" virtual table module
384 int sqlite3DbpageRegister(sqlite3
*db
){
385 static sqlite3_module dbpage_module
= {
387 dbpageConnect
, /* xCreate */
388 dbpageConnect
, /* xConnect */
389 dbpageBestIndex
, /* xBestIndex */
390 dbpageDisconnect
, /* xDisconnect */
391 dbpageDisconnect
, /* xDestroy */
392 dbpageOpen
, /* xOpen - open a cursor */
393 dbpageClose
, /* xClose - close a cursor */
394 dbpageFilter
, /* xFilter - configure scan constraints */
395 dbpageNext
, /* xNext - advance a cursor */
396 dbpageEof
, /* xEof - check for end of scan */
397 dbpageColumn
, /* xColumn - read data */
398 dbpageRowid
, /* xRowid - read data */
399 dbpageUpdate
, /* xUpdate */
400 dbpageBegin
, /* xBegin */
411 return sqlite3_create_module(db
, "sqlite_dbpage", &dbpage_module
, 0);
413 #elif defined(SQLITE_ENABLE_DBPAGE_VTAB)
414 int sqlite3DbpageRegister(sqlite3
*db
){ return SQLITE_OK
; }
415 #endif /* SQLITE_ENABLE_DBSTAT_VTAB */