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 sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY); 77 rc = sqlite3_declare_vtab(db, 78 "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)"); 79 if( rc==SQLITE_OK ){ 80 pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable)); 81 if( pTab==0 ) rc = SQLITE_NOMEM_BKPT; 82 } 83 84 assert( rc==SQLITE_OK || pTab==0 ); 85 if( rc==SQLITE_OK ){ 86 memset(pTab, 0, sizeof(DbpageTable)); 87 pTab->db = db; 88 } 89 90 *ppVtab = (sqlite3_vtab*)pTab; 91 return rc; 92 } 93 94 /* 95 ** Disconnect from or destroy a dbpagevfs virtual table. 96 */ 97 static int dbpageDisconnect(sqlite3_vtab *pVtab){ 98 sqlite3_free(pVtab); 99 return SQLITE_OK; 100 } 101 102 /* 103 ** idxNum: 104 ** 105 ** 0 schema=main, full table scan 106 ** 1 schema=main, pgno=?1 107 ** 2 schema=?1, full table scan 108 ** 3 schema=?1, pgno=?2 109 */ 110 static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ 111 int i; 112 int iPlan = 0; 113 114 /* If there is a schema= constraint, it must be honored. Report a 115 ** ridiculously large estimated cost if the schema= constraint is 116 ** unavailable 117 */ 118 for(i=0; i<pIdxInfo->nConstraint; i++){ 119 struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i]; 120 if( p->iColumn!=DBPAGE_COLUMN_SCHEMA ) continue; 121 if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; 122 if( !p->usable ){ 123 /* No solution. */ 124 return SQLITE_CONSTRAINT; 125 } 126 iPlan = 2; 127 pIdxInfo->aConstraintUsage[i].argvIndex = 1; 128 pIdxInfo->aConstraintUsage[i].omit = 1; 129 break; 130 } 131 132 /* If we reach this point, it means that either there is no schema= 133 ** constraint (in which case we use the "main" schema) or else the 134 ** schema constraint was accepted. Lower the estimated cost accordingly 135 */ 136 pIdxInfo->estimatedCost = 1.0e6; 137 138 /* Check for constraints against pgno */ 139 for(i=0; i<pIdxInfo->nConstraint; i++){ 140 struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i]; 141 if( p->usable && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ 142 pIdxInfo->estimatedRows = 1; 143 pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE; 144 pIdxInfo->estimatedCost = 1.0; 145 pIdxInfo->aConstraintUsage[i].argvIndex = iPlan ? 2 : 1; 146 pIdxInfo->aConstraintUsage[i].omit = 1; 147 iPlan |= 1; 148 break; 149 } 150 } 151 pIdxInfo->idxNum = iPlan; 152 153 if( pIdxInfo->nOrderBy>=1 154 && pIdxInfo->aOrderBy[0].iColumn<=0 155 && pIdxInfo->aOrderBy[0].desc==0 156 ){ 157 pIdxInfo->orderByConsumed = 1; 158 } 159 sqlite3VtabUsesAllSchemas(pIdxInfo); 160 return SQLITE_OK; 161 } 162 163 /* 164 ** Open a new dbpagevfs cursor. 165 */ 166 static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ 167 DbpageCursor *pCsr; 168 169 pCsr = (DbpageCursor *)sqlite3_malloc64(sizeof(DbpageCursor)); 170 if( pCsr==0 ){ 171 return SQLITE_NOMEM_BKPT; 172 }else{ 173 memset(pCsr, 0, sizeof(DbpageCursor)); 174 pCsr->base.pVtab = pVTab; 175 pCsr->pgno = -1; 176 } 177 178 *ppCursor = (sqlite3_vtab_cursor *)pCsr; 179 return SQLITE_OK; 180 } 181 182 /* 183 ** Close a dbpagevfs cursor. 184 */ 185 static int dbpageClose(sqlite3_vtab_cursor *pCursor){ 186 DbpageCursor *pCsr = (DbpageCursor *)pCursor; 187 if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1); 188 sqlite3_free(pCsr); 189 return SQLITE_OK; 190 } 191 192 /* 193 ** Move a dbpagevfs cursor to the next entry in the file. 194 */ 195 static int dbpageNext(sqlite3_vtab_cursor *pCursor){ 196 int rc = SQLITE_OK; 197 DbpageCursor *pCsr = (DbpageCursor *)pCursor; 198 pCsr->pgno++; 199 return rc; 200 } 201 202 static int dbpageEof(sqlite3_vtab_cursor *pCursor){ 203 DbpageCursor *pCsr = (DbpageCursor *)pCursor; 204 return pCsr->pgno > pCsr->mxPgno; 205 } 206 207 /* 208 ** idxNum: 209 ** 210 ** 0 schema=main, full table scan 211 ** 1 schema=main, pgno=?1 212 ** 2 schema=?1, full table scan 213 ** 3 schema=?1, pgno=?2 214 ** 215 ** idxStr is not used 216 */ 217 static int dbpageFilter( 218 sqlite3_vtab_cursor *pCursor, 219 int idxNum, const char *idxStr, 220 int argc, sqlite3_value **argv 221 ){ 222 DbpageCursor *pCsr = (DbpageCursor *)pCursor; 223 DbpageTable *pTab = (DbpageTable *)pCursor->pVtab; 224 int rc; 225 sqlite3 *db = pTab->db; 226 Btree *pBt; 227 228 /* Default setting is no rows of result */ 229 pCsr->pgno = 1; 230 pCsr->mxPgno = 0; 231 232 if( idxNum & 2 ){ 233 const char *zSchema; 234 assert( argc>=1 ); 235 zSchema = (const char*)sqlite3_value_text(argv[0]); 236 pCsr->iDb = sqlite3FindDbName(db, zSchema); 237 if( pCsr->iDb<0 ) return SQLITE_OK; 238 }else{ 239 pCsr->iDb = 0; 240 } 241 pBt = db->aDb[pCsr->iDb].pBt; 242 if( pBt==0 ) return SQLITE_OK; 243 pCsr->pPager = sqlite3BtreePager(pBt); 244 pCsr->szPage = sqlite3BtreeGetPageSize(pBt); 245 pCsr->mxPgno = sqlite3BtreeLastPage(pBt); 246 if( idxNum & 1 ){ 247 assert( argc>(idxNum>>1) ); 248 pCsr->pgno = sqlite3_value_int(argv[idxNum>>1]); 249 if( pCsr->pgno<1 || pCsr->pgno>pCsr->mxPgno ){ 250 pCsr->pgno = 1; 251 pCsr->mxPgno = 0; 252 }else{ 253 pCsr->mxPgno = pCsr->pgno; 254 } 255 }else{ 256 assert( pCsr->pgno==1 ); 257 } 258 if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1); 259 rc = sqlite3PagerGet(pCsr->pPager, 1, &pCsr->pPage1, 0); 260 return rc; 261 } 262 263 static int dbpageColumn( 264 sqlite3_vtab_cursor *pCursor, 265 sqlite3_context *ctx, 266 int i 267 ){ 268 DbpageCursor *pCsr = (DbpageCursor *)pCursor; 269 int rc = SQLITE_OK; 270 switch( i ){ 271 case 0: { /* pgno */ 272 sqlite3_result_int(ctx, pCsr->pgno); 273 break; 274 } 275 case 1: { /* data */ 276 DbPage *pDbPage = 0; 277 if( pCsr->pgno==((PENDING_BYTE/pCsr->szPage)+1) ){ 278 /* The pending byte page. Assume it is zeroed out. Attempting to 279 ** request this page from the page is an SQLITE_CORRUPT error. */ 280 sqlite3_result_zeroblob(ctx, pCsr->szPage); 281 }else{ 282 rc = sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0); 283 if( rc==SQLITE_OK ){ 284 sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pCsr->szPage, 285 SQLITE_TRANSIENT); 286 } 287 sqlite3PagerUnref(pDbPage); 288 } 289 break; 290 } 291 default: { /* schema */ 292 sqlite3 *db = sqlite3_context_db_handle(ctx); 293 sqlite3_result_text(ctx, db->aDb[pCsr->iDb].zDbSName, -1, SQLITE_STATIC); 294 break; 295 } 296 } 297 return rc; 298 } 299 300 static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ 301 DbpageCursor *pCsr = (DbpageCursor *)pCursor; 302 *pRowid = pCsr->pgno; 303 return SQLITE_OK; 304 } 305 306 static int dbpageUpdate( 307 sqlite3_vtab *pVtab, 308 int argc, 309 sqlite3_value **argv, 310 sqlite_int64 *pRowid 311 ){ 312 DbpageTable *pTab = (DbpageTable *)pVtab; 313 Pgno pgno; 314 DbPage *pDbPage = 0; 315 int rc = SQLITE_OK; 316 char *zErr = 0; 317 const char *zSchema; 318 int iDb; 319 Btree *pBt; 320 Pager *pPager; 321 int szPage; 322 323 if( pTab->db->flags & SQLITE_Defensive ){ 324 zErr = "read-only"; 325 goto update_fail; 326 } 327 if( argc==1 ){ 328 zErr = "cannot delete"; 329 goto update_fail; 330 } 331 pgno = sqlite3_value_int(argv[0]); 332 if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){ 333 zErr = "cannot insert"; 334 goto update_fail; 335 } 336 zSchema = (const char*)sqlite3_value_text(argv[4]); 337 iDb = zSchema ? sqlite3FindDbName(pTab->db, zSchema) : -1; 338 if( iDb<0 ){ 339 zErr = "no such schema"; 340 goto update_fail; 341 } 342 pBt = pTab->db->aDb[iDb].pBt; 343 if( pgno<1 || pBt==0 || pgno>sqlite3BtreeLastPage(pBt) ){ 344 zErr = "bad page number"; 345 goto update_fail; 346 } 347 szPage = sqlite3BtreeGetPageSize(pBt); 348 if( sqlite3_value_type(argv[3])!=SQLITE_BLOB 349 || sqlite3_value_bytes(argv[3])!=szPage 350 ){ 351 zErr = "bad page value"; 352 goto update_fail; 353 } 354 pPager = sqlite3BtreePager(pBt); 355 rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0); 356 if( rc==SQLITE_OK ){ 357 const void *pData = sqlite3_value_blob(argv[3]); 358 assert( pData!=0 || pTab->db->mallocFailed ); 359 if( pData 360 && (rc = sqlite3PagerWrite(pDbPage))==SQLITE_OK 361 ){ 362 memcpy(sqlite3PagerGetData(pDbPage), pData, szPage); 363 } 364 } 365 sqlite3PagerUnref(pDbPage); 366 return rc; 367 368 update_fail: 369 sqlite3_free(pVtab->zErrMsg); 370 pVtab->zErrMsg = sqlite3_mprintf("%s", zErr); 371 return SQLITE_ERROR; 372 } 373 374 /* Since we do not know in advance which database files will be 375 ** written by the sqlite_dbpage virtual table, start a write transaction 376 ** on them all. 377 */ 378 static int dbpageBegin(sqlite3_vtab *pVtab){ 379 DbpageTable *pTab = (DbpageTable *)pVtab; 380 sqlite3 *db = pTab->db; 381 int i; 382 int rc = SQLITE_OK; 383 for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ 384 Btree *pBt = db->aDb[i].pBt; 385 if( pBt ) rc = sqlite3BtreeBeginTrans(pBt, 1, 0); 386 } 387 return rc; 388 } 389 390 391 /* 392 ** Invoke this routine to register the "dbpage" virtual table module 393 */ 394 int sqlite3DbpageRegister(sqlite3 *db){ 395 static sqlite3_module dbpage_module = { 396 0, /* iVersion */ 397 dbpageConnect, /* xCreate */ 398 dbpageConnect, /* xConnect */ 399 dbpageBestIndex, /* xBestIndex */ 400 dbpageDisconnect, /* xDisconnect */ 401 dbpageDisconnect, /* xDestroy */ 402 dbpageOpen, /* xOpen - open a cursor */ 403 dbpageClose, /* xClose - close a cursor */ 404 dbpageFilter, /* xFilter - configure scan constraints */ 405 dbpageNext, /* xNext - advance a cursor */ 406 dbpageEof, /* xEof - check for end of scan */ 407 dbpageColumn, /* xColumn - read data */ 408 dbpageRowid, /* xRowid - read data */ 409 dbpageUpdate, /* xUpdate */ 410 dbpageBegin, /* xBegin */ 411 0, /* xSync */ 412 0, /* xCommit */ 413 0, /* xRollback */ 414 0, /* xFindMethod */ 415 0, /* xRename */ 416 0, /* xSavepoint */ 417 0, /* xRelease */ 418 0, /* xRollbackTo */ 419 0 /* xShadowName */ 420 }; 421 return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0); 422 } 423 #elif defined(SQLITE_ENABLE_DBPAGE_VTAB) 424 int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; } 425 #endif /* SQLITE_ENABLE_DBSTAT_VTAB */ 426