Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix a locking-page related problem with the ".recover" command. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | dbdata |
Files: | files | file ages | folders |
SHA3-256: |
afdae10424f0f3d0f10a4b73e9732aa5 |
User & Date: | dan 2019-04-26 15:14:53.514 |
Context
2019-04-26
| ||
15:40 | Fix another problem with database freelist handling in the ".recover" command. (check-in: bee2652ac2 user: dan tags: dbdata) | |
15:14 | Fix a locking-page related problem with the ".recover" command. (check-in: afdae10424 user: dan tags: dbdata) | |
2019-04-25
| ||
20:06 | Merge latest trunk changes into this branch. (check-in: 1da302d85d user: dan tags: dbdata) | |
Changes
Changes to ext/misc/dbdata.c.
︙ | ︙ | |||
85 86 87 88 89 90 91 92 93 94 95 96 97 98 | int iPgno; /* Current page number */ u8 *aPage; /* Buffer containing page */ int nPage; /* Size of aPage[] in bytes */ int nCell; /* Number of cells on aPage[] */ int iCell; /* Current cell number */ int bOnePage; /* True to stop after one page */ sqlite3_int64 iRowid; /* Only for the sqlite_dbdata table */ u8 *pRec; /* Buffer containing current record */ int nRec; /* Size of pRec[] in bytes */ int nHdr; /* Size of header in bytes */ int iField; /* Current field number */ | > | 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | int iPgno; /* Current page number */ u8 *aPage; /* Buffer containing page */ int nPage; /* Size of aPage[] in bytes */ int nCell; /* Number of cells on aPage[] */ int iCell; /* Current cell number */ int bOnePage; /* True to stop after one page */ int szDb; sqlite3_int64 iRowid; /* Only for the sqlite_dbdata table */ u8 *pRec; /* Buffer containing current record */ int nRec; /* Size of pRec[] in bytes */ int nHdr; /* Size of header in bytes */ int iField; /* Current field number */ |
︙ | ︙ | |||
299 300 301 302 303 304 305 | sqlite3_stmt *pStmt = pCsr->pStmt; *ppPage = 0; *pnPage = 0; sqlite3_bind_int64(pStmt, 2, pgno); if( SQLITE_ROW==sqlite3_step(pStmt) ){ int nCopy = sqlite3_column_bytes(pStmt, 0); | > > | | | | | | > | | 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 | sqlite3_stmt *pStmt = pCsr->pStmt; *ppPage = 0; *pnPage = 0; sqlite3_bind_int64(pStmt, 2, pgno); if( SQLITE_ROW==sqlite3_step(pStmt) ){ int nCopy = sqlite3_column_bytes(pStmt, 0); if( nCopy>0 ){ u8 *pPage; pPage = (u8*)sqlite3_malloc64(nCopy); if( pPage==0 ){ rc = SQLITE_NOMEM; }else{ const u8 *pCopy = sqlite3_column_blob(pStmt, 0); memcpy(pPage, pCopy, nCopy); } *ppPage = pPage; *pnPage = nCopy; } } rc2 = sqlite3_reset(pStmt); if( rc==SQLITE_OK ) rc = rc2; return rc; } /* ** Read a varint. Put the value in *pVal and return the number of bytes. */ |
︙ | ︙ | |||
415 416 417 418 419 420 421 | pCsr->iRowid++; while( 1 ){ int rc; int iOff = (pCsr->iPgno==1 ? 100 : 0); if( pCsr->aPage==0 ){ | > > | | > > > | 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 | pCsr->iRowid++; while( 1 ){ int rc; int iOff = (pCsr->iPgno==1 ? 100 : 0); if( pCsr->aPage==0 ){ while( 1 ){ if( pCsr->bOnePage==0 && pCsr->iPgno>pCsr->szDb ) return SQLITE_OK; rc = dbdataLoadPage(pCsr, pCsr->iPgno, &pCsr->aPage, &pCsr->nPage); if( rc!=SQLITE_OK ) return rc; if( pCsr->aPage ) break; pCsr->iPgno++; } pCsr->iCell = pTab->bPtr ? -2 : 0; pCsr->nCell = get_uint16(&pCsr->aPage[iOff+3]); } if( pTab->bPtr ){ if( pCsr->aPage[iOff]!=0x02 && pCsr->aPage[iOff]!=0x05 ){ pCsr->iCell = pCsr->nCell; |
︙ | ︙ | |||
569 570 571 572 573 574 575 576 577 578 579 580 581 582 | /* We have reached EOF if previous sqlite3_step() returned ** anything other than SQLITE_ROW; */ static int dbdataEof(sqlite3_vtab_cursor *pCursor){ DbdataCursor *pCsr = (DbdataCursor*)pCursor; return pCsr->aPage==0; } /* Position a cursor back to the beginning. */ static int dbdataFilter( sqlite3_vtab_cursor *pCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv | > > > > > > > > > > > > > > > > > > | 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 | /* We have reached EOF if previous sqlite3_step() returned ** anything other than SQLITE_ROW; */ static int dbdataEof(sqlite3_vtab_cursor *pCursor){ DbdataCursor *pCsr = (DbdataCursor*)pCursor; return pCsr->aPage==0; } static int dbdataDbsize(DbdataCursor *pCsr, const char *zSchema){ DbdataTable *pTab = (DbdataTable*)pCsr->base.pVtab; char *zSql = 0; int rc, rc2; sqlite3_stmt *pStmt = 0; zSql = sqlite3_mprintf("PRAGMA %Q.page_count", zSchema); if( zSql==0 ) return SQLITE_NOMEM; rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ pCsr->szDb = sqlite3_column_int(pStmt, 0); } rc2 = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ) rc = rc2; return rc; } /* Position a cursor back to the beginning. */ static int dbdataFilter( sqlite3_vtab_cursor *pCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv |
︙ | ︙ | |||
590 591 592 593 594 595 596 597 598 | assert( pCsr->iPgno==1 ); if( idxNum & 0x01 ){ zSchema = (const char*)sqlite3_value_text(argv[0]); } if( idxNum & 0x02 ){ pCsr->iPgno = sqlite3_value_int(argv[(idxNum & 0x01)]); pCsr->bOnePage = 1; } | > > > > | | | | | | | | > | 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 | assert( pCsr->iPgno==1 ); if( idxNum & 0x01 ){ zSchema = (const char*)sqlite3_value_text(argv[0]); } if( idxNum & 0x02 ){ pCsr->iPgno = sqlite3_value_int(argv[(idxNum & 0x01)]); pCsr->bOnePage = 1; }else{ pCsr->nPage = dbdataDbsize(pCsr, zSchema); rc = dbdataDbsize(pCsr, zSchema); } if( rc==SQLITE_OK ){ if( pTab->pStmt ){ pCsr->pStmt = pTab->pStmt; pTab->pStmt = 0; }else{ rc = sqlite3_prepare_v2(pTab->db, "SELECT data FROM sqlite_dbpage(?) WHERE pgno=?", -1, &pCsr->pStmt, 0 ); } } if( rc==SQLITE_OK ){ rc = sqlite3_bind_text(pCsr->pStmt, 1, zSchema, -1, SQLITE_TRANSIENT); }else{ pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db)); } if( rc==SQLITE_OK ){ |
︙ | ︙ |
Changes to src/shell.c.in.
︙ | ︙ | |||
6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 | rc = sqlite3_exec(db, zSql, 0, 0, &zErr); if( rc!=SQLITE_OK ){ raw_printf(stderr, "SQL error: %s\n", zErr); } *pRc = rc; } } static void *shellMalloc(int *pRc, sqlite3_int64 nByte){ void *pRet = 0; if( *pRc==SQLITE_OK ){ pRet = sqlite3_malloc64(nByte); if( pRet==0 ){ *pRc = SQLITE_NOMEM; | > > > > > > > > > > > > > > > > | 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 | rc = sqlite3_exec(db, zSql, 0, 0, &zErr); if( rc!=SQLITE_OK ){ raw_printf(stderr, "SQL error: %s\n", zErr); } *pRc = rc; } } static void shellExecPrintf(sqlite3 *db, int *pRc, const char *zFmt, ...){ char *z = 0; if( *pRc==SQLITE_OK ){ va_list ap; va_start(ap, zFmt); z = sqlite3_vmprintf(zFmt, ap); va_end(ap); if( z==0 ){ *pRc = SQLITE_NOMEM; }else{ shellExec(db, pRc, z); } sqlite3_free(z); } } static void *shellMalloc(int *pRc, sqlite3_int64 nByte){ void *pRet = 0; if( *pRc==SQLITE_OK ){ pRet = sqlite3_malloc64(nByte); if( pRet==0 ){ *pRc = SQLITE_NOMEM; |
︙ | ︙ | |||
6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 | ** on stream pState->out. */ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){ int rc = SQLITE_OK; sqlite3_stmt *pLoop = 0; /* Loop through all root pages */ sqlite3_stmt *pPages = 0; /* Loop through all pages in a group */ sqlite3_stmt *pCells = 0; /* Loop through all cells in a page */ int i; int bFreelist = 1; /* 0 if --freelist-corrupt is specified */ for(i=1; i<nArg; i++){ char *z = azArg[i]; int n; if( z[0]=='-' && z[1]=='-' ) z++; n = strlen(z); if( n<=17 && memcmp("-freelist-corrupt", z, n)==0 ){ bFreelist = 0; } else{ | > > > > > > | | < < > | | > > > > > | | | 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 | ** on stream pState->out. */ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){ int rc = SQLITE_OK; sqlite3_stmt *pLoop = 0; /* Loop through all root pages */ sqlite3_stmt *pPages = 0; /* Loop through all pages in a group */ sqlite3_stmt *pCells = 0; /* Loop through all cells in a page */ const char *zRecoveryDb = ""; /* Name of "recovery" database */ int i; int bFreelist = 1; /* 0 if --freelist-corrupt is specified */ for(i=1; i<nArg; i++){ char *z = azArg[i]; int n; if( z[0]=='-' && z[1]=='-' ) z++; n = strlen(z); if( n<=17 && memcmp("-freelist-corrupt", z, n)==0 ){ bFreelist = 0; } if( n<=12 && memcmp("-recovery-db", z, n)==0 && i<(nArg-1) ){ i++; zRecoveryDb = azArg[i]; } else{ raw_printf(stderr, "unexpected option: %s\n", azArg[i]); raw_printf(stderr, "options are:\n"); raw_printf(stderr, " --freelist-corrupt\n"); raw_printf(stderr, " --recovery-db DATABASE\n"); return 1; } } shellExecPrintf(pState->db, &rc, /* Attach an in-memory database named 'recovery'. Create an indexed ** cache of the sqlite_dbptr virtual table. */ "ATTACH %Q AS recovery;" "DROP TABLE IF EXISTS recovery.dbptr;" "DROP TABLE IF EXISTS recovery.freelist;" "DROP TABLE IF EXISTS recovery.map;" "DROP TABLE IF EXISTS recovery.schema;" "CREATE TABLE recovery.dbptr(" " pgno, child, PRIMARY KEY(child, pgno)" ") WITHOUT ROWID;" "INSERT OR IGNORE INTO recovery.dbptr(pgno, child) " " SELECT * FROM sqlite_dbptr;" /* Delete any pointer to page 1. This ensures that page 1 is considered ** a root page, regardless of how corrupt the db is. */ "DELETE FROM recovery.dbptr WHERE child = 1;" /* Delete all pointers to any pages that have more than one pointer ** to them. Such pages will be treated as root pages when recovering ** data. */ "DELETE FROM recovery.dbptr WHERE child IN (" " SELECT child FROM recovery.dbptr GROUP BY child HAVING count(*)>1" ");" "CREATE TABLE recovery.freelist(pgno INTEGER PRIMARY KEY);", zRecoveryDb ); if( bFreelist ){ shellExec(pState->db, &rc, "WITH trunk(pgno) AS (" " SELECT shell_int32(" " (SELECT data FROM sqlite_dbpage WHERE pgno=1), 8) AS x " |
︙ | ︙ |