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 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 */ 49 }; 50 51 struct DbpageTable { 52 sqlite3_vtab base; /* Base class. Must be first */ 53 sqlite3 *db; /* The database */ 54 }; 55 56 /* Columns */ 57 #define DBPAGE_COLUMN_PGNO 0 58 #define DBPAGE_COLUMN_DATA 1 59 #define DBPAGE_COLUMN_SCHEMA 2 60 61 62 63 /* 64 ** Connect to or create a dbpagevfs virtual table. 65 */ 66 static int dbpageConnect( 67 sqlite3 *db, 68 void *pAux, 69 int argc, const char *const*argv, 70 sqlite3_vtab **ppVtab, 71 char **pzErr 72 ){ 73 DbpageTable *pTab = 0; 74 int rc = SQLITE_OK; 75 76 rc = sqlite3_declare_vtab(db, 77 "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)"); 78 if( rc==SQLITE_OK ){ 79 pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable)); 80 if( pTab==0 ) rc = SQLITE_NOMEM_BKPT; 81 } 82 83 assert( rc==SQLITE_OK || pTab==0 ); 84 if( rc==SQLITE_OK ){ 85 memset(pTab, 0, sizeof(DbpageTable)); 86 pTab->db = db; 87 } 88 89 *ppVtab = (sqlite3_vtab*)pTab; 90 return rc; 91 } 92 93 /* 94 ** Disconnect from or destroy a dbpagevfs virtual table. 95 */ 96 static int dbpageDisconnect(sqlite3_vtab *pVtab){ 97 sqlite3_free(pVtab); 98 return SQLITE_OK; 99 } 100 101 /* 102 ** idxNum: 103 ** 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 108 */ 109 static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ 110 int i; 111 int iPlan = 0; 112 113 /* If there is a schema= constraint, it must be honored. Report a 114 ** ridiculously large estimated cost if the schema= constraint is 115 ** unavailable 116 */ 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; 121 if( !p->usable ){ 122 /* No solution. */ 123 return SQLITE_CONSTRAINT; 124 } 125 iPlan = 2; 126 pIdxInfo->aConstraintUsage[i].argvIndex = 1; 127 pIdxInfo->aConstraintUsage[i].omit = 1; 128 break; 129 } 130 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 134 */ 135 pIdxInfo->estimatedCost = 1.0e6; 136 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; 146 iPlan |= 1; 147 break; 148 } 149 } 150 pIdxInfo->idxNum = iPlan; 151 152 if( pIdxInfo->nOrderBy>=1 153 && pIdxInfo->aOrderBy[0].iColumn<=0 154 && pIdxInfo->aOrderBy[0].desc==0 155 ){ 156 pIdxInfo->orderByConsumed = 1; 157 } 158 return SQLITE_OK; 159 } 160 161 /* 162 ** Open a new dbpagevfs cursor. 163 */ 164 static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ 165 DbpageCursor *pCsr; 166 167 pCsr = (DbpageCursor *)sqlite3_malloc64(sizeof(DbpageCursor)); 168 if( pCsr==0 ){ 169 return SQLITE_NOMEM_BKPT; 170 }else{ 171 memset(pCsr, 0, sizeof(DbpageCursor)); 172 pCsr->base.pVtab = pVTab; 173 pCsr->pgno = -1; 174 } 175 176 *ppCursor = (sqlite3_vtab_cursor *)pCsr; 177 return SQLITE_OK; 178 } 179 180 /* 181 ** Close a dbpagevfs cursor. 182 */ 183 static int dbpageClose(sqlite3_vtab_cursor *pCursor){ 184 DbpageCursor *pCsr = (DbpageCursor *)pCursor; 185 if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1); 186 sqlite3_free(pCsr); 187 return SQLITE_OK; 188 } 189 190 /* 191 ** Move a dbpagevfs cursor to the next entry in the file. 192 */ 193 static int dbpageNext(sqlite3_vtab_cursor *pCursor){ 194 int rc = SQLITE_OK; 195 DbpageCursor *pCsr = (DbpageCursor *)pCursor; 196 pCsr->pgno++; 197 return rc; 198 } 199 200 static int dbpageEof(sqlite3_vtab_cursor *pCursor){ 201 DbpageCursor *pCsr = (DbpageCursor *)pCursor; 202 return pCsr->pgno > pCsr->mxPgno; 203 } 204 205 /* 206 ** idxNum: 207 ** 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 212 ** 213 ** idxStr is not used 214 */ 215 static int dbpageFilter( 216 sqlite3_vtab_cursor *pCursor, 217 int idxNum, const char *idxStr, 218 int argc, sqlite3_value **argv 219 ){ 220 DbpageCursor *pCsr = (DbpageCursor *)pCursor; 221 DbpageTable *pTab = (DbpageTable *)pCursor->pVtab; 222 int rc; 223 sqlite3 *db = pTab->db; 224 Btree *pBt; 225 226 /* Default setting is no rows of result */ 227 pCsr->pgno = 1; 228 pCsr->mxPgno = 0; 229 230 if( idxNum & 2 ){ 231 const char *zSchema; 232 assert( argc>=1 ); 233 zSchema = (const char*)sqlite3_value_text(argv[0]); 234 pCsr->iDb = sqlite3FindDbName(db, zSchema); 235 if( pCsr->iDb<0 ) return SQLITE_OK; 236 }else{ 237 pCsr->iDb = 0; 238 } 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); 244 if( idxNum & 1 ){ 245 assert( argc>(idxNum>>1) ); 246 pCsr->pgno = sqlite3_value_int(argv[idxNum>>1]); 247 if( pCsr->pgno<1 || pCsr->pgno>pCsr->mxPgno ){ 248 pCsr->pgno = 1; 249 pCsr->mxPgno = 0; 250 }else{ 251 pCsr->mxPgno = pCsr->pgno; 252 } 253 }else{ 254 assert( pCsr->pgno==1 ); 255 } 256 if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1); 257 rc = sqlite3PagerGet(pCsr->pPager, 1, &pCsr->pPage1, 0); 258 return rc; 259 } 260 261 static int dbpageColumn( 262 sqlite3_vtab_cursor *pCursor, 263 sqlite3_context *ctx, 264 int i 265 ){ 266 DbpageCursor *pCsr = (DbpageCursor *)pCursor; 267 int rc = SQLITE_OK; 268 switch( i ){ 269 case 0: { /* pgno */ 270 sqlite3_result_int(ctx, pCsr->pgno); 271 break; 272 } 273 case 1: { /* data */ 274 DbPage *pDbPage = 0; 275 rc = sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0); 276 if( rc==SQLITE_OK ){ 277 sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pCsr->szPage, 278 SQLITE_TRANSIENT); 279 } 280 sqlite3PagerUnref(pDbPage); 281 break; 282 } 283 default: { /* schema */ 284 sqlite3 *db = sqlite3_context_db_handle(ctx); 285 sqlite3_result_text(ctx, db->aDb[pCsr->iDb].zDbSName, -1, SQLITE_STATIC); 286 break; 287 } 288 } 289 return SQLITE_OK; 290 } 291 292 static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ 293 DbpageCursor *pCsr = (DbpageCursor *)pCursor; 294 *pRowid = pCsr->pgno; 295 return SQLITE_OK; 296 } 297 298 static int dbpageUpdate( 299 sqlite3_vtab *pVtab, 300 int argc, 301 sqlite3_value **argv, 302 sqlite_int64 *pRowid 303 ){ 304 DbpageTable *pTab = (DbpageTable *)pVtab; 305 Pgno pgno; 306 DbPage *pDbPage = 0; 307 int rc = SQLITE_OK; 308 char *zErr = 0; 309 const char *zSchema; 310 int iDb; 311 Btree *pBt; 312 Pager *pPager; 313 int szPage; 314 315 if( pTab->db->flags & SQLITE_Defensive ){ 316 zErr = "read-only"; 317 goto update_fail; 318 } 319 if( argc==1 ){ 320 zErr = "cannot delete"; 321 goto update_fail; 322 } 323 pgno = sqlite3_value_int(argv[0]); 324 if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){ 325 zErr = "cannot insert"; 326 goto update_fail; 327 } 328 zSchema = (const char*)sqlite3_value_text(argv[4]); 329 iDb = zSchema ? sqlite3FindDbName(pTab->db, zSchema) : -1; 330 if( iDb<0 ){ 331 zErr = "no such schema"; 332 goto update_fail; 333 } 334 pBt = pTab->db->aDb[iDb].pBt; 335 if( pgno<1 || pBt==0 || pgno>(int)sqlite3BtreeLastPage(pBt) ){ 336 zErr = "bad page number"; 337 goto update_fail; 338 } 339 szPage = sqlite3BtreeGetPageSize(pBt); 340 if( sqlite3_value_type(argv[3])!=SQLITE_BLOB 341 || sqlite3_value_bytes(argv[3])!=szPage 342 ){ 343 zErr = "bad page value"; 344 goto update_fail; 345 } 346 pPager = sqlite3BtreePager(pBt); 347 rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0); 348 if( rc==SQLITE_OK ){ 349 rc = sqlite3PagerWrite(pDbPage); 350 if( rc==SQLITE_OK ){ 351 memcpy(sqlite3PagerGetData(pDbPage), 352 sqlite3_value_blob(argv[3]), 353 szPage); 354 } 355 } 356 sqlite3PagerUnref(pDbPage); 357 return rc; 358 359 update_fail: 360 sqlite3_free(pVtab->zErrMsg); 361 pVtab->zErrMsg = sqlite3_mprintf("%s", zErr); 362 return SQLITE_ERROR; 363 } 364 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 367 ** on them all. 368 */ 369 static int dbpageBegin(sqlite3_vtab *pVtab){ 370 DbpageTable *pTab = (DbpageTable *)pVtab; 371 sqlite3 *db = pTab->db; 372 int i; 373 for(i=0; i<db->nDb; i++){ 374 Btree *pBt = db->aDb[i].pBt; 375 if( pBt ) sqlite3BtreeBeginTrans(pBt, 1, 0); 376 } 377 return SQLITE_OK; 378 } 379 380 381 /* 382 ** Invoke this routine to register the "dbpage" virtual table module 383 */ 384 int sqlite3DbpageRegister(sqlite3 *db){ 385 static sqlite3_module dbpage_module = { 386 0, /* iVersion */ 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 */ 401 0, /* xSync */ 402 0, /* xCommit */ 403 0, /* xRollback */ 404 0, /* xFindMethod */ 405 0, /* xRename */ 406 0, /* xSavepoint */ 407 0, /* xRelease */ 408 0, /* xRollbackTo */ 409 0 /* xShadowName */ 410 }; 411 return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0); 412 } 413 #elif defined(SQLITE_ENABLE_DBPAGE_VTAB) 414 int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; } 415 #endif /* SQLITE_ENABLE_DBSTAT_VTAB */ 416