xref: /sqlite-3.40.0/src/dbpage.c (revision c7dd9b60)
1a43c8c8aSdrh /*
2a43c8c8aSdrh ** 2017-10-11
3a43c8c8aSdrh **
4a43c8c8aSdrh ** The author disclaims copyright to this source code.  In place of
5a43c8c8aSdrh ** a legal notice, here is a blessing:
6a43c8c8aSdrh **
7a43c8c8aSdrh **    May you do good and not evil.
8a43c8c8aSdrh **    May you find forgiveness for yourself and forgive others.
9a43c8c8aSdrh **    May you share freely, never taking more than you give.
10a43c8c8aSdrh **
11a43c8c8aSdrh ******************************************************************************
12a43c8c8aSdrh **
13a43c8c8aSdrh ** This file contains an implementation of the "sqlite_dbpage" virtual table.
14a43c8c8aSdrh **
15a43c8c8aSdrh ** The sqlite_dbpage virtual table is used to read or write whole raw
16a43c8c8aSdrh ** pages of the database file.  The pager interface is used so that
17a43c8c8aSdrh ** uncommitted changes and changes recorded in the WAL file are correctly
18a43c8c8aSdrh ** retrieved.
1934d0b1acSdrh **
2034d0b1acSdrh ** Usage example:
2134d0b1acSdrh **
2234d0b1acSdrh **    SELECT data FROM sqlite_dbpage('aux1') WHERE pgno=123;
2334d0b1acSdrh **
2434d0b1acSdrh ** This is an eponymous virtual table so it does not need to be created before
2534d0b1acSdrh ** use.  The optional argument to the sqlite_dbpage() table name is the
2634d0b1acSdrh ** schema for the database file that is to be read.  The default schema is
2734d0b1acSdrh ** "main".
2834d0b1acSdrh **
2934d0b1acSdrh ** The data field of sqlite_dbpage table can be updated.  The new
3034d0b1acSdrh ** value must be a BLOB which is the correct page size, otherwise the
3134d0b1acSdrh ** update fails.  Rows may not be deleted or inserted.
32a43c8c8aSdrh */
33a43c8c8aSdrh 
34a43c8c8aSdrh #include "sqliteInt.h"   /* Requires access to internal data structures */
35a43c8c8aSdrh #if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
36a43c8c8aSdrh     && !defined(SQLITE_OMIT_VIRTUALTABLE)
37a43c8c8aSdrh 
38a43c8c8aSdrh typedef struct DbpageTable DbpageTable;
39a43c8c8aSdrh typedef struct DbpageCursor DbpageCursor;
40a43c8c8aSdrh 
41a43c8c8aSdrh struct DbpageCursor {
42a43c8c8aSdrh   sqlite3_vtab_cursor base;       /* Base class.  Must be first */
43a43c8c8aSdrh   int pgno;                       /* Current page number */
4434d0b1acSdrh   int mxPgno;                     /* Last page to visit on this scan */
453cd8aaa7Sdrh   Pager *pPager;                  /* Pager being read/written */
463cd8aaa7Sdrh   DbPage *pPage1;                 /* Page 1 of the database */
473cd8aaa7Sdrh   int iDb;                        /* Index of database to analyze */
483cd8aaa7Sdrh   int szPage;                     /* Size of each page in bytes */
49a43c8c8aSdrh };
50a43c8c8aSdrh 
51a43c8c8aSdrh struct DbpageTable {
52a43c8c8aSdrh   sqlite3_vtab base;              /* Base class.  Must be first */
53a43c8c8aSdrh   sqlite3 *db;                    /* The database */
54a43c8c8aSdrh };
55a43c8c8aSdrh 
563cd8aaa7Sdrh /* Columns */
573cd8aaa7Sdrh #define DBPAGE_COLUMN_PGNO    0
583cd8aaa7Sdrh #define DBPAGE_COLUMN_DATA    1
593cd8aaa7Sdrh #define DBPAGE_COLUMN_SCHEMA  2
603cd8aaa7Sdrh 
613cd8aaa7Sdrh 
623cd8aaa7Sdrh 
63a43c8c8aSdrh /*
64a43c8c8aSdrh ** Connect to or create a dbpagevfs virtual table.
65a43c8c8aSdrh */
dbpageConnect(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)66a43c8c8aSdrh static int dbpageConnect(
67a43c8c8aSdrh   sqlite3 *db,
68a43c8c8aSdrh   void *pAux,
69a43c8c8aSdrh   int argc, const char *const*argv,
70a43c8c8aSdrh   sqlite3_vtab **ppVtab,
71a43c8c8aSdrh   char **pzErr
72a43c8c8aSdrh ){
73a43c8c8aSdrh   DbpageTable *pTab = 0;
74a43c8c8aSdrh   int rc = SQLITE_OK;
75a43c8c8aSdrh 
762b1c2aadSdrh   sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
77a43c8c8aSdrh   rc = sqlite3_declare_vtab(db,
7834d0b1acSdrh           "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
79a43c8c8aSdrh   if( rc==SQLITE_OK ){
80a43c8c8aSdrh     pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable));
81a43c8c8aSdrh     if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
82a43c8c8aSdrh   }
83a43c8c8aSdrh 
84a43c8c8aSdrh   assert( rc==SQLITE_OK || pTab==0 );
85a43c8c8aSdrh   if( rc==SQLITE_OK ){
86a43c8c8aSdrh     memset(pTab, 0, sizeof(DbpageTable));
87a43c8c8aSdrh     pTab->db = db;
88a43c8c8aSdrh   }
89a43c8c8aSdrh 
90a43c8c8aSdrh   *ppVtab = (sqlite3_vtab*)pTab;
91a43c8c8aSdrh   return rc;
92a43c8c8aSdrh }
93a43c8c8aSdrh 
94a43c8c8aSdrh /*
95a43c8c8aSdrh ** Disconnect from or destroy a dbpagevfs virtual table.
96a43c8c8aSdrh */
dbpageDisconnect(sqlite3_vtab * pVtab)97a43c8c8aSdrh static int dbpageDisconnect(sqlite3_vtab *pVtab){
98a43c8c8aSdrh   sqlite3_free(pVtab);
99a43c8c8aSdrh   return SQLITE_OK;
100a43c8c8aSdrh }
101a43c8c8aSdrh 
102a43c8c8aSdrh /*
103a43c8c8aSdrh ** idxNum:
104a43c8c8aSdrh **
1053cd8aaa7Sdrh **     0     schema=main, full table scan
1063cd8aaa7Sdrh **     1     schema=main, pgno=?1
1073cd8aaa7Sdrh **     2     schema=?1, full table scan
1083cd8aaa7Sdrh **     3     schema=?1, pgno=?2
109a43c8c8aSdrh */
dbpageBestIndex(sqlite3_vtab * tab,sqlite3_index_info * pIdxInfo)110a43c8c8aSdrh static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
11134d0b1acSdrh   int i;
1123cd8aaa7Sdrh   int iPlan = 0;
1133cd8aaa7Sdrh 
1143cd8aaa7Sdrh   /* If there is a schema= constraint, it must be honored.  Report a
1153cd8aaa7Sdrh   ** ridiculously large estimated cost if the schema= constraint is
1163cd8aaa7Sdrh   ** unavailable
1173cd8aaa7Sdrh   */
1183cd8aaa7Sdrh   for(i=0; i<pIdxInfo->nConstraint; i++){
1193cd8aaa7Sdrh     struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
1203cd8aaa7Sdrh     if( p->iColumn!=DBPAGE_COLUMN_SCHEMA ) continue;
1213cd8aaa7Sdrh     if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
1223cd8aaa7Sdrh     if( !p->usable ){
12320b3fc4dSdrh       /* No solution. */
12420b3fc4dSdrh       return SQLITE_CONSTRAINT;
1253cd8aaa7Sdrh     }
1263cd8aaa7Sdrh     iPlan = 2;
1273cd8aaa7Sdrh     pIdxInfo->aConstraintUsage[i].argvIndex = 1;
1283cd8aaa7Sdrh     pIdxInfo->aConstraintUsage[i].omit = 1;
1293cd8aaa7Sdrh     break;
1303cd8aaa7Sdrh   }
1313cd8aaa7Sdrh 
1323cd8aaa7Sdrh   /* If we reach this point, it means that either there is no schema=
1333cd8aaa7Sdrh   ** constraint (in which case we use the "main" schema) or else the
1343cd8aaa7Sdrh   ** schema constraint was accepted.  Lower the estimated cost accordingly
1353cd8aaa7Sdrh   */
1363cd8aaa7Sdrh   pIdxInfo->estimatedCost = 1.0e6;
1373cd8aaa7Sdrh 
1383cd8aaa7Sdrh   /* Check for constraints against pgno */
13934d0b1acSdrh   for(i=0; i<pIdxInfo->nConstraint; i++){
14034d0b1acSdrh     struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
14134d0b1acSdrh     if( p->usable && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
14234d0b1acSdrh       pIdxInfo->estimatedRows = 1;
14334d0b1acSdrh       pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
14434d0b1acSdrh       pIdxInfo->estimatedCost = 1.0;
1453cd8aaa7Sdrh       pIdxInfo->aConstraintUsage[i].argvIndex = iPlan ? 2 : 1;
14634d0b1acSdrh       pIdxInfo->aConstraintUsage[i].omit = 1;
1473cd8aaa7Sdrh       iPlan |= 1;
14834d0b1acSdrh       break;
14934d0b1acSdrh     }
15034d0b1acSdrh   }
1513cd8aaa7Sdrh   pIdxInfo->idxNum = iPlan;
1523cd8aaa7Sdrh 
15334d0b1acSdrh   if( pIdxInfo->nOrderBy>=1
15434d0b1acSdrh    && pIdxInfo->aOrderBy[0].iColumn<=0
15534d0b1acSdrh    && pIdxInfo->aOrderBy[0].desc==0
15634d0b1acSdrh   ){
15734d0b1acSdrh     pIdxInfo->orderByConsumed = 1;
15834d0b1acSdrh   }
1597d0ae003Sdrh   sqlite3VtabUsesAllSchemas(pIdxInfo);
160a43c8c8aSdrh   return SQLITE_OK;
161a43c8c8aSdrh }
162a43c8c8aSdrh 
163a43c8c8aSdrh /*
164a43c8c8aSdrh ** Open a new dbpagevfs cursor.
165a43c8c8aSdrh */
dbpageOpen(sqlite3_vtab * pVTab,sqlite3_vtab_cursor ** ppCursor)166a43c8c8aSdrh static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
167a43c8c8aSdrh   DbpageCursor *pCsr;
168a43c8c8aSdrh 
169a43c8c8aSdrh   pCsr = (DbpageCursor *)sqlite3_malloc64(sizeof(DbpageCursor));
170a43c8c8aSdrh   if( pCsr==0 ){
171a43c8c8aSdrh     return SQLITE_NOMEM_BKPT;
172a43c8c8aSdrh   }else{
173a43c8c8aSdrh     memset(pCsr, 0, sizeof(DbpageCursor));
174a43c8c8aSdrh     pCsr->base.pVtab = pVTab;
175a43c8c8aSdrh     pCsr->pgno = -1;
176a43c8c8aSdrh   }
177a43c8c8aSdrh 
178a43c8c8aSdrh   *ppCursor = (sqlite3_vtab_cursor *)pCsr;
179a43c8c8aSdrh   return SQLITE_OK;
180a43c8c8aSdrh }
181a43c8c8aSdrh 
182a43c8c8aSdrh /*
183a43c8c8aSdrh ** Close a dbpagevfs cursor.
184a43c8c8aSdrh */
dbpageClose(sqlite3_vtab_cursor * pCursor)185a43c8c8aSdrh static int dbpageClose(sqlite3_vtab_cursor *pCursor){
186a43c8c8aSdrh   DbpageCursor *pCsr = (DbpageCursor *)pCursor;
1873cd8aaa7Sdrh   if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1);
188a43c8c8aSdrh   sqlite3_free(pCsr);
189a43c8c8aSdrh   return SQLITE_OK;
190a43c8c8aSdrh }
191a43c8c8aSdrh 
192a43c8c8aSdrh /*
193a43c8c8aSdrh ** Move a dbpagevfs cursor to the next entry in the file.
194a43c8c8aSdrh */
dbpageNext(sqlite3_vtab_cursor * pCursor)195a43c8c8aSdrh static int dbpageNext(sqlite3_vtab_cursor *pCursor){
196a43c8c8aSdrh   int rc = SQLITE_OK;
197a43c8c8aSdrh   DbpageCursor *pCsr = (DbpageCursor *)pCursor;
198a43c8c8aSdrh   pCsr->pgno++;
199a43c8c8aSdrh   return rc;
200a43c8c8aSdrh }
201a43c8c8aSdrh 
dbpageEof(sqlite3_vtab_cursor * pCursor)202a43c8c8aSdrh static int dbpageEof(sqlite3_vtab_cursor *pCursor){
203a43c8c8aSdrh   DbpageCursor *pCsr = (DbpageCursor *)pCursor;
20434d0b1acSdrh   return pCsr->pgno > pCsr->mxPgno;
205a43c8c8aSdrh }
206a43c8c8aSdrh 
2073cd8aaa7Sdrh /*
2083cd8aaa7Sdrh ** idxNum:
2093cd8aaa7Sdrh **
2103cd8aaa7Sdrh **     0     schema=main, full table scan
2113cd8aaa7Sdrh **     1     schema=main, pgno=?1
2123cd8aaa7Sdrh **     2     schema=?1, full table scan
2133cd8aaa7Sdrh **     3     schema=?1, pgno=?2
2143cd8aaa7Sdrh **
2153cd8aaa7Sdrh ** idxStr is not used
2163cd8aaa7Sdrh */
dbpageFilter(sqlite3_vtab_cursor * pCursor,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)217a43c8c8aSdrh static int dbpageFilter(
218a43c8c8aSdrh   sqlite3_vtab_cursor *pCursor,
219a43c8c8aSdrh   int idxNum, const char *idxStr,
220a43c8c8aSdrh   int argc, sqlite3_value **argv
221a43c8c8aSdrh ){
222a43c8c8aSdrh   DbpageCursor *pCsr = (DbpageCursor *)pCursor;
223a43c8c8aSdrh   DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
2240503f2acSdrh   int rc;
2253cd8aaa7Sdrh   sqlite3 *db = pTab->db;
2263cd8aaa7Sdrh   Btree *pBt;
227a43c8c8aSdrh 
2283cd8aaa7Sdrh   /* Default setting is no rows of result */
2293cd8aaa7Sdrh   pCsr->pgno = 1;
2303cd8aaa7Sdrh   pCsr->mxPgno = 0;
2313cd8aaa7Sdrh 
2323cd8aaa7Sdrh   if( idxNum & 2 ){
2333cd8aaa7Sdrh     const char *zSchema;
2343cd8aaa7Sdrh     assert( argc>=1 );
2353cd8aaa7Sdrh     zSchema = (const char*)sqlite3_value_text(argv[0]);
2363cd8aaa7Sdrh     pCsr->iDb = sqlite3FindDbName(db, zSchema);
2373cd8aaa7Sdrh     if( pCsr->iDb<0 ) return SQLITE_OK;
2383cd8aaa7Sdrh   }else{
2393cd8aaa7Sdrh     pCsr->iDb = 0;
2403cd8aaa7Sdrh   }
2413cd8aaa7Sdrh   pBt = db->aDb[pCsr->iDb].pBt;
2423cd8aaa7Sdrh   if( pBt==0 ) return SQLITE_OK;
2433cd8aaa7Sdrh   pCsr->pPager = sqlite3BtreePager(pBt);
2443cd8aaa7Sdrh   pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
2453cd8aaa7Sdrh   pCsr->mxPgno = sqlite3BtreeLastPage(pBt);
2463cd8aaa7Sdrh   if( idxNum & 1 ){
2473cd8aaa7Sdrh     assert( argc>(idxNum>>1) );
2483cd8aaa7Sdrh     pCsr->pgno = sqlite3_value_int(argv[idxNum>>1]);
2493cd8aaa7Sdrh     if( pCsr->pgno<1 || pCsr->pgno>pCsr->mxPgno ){
25034d0b1acSdrh       pCsr->pgno = 1;
25134d0b1acSdrh       pCsr->mxPgno = 0;
25234d0b1acSdrh     }else{
25334d0b1acSdrh       pCsr->mxPgno = pCsr->pgno;
25434d0b1acSdrh     }
25534d0b1acSdrh   }else{
2563cd8aaa7Sdrh     assert( pCsr->pgno==1 );
25734d0b1acSdrh   }
2580503f2acSdrh   if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1);
2593cd8aaa7Sdrh   rc = sqlite3PagerGet(pCsr->pPager, 1, &pCsr->pPage1, 0);
260a43c8c8aSdrh   return rc;
261a43c8c8aSdrh }
262a43c8c8aSdrh 
dbpageColumn(sqlite3_vtab_cursor * pCursor,sqlite3_context * ctx,int i)263a43c8c8aSdrh static int dbpageColumn(
264a43c8c8aSdrh   sqlite3_vtab_cursor *pCursor,
265a43c8c8aSdrh   sqlite3_context *ctx,
266a43c8c8aSdrh   int i
267a43c8c8aSdrh ){
268a43c8c8aSdrh   DbpageCursor *pCsr = (DbpageCursor *)pCursor;
269a43c8c8aSdrh   int rc = SQLITE_OK;
270a43c8c8aSdrh   switch( i ){
271a43c8c8aSdrh     case 0: {           /* pgno */
272a43c8c8aSdrh       sqlite3_result_int(ctx, pCsr->pgno);
273a43c8c8aSdrh       break;
274a43c8c8aSdrh     }
275a43c8c8aSdrh     case 1: {           /* data */
276a43c8c8aSdrh       DbPage *pDbPage = 0;
2777985e05aSdan       if( pCsr->pgno==((PENDING_BYTE/pCsr->szPage)+1) ){
2787985e05aSdan         /* The pending byte page. Assume it is zeroed out. Attempting to
2797985e05aSdan         ** request this page from the page is an SQLITE_CORRUPT error. */
2807985e05aSdan         sqlite3_result_zeroblob(ctx, pCsr->szPage);
2817985e05aSdan       }else{
2823cd8aaa7Sdrh         rc = sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
283a43c8c8aSdrh         if( rc==SQLITE_OK ){
2843cd8aaa7Sdrh           sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pCsr->szPage,
285a43c8c8aSdrh               SQLITE_TRANSIENT);
286a43c8c8aSdrh         }
287a43c8c8aSdrh         sqlite3PagerUnref(pDbPage);
2887985e05aSdan       }
289a43c8c8aSdrh       break;
290a43c8c8aSdrh     }
291a43c8c8aSdrh     default: {          /* schema */
292a43c8c8aSdrh       sqlite3 *db = sqlite3_context_db_handle(ctx);
2933cd8aaa7Sdrh       sqlite3_result_text(ctx, db->aDb[pCsr->iDb].zDbSName, -1, SQLITE_STATIC);
294a43c8c8aSdrh       break;
295a43c8c8aSdrh     }
296a43c8c8aSdrh   }
2975ca0b386Sdan   return rc;
298a43c8c8aSdrh }
299a43c8c8aSdrh 
dbpageRowid(sqlite3_vtab_cursor * pCursor,sqlite_int64 * pRowid)300a43c8c8aSdrh static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
301a43c8c8aSdrh   DbpageCursor *pCsr = (DbpageCursor *)pCursor;
302a43c8c8aSdrh   *pRowid = pCsr->pgno;
303a43c8c8aSdrh   return SQLITE_OK;
304a43c8c8aSdrh }
305a43c8c8aSdrh 
dbpageUpdate(sqlite3_vtab * pVtab,int argc,sqlite3_value ** argv,sqlite_int64 * pRowid)30634d0b1acSdrh static int dbpageUpdate(
30734d0b1acSdrh   sqlite3_vtab *pVtab,
30834d0b1acSdrh   int argc,
30934d0b1acSdrh   sqlite3_value **argv,
31034d0b1acSdrh   sqlite_int64 *pRowid
31134d0b1acSdrh ){
31234d0b1acSdrh   DbpageTable *pTab = (DbpageTable *)pVtab;
313aca84e6aSmistachkin   Pgno pgno;
31434d0b1acSdrh   DbPage *pDbPage = 0;
31534d0b1acSdrh   int rc = SQLITE_OK;
31634d0b1acSdrh   char *zErr = 0;
3173cd8aaa7Sdrh   const char *zSchema;
3183cd8aaa7Sdrh   int iDb;
3193cd8aaa7Sdrh   Btree *pBt;
3203cd8aaa7Sdrh   Pager *pPager;
3213cd8aaa7Sdrh   int szPage;
32234d0b1acSdrh 
323a296cda0Sdrh   if( pTab->db->flags & SQLITE_Defensive ){
324a296cda0Sdrh     zErr = "read-only";
325a296cda0Sdrh     goto update_fail;
326a296cda0Sdrh   }
32734d0b1acSdrh   if( argc==1 ){
32834d0b1acSdrh     zErr = "cannot delete";
32934d0b1acSdrh     goto update_fail;
33034d0b1acSdrh   }
33134d0b1acSdrh   pgno = sqlite3_value_int(argv[0]);
332aca84e6aSmistachkin   if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){
33334d0b1acSdrh     zErr = "cannot insert";
33434d0b1acSdrh     goto update_fail;
33534d0b1acSdrh   }
3363cd8aaa7Sdrh   zSchema = (const char*)sqlite3_value_text(argv[4]);
3373cd8aaa7Sdrh   iDb = zSchema ? sqlite3FindDbName(pTab->db, zSchema) : -1;
3383cd8aaa7Sdrh   if( iDb<0 ){
3393cd8aaa7Sdrh     zErr = "no such schema";
3403cd8aaa7Sdrh     goto update_fail;
3413cd8aaa7Sdrh   }
3423cd8aaa7Sdrh   pBt = pTab->db->aDb[iDb].pBt;
343e684ac6fSdrh   if( pgno<1 || pBt==0 || pgno>sqlite3BtreeLastPage(pBt) ){
3443cd8aaa7Sdrh     zErr = "bad page number";
3453cd8aaa7Sdrh     goto update_fail;
3463cd8aaa7Sdrh   }
3473cd8aaa7Sdrh   szPage = sqlite3BtreeGetPageSize(pBt);
34834d0b1acSdrh   if( sqlite3_value_type(argv[3])!=SQLITE_BLOB
3493cd8aaa7Sdrh    || sqlite3_value_bytes(argv[3])!=szPage
35034d0b1acSdrh   ){
35134d0b1acSdrh     zErr = "bad page value";
35234d0b1acSdrh     goto update_fail;
35334d0b1acSdrh   }
3543cd8aaa7Sdrh   pPager = sqlite3BtreePager(pBt);
3553cd8aaa7Sdrh   rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0);
35634d0b1acSdrh   if( rc==SQLITE_OK ){
357*c7dd9b60Sdrh     const void *pData = sqlite3_value_blob(argv[3]);
358*c7dd9b60Sdrh     assert( pData!=0 || pTab->db->mallocFailed );
359*c7dd9b60Sdrh     if( pData
360*c7dd9b60Sdrh      && (rc = sqlite3PagerWrite(pDbPage))==SQLITE_OK
361*c7dd9b60Sdrh     ){
362*c7dd9b60Sdrh       memcpy(sqlite3PagerGetData(pDbPage), pData, szPage);
36334d0b1acSdrh     }
36434d0b1acSdrh   }
36534d0b1acSdrh   sqlite3PagerUnref(pDbPage);
36634d0b1acSdrh   return rc;
36734d0b1acSdrh 
36834d0b1acSdrh update_fail:
36934d0b1acSdrh   sqlite3_free(pVtab->zErrMsg);
37034d0b1acSdrh   pVtab->zErrMsg = sqlite3_mprintf("%s", zErr);
37134d0b1acSdrh   return SQLITE_ERROR;
37234d0b1acSdrh }
37334d0b1acSdrh 
3743cd8aaa7Sdrh /* Since we do not know in advance which database files will be
3753cd8aaa7Sdrh ** written by the sqlite_dbpage virtual table, start a write transaction
3763cd8aaa7Sdrh ** on them all.
3773cd8aaa7Sdrh */
dbpageBegin(sqlite3_vtab * pVtab)3783cd8aaa7Sdrh static int dbpageBegin(sqlite3_vtab *pVtab){
3793cd8aaa7Sdrh   DbpageTable *pTab = (DbpageTable *)pVtab;
3803cd8aaa7Sdrh   sqlite3 *db = pTab->db;
3813cd8aaa7Sdrh   int i;
382e36281fcSdan   int rc = SQLITE_OK;
383e36281fcSdan   for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
3843cd8aaa7Sdrh     Btree *pBt = db->aDb[i].pBt;
385e36281fcSdan     if( pBt ) rc = sqlite3BtreeBeginTrans(pBt, 1, 0);
3863cd8aaa7Sdrh   }
387e36281fcSdan   return rc;
3883cd8aaa7Sdrh }
3893cd8aaa7Sdrh 
3903cd8aaa7Sdrh 
391a43c8c8aSdrh /*
392a43c8c8aSdrh ** Invoke this routine to register the "dbpage" virtual table module
393a43c8c8aSdrh */
sqlite3DbpageRegister(sqlite3 * db)394a43c8c8aSdrh int sqlite3DbpageRegister(sqlite3 *db){
395a43c8c8aSdrh   static sqlite3_module dbpage_module = {
396a43c8c8aSdrh     0,                            /* iVersion */
397a43c8c8aSdrh     dbpageConnect,                /* xCreate */
398a43c8c8aSdrh     dbpageConnect,                /* xConnect */
399a43c8c8aSdrh     dbpageBestIndex,              /* xBestIndex */
400a43c8c8aSdrh     dbpageDisconnect,             /* xDisconnect */
401a43c8c8aSdrh     dbpageDisconnect,             /* xDestroy */
402a43c8c8aSdrh     dbpageOpen,                   /* xOpen - open a cursor */
403a43c8c8aSdrh     dbpageClose,                  /* xClose - close a cursor */
404a43c8c8aSdrh     dbpageFilter,                 /* xFilter - configure scan constraints */
405a43c8c8aSdrh     dbpageNext,                   /* xNext - advance a cursor */
406a43c8c8aSdrh     dbpageEof,                    /* xEof - check for end of scan */
407a43c8c8aSdrh     dbpageColumn,                 /* xColumn - read data */
408a43c8c8aSdrh     dbpageRowid,                  /* xRowid - read data */
40934d0b1acSdrh     dbpageUpdate,                 /* xUpdate */
4103cd8aaa7Sdrh     dbpageBegin,                  /* xBegin */
411a43c8c8aSdrh     0,                            /* xSync */
412a43c8c8aSdrh     0,                            /* xCommit */
413a43c8c8aSdrh     0,                            /* xRollback */
414a43c8c8aSdrh     0,                            /* xFindMethod */
415a43c8c8aSdrh     0,                            /* xRename */
416a43c8c8aSdrh     0,                            /* xSavepoint */
417a43c8c8aSdrh     0,                            /* xRelease */
418a43c8c8aSdrh     0,                            /* xRollbackTo */
41984c501baSdrh     0                             /* xShadowName */
420a43c8c8aSdrh   };
421a43c8c8aSdrh   return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
422a43c8c8aSdrh }
423a43c8c8aSdrh #elif defined(SQLITE_ENABLE_DBPAGE_VTAB)
sqlite3DbpageRegister(sqlite3 * db)424a43c8c8aSdrh int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; }
425a43c8c8aSdrh #endif /* SQLITE_ENABLE_DBSTAT_VTAB */
426