xref: /sqlite-3.40.0/src/dbpage.c (revision b5ef728d)
1 /*
2 ** 2017-10-11
3 **
4 ** The author disclaims copyright to this source code.  In place of
5 ** a legal notice, here is a blessing:
6 **
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.
10 **
11 ******************************************************************************
12 **
13 ** This file contains an implementation of the "sqlite_dbpage" virtual table.
14 **
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
18 ** retrieved.
19 **
20 ** Usage example:
21 **
22 **    SELECT data FROM sqlite_dbpage('aux1') WHERE pgno=123;
23 **
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
27 ** "main".
28 **
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.
32 */
33 
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)
37 
38 typedef struct DbpageTable DbpageTable;
39 typedef struct DbpageCursor DbpageCursor;
40 
41 struct 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 };
46 
47 struct DbpageTable {
48   sqlite3_vtab base;              /* Base class.  Must be first */
49   sqlite3 *db;                    /* The database */
50   Pager *pPager;                  /* Pager being read/written */
51   int iDb;                        /* Index of database to analyze */
52   int szPage;                     /* Size of each page in bytes */
53   int nPage;                      /* Number of pages in the file */
54 };
55 
56 /*
57 ** Connect to or create a dbpagevfs virtual table.
58 */
59 static int dbpageConnect(
60   sqlite3 *db,
61   void *pAux,
62   int argc, const char *const*argv,
63   sqlite3_vtab **ppVtab,
64   char **pzErr
65 ){
66   DbpageTable *pTab = 0;
67   int rc = SQLITE_OK;
68   int iDb;
69 
70   if( argc>=4 ){
71     Token nm;
72     sqlite3TokenInit(&nm, (char*)argv[3]);
73     iDb = sqlite3FindDb(db, &nm);
74     if( iDb<0 ){
75       *pzErr = sqlite3_mprintf("no such schema: %s", argv[3]);
76       return SQLITE_ERROR;
77     }
78   }else{
79     iDb = 0;
80   }
81   rc = sqlite3_declare_vtab(db,
82           "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
83   if( rc==SQLITE_OK ){
84     pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable));
85     if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
86   }
87 
88   assert( rc==SQLITE_OK || pTab==0 );
89   if( rc==SQLITE_OK ){
90     Btree *pBt = db->aDb[iDb].pBt;
91     memset(pTab, 0, sizeof(DbpageTable));
92     pTab->db = db;
93     pTab->iDb = iDb;
94     pTab->pPager = pBt ? sqlite3BtreePager(pBt) : 0;
95   }
96 
97   *ppVtab = (sqlite3_vtab*)pTab;
98   return rc;
99 }
100 
101 /*
102 ** Disconnect from or destroy a dbpagevfs virtual table.
103 */
104 static int dbpageDisconnect(sqlite3_vtab *pVtab){
105   sqlite3_free(pVtab);
106   return SQLITE_OK;
107 }
108 
109 /*
110 ** idxNum:
111 **
112 **     0     full table scan
113 **     1     pgno=?1
114 */
115 static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
116   int i;
117   pIdxInfo->estimatedCost = 1.0e6;  /* Initial cost estimate */
118   for(i=0; i<pIdxInfo->nConstraint; i++){
119     struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
120     if( p->usable && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
121       pIdxInfo->estimatedRows = 1;
122       pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
123       pIdxInfo->estimatedCost = 1.0;
124       pIdxInfo->idxNum = 1;
125       pIdxInfo->aConstraintUsage[i].argvIndex = 1;
126       pIdxInfo->aConstraintUsage[i].omit = 1;
127       break;
128     }
129   }
130   if( pIdxInfo->nOrderBy>=1
131    && pIdxInfo->aOrderBy[0].iColumn<=0
132    && pIdxInfo->aOrderBy[0].desc==0
133   ){
134     pIdxInfo->orderByConsumed = 1;
135   }
136   return SQLITE_OK;
137 }
138 
139 /*
140 ** Open a new dbpagevfs cursor.
141 */
142 static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
143   DbpageCursor *pCsr;
144 
145   pCsr = (DbpageCursor *)sqlite3_malloc64(sizeof(DbpageCursor));
146   if( pCsr==0 ){
147     return SQLITE_NOMEM_BKPT;
148   }else{
149     memset(pCsr, 0, sizeof(DbpageCursor));
150     pCsr->base.pVtab = pVTab;
151     pCsr->pgno = -1;
152   }
153 
154   *ppCursor = (sqlite3_vtab_cursor *)pCsr;
155   return SQLITE_OK;
156 }
157 
158 /*
159 ** Close a dbpagevfs cursor.
160 */
161 static int dbpageClose(sqlite3_vtab_cursor *pCursor){
162   DbpageCursor *pCsr = (DbpageCursor *)pCursor;
163   sqlite3_free(pCsr);
164   return SQLITE_OK;
165 }
166 
167 /*
168 ** Move a dbpagevfs cursor to the next entry in the file.
169 */
170 static int dbpageNext(sqlite3_vtab_cursor *pCursor){
171   int rc = SQLITE_OK;
172   DbpageCursor *pCsr = (DbpageCursor *)pCursor;
173   pCsr->pgno++;
174   return rc;
175 }
176 
177 static int dbpageEof(sqlite3_vtab_cursor *pCursor){
178   DbpageCursor *pCsr = (DbpageCursor *)pCursor;
179   return pCsr->pgno > pCsr->mxPgno;
180 }
181 
182 static int dbpageFilter(
183   sqlite3_vtab_cursor *pCursor,
184   int idxNum, const char *idxStr,
185   int argc, sqlite3_value **argv
186 ){
187   DbpageCursor *pCsr = (DbpageCursor *)pCursor;
188   DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
189   int rc = SQLITE_OK;
190   Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
191 
192   pTab->szPage = sqlite3BtreeGetPageSize(pBt);
193   pTab->nPage = sqlite3BtreeLastPage(pBt);
194   if( idxNum==1 ){
195     pCsr->pgno = sqlite3_value_int(argv[0]);
196     if( pCsr->pgno<1 || pCsr->pgno>pTab->nPage ){
197       pCsr->pgno = 1;
198       pCsr->mxPgno = 0;
199     }else{
200       pCsr->mxPgno = pCsr->pgno;
201     }
202   }else{
203     pCsr->pgno = 1;
204     pCsr->mxPgno = pTab->nPage;
205   }
206   return rc;
207 }
208 
209 static int dbpageColumn(
210   sqlite3_vtab_cursor *pCursor,
211   sqlite3_context *ctx,
212   int i
213 ){
214   DbpageCursor *pCsr = (DbpageCursor *)pCursor;
215   DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
216   int rc = SQLITE_OK;
217   switch( i ){
218     case 0: {           /* pgno */
219       sqlite3_result_int(ctx, pCsr->pgno);
220       break;
221     }
222     case 1: {           /* data */
223       DbPage *pDbPage = 0;
224       rc = sqlite3PagerGet(pTab->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
225       if( rc==SQLITE_OK ){
226         sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pTab->szPage,
227                             SQLITE_TRANSIENT);
228       }
229       sqlite3PagerUnref(pDbPage);
230       break;
231     }
232     default: {          /* schema */
233       sqlite3 *db = sqlite3_context_db_handle(ctx);
234       sqlite3_result_text(ctx, db->aDb[pTab->iDb].zDbSName, -1, SQLITE_STATIC);
235       break;
236     }
237   }
238   return SQLITE_OK;
239 }
240 
241 static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
242   DbpageCursor *pCsr = (DbpageCursor *)pCursor;
243   *pRowid = pCsr->pgno;
244   return SQLITE_OK;
245 }
246 
247 static int dbpageUpdate(
248   sqlite3_vtab *pVtab,
249   int argc,
250   sqlite3_value **argv,
251   sqlite_int64 *pRowid
252 ){
253   DbpageTable *pTab = (DbpageTable *)pVtab;
254   int pgno;
255   DbPage *pDbPage = 0;
256   int rc = SQLITE_OK;
257   char *zErr = 0;
258 
259   if( argc==1 ){
260     zErr = "cannot delete";
261     goto update_fail;
262   }
263   pgno = sqlite3_value_int(argv[0]);
264   if( pgno<1 || pgno>pTab->nPage ){
265     zErr = "bad page number";
266     goto update_fail;
267   }
268   if( sqlite3_value_int(argv[1])!=pgno ){
269     zErr = "cannot insert";
270     goto update_fail;
271   }
272   if( sqlite3_value_type(argv[3])!=SQLITE_BLOB
273    || sqlite3_value_bytes(argv[3])!=pTab->szPage
274   ){
275     zErr = "bad page value";
276     goto update_fail;
277   }
278   rc = sqlite3PagerGet(pTab->pPager, pgno, (DbPage**)&pDbPage, 0);
279   if( rc==SQLITE_OK ){
280     rc = sqlite3PagerWrite(pDbPage);
281     if( rc==SQLITE_OK ){
282       memcpy(sqlite3PagerGetData(pDbPage),
283              sqlite3_value_blob(argv[3]),
284              pTab->szPage);
285     }
286   }
287   sqlite3PagerUnref(pDbPage);
288   return rc;
289 
290 update_fail:
291   sqlite3_free(pVtab->zErrMsg);
292   pVtab->zErrMsg = sqlite3_mprintf("%s", zErr);
293   return SQLITE_ERROR;
294 }
295 
296 /*
297 ** Invoke this routine to register the "dbpage" virtual table module
298 */
299 int sqlite3DbpageRegister(sqlite3 *db){
300   static sqlite3_module dbpage_module = {
301     0,                            /* iVersion */
302     dbpageConnect,                /* xCreate */
303     dbpageConnect,                /* xConnect */
304     dbpageBestIndex,              /* xBestIndex */
305     dbpageDisconnect,             /* xDisconnect */
306     dbpageDisconnect,             /* xDestroy */
307     dbpageOpen,                   /* xOpen - open a cursor */
308     dbpageClose,                  /* xClose - close a cursor */
309     dbpageFilter,                 /* xFilter - configure scan constraints */
310     dbpageNext,                   /* xNext - advance a cursor */
311     dbpageEof,                    /* xEof - check for end of scan */
312     dbpageColumn,                 /* xColumn - read data */
313     dbpageRowid,                  /* xRowid - read data */
314     dbpageUpdate,                 /* xUpdate */
315     0,                            /* xBegin */
316     0,                            /* xSync */
317     0,                            /* xCommit */
318     0,                            /* xRollback */
319     0,                            /* xFindMethod */
320     0,                            /* xRename */
321     0,                            /* xSavepoint */
322     0,                            /* xRelease */
323     0,                            /* xRollbackTo */
324   };
325   return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
326 }
327 #elif defined(SQLITE_ENABLE_DBPAGE_VTAB)
328 int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; }
329 #endif /* SQLITE_ENABLE_DBSTAT_VTAB */
330