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