xref: /sqlite-3.40.0/src/dbpage.c (revision a43c8c8a)
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 
21 #include "sqliteInt.h"   /* Requires access to internal data structures */
22 #if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
23     && !defined(SQLITE_OMIT_VIRTUALTABLE)
24 
25 typedef struct DbpageTable DbpageTable;
26 typedef struct DbpageCursor DbpageCursor;
27 
28 struct DbpageCursor {
29   sqlite3_vtab_cursor base;       /* Base class.  Must be first */
30   int pgno;                       /* Current page number */
31 };
32 
33 struct DbpageTable {
34   sqlite3_vtab base;              /* Base class.  Must be first */
35   sqlite3 *db;                    /* The database */
36   Pager *pPager;                  /* Pager being read/written */
37   int iDb;                        /* Index of database to analyze */
38   int szPage;                     /* Size of each page in bytes */
39   int nPage;                      /* Number of pages in the file */
40 };
41 
42 /*
43 ** Connect to or create a dbpagevfs virtual table.
44 */
45 static int dbpageConnect(
46   sqlite3 *db,
47   void *pAux,
48   int argc, const char *const*argv,
49   sqlite3_vtab **ppVtab,
50   char **pzErr
51 ){
52   DbpageTable *pTab = 0;
53   int rc = SQLITE_OK;
54   int iDb;
55 
56   if( argc>=4 ){
57     Token nm;
58     sqlite3TokenInit(&nm, (char*)argv[3]);
59     iDb = sqlite3FindDb(db, &nm);
60     if( iDb<0 ){
61       *pzErr = sqlite3_mprintf("no such schema: %s", argv[3]);
62       return SQLITE_ERROR;
63     }
64   }else{
65     iDb = 0;
66   }
67   rc = sqlite3_declare_vtab(db,
68           "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB)");
69   if( rc==SQLITE_OK ){
70     pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable));
71     if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
72   }
73 
74   assert( rc==SQLITE_OK || pTab==0 );
75   if( rc==SQLITE_OK ){
76     Btree *pBt = db->aDb[iDb].pBt;
77     memset(pTab, 0, sizeof(DbpageTable));
78     pTab->db = db;
79     pTab->iDb = iDb;
80     pTab->pPager = pBt ? sqlite3BtreePager(pBt) : 0;
81   }
82 
83   *ppVtab = (sqlite3_vtab*)pTab;
84   return rc;
85 }
86 
87 /*
88 ** Disconnect from or destroy a dbpagevfs virtual table.
89 */
90 static int dbpageDisconnect(sqlite3_vtab *pVtab){
91   sqlite3_free(pVtab);
92   return SQLITE_OK;
93 }
94 
95 /*
96 ** idxNum:
97 **
98 **     0     full table scan
99 **     1     pgno=?1
100 */
101 static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
102   pIdxInfo->estimatedCost = 1.0e6;  /* Initial cost estimate */
103   return SQLITE_OK;
104 }
105 
106 /*
107 ** Open a new dbpagevfs cursor.
108 */
109 static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
110   DbpageCursor *pCsr;
111 
112   pCsr = (DbpageCursor *)sqlite3_malloc64(sizeof(DbpageCursor));
113   if( pCsr==0 ){
114     return SQLITE_NOMEM_BKPT;
115   }else{
116     memset(pCsr, 0, sizeof(DbpageCursor));
117     pCsr->base.pVtab = pVTab;
118     pCsr->pgno = -1;
119   }
120 
121   *ppCursor = (sqlite3_vtab_cursor *)pCsr;
122   return SQLITE_OK;
123 }
124 
125 /*
126 ** Close a dbpagevfs cursor.
127 */
128 static int dbpageClose(sqlite3_vtab_cursor *pCursor){
129   DbpageCursor *pCsr = (DbpageCursor *)pCursor;
130   sqlite3_free(pCsr);
131   return SQLITE_OK;
132 }
133 
134 /*
135 ** Move a dbpagevfs cursor to the next entry in the file.
136 */
137 static int dbpageNext(sqlite3_vtab_cursor *pCursor){
138   int rc = SQLITE_OK;
139   DbpageCursor *pCsr = (DbpageCursor *)pCursor;
140   pCsr->pgno++;
141   return rc;
142 }
143 
144 static int dbpageEof(sqlite3_vtab_cursor *pCursor){
145   DbpageCursor *pCsr = (DbpageCursor *)pCursor;
146   DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
147   return pCsr->pgno >= pTab->nPage;
148 }
149 
150 static int dbpageFilter(
151   sqlite3_vtab_cursor *pCursor,
152   int idxNum, const char *idxStr,
153   int argc, sqlite3_value **argv
154 ){
155   DbpageCursor *pCsr = (DbpageCursor *)pCursor;
156   DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
157   int rc = SQLITE_OK;
158   Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
159 
160   if( idxNum==1 ){
161     pCsr->pgno = sqlite3_value_int(argv[0]);
162   }else{
163     pCsr->pgno = 0;
164   }
165   pTab->szPage = sqlite3BtreeGetPageSize(pBt);
166   pTab->nPage = sqlite3BtreeLastPage(pBt);
167   return rc;
168 }
169 
170 static int dbpageColumn(
171   sqlite3_vtab_cursor *pCursor,
172   sqlite3_context *ctx,
173   int i
174 ){
175   DbpageCursor *pCsr = (DbpageCursor *)pCursor;
176   DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
177   int rc = SQLITE_OK;
178   switch( i ){
179     case 0: {           /* pgno */
180       sqlite3_result_int(ctx, pCsr->pgno);
181       break;
182     }
183     case 1: {           /* data */
184       DbPage *pDbPage = 0;
185       rc = sqlite3PagerGet(pTab->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
186       if( rc==SQLITE_OK ){
187         sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pTab->szPage,
188                             SQLITE_TRANSIENT);
189       }
190       sqlite3PagerUnref(pDbPage);
191       break;
192     }
193     default: {          /* schema */
194       sqlite3 *db = sqlite3_context_db_handle(ctx);
195       sqlite3_result_text(ctx, db->aDb[pTab->iDb].zDbSName, -1, SQLITE_STATIC);
196       break;
197     }
198   }
199   return SQLITE_OK;
200 }
201 
202 static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
203   DbpageCursor *pCsr = (DbpageCursor *)pCursor;
204   *pRowid = pCsr->pgno;
205   return SQLITE_OK;
206 }
207 
208 /*
209 ** Invoke this routine to register the "dbpage" virtual table module
210 */
211 int sqlite3DbpageRegister(sqlite3 *db){
212   static sqlite3_module dbpage_module = {
213     0,                            /* iVersion */
214     dbpageConnect,                /* xCreate */
215     dbpageConnect,                /* xConnect */
216     dbpageBestIndex,              /* xBestIndex */
217     dbpageDisconnect,             /* xDisconnect */
218     dbpageDisconnect,             /* xDestroy */
219     dbpageOpen,                   /* xOpen - open a cursor */
220     dbpageClose,                  /* xClose - close a cursor */
221     dbpageFilter,                 /* xFilter - configure scan constraints */
222     dbpageNext,                   /* xNext - advance a cursor */
223     dbpageEof,                    /* xEof - check for end of scan */
224     dbpageColumn,                 /* xColumn - read data */
225     dbpageRowid,                  /* xRowid - read data */
226     0,                            /* xUpdate */
227     0,                            /* xBegin */
228     0,                            /* xSync */
229     0,                            /* xCommit */
230     0,                            /* xRollback */
231     0,                            /* xFindMethod */
232     0,                            /* xRename */
233     0,                            /* xSavepoint */
234     0,                            /* xRelease */
235     0,                            /* xRollbackTo */
236   };
237   return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
238 }
239 #elif defined(SQLITE_ENABLE_DBPAGE_VTAB)
240 int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; }
241 #endif /* SQLITE_ENABLE_DBSTAT_VTAB */
242