/ Check-in [50fe4845]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add the ".recover" command to the shell tool. For recovering as much data as possible from corrupt databases.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 50fe48458942fa7a6bcc76316c6321f95b23dc34f2f8e0a483826483b2fb16f6
User & Date: dan 2019-04-27 20:30:19
Context
2019-04-29
11:27
Fix a stack overflow that could occur when renaming a table that has a trigger containing a window function invocation that itself contains a specific syntax error. check-in: c621fc66 user: dan tags: trunk
2019-04-28
19:27
Take collating sequence into account when removing redundant columns from indexes on WITHOUT ROWID tables. This is the first proof-of-concept fix for ticket [3182d3879020ef3]. More testing needed. check-in: b34fa5bf user: drh tags: tkt-3182d38790
2019-04-27
20:30
Add the ".recover" command to the shell tool. For recovering as much data as possible from corrupt databases. check-in: 50fe4845 user: dan tags: trunk
20:16
Fix a minor typo in a comment. No changes to code. check-in: 95209072 user: drh tags: trunk
20:15
Fix building the shell with SQLITE_OMIT_VIRTUAL_TABLE. And without SQLITE_ENABLE_DBPAGE_VTAB. Closed-Leaf check-in: 425d708c user: dan tags: dbdata
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Added ext/misc/dbdata.c.

            1  +/*
            2  +** 2019-04-17
            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 two eponymous virtual tables,
           14  +** "sqlite_dbdata" and "sqlite_dbptr". Both modules require that the
           15  +** "sqlite_dbpage" eponymous virtual table be available.
           16  +**
           17  +** SQLITE_DBDATA:
           18  +**   sqlite_dbdata is used to extract data directly from a database b-tree
           19  +**   page and its associated overflow pages, bypassing the b-tree layer.
           20  +**   The table schema is equivalent to:
           21  +**
           22  +**     CREATE TABLE sqlite_dbdata(
           23  +**       pgno INTEGER,
           24  +**       cell INTEGER,
           25  +**       field INTEGER,
           26  +**       value ANY,
           27  +**       schema TEXT HIDDEN
           28  +**     );
           29  +**
           30  +**   IMPORTANT: THE VIRTUAL TABLE SCHEMA ABOVE IS SUBJECT TO CHANGE. IN THE
           31  +**   FUTURE NEW NON-HIDDEN COLUMNS MAY BE ADDED BETWEEN "value" AND
           32  +**   "schema".
           33  +**
           34  +**   Each page of the database is inspected. If it cannot be interpreted as
           35  +**   a b-tree page, or if it is a b-tree page containing 0 entries, the
           36  +**   sqlite_dbdata table contains no rows for that page.  Otherwise, the
           37  +**   table contains one row for each field in the record associated with
           38  +**   each cell on the page. For intkey b-trees, the key value is stored in
           39  +**   field -1.
           40  +**
           41  +**   For example, for the database:
           42  +**
           43  +**     CREATE TABLE t1(a, b);     -- root page is page 2
           44  +**     INSERT INTO t1(rowid, a, b) VALUES(5, 'v', 'five');
           45  +**     INSERT INTO t1(rowid, a, b) VALUES(10, 'x', 'ten');
           46  +**
           47  +**   the sqlite_dbdata table contains, as well as from entries related to 
           48  +**   page 1, content equivalent to:
           49  +**
           50  +**     INSERT INTO sqlite_dbdata(pgno, cell, field, value) VALUES
           51  +**         (2, 0, -1, 5     ),
           52  +**         (2, 0,  0, 'v'   ),
           53  +**         (2, 0,  1, 'five'),
           54  +**         (2, 1, -1, 10    ),
           55  +**         (2, 1,  0, 'x'   ),
           56  +**         (2, 1,  1, 'ten' );
           57  +**
           58  +**   If database corruption is encountered, this module does not report an
           59  +**   error. Instead, it attempts to extract as much data as possible and
           60  +**   ignores the corruption.
           61  +**
           62  +** SQLITE_DBPTR:
           63  +**   The sqlite_dbptr table has the following schema:
           64  +**
           65  +**     CREATE TABLE sqlite_dbptr(
           66  +**       pgno INTEGER,
           67  +**       child INTEGER,
           68  +**       schema TEXT HIDDEN
           69  +**     );
           70  +**
           71  +**   It contains one entry for each b-tree pointer between a parent and
           72  +**   child page in the database.
           73  +*/
           74  +#if !defined(SQLITEINT_H) 
           75  +#include "sqlite3ext.h"
           76  +
           77  +typedef unsigned char u8;
           78  +
           79  +#endif
           80  +SQLITE_EXTENSION_INIT1
           81  +#include <string.h>
           82  +#include <assert.h>
           83  +
           84  +typedef struct DbdataTable DbdataTable;
           85  +typedef struct DbdataCursor DbdataCursor;
           86  +
           87  +/* Cursor object */
           88  +struct DbdataCursor {
           89  +  sqlite3_vtab_cursor base;       /* Base class.  Must be first */
           90  +  sqlite3_stmt *pStmt;            /* For fetching database pages */
           91  +
           92  +  int iPgno;                      /* Current page number */
           93  +  u8 *aPage;                      /* Buffer containing page */
           94  +  int nPage;                      /* Size of aPage[] in bytes */
           95  +  int nCell;                      /* Number of cells on aPage[] */
           96  +  int iCell;                      /* Current cell number */
           97  +  int bOnePage;                   /* True to stop after one page */
           98  +  int szDb;
           99  +  sqlite3_int64 iRowid;
          100  +
          101  +  /* Only for the sqlite_dbdata table */
          102  +  u8 *pRec;                       /* Buffer containing current record */
          103  +  int nRec;                       /* Size of pRec[] in bytes */
          104  +  int nHdr;                       /* Size of header in bytes */
          105  +  int iField;                     /* Current field number */
          106  +  u8 *pHdrPtr;
          107  +  u8 *pPtr;
          108  +  
          109  +  sqlite3_int64 iIntkey;          /* Integer key value */
          110  +};
          111  +
          112  +/* Table object */
          113  +struct DbdataTable {
          114  +  sqlite3_vtab base;              /* Base class.  Must be first */
          115  +  sqlite3 *db;                    /* The database connection */
          116  +  sqlite3_stmt *pStmt;            /* For fetching database pages */
          117  +  int bPtr;                       /* True for sqlite3_dbptr table */
          118  +};
          119  +
          120  +/* Column and schema definitions for sqlite_dbdata */
          121  +#define DBDATA_COLUMN_PGNO        0
          122  +#define DBDATA_COLUMN_CELL        1
          123  +#define DBDATA_COLUMN_FIELD       2
          124  +#define DBDATA_COLUMN_VALUE       3
          125  +#define DBDATA_COLUMN_SCHEMA      4
          126  +#define DBDATA_SCHEMA             \
          127  +      "CREATE TABLE x("           \
          128  +      "  pgno INTEGER,"           \
          129  +      "  cell INTEGER,"           \
          130  +      "  field INTEGER,"          \
          131  +      "  value ANY,"              \
          132  +      "  schema TEXT HIDDEN"      \
          133  +      ")"
          134  +
          135  +/* Column and schema definitions for sqlite_dbptr */
          136  +#define DBPTR_COLUMN_PGNO         0
          137  +#define DBPTR_COLUMN_CHILD        1
          138  +#define DBPTR_COLUMN_SCHEMA       2
          139  +#define DBPTR_SCHEMA              \
          140  +      "CREATE TABLE x("           \
          141  +      "  pgno INTEGER,"           \
          142  +      "  child INTEGER,"          \
          143  +      "  schema TEXT HIDDEN"      \
          144  +      ")"
          145  +
          146  +/*
          147  +** Connect to an sqlite_dbdata (pAux==0) or sqlite_dbptr (pAux!=0) virtual 
          148  +** table.
          149  +*/
          150  +static int dbdataConnect(
          151  +  sqlite3 *db,
          152  +  void *pAux,
          153  +  int argc, const char *const*argv,
          154  +  sqlite3_vtab **ppVtab,
          155  +  char **pzErr
          156  +){
          157  +  DbdataTable *pTab = 0;
          158  +  int rc = sqlite3_declare_vtab(db, pAux ? DBPTR_SCHEMA : DBDATA_SCHEMA);
          159  +
          160  +  if( rc==SQLITE_OK ){
          161  +    pTab = (DbdataTable*)sqlite3_malloc64(sizeof(DbdataTable));
          162  +    if( pTab==0 ){
          163  +      rc = SQLITE_NOMEM;
          164  +    }else{
          165  +      memset(pTab, 0, sizeof(DbdataTable));
          166  +      pTab->db = db;
          167  +      pTab->bPtr = (pAux!=0);
          168  +    }
          169  +  }
          170  +
          171  +  *ppVtab = (sqlite3_vtab*)pTab;
          172  +  return rc;
          173  +}
          174  +
          175  +/*
          176  +** Disconnect from or destroy a sqlite_dbdata or sqlite_dbptr virtual table.
          177  +*/
          178  +static int dbdataDisconnect(sqlite3_vtab *pVtab){
          179  +  DbdataTable *pTab = (DbdataTable*)pVtab;
          180  +  if( pTab ){
          181  +    sqlite3_finalize(pTab->pStmt);
          182  +    sqlite3_free(pVtab);
          183  +  }
          184  +  return SQLITE_OK;
          185  +}
          186  +
          187  +/*
          188  +** This function interprets two types of constraints:
          189  +**
          190  +**       schema=?
          191  +**       pgno=?
          192  +**
          193  +** If neither are present, idxNum is set to 0. If schema=? is present,
          194  +** the 0x01 bit in idxNum is set. If pgno=? is present, the 0x02 bit
          195  +** in idxNum is set.
          196  +**
          197  +** If both parameters are present, schema is in position 0 and pgno in
          198  +** position 1.
          199  +*/
          200  +static int dbdataBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdx){
          201  +  DbdataTable *pTab = (DbdataTable*)tab;
          202  +  int i;
          203  +  int iSchema = -1;
          204  +  int iPgno = -1;
          205  +  int colSchema = (pTab->bPtr ? DBPTR_COLUMN_SCHEMA : DBDATA_COLUMN_SCHEMA);
          206  +
          207  +  for(i=0; i<pIdx->nConstraint; i++){
          208  +    struct sqlite3_index_constraint *p = &pIdx->aConstraint[i];
          209  +    if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
          210  +      if( p->iColumn==colSchema ){
          211  +        if( p->usable==0 ) return SQLITE_CONSTRAINT;
          212  +        iSchema = i;
          213  +      }
          214  +      if( p->iColumn==DBDATA_COLUMN_PGNO && p->usable ){
          215  +        iPgno = i;
          216  +      }
          217  +    }
          218  +  }
          219  +
          220  +  if( iSchema>=0 ){
          221  +    pIdx->aConstraintUsage[iSchema].argvIndex = 1;
          222  +    pIdx->aConstraintUsage[iSchema].omit = 1;
          223  +  }
          224  +  if( iPgno>=0 ){
          225  +    pIdx->aConstraintUsage[iPgno].argvIndex = 1 + (iSchema>=0);
          226  +    pIdx->aConstraintUsage[iPgno].omit = 1;
          227  +    pIdx->estimatedCost = 100;
          228  +    pIdx->estimatedRows =  50;
          229  +
          230  +    if( pTab->bPtr==0 && pIdx->nOrderBy && pIdx->aOrderBy[0].desc==0 ){
          231  +      int iCol = pIdx->aOrderBy[0].iColumn;
          232  +      if( pIdx->nOrderBy==1 ){
          233  +        pIdx->orderByConsumed = (iCol==0 || iCol==1);
          234  +      }else if( pIdx->nOrderBy==2 && pIdx->aOrderBy[1].desc==0 && iCol==0 ){
          235  +        pIdx->orderByConsumed = (pIdx->aOrderBy[1].iColumn==1);
          236  +      }
          237  +    }
          238  +
          239  +  }else{
          240  +    pIdx->estimatedCost = 100000000;
          241  +    pIdx->estimatedRows = 1000000000;
          242  +  }
          243  +  pIdx->idxNum = (iSchema>=0 ? 0x01 : 0x00) | (iPgno>=0 ? 0x02 : 0x00);
          244  +  return SQLITE_OK;
          245  +}
          246  +
          247  +/*
          248  +** Open a new sqlite_dbdata or sqlite_dbptr cursor.
          249  +*/
          250  +static int dbdataOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
          251  +  DbdataCursor *pCsr;
          252  +
          253  +  pCsr = (DbdataCursor*)sqlite3_malloc64(sizeof(DbdataCursor));
          254  +  if( pCsr==0 ){
          255  +    return SQLITE_NOMEM;
          256  +  }else{
          257  +    memset(pCsr, 0, sizeof(DbdataCursor));
          258  +    pCsr->base.pVtab = pVTab;
          259  +  }
          260  +
          261  +  *ppCursor = (sqlite3_vtab_cursor *)pCsr;
          262  +  return SQLITE_OK;
          263  +}
          264  +
          265  +/*
          266  +** Restore a cursor object to the state it was in when first allocated 
          267  +** by dbdataOpen().
          268  +*/
          269  +static void dbdataResetCursor(DbdataCursor *pCsr){
          270  +  DbdataTable *pTab = (DbdataTable*)(pCsr->base.pVtab);
          271  +  if( pTab->pStmt==0 ){
          272  +    pTab->pStmt = pCsr->pStmt;
          273  +  }else{
          274  +    sqlite3_finalize(pCsr->pStmt);
          275  +  }
          276  +  pCsr->pStmt = 0;
          277  +  pCsr->iPgno = 1;
          278  +  pCsr->iCell = 0;
          279  +  pCsr->iField = 0;
          280  +  pCsr->bOnePage = 0;
          281  +}
          282  +
          283  +/*
          284  +** Close an sqlite_dbdata or sqlite_dbptr cursor.
          285  +*/
          286  +static int dbdataClose(sqlite3_vtab_cursor *pCursor){
          287  +  DbdataCursor *pCsr = (DbdataCursor*)pCursor;
          288  +  dbdataResetCursor(pCsr);
          289  +  sqlite3_free(pCsr);
          290  +  return SQLITE_OK;
          291  +}
          292  +
          293  +/* 
          294  +** Utility methods to decode 16 and 32-bit big-endian unsigned integers. 
          295  +*/
          296  +static unsigned int get_uint16(unsigned char *a){
          297  +  return (a[0]<<8)|a[1];
          298  +}
          299  +static unsigned int get_uint32(unsigned char *a){
          300  +  return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|a[3];
          301  +}
          302  +
          303  +/*
          304  +** Load page pgno from the database via the sqlite_dbpage virtual table.
          305  +** If successful, set (*ppPage) to point to a buffer containing the page
          306  +** data, (*pnPage) to the size of that buffer in bytes and return
          307  +** SQLITE_OK. In this case it is the responsibility of the caller to
          308  +** eventually free the buffer using sqlite3_free().
          309  +**
          310  +** Or, if an error occurs, set both (*ppPage) and (*pnPage) to 0 and
          311  +** return an SQLite error code.
          312  +*/
          313  +static int dbdataLoadPage(
          314  +  DbdataCursor *pCsr,             /* Cursor object */
          315  +  unsigned int pgno,              /* Page number of page to load */
          316  +  u8 **ppPage,                    /* OUT: pointer to page buffer */
          317  +  int *pnPage                     /* OUT: Size of (*ppPage) in bytes */
          318  +){
          319  +  int rc2;
          320  +  int rc = SQLITE_OK;
          321  +  sqlite3_stmt *pStmt = pCsr->pStmt;
          322  +
          323  +  *ppPage = 0;
          324  +  *pnPage = 0;
          325  +  sqlite3_bind_int64(pStmt, 2, pgno);
          326  +  if( SQLITE_ROW==sqlite3_step(pStmt) ){
          327  +    int nCopy = sqlite3_column_bytes(pStmt, 0);
          328  +    if( nCopy>0 ){
          329  +      u8 *pPage;
          330  +      pPage = (u8*)sqlite3_malloc64(nCopy);
          331  +      if( pPage==0 ){
          332  +        rc = SQLITE_NOMEM;
          333  +      }else{
          334  +        const u8 *pCopy = sqlite3_column_blob(pStmt, 0);
          335  +        memcpy(pPage, pCopy, nCopy);
          336  +      }
          337  +      *ppPage = pPage;
          338  +      *pnPage = nCopy;
          339  +    }
          340  +  }
          341  +  rc2 = sqlite3_reset(pStmt);
          342  +  if( rc==SQLITE_OK ) rc = rc2;
          343  +
          344  +  return rc;
          345  +}
          346  +
          347  +/*
          348  +** Read a varint.  Put the value in *pVal and return the number of bytes.
          349  +*/
          350  +static int dbdataGetVarint(const u8 *z, sqlite3_int64 *pVal){
          351  +  sqlite3_int64 v = 0;
          352  +  int i;
          353  +  for(i=0; i<8; i++){
          354  +    v = (v<<7) + (z[i]&0x7f);
          355  +    if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; }
          356  +  }
          357  +  v = (v<<8) + (z[i]&0xff);
          358  +  *pVal = v;
          359  +  return 9;
          360  +}
          361  +
          362  +/*
          363  +** Return the number of bytes of space used by an SQLite value of type
          364  +** eType.
          365  +*/
          366  +static int dbdataValueBytes(int eType){
          367  +  switch( eType ){
          368  +    case 0: case 8: case 9:
          369  +    case 10: case 11:
          370  +      return 0;
          371  +    case 1:
          372  +      return 1;
          373  +    case 2:
          374  +      return 2;
          375  +    case 3:
          376  +      return 3;
          377  +    case 4:
          378  +      return 4;
          379  +    case 5:
          380  +      return 6;
          381  +    case 6:
          382  +    case 7:
          383  +      return 8;
          384  +    default:
          385  +      return ((eType-12) / 2);
          386  +  }
          387  +}
          388  +
          389  +/*
          390  +** Load a value of type eType from buffer pData and use it to set the
          391  +** result of context object pCtx.
          392  +*/
          393  +static void dbdataValue(sqlite3_context *pCtx, int eType, u8 *pData){
          394  +  switch( eType ){
          395  +    case 0: 
          396  +    case 10: 
          397  +    case 11: 
          398  +      sqlite3_result_null(pCtx);
          399  +      break;
          400  +    
          401  +    case 8: 
          402  +      sqlite3_result_int(pCtx, 0);
          403  +      break;
          404  +    case 9:
          405  +      sqlite3_result_int(pCtx, 1);
          406  +      break;
          407  +
          408  +    case 1: case 2: case 3: case 4: case 5: case 6: case 7: {
          409  +      sqlite3_uint64 v = (signed char)pData[0];
          410  +      pData++;
          411  +      switch( eType ){
          412  +        case 7:
          413  +        case 6:  v = (v<<16) + (pData[0]<<8) + pData[1];  pData += 2;
          414  +        case 5:  v = (v<<16) + (pData[0]<<8) + pData[1];  pData += 2;
          415  +        case 4:  v = (v<<8) + pData[0];  pData++;
          416  +        case 3:  v = (v<<8) + pData[0];  pData++;
          417  +        case 2:  v = (v<<8) + pData[0];  pData++;
          418  +      }
          419  +
          420  +      if( eType==7 ){
          421  +        double r;
          422  +        memcpy(&r, &v, sizeof(r));
          423  +        sqlite3_result_double(pCtx, r);
          424  +      }else{
          425  +        sqlite3_result_int64(pCtx, (sqlite3_int64)v);
          426  +      }
          427  +      break;
          428  +    }
          429  +
          430  +    default: {
          431  +      int n = ((eType-12) / 2);
          432  +      if( eType % 2 ){
          433  +        sqlite3_result_text(pCtx, (const char*)pData, n, SQLITE_TRANSIENT);
          434  +      }else{
          435  +        sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT);
          436  +      }
          437  +    }
          438  +  }
          439  +}
          440  +
          441  +
          442  +/*
          443  +** Move an sqlite_dbdata or sqlite_dbptr cursor to the next entry.
          444  +*/
          445  +static int dbdataNext(sqlite3_vtab_cursor *pCursor){
          446  +  DbdataCursor *pCsr = (DbdataCursor*)pCursor;
          447  +  DbdataTable *pTab = (DbdataTable*)pCursor->pVtab;
          448  +
          449  +  pCsr->iRowid++;
          450  +  while( 1 ){
          451  +    int rc;
          452  +    int iOff = (pCsr->iPgno==1 ? 100 : 0);
          453  +
          454  +    if( pCsr->aPage==0 ){
          455  +      while( 1 ){
          456  +        if( pCsr->bOnePage==0 && pCsr->iPgno>pCsr->szDb ) return SQLITE_OK;
          457  +        rc = dbdataLoadPage(pCsr, pCsr->iPgno, &pCsr->aPage, &pCsr->nPage);
          458  +        if( rc!=SQLITE_OK ) return rc;
          459  +        if( pCsr->aPage ) break;
          460  +        pCsr->iPgno++;
          461  +      }
          462  +      pCsr->iCell = pTab->bPtr ? -2 : 0;
          463  +      pCsr->nCell = get_uint16(&pCsr->aPage[iOff+3]);
          464  +    }
          465  +
          466  +    if( pTab->bPtr ){
          467  +      if( pCsr->aPage[iOff]!=0x02 && pCsr->aPage[iOff]!=0x05 ){
          468  +        pCsr->iCell = pCsr->nCell;
          469  +      }
          470  +      pCsr->iCell++;
          471  +      if( pCsr->iCell>=pCsr->nCell ){
          472  +        sqlite3_free(pCsr->aPage);
          473  +        pCsr->aPage = 0;
          474  +        if( pCsr->bOnePage ) return SQLITE_OK;
          475  +        pCsr->iPgno++;
          476  +      }else{
          477  +        return SQLITE_OK;
          478  +      }
          479  +    }else{
          480  +      /* If there is no record loaded, load it now. */
          481  +      if( pCsr->pRec==0 ){
          482  +        int bHasRowid = 0;
          483  +        int nPointer = 0;
          484  +        sqlite3_int64 nPayload = 0;
          485  +        sqlite3_int64 nHdr = 0;
          486  +        int iHdr;
          487  +        int U, X;
          488  +        int nLocal;
          489  +  
          490  +        switch( pCsr->aPage[iOff] ){
          491  +          case 0x02:
          492  +            nPointer = 4;
          493  +            break;
          494  +          case 0x0a:
          495  +            break;
          496  +          case 0x0d:
          497  +            bHasRowid = 1;
          498  +            break;
          499  +          default:
          500  +            /* This is not a b-tree page with records on it. Continue. */
          501  +            pCsr->iCell = pCsr->nCell;
          502  +            break;
          503  +        }
          504  +
          505  +        if( pCsr->iCell>=pCsr->nCell ){
          506  +          sqlite3_free(pCsr->aPage);
          507  +          pCsr->aPage = 0;
          508  +          if( pCsr->bOnePage ) return SQLITE_OK;
          509  +          pCsr->iPgno++;
          510  +          continue;
          511  +        }
          512  +  
          513  +        iOff += 8 + nPointer + pCsr->iCell*2;
          514  +        iOff = get_uint16(&pCsr->aPage[iOff]);
          515  +  
          516  +        /* For an interior node cell, skip past the child-page number */
          517  +        iOff += nPointer;
          518  +  
          519  +        /* Load the "byte of payload including overflow" field */
          520  +        iOff += dbdataGetVarint(&pCsr->aPage[iOff], &nPayload);
          521  +  
          522  +        /* If this is a leaf intkey cell, load the rowid */
          523  +        if( bHasRowid ){
          524  +          iOff += dbdataGetVarint(&pCsr->aPage[iOff], &pCsr->iIntkey);
          525  +        }
          526  +  
          527  +        /* Allocate space for payload */
          528  +        pCsr->pRec = (u8*)sqlite3_malloc64(nPayload);
          529  +        if( pCsr->pRec==0 ) return SQLITE_NOMEM;
          530  +        pCsr->nRec = nPayload;
          531  +  
          532  +        U = pCsr->nPage;
          533  +        if( bHasRowid ){
          534  +          X = U-35;
          535  +        }else{
          536  +          X = ((U-12)*64/255)-23;
          537  +        }
          538  +        if( nPayload<=X ){
          539  +          nLocal = nPayload;
          540  +        }else{
          541  +          int M, K;
          542  +          M = ((U-12)*32/255)-23;
          543  +          K = M+((nPayload-M)%(U-4));
          544  +          if( K<=X ){
          545  +            nLocal = K;
          546  +          }else{
          547  +            nLocal = M;
          548  +          }
          549  +        }
          550  +  
          551  +        /* Load the nLocal bytes of payload */
          552  +        memcpy(pCsr->pRec, &pCsr->aPage[iOff], nLocal);
          553  +        iOff += nLocal;
          554  +  
          555  +        /* Load content from overflow pages */
          556  +        if( nPayload>nLocal ){
          557  +          sqlite3_int64 nRem = nPayload - nLocal;
          558  +          unsigned int pgnoOvfl = get_uint32(&pCsr->aPage[iOff]);
          559  +          while( nRem>0 ){
          560  +            u8 *aOvfl = 0;
          561  +            int nOvfl = 0;
          562  +            int nCopy;
          563  +            rc = dbdataLoadPage(pCsr, pgnoOvfl, &aOvfl, &nOvfl);
          564  +            assert( rc!=SQLITE_OK || nOvfl==pCsr->nPage );
          565  +            if( rc!=SQLITE_OK ) return rc;
          566  +  
          567  +            nCopy = U-4;
          568  +            if( nCopy>nRem ) nCopy = nRem;
          569  +            memcpy(&pCsr->pRec[nPayload-nRem], &aOvfl[4], nCopy);
          570  +            nRem -= nCopy;
          571  +  
          572  +            pgnoOvfl = get_uint32(aOvfl);
          573  +            sqlite3_free(aOvfl);
          574  +          }
          575  +        }
          576  +  
          577  +        iHdr = dbdataGetVarint(pCsr->pRec, &nHdr);
          578  +        pCsr->nHdr = nHdr;
          579  +        pCsr->pHdrPtr = &pCsr->pRec[iHdr];
          580  +        pCsr->pPtr = &pCsr->pRec[pCsr->nHdr];
          581  +        pCsr->iField = (bHasRowid ? -1 : 0);
          582  +      }else{
          583  +        pCsr->iField++;
          584  +        if( pCsr->iField>0 ){
          585  +          sqlite3_int64 iType;
          586  +          pCsr->pHdrPtr += dbdataGetVarint(pCsr->pHdrPtr, &iType);
          587  +          pCsr->pPtr += dbdataValueBytes(iType);
          588  +        }
          589  +      }
          590  +
          591  +      if( pCsr->iField<0 || pCsr->pHdrPtr<&pCsr->pRec[pCsr->nHdr] ){
          592  +        return SQLITE_OK;
          593  +      }
          594  +  
          595  +      /* Advance to the next cell. The next iteration of the loop will load
          596  +      ** the record and so on. */
          597  +      sqlite3_free(pCsr->pRec);
          598  +      pCsr->pRec = 0;
          599  +      pCsr->iCell++;
          600  +    }
          601  +  }
          602  +
          603  +  assert( !"can't get here" );
          604  +  return SQLITE_OK;
          605  +}
          606  +
          607  +/* 
          608  +** Return true if the cursor is at EOF.
          609  +*/
          610  +static int dbdataEof(sqlite3_vtab_cursor *pCursor){
          611  +  DbdataCursor *pCsr = (DbdataCursor*)pCursor;
          612  +  return pCsr->aPage==0;
          613  +}
          614  +
          615  +/* 
          616  +** Determine the size in pages of database zSchema (where zSchema is
          617  +** "main", "temp" or the name of an attached database) and set 
          618  +** pCsr->szDb accordingly. If successful, return SQLITE_OK. Otherwise,
          619  +** an SQLite error code.
          620  +*/
          621  +static int dbdataDbsize(DbdataCursor *pCsr, const char *zSchema){
          622  +  DbdataTable *pTab = (DbdataTable*)pCsr->base.pVtab;
          623  +  char *zSql = 0;
          624  +  int rc, rc2;
          625  +  sqlite3_stmt *pStmt = 0;
          626  +
          627  +  zSql = sqlite3_mprintf("PRAGMA %Q.page_count", zSchema);
          628  +  if( zSql==0 ) return SQLITE_NOMEM;
          629  +  rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0);
          630  +  sqlite3_free(zSql);
          631  +  if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
          632  +    pCsr->szDb = sqlite3_column_int(pStmt, 0);
          633  +  }
          634  +  rc2 = sqlite3_finalize(pStmt);
          635  +  if( rc==SQLITE_OK ) rc = rc2;
          636  +  return rc;
          637  +}
          638  +
          639  +/* 
          640  +** xFilter method for sqlite_dbdata and sqlite_dbptr.
          641  +*/
          642  +static int dbdataFilter(
          643  +  sqlite3_vtab_cursor *pCursor, 
          644  +  int idxNum, const char *idxStr,
          645  +  int argc, sqlite3_value **argv
          646  +){
          647  +  DbdataCursor *pCsr = (DbdataCursor*)pCursor;
          648  +  DbdataTable *pTab = (DbdataTable*)pCursor->pVtab;
          649  +  int rc = SQLITE_OK;
          650  +  const char *zSchema = "main";
          651  +
          652  +  dbdataResetCursor(pCsr);
          653  +  assert( pCsr->iPgno==1 );
          654  +  if( idxNum & 0x01 ){
          655  +    zSchema = (const char*)sqlite3_value_text(argv[0]);
          656  +  }
          657  +  if( idxNum & 0x02 ){
          658  +    pCsr->iPgno = sqlite3_value_int(argv[(idxNum & 0x01)]);
          659  +    pCsr->bOnePage = 1;
          660  +  }else{
          661  +    pCsr->nPage = dbdataDbsize(pCsr, zSchema);
          662  +    rc = dbdataDbsize(pCsr, zSchema);
          663  +  }
          664  +
          665  +  if( rc==SQLITE_OK ){
          666  +    if( pTab->pStmt ){
          667  +      pCsr->pStmt = pTab->pStmt;
          668  +      pTab->pStmt = 0;
          669  +    }else{
          670  +      rc = sqlite3_prepare_v2(pTab->db, 
          671  +          "SELECT data FROM sqlite_dbpage(?) WHERE pgno=?", -1,
          672  +          &pCsr->pStmt, 0
          673  +      );
          674  +    }
          675  +  }
          676  +  if( rc==SQLITE_OK ){
          677  +    rc = sqlite3_bind_text(pCsr->pStmt, 1, zSchema, -1, SQLITE_TRANSIENT);
          678  +  }else{
          679  +    pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db));
          680  +  }
          681  +  if( rc==SQLITE_OK ){
          682  +    rc = dbdataNext(pCursor);
          683  +  }
          684  +  return rc;
          685  +}
          686  +
          687  +/* 
          688  +** Return a column for the sqlite_dbdata or sqlite_dbptr table.
          689  +*/
          690  +static int dbdataColumn(
          691  +  sqlite3_vtab_cursor *pCursor, 
          692  +  sqlite3_context *ctx, 
          693  +  int i
          694  +){
          695  +  DbdataCursor *pCsr = (DbdataCursor*)pCursor;
          696  +  DbdataTable *pTab = (DbdataTable*)pCursor->pVtab;
          697  +  if( pTab->bPtr ){
          698  +    switch( i ){
          699  +      case DBPTR_COLUMN_PGNO:
          700  +        sqlite3_result_int64(ctx, pCsr->iPgno);
          701  +        break;
          702  +      case DBPTR_COLUMN_CHILD: {
          703  +        int iOff = pCsr->iPgno==1 ? 100 : 0;
          704  +        if( pCsr->iCell<0 ){
          705  +          iOff += 8;
          706  +        }else{
          707  +          iOff += 12 + pCsr->iCell*2;
          708  +          iOff = get_uint16(&pCsr->aPage[iOff]);
          709  +        }
          710  +        sqlite3_result_int64(ctx, get_uint32(&pCsr->aPage[iOff]));
          711  +        break;
          712  +      }
          713  +    }
          714  +  }else{
          715  +    switch( i ){
          716  +      case DBDATA_COLUMN_PGNO:
          717  +        sqlite3_result_int64(ctx, pCsr->iPgno);
          718  +        break;
          719  +      case DBDATA_COLUMN_CELL:
          720  +        sqlite3_result_int(ctx, pCsr->iCell);
          721  +        break;
          722  +      case DBDATA_COLUMN_FIELD:
          723  +        sqlite3_result_int(ctx, pCsr->iField);
          724  +        break;
          725  +      case DBDATA_COLUMN_VALUE: {
          726  +        if( pCsr->iField<0 ){
          727  +          sqlite3_result_int64(ctx, pCsr->iIntkey);
          728  +        }else{
          729  +          sqlite3_int64 iType;
          730  +          dbdataGetVarint(pCsr->pHdrPtr, &iType);
          731  +          dbdataValue(ctx, iType, pCsr->pPtr);
          732  +        }
          733  +        break;
          734  +      }
          735  +    }
          736  +  }
          737  +  return SQLITE_OK;
          738  +}
          739  +
          740  +/* 
          741  +** Return the rowid for an sqlite_dbdata or sqlite_dptr table.
          742  +*/
          743  +static int dbdataRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
          744  +  DbdataCursor *pCsr = (DbdataCursor*)pCursor;
          745  +  *pRowid = pCsr->iRowid;
          746  +  return SQLITE_OK;
          747  +}
          748  +
          749  +
          750  +/*
          751  +** Invoke this routine to register the "sqlite_dbdata" virtual table module
          752  +*/
          753  +static int sqlite3DbdataRegister(sqlite3 *db){
          754  +  static sqlite3_module dbdata_module = {
          755  +    0,                            /* iVersion */
          756  +    0,                            /* xCreate */
          757  +    dbdataConnect,                /* xConnect */
          758  +    dbdataBestIndex,              /* xBestIndex */
          759  +    dbdataDisconnect,             /* xDisconnect */
          760  +    0,                            /* xDestroy */
          761  +    dbdataOpen,                   /* xOpen - open a cursor */
          762  +    dbdataClose,                  /* xClose - close a cursor */
          763  +    dbdataFilter,                 /* xFilter - configure scan constraints */
          764  +    dbdataNext,                   /* xNext - advance a cursor */
          765  +    dbdataEof,                    /* xEof - check for end of scan */
          766  +    dbdataColumn,                 /* xColumn - read data */
          767  +    dbdataRowid,                  /* xRowid - read data */
          768  +    0,                            /* xUpdate */
          769  +    0,                            /* xBegin */
          770  +    0,                            /* xSync */
          771  +    0,                            /* xCommit */
          772  +    0,                            /* xRollback */
          773  +    0,                            /* xFindMethod */
          774  +    0,                            /* xRename */
          775  +    0,                            /* xSavepoint */
          776  +    0,                            /* xRelease */
          777  +    0,                            /* xRollbackTo */
          778  +    0                             /* xShadowName */
          779  +  };
          780  +
          781  +  int rc = sqlite3_create_module(db, "sqlite_dbdata", &dbdata_module, 0);
          782  +  if( rc==SQLITE_OK ){
          783  +    rc = sqlite3_create_module(db, "sqlite_dbptr", &dbdata_module, (void*)1);
          784  +  }
          785  +  return rc;
          786  +}
          787  +
          788  +#ifdef _WIN32
          789  +__declspec(dllexport)
          790  +#endif
          791  +int sqlite3_dbdata_init(
          792  +  sqlite3 *db, 
          793  +  char **pzErrMsg, 
          794  +  const sqlite3_api_routines *pApi
          795  +){
          796  +  SQLITE_EXTENSION_INIT2(pApi);
          797  +  return sqlite3DbdataRegister(db);
          798  +}

Changes to main.mk.

   734    734   	$(TOP)/ext/misc/fileio.c \
   735    735   	$(TOP)/ext/misc/completion.c \
   736    736   	$(TOP)/ext/misc/sqlar.c \
   737    737   	$(TOP)/ext/expert/sqlite3expert.c \
   738    738   	$(TOP)/ext/expert/sqlite3expert.h \
   739    739   	$(TOP)/ext/misc/zipfile.c \
   740    740   	$(TOP)/ext/misc/memtrace.c \
          741  +	$(TOP)/ext/misc/dbdata.c \
   741    742           $(TOP)/src/test_windirent.c
   742    743   
   743    744   shell.c:	$(SHELL_SRC) $(TOP)/tool/mkshellc.tcl
   744    745   	tclsh $(TOP)/tool/mkshellc.tcl >shell.c
   745    746   
   746    747   
   747    748   

Changes to src/shell.c.in.

   943    943   INCLUDE ../ext/misc/memtrace.c
   944    944   #ifdef SQLITE_HAVE_ZLIB
   945    945   INCLUDE ../ext/misc/zipfile.c
   946    946   INCLUDE ../ext/misc/sqlar.c
   947    947   #endif
   948    948   INCLUDE ../ext/expert/sqlite3expert.h
   949    949   INCLUDE ../ext/expert/sqlite3expert.c
          950  +
          951  +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
          952  +INCLUDE ../ext/misc/dbdata.c
          953  +#endif
   950    954   
   951    955   #if defined(SQLITE_ENABLE_SESSION)
   952    956   /*
   953    957   ** State information for a single open session
   954    958   */
   955    959   typedef struct OpenSession OpenSession;
   956    960   struct OpenSession {
................................................................................
  3570   3574     "   --once                    Do no more than one progress interrupt",
  3571   3575     "   --quiet|-q                No output except at interrupts",
  3572   3576     "   --reset                   Reset the count for each input and interrupt",
  3573   3577   #endif
  3574   3578     ".prompt MAIN CONTINUE    Replace the standard prompts",
  3575   3579     ".quit                    Exit this program",
  3576   3580     ".read FILE               Read input from FILE",
         3581  +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
         3582  +  ".recover                 Recover as much data as possible from corrupt db.",
         3583  +#endif
  3577   3584     ".restore ?DB? FILE       Restore content of DB (default \"main\") from FILE",
  3578   3585     ".save FILE               Write in-memory database into FILE",
  3579   3586     ".scanstats on|off        Turn sqlite3_stmt_scanstatus() metrics on or off",
  3580   3587     ".schema ?PATTERN?        Show the CREATE statements matching PATTERN",
  3581   3588     "     Options:",
  3582   3589     "         --indent            Try to pretty-print the schema",
  3583   3590     ".selftest ?OPTIONS?      Run tests defined in the SELFTEST table",
................................................................................
  3926   3933       p->lineno = nLine;
  3927   3934     }
  3928   3935     sqlite3_free(a);
  3929   3936     utf8_printf(stderr,"Error on line %d of --hexdb input\n", nLine);
  3930   3937     return 0;
  3931   3938   }
  3932   3939   #endif /* SQLITE_ENABLE_DESERIALIZE */
         3940  +
         3941  +/*
         3942  +** Scalar function "shell_int32". The first argument to this function
         3943  +** must be a blob. The second a non-negative integer. This function
         3944  +** reads and returns a 32-bit big-endian integer from byte
         3945  +** offset (4*<arg2>) of the blob.
         3946  +*/
         3947  +static void shellInt32(
         3948  +  sqlite3_context *context, 
         3949  +  int argc, 
         3950  +  sqlite3_value **argv
         3951  +){
         3952  +  const unsigned char *pBlob;
         3953  +  int nBlob;
         3954  +  int iInt;
         3955  +  
         3956  +  nBlob = sqlite3_value_bytes(argv[0]);
         3957  +  pBlob = (const unsigned char*)sqlite3_value_blob(argv[0]);
         3958  +  iInt = sqlite3_value_int(argv[1]);
         3959  +
         3960  +  if( iInt>=0 && (iInt+1)*4<=nBlob ){
         3961  +    const unsigned char *a = &pBlob[iInt*4];
         3962  +    sqlite3_int64 iVal = ((sqlite3_int64)a[0]<<24)
         3963  +                       + ((sqlite3_int64)a[1]<<16)
         3964  +                       + ((sqlite3_int64)a[2]<< 8)
         3965  +                       + ((sqlite3_int64)a[3]<< 0);
         3966  +    sqlite3_result_int64(context, iVal);
         3967  +  }
         3968  +}
         3969  +
         3970  +/*
         3971  +** Scalar function "shell_escape_crnl" used by the .recover command.
         3972  +** The argument passed to this function is the output of built-in
         3973  +** function quote(). If the first character of the input is "'", 
         3974  +** indicating that the value passed to quote() was a text value,
         3975  +** then this function searches the input for "\n" and "\r" characters
         3976  +** and adds a wrapper similar to the following:
         3977  +**
         3978  +**   replace(replace(<input>, '\n', char(10), '\r', char(13));
         3979  +**
         3980  +** Or, if the first character of the input is not "'", then a copy
         3981  +** of the input is returned.
         3982  +*/
         3983  +static void shellEscapeCrnl(
         3984  +  sqlite3_context *context, 
         3985  +  int argc, 
         3986  +  sqlite3_value **argv
         3987  +){
         3988  +  const char *zText = (const char*)sqlite3_value_text(argv[0]);
         3989  +  if( zText[0]=='\'' ){
         3990  +    int nText = sqlite3_value_bytes(argv[0]);
         3991  +    int i;
         3992  +    char zBuf1[20];
         3993  +    char zBuf2[20];
         3994  +    const char *zNL = 0;
         3995  +    const char *zCR = 0;
         3996  +    int nCR = 0;
         3997  +    int nNL = 0;
         3998  +
         3999  +    for(i=0; zText[i]; i++){
         4000  +      if( zNL==0 && zText[i]=='\n' ){
         4001  +        zNL = unused_string(zText, "\\n", "\\012", zBuf1);
         4002  +        nNL = (int)strlen(zNL);
         4003  +      }
         4004  +      if( zCR==0 && zText[i]=='\r' ){
         4005  +        zCR = unused_string(zText, "\\r", "\\015", zBuf2);
         4006  +        nCR = (int)strlen(zCR);
         4007  +      }
         4008  +    }
         4009  +
         4010  +    if( zNL || zCR ){
         4011  +      int iOut = 0;
         4012  +      i64 nMax = (nNL > nCR) ? nNL : nCR;
         4013  +      i64 nAlloc = nMax * nText + (nMax+12)*2;
         4014  +      char *zOut = (char*)sqlite3_malloc64(nAlloc);
         4015  +      if( zOut==0 ){
         4016  +        sqlite3_result_error_nomem(context);
         4017  +        return;
         4018  +      }
         4019  +
         4020  +      if( zNL && zCR ){
         4021  +        memcpy(&zOut[iOut], "replace(replace(", 16);
         4022  +        iOut += 16;
         4023  +      }else{
         4024  +        memcpy(&zOut[iOut], "replace(", 8);
         4025  +        iOut += 8;
         4026  +      }
         4027  +      for(i=0; zText[i]; i++){
         4028  +        if( zText[i]=='\n' ){
         4029  +          memcpy(&zOut[iOut], zNL, nNL);
         4030  +          iOut += nNL;
         4031  +        }else if( zText[i]=='\r' ){
         4032  +          memcpy(&zOut[iOut], zCR, nCR);
         4033  +          iOut += nCR;
         4034  +        }else{
         4035  +          zOut[iOut] = zText[i];
         4036  +          iOut++;
         4037  +        }
         4038  +      }
         4039  +
         4040  +      if( zNL ){
         4041  +        memcpy(&zOut[iOut], ",'", 2); iOut += 2;
         4042  +        memcpy(&zOut[iOut], zNL, nNL); iOut += nNL;
         4043  +        memcpy(&zOut[iOut], "', char(10))", 12); iOut += 12;
         4044  +      }
         4045  +      if( zCR ){
         4046  +        memcpy(&zOut[iOut], ",'", 2); iOut += 2;
         4047  +        memcpy(&zOut[iOut], zCR, nCR); iOut += nCR;
         4048  +        memcpy(&zOut[iOut], "', char(13))", 12); iOut += 12;
         4049  +      }
         4050  +
         4051  +      sqlite3_result_text(context, zOut, iOut, SQLITE_TRANSIENT);
         4052  +      sqlite3_free(zOut);
         4053  +      return;
         4054  +    }
         4055  +  }
         4056  +
         4057  +  sqlite3_result_value(context, argv[0]);
         4058  +}
  3933   4059   
  3934   4060   /* Flags for open_db().
  3935   4061   **
  3936   4062   ** The default behavior of open_db() is to exit(1) if the database fails to
  3937   4063   ** open.  The OPEN_DB_KEEPALIVE flag changes that so that it prints an error
  3938   4064   ** but still returns without calling exit.
  3939   4065   **
................................................................................
  3995   4121       }
  3996   4122   #ifndef SQLITE_OMIT_LOAD_EXTENSION
  3997   4123       sqlite3_enable_load_extension(p->db, 1);
  3998   4124   #endif
  3999   4125       sqlite3_fileio_init(p->db, 0, 0);
  4000   4126       sqlite3_shathree_init(p->db, 0, 0);
  4001   4127       sqlite3_completion_init(p->db, 0, 0);
         4128  +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
         4129  +    sqlite3_dbdata_init(p->db, 0, 0);
         4130  +#endif
  4002   4131   #ifdef SQLITE_HAVE_ZLIB
  4003   4132       sqlite3_zipfile_init(p->db, 0, 0);
  4004   4133       sqlite3_sqlar_init(p->db, 0, 0);
  4005   4134   #endif
  4006   4135       sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0,
  4007   4136                               shellAddSchemaName, 0, 0);
  4008   4137       sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0,
  4009   4138                               shellModuleSchema, 0, 0);
  4010   4139       sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p,
  4011   4140                               shellPutsFunc, 0, 0);
         4141  +    sqlite3_create_function(p->db, "shell_escape_crnl", 1, SQLITE_UTF8, 0,
         4142  +                            shellEscapeCrnl, 0, 0);
         4143  +    sqlite3_create_function(p->db, "shell_int32", 2, SQLITE_UTF8, 0,
         4144  +                            shellInt32, 0, 0);
  4012   4145   #ifndef SQLITE_NOHAVE_SYSTEM
  4013   4146       sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0,
  4014   4147                               editFunc, 0, 0);
  4015   4148       sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0,
  4016   4149                               editFunc, 0, 0);
  4017   4150   #endif
  4018   4151       if( p->openMode==SHELL_OPEN_ZIPFILE ){
................................................................................
  5259   5392    usage:
  5260   5393     raw_printf(stderr, "Usage %s sub-command ?switches...?\n", azArg[0]);
  5261   5394     raw_printf(stderr, "Where sub-commands are:\n");
  5262   5395     raw_printf(stderr, "    fkey-indexes\n");
  5263   5396     return SQLITE_ERROR;
  5264   5397   }
  5265   5398   
  5266         -#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
  5267         -/*********************************************************************************
  5268         -** The ".archive" or ".ar" command.
  5269         -*/
         5399  +#if !defined SQLITE_OMIT_VIRTUALTABLE
  5270   5400   static void shellPrepare(
  5271   5401     sqlite3 *db, 
  5272   5402     int *pRc, 
  5273   5403     const char *zSql, 
  5274   5404     sqlite3_stmt **ppStmt
  5275   5405   ){
  5276   5406     *ppStmt = 0;
................................................................................
  5333   5463       if( rc!=SQLITE_OK ){
  5334   5464         sqlite3 *db = sqlite3_db_handle(pStmt);
  5335   5465         raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
  5336   5466       }
  5337   5467       *pRc = rc;
  5338   5468     }
  5339   5469   }
         5470  +#endif /* !defined SQLITE_OMIT_VIRTUALTABLE */
         5471  +
         5472  +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
         5473  +/*********************************************************************************
         5474  +** The ".archive" or ".ar" command.
         5475  +*/
  5340   5476   /*
  5341   5477   ** Structure representing a single ".ar" command.
  5342   5478   */
  5343   5479   typedef struct ArCommand ArCommand;
  5344   5480   struct ArCommand {
  5345   5481     u8 eCmd;                        /* An AR_CMD_* value */
  5346   5482     u8 bVerbose;                    /* True if --verbose */
................................................................................
  6022   6158   
  6023   6159     return rc;
  6024   6160   }
  6025   6161   /* End of the ".archive" or ".ar" command logic
  6026   6162   **********************************************************************************/
  6027   6163   #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) */
  6028   6164   
         6165  +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
         6166  +/*
         6167  +** If (*pRc) is not SQLITE_OK when this function is called, it is a no-op.
         6168  +** Otherwise, the SQL statement or statements in zSql are executed using
         6169  +** database connection db and the error code written to *pRc before
         6170  +** this function returns.
         6171  +*/
         6172  +static void shellExec(sqlite3 *db, int *pRc, const char *zSql){
         6173  +  int rc = *pRc;
         6174  +  if( rc==SQLITE_OK ){
         6175  +    char *zErr = 0;
         6176  +    rc = sqlite3_exec(db, zSql, 0, 0, &zErr);
         6177  +    if( rc!=SQLITE_OK ){
         6178  +      raw_printf(stderr, "SQL error: %s\n", zErr);
         6179  +    }
         6180  +    *pRc = rc;
         6181  +  }
         6182  +}
         6183  +
         6184  +/*
         6185  +** Like shellExec(), except that zFmt is a printf() style format string.
         6186  +*/
         6187  +static void shellExecPrintf(sqlite3 *db, int *pRc, const char *zFmt, ...){
         6188  +  char *z = 0;
         6189  +  if( *pRc==SQLITE_OK ){
         6190  +    va_list ap;
         6191  +    va_start(ap, zFmt);
         6192  +    z = sqlite3_vmprintf(zFmt, ap);
         6193  +    va_end(ap);
         6194  +    if( z==0 ){
         6195  +      *pRc = SQLITE_NOMEM;
         6196  +    }else{
         6197  +      shellExec(db, pRc, z);
         6198  +    }
         6199  +    sqlite3_free(z);
         6200  +  }
         6201  +}
         6202  +
         6203  +/*
         6204  +** If *pRc is not SQLITE_OK when this function is called, it is a no-op.
         6205  +** Otherwise, an attempt is made to allocate, zero and return a pointer
         6206  +** to a buffer nByte bytes in size. If an OOM error occurs, *pRc is set
         6207  +** to SQLITE_NOMEM and NULL returned.
         6208  +*/
         6209  +static void *shellMalloc(int *pRc, sqlite3_int64 nByte){
         6210  +  void *pRet = 0;
         6211  +  if( *pRc==SQLITE_OK ){
         6212  +    pRet = sqlite3_malloc64(nByte);
         6213  +    if( pRet==0 ){
         6214  +      *pRc = SQLITE_NOMEM;
         6215  +    }else{
         6216  +      memset(pRet, 0, nByte);
         6217  +    }
         6218  +  }
         6219  +  return pRet;
         6220  +}
         6221  +
         6222  +/*
         6223  +** If *pRc is not SQLITE_OK when this function is called, it is a no-op.
         6224  +** Otherwise, zFmt is treated as a printf() style string. The result of
         6225  +** formatting it along with any trailing arguments is written into a 
         6226  +** buffer obtained from sqlite3_malloc(), and pointer to which is returned.
         6227  +** It is the responsibility of the caller to eventually free this buffer
         6228  +** using a call to sqlite3_free().
         6229  +** 
         6230  +** If an OOM error occurs, (*pRc) is set to SQLITE_NOMEM and a NULL 
         6231  +** pointer returned.
         6232  +*/
         6233  +static char *shellMPrintf(int *pRc, const char *zFmt, ...){
         6234  +  char *z = 0;
         6235  +  if( *pRc==SQLITE_OK ){
         6236  +    va_list ap;
         6237  +    va_start(ap, zFmt);
         6238  +    z = sqlite3_vmprintf(zFmt, ap);
         6239  +    va_end(ap);
         6240  +    if( z==0 ){
         6241  +      *pRc = SQLITE_NOMEM;
         6242  +    }
         6243  +  }
         6244  +  return z;
         6245  +}
         6246  +
         6247  +/*
         6248  +** When running the ".recover" command, each output table, and the special
         6249  +** orphaned row table if it is required, is represented by an instance
         6250  +** of the following struct.
         6251  +*/
         6252  +typedef struct RecoverTable RecoverTable;
         6253  +struct RecoverTable {
         6254  +  char *zQuoted;                  /* Quoted version of table name */
         6255  +  int nCol;                       /* Number of columns in table */
         6256  +  char **azlCol;                  /* Array of column lists */
         6257  +  int iPk;                        /* Index of IPK column */
         6258  +};
         6259  +
         6260  +/*
         6261  +** Free a RecoverTable object allocated by recoverFindTable() or
         6262  +** recoverOrphanTable().
         6263  +*/
         6264  +static void recoverFreeTable(RecoverTable *pTab){
         6265  +  if( pTab ){
         6266  +    sqlite3_free(pTab->zQuoted);
         6267  +    if( pTab->azlCol ){
         6268  +      int i;
         6269  +      for(i=0; i<=pTab->nCol; i++){
         6270  +        sqlite3_free(pTab->azlCol[i]);
         6271  +      }
         6272  +      sqlite3_free(pTab->azlCol);
         6273  +    }
         6274  +    sqlite3_free(pTab);
         6275  +  }
         6276  +}
         6277  +
         6278  +/*
         6279  +** This function is a no-op if (*pRc) is not SQLITE_OK when it is called.
         6280  +** Otherwise, it allocates and returns a RecoverTable object based on the
         6281  +** final four arguments passed to this function. It is the responsibility
         6282  +** of the caller to eventually free the returned object using
         6283  +** recoverFreeTable().
         6284  +*/
         6285  +static RecoverTable *recoverNewTable(
         6286  +  int *pRc,                       /* IN/OUT: Error code */
         6287  +  const char *zName,              /* Name of table */
         6288  +  const char *zSql,               /* CREATE TABLE statement */
         6289  +  int bIntkey, 
         6290  +  int nCol
         6291  +){
         6292  +  sqlite3 *dbtmp = 0;             /* sqlite3 handle for testing CREATE TABLE */
         6293  +  int rc = *pRc;
         6294  +  RecoverTable *pTab = 0;
         6295  +
         6296  +  pTab = (RecoverTable*)shellMalloc(&rc, sizeof(RecoverTable));
         6297  +  if( rc==SQLITE_OK ){
         6298  +    int nSqlCol = 0;
         6299  +    int bSqlIntkey = 0;
         6300  +    sqlite3_stmt *pStmt = 0;
         6301  +    
         6302  +    rc = sqlite3_open("", &dbtmp);
         6303  +    if( rc==SQLITE_OK ){
         6304  +      rc = sqlite3_exec(dbtmp, "PRAGMA writable_schema = on", 0, 0, 0);
         6305  +    }
         6306  +    if( rc==SQLITE_OK ){
         6307  +      rc = sqlite3_exec(dbtmp, zSql, 0, 0, 0);
         6308  +      if( rc==SQLITE_ERROR ){
         6309  +        rc = SQLITE_OK;
         6310  +        goto finished;
         6311  +      }
         6312  +    }
         6313  +    shellPreparePrintf(dbtmp, &rc, &pStmt, 
         6314  +        "SELECT count(*) FROM pragma_table_info(%Q)", zName
         6315  +    );
         6316  +    if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
         6317  +      nSqlCol = sqlite3_column_int(pStmt, 0);
         6318  +    }
         6319  +    shellFinalize(&rc, pStmt);
         6320  +
         6321  +    if( rc!=SQLITE_OK || nSqlCol<nCol ){
         6322  +      goto finished;
         6323  +    }
         6324  +
         6325  +    shellPreparePrintf(dbtmp, &rc, &pStmt, 
         6326  +      "SELECT ("
         6327  +      "  SELECT substr(data,1,1)==X'0D' FROM sqlite_dbpage WHERE pgno=rootpage"
         6328  +      ") FROM sqlite_master WHERE name = %Q", zName
         6329  +    );
         6330  +    if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
         6331  +      bSqlIntkey = sqlite3_column_int(pStmt, 0);
         6332  +    }
         6333  +    shellFinalize(&rc, pStmt);
         6334  +
         6335  +    if( bIntkey==bSqlIntkey ){
         6336  +      int i;
         6337  +      const char *zPk = "_rowid_";
         6338  +      sqlite3_stmt *pPkFinder = 0;
         6339  +
         6340  +      /* If this is an intkey table and there is an INTEGER PRIMARY KEY,
         6341  +      ** set zPk to the name of the PK column, and pTab->iPk to the index
         6342  +      ** of the column, where columns are 0-numbered from left to right.
         6343  +      ** Or, if this is a WITHOUT ROWID table or if there is no IPK column,
         6344  +      ** leave zPk as "_rowid_" and pTab->iPk at -2.  */
         6345  +      pTab->iPk = -2;
         6346  +      if( bIntkey ){
         6347  +        shellPreparePrintf(dbtmp, &rc, &pPkFinder, 
         6348  +          "SELECT cid, name FROM pragma_table_info(%Q) "
         6349  +          "  WHERE pk=1 AND type='integer' COLLATE nocase"
         6350  +          "  AND NOT EXISTS (SELECT cid FROM pragma_table_info(%Q) WHERE pk=2)"
         6351  +          , zName, zName
         6352  +        );
         6353  +        if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPkFinder) ){
         6354  +          pTab->iPk = sqlite3_column_int(pPkFinder, 0);
         6355  +          zPk = (const char*)sqlite3_column_text(pPkFinder, 1);
         6356  +        }
         6357  +      }
         6358  +
         6359  +      pTab->zQuoted = shellMPrintf(&rc, "%Q", zName);
         6360  +      pTab->azlCol = (char**)shellMalloc(&rc, sizeof(char*) * (nSqlCol+1));
         6361  +      pTab->nCol = nSqlCol;
         6362  +
         6363  +      if( bIntkey ){
         6364  +        pTab->azlCol[0] = shellMPrintf(&rc, "%Q", zPk);
         6365  +      }else{
         6366  +        pTab->azlCol[0] = shellMPrintf(&rc, "");
         6367  +      }
         6368  +      i = 1;
         6369  +      shellPreparePrintf(dbtmp, &rc, &pStmt, 
         6370  +          "SELECT %Q || group_concat(name, ', ') "
         6371  +          "  FILTER (WHERE cid!=%d) OVER (ORDER BY %s cid) "
         6372  +          "FROM pragma_table_info(%Q)", 
         6373  +          bIntkey ? ", " : "", pTab->iPk, 
         6374  +          bIntkey ? "" : "(CASE WHEN pk=0 THEN 1000000 ELSE pk END), ",
         6375  +          zName
         6376  +      );
         6377  +      while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
         6378  +        const char *zText = (const char*)sqlite3_column_text(pStmt, 0);
         6379  +        pTab->azlCol[i] = shellMPrintf(&rc, "%s%s", pTab->azlCol[0], zText);
         6380  +        i++;
         6381  +      }
         6382  +      shellFinalize(&rc, pStmt);
         6383  +
         6384  +      shellFinalize(&rc, pPkFinder);
         6385  +    }
         6386  +  }
         6387  +
         6388  + finished:
         6389  +  sqlite3_close(dbtmp);
         6390  +  *pRc = rc;
         6391  +  if( rc!=SQLITE_OK ){
         6392  +    recoverFreeTable(pTab);
         6393  +    pTab = 0;
         6394  +  }
         6395  +  return pTab;
         6396  +}
         6397  +
         6398  +/*
         6399  +** This function is called to search the schema recovered from the
         6400  +** sqlite_master table of the (possibly) corrupt database as part
         6401  +** of a ".recover" command. Specifically, for a table with root page
         6402  +** iRoot and at least nCol columns. Additionally, if bIntkey is 0, the
         6403  +** table must be a WITHOUT ROWID table, or if non-zero, not one of
         6404  +** those.
         6405  +**
         6406  +** If a table is found, a (RecoverTable*) object is returned. Or, if
         6407  +** no such table is found, but bIntkey is false and iRoot is the 
         6408  +** root page of an index in the recovered schema, then (*pbNoop) is
         6409  +** set to true and NULL returned. Or, if there is no such table or
         6410  +** index, NULL is returned and (*pbNoop) set to 0, indicating that
         6411  +** the caller should write data to the orphans table.
         6412  +*/
         6413  +static RecoverTable *recoverFindTable(
         6414  +  ShellState *pState,             /* Shell state object */
         6415  +  int *pRc,                       /* IN/OUT: Error code */
         6416  +  int iRoot,                      /* Root page of table */
         6417  +  int bIntkey,                    /* True for an intkey table */
         6418  +  int nCol,                       /* Number of columns in table */
         6419  +  int *pbNoop                     /* OUT: True if iRoot is root of index */
         6420  +){
         6421  +  sqlite3_stmt *pStmt = 0;
         6422  +  RecoverTable *pRet = 0;
         6423  +  int bNoop = 0;
         6424  +  const char *zSql = 0;
         6425  +  const char *zName = 0;
         6426  +
         6427  +  /* Search the recovered schema for an object with root page iRoot. */
         6428  +  shellPreparePrintf(pState->db, pRc, &pStmt,
         6429  +      "SELECT type, name, sql FROM recovery.schema WHERE rootpage=%d", iRoot
         6430  +  );
         6431  +  while( *pRc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
         6432  +    const char *zType = (const char*)sqlite3_column_text(pStmt, 0);
         6433  +    if( bIntkey==0 && sqlite3_stricmp(zType, "index")==0 ){
         6434  +      bNoop = 1;
         6435  +      break;
         6436  +    }
         6437  +    if( sqlite3_stricmp(zType, "table")==0 ){
         6438  +      zName = (const char*)sqlite3_column_text(pStmt, 1);
         6439  +      zSql = (const char*)sqlite3_column_text(pStmt, 2);
         6440  +      pRet = recoverNewTable(pRc, zName, zSql, bIntkey, nCol);
         6441  +      break;
         6442  +    }
         6443  +  }
         6444  +
         6445  +  shellFinalize(pRc, pStmt);
         6446  +  *pbNoop = bNoop;
         6447  +  return pRet;
         6448  +}
         6449  +
         6450  +/*
         6451  +** Return a RecoverTable object representing the orphans table.
         6452  +*/
         6453  +static RecoverTable *recoverOrphanTable(
         6454  +  ShellState *pState,             /* Shell state object */
         6455  +  int *pRc,                       /* IN/OUT: Error code */
         6456  +  const char *zLostAndFound,      /* Base name for orphans table */
         6457  +  int nCol                        /* Number of user data columns */
         6458  +){
         6459  +  RecoverTable *pTab = 0;
         6460  +  if( nCol>=0 && *pRc==SQLITE_OK ){
         6461  +    int i;
         6462  +
         6463  +    /* This block determines the name of the orphan table. The prefered
         6464  +    ** name is zLostAndFound. But if that clashes with another name
         6465  +    ** in the recovered schema, try zLostAndFound_0, zLostAndFound_1
         6466  +    ** and so on until a non-clashing name is found.  */
         6467  +    int iTab = 0;
         6468  +    char *zTab = shellMPrintf(pRc, "%s", zLostAndFound);
         6469  +    sqlite3_stmt *pTest = 0;
         6470  +    shellPrepare(pState->db, pRc,
         6471  +        "SELECT 1 FROM recovery.schema WHERE name=?", &pTest
         6472  +    );
         6473  +    if( pTest ) sqlite3_bind_text(pTest, 1, zTab, -1, SQLITE_TRANSIENT);
         6474  +    while( *pRc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pTest) ){
         6475  +      shellReset(pRc, pTest);
         6476  +      sqlite3_free(zTab);
         6477  +      zTab = shellMPrintf(pRc, "%s_%d", zLostAndFound, iTab++);
         6478  +      sqlite3_bind_text(pTest, 1, zTab, -1, SQLITE_TRANSIENT);
         6479  +    }
         6480  +    shellFinalize(pRc, pTest);
         6481  +
         6482  +    pTab = (RecoverTable*)shellMalloc(pRc, sizeof(RecoverTable));
         6483  +    if( pTab ){
         6484  +      pTab->zQuoted = shellMPrintf(pRc, "%Q", zTab);
         6485  +      pTab->nCol = nCol;
         6486  +      pTab->iPk = -2;
         6487  +      if( nCol>0 ){
         6488  +        pTab->azlCol = (char**)shellMalloc(pRc, sizeof(char*) * (nCol+1));
         6489  +        if( pTab->azlCol ){
         6490  +          pTab->azlCol[nCol] = shellMPrintf(pRc, "");
         6491  +          for(i=nCol-1; i>=0; i--){
         6492  +            pTab->azlCol[i] = shellMPrintf(pRc, "%s, NULL", pTab->azlCol[i+1]);
         6493  +          }
         6494  +        }
         6495  +      }
         6496  +
         6497  +      if( *pRc!=SQLITE_OK ){
         6498  +        recoverFreeTable(pTab);
         6499  +        pTab = 0;
         6500  +      }else{
         6501  +        raw_printf(pState->out, 
         6502  +            "CREATE TABLE %s(rootpgno INTEGER, "
         6503  +            "pgno INTEGER, nfield INTEGER, id INTEGER", pTab->zQuoted
         6504  +        );
         6505  +        for(i=0; i<nCol; i++){
         6506  +          raw_printf(pState->out, ", c%d", i);
         6507  +        }
         6508  +        raw_printf(pState->out, ");\n");
         6509  +      }
         6510  +    }
         6511  +    sqlite3_free(zTab);
         6512  +  }
         6513  +  return pTab;
         6514  +}
         6515  +
         6516  +/*
         6517  +** This function is called to recover data from the database. A script
         6518  +** to construct a new database containing all recovered data is output
         6519  +** on stream pState->out.
         6520  +*/
         6521  +static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
         6522  +  int rc = SQLITE_OK;
         6523  +  sqlite3_stmt *pLoop = 0;        /* Loop through all root pages */
         6524  +  sqlite3_stmt *pPages = 0;       /* Loop through all pages in a group */
         6525  +  sqlite3_stmt *pCells = 0;       /* Loop through all cells in a page */
         6526  +  const char *zRecoveryDb = "";   /* Name of "recovery" database */
         6527  +  const char *zLostAndFound = "lost_and_found";
         6528  +  int i;
         6529  +  int nOrphan = -1;
         6530  +  RecoverTable *pOrphan = 0;
         6531  +
         6532  +  int bFreelist = 1;              /* 0 if --freelist-corrupt is specified */
         6533  +  for(i=1; i<nArg; i++){
         6534  +    char *z = azArg[i];
         6535  +    int n;
         6536  +    if( z[0]=='-' && z[1]=='-' ) z++;
         6537  +    n = strlen(z);
         6538  +    if( n<=17 && memcmp("-freelist-corrupt", z, n)==0 ){
         6539  +      bFreelist = 0;
         6540  +    }else
         6541  +    if( n<=12 && memcmp("-recovery-db", z, n)==0 && i<(nArg-1) ){
         6542  +      i++;
         6543  +      zRecoveryDb = azArg[i];
         6544  +    }else
         6545  +    if( n<=15 && memcmp("-lost-and-found", z, n)==0 && i<(nArg-1) ){
         6546  +      i++;
         6547  +      zLostAndFound = azArg[i];
         6548  +    }
         6549  +    else{
         6550  +      raw_printf(stderr, "unexpected option: %s\n", azArg[i]); 
         6551  +      raw_printf(stderr, "options are:\n");
         6552  +      raw_printf(stderr, "    --freelist-corrupt\n");
         6553  +      raw_printf(stderr, "    --recovery-db DATABASE\n");
         6554  +      raw_printf(stderr, "    --lost-and-found TABLE-NAME\n");
         6555  +      return 1;
         6556  +    }
         6557  +  }
         6558  +
         6559  +  shellExecPrintf(pState->db, &rc,
         6560  +    /* Attach an in-memory database named 'recovery'. Create an indexed 
         6561  +    ** cache of the sqlite_dbptr virtual table. */
         6562  +    "ATTACH %Q AS recovery;"
         6563  +    "DROP TABLE IF EXISTS recovery.dbptr;"
         6564  +    "DROP TABLE IF EXISTS recovery.freelist;"
         6565  +    "DROP TABLE IF EXISTS recovery.map;"
         6566  +    "DROP TABLE IF EXISTS recovery.schema;"
         6567  +    "CREATE TABLE recovery.freelist(pgno INTEGER PRIMARY KEY);", zRecoveryDb
         6568  +  );
         6569  +
         6570  +  if( bFreelist ){
         6571  +    shellExec(pState->db, &rc,
         6572  +      "WITH trunk(pgno) AS ("
         6573  +      "  SELECT shell_int32("
         6574  +      "      (SELECT data FROM sqlite_dbpage WHERE pgno=1), 8) AS x "
         6575  +      "      WHERE x>0"
         6576  +      "    UNION"
         6577  +      "  SELECT shell_int32("
         6578  +      "      (SELECT data FROM sqlite_dbpage WHERE pgno=trunk.pgno), 0) AS x "
         6579  +      "      FROM trunk WHERE x>0"
         6580  +      "),"
         6581  +      "freelist(data, n, freepgno) AS ("
         6582  +      "  SELECT data, shell_int32(data, 1)-1, t.pgno "
         6583  +      "      FROM trunk t, sqlite_dbpage s WHERE s.pgno=t.pgno"
         6584  +      "    UNION ALL"
         6585  +      "  SELECT data, n-1, shell_int32(data, 2+n) "
         6586  +      "      FROM freelist WHERE n>=0"
         6587  +      ")"
         6588  +      "REPLACE INTO recovery.freelist SELECT freepgno FROM freelist;"
         6589  +    );
         6590  +  }
         6591  +
         6592  +  shellExec(pState->db, &rc, 
         6593  +    "CREATE TABLE recovery.dbptr("
         6594  +    "      pgno, child, PRIMARY KEY(child, pgno)"
         6595  +    ") WITHOUT ROWID;"
         6596  +    "INSERT OR IGNORE INTO recovery.dbptr(pgno, child) "
         6597  +    "    SELECT * FROM sqlite_dbptr"
         6598  +    "      WHERE pgno NOT IN freelist AND child NOT IN freelist;"
         6599  +
         6600  +    /* Delete any pointer to page 1. This ensures that page 1 is considered
         6601  +    ** a root page, regardless of how corrupt the db is. */
         6602  +    "DELETE FROM recovery.dbptr WHERE child = 1;"
         6603  +
         6604  +    /* Delete all pointers to any pages that have more than one pointer
         6605  +    ** to them. Such pages will be treated as root pages when recovering
         6606  +    ** data.  */
         6607  +    "DELETE FROM recovery.dbptr WHERE child IN ("
         6608  +    "  SELECT child FROM recovery.dbptr GROUP BY child HAVING count(*)>1"
         6609  +    ");"
         6610  +
         6611  +    /* Create the "map" table that will (eventually) contain instructions
         6612  +    ** for dealing with each page in the db that contains one or more 
         6613  +    ** records. */
         6614  +    "CREATE TABLE recovery.map("
         6615  +      "pgno INTEGER PRIMARY KEY, maxlen INT, intkey, root INT"
         6616  +    ");"
         6617  +
         6618  +    /* Populate table [map]. If there are circular loops of pages in the
         6619  +    ** database, the following adds all pages in such a loop to the map
         6620  +    ** as individual root pages. This could be handled better.  */
         6621  +    "WITH pages(i, maxlen) AS ("
         6622  +    "  SELECT page_count, ("
         6623  +    "    SELECT max(field+1) FROM sqlite_dbdata WHERE pgno=page_count"
         6624  +    "  ) FROM pragma_page_count"
         6625  +    "    UNION ALL"
         6626  +    "  SELECT i-1, ("
         6627  +    "    SELECT max(field+1) FROM sqlite_dbdata WHERE pgno=i-1"
         6628  +    "  ) FROM pages WHERE i>=2"
         6629  +    ")"
         6630  +    "INSERT INTO recovery.map(pgno, maxlen, intkey, root) "
         6631  +    "  SELECT i, maxlen, NULL, ("
         6632  +    "    WITH p(orig, pgno, parent) AS ("
         6633  +    "      SELECT 0, i, (SELECT pgno FROM recovery.dbptr WHERE child=i)"
         6634  +    "        UNION ALL"
         6635  +    "      SELECT i, p.parent, "
         6636  +    "        (SELECT pgno FROM recovery.dbptr WHERE child=p.parent) FROM p"
         6637  +    "    )"
         6638  +    "    SELECT pgno FROM p WHERE (parent IS NULL OR pgno = orig)"
         6639  +    ") "
         6640  +    "FROM pages WHERE maxlen > 0 AND i NOT IN freelist;"
         6641  +    "UPDATE recovery.map AS o SET intkey = ("
         6642  +    "  SELECT substr(data, 1, 1)==X'0D' FROM sqlite_dbpage WHERE pgno=o.pgno"
         6643  +    ");"
         6644  +
         6645  +    /* Extract data from page 1 and any linked pages into table
         6646  +    ** recovery.schema. With the same schema as an sqlite_master table.  */
         6647  +    "CREATE TABLE recovery.schema(type, name, tbl_name, rootpage, sql);"
         6648  +    "INSERT INTO recovery.schema SELECT "
         6649  +    "  max(CASE WHEN field=0 THEN value ELSE NULL END),"
         6650  +    "  max(CASE WHEN field=1 THEN value ELSE NULL END),"
         6651  +    "  max(CASE WHEN field=2 THEN value ELSE NULL END),"
         6652  +    "  max(CASE WHEN field=3 THEN value ELSE NULL END),"
         6653  +    "  max(CASE WHEN field=4 THEN value ELSE NULL END)"
         6654  +    "FROM sqlite_dbdata WHERE pgno IN ("
         6655  +    "  SELECT pgno FROM recovery.map WHERE root=1"
         6656  +    ")"
         6657  +    "GROUP BY pgno, cell;"
         6658  +    "CREATE INDEX recovery.schema_rootpage ON schema(rootpage);"
         6659  +  );
         6660  +
         6661  +  /* Open a transaction, then print out all non-virtual, non-"sqlite_%" 
         6662  +  ** CREATE TABLE statements that extracted from the existing schema.  */
         6663  +  if( rc==SQLITE_OK ){
         6664  +    sqlite3_stmt *pStmt = 0;
         6665  +    raw_printf(pState->out, "BEGIN;\n");
         6666  +    raw_printf(pState->out, "PRAGMA writable_schema = on;\n");
         6667  +    shellPrepare(pState->db, &rc,
         6668  +        "SELECT sql FROM recovery.schema "
         6669  +        "WHERE type='table' AND sql LIKE 'create table%'", &pStmt
         6670  +    );
         6671  +    while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
         6672  +      const char *zCreateTable = (const char*)sqlite3_column_text(pStmt, 0);
         6673  +      raw_printf(pState->out, "CREATE TABLE IF NOT EXISTS %s;\n", 
         6674  +          &zCreateTable[12]
         6675  +      );
         6676  +    }
         6677  +    shellFinalize(&rc, pStmt);
         6678  +  }
         6679  +
         6680  +  /* Figure out if an orphan table will be required. And if so, how many
         6681  +  ** user columns it should contain */
         6682  +  shellPrepare(pState->db, &rc, 
         6683  +      "SELECT coalesce(max(maxlen), -2) FROM recovery.map" 
         6684  +      "  WHERE root>1 AND root NOT IN (SELECT rootpage FROM recovery.schema)"
         6685  +      , &pLoop
         6686  +  );
         6687  +  if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pLoop) ){
         6688  +    nOrphan = sqlite3_column_int(pLoop, 0);
         6689  +  }
         6690  +  shellFinalize(&rc, pLoop);
         6691  +  pLoop = 0;
         6692  +  pOrphan = recoverOrphanTable(pState, &rc, zLostAndFound, nOrphan);
         6693  +
         6694  +  shellPrepare(pState->db, &rc,
         6695  +      "SELECT pgno FROM recovery.map WHERE root=?", &pPages
         6696  +  );
         6697  +  shellPrepare(pState->db, &rc,
         6698  +      "SELECT max(field), group_concat(shell_escape_crnl(quote(value)), ', ')"
         6699  +      "FROM sqlite_dbdata WHERE pgno = ? AND field != ?"
         6700  +      "GROUP BY cell", &pCells
         6701  +  );
         6702  +
         6703  +  /* Loop through each root page. */
         6704  +  shellPrepare(pState->db, &rc, 
         6705  +      "SELECT root, intkey, max(maxlen) FROM recovery.map" 
         6706  +      " WHERE root>1 GROUP BY root, intkey ORDER BY root=("
         6707  +      "  SELECT rootpage FROM recovery.schema WHERE name='sqlite_sequence'"
         6708  +      ")", &pLoop
         6709  +  );
         6710  +  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pLoop) ){
         6711  +    int iRoot = sqlite3_column_int(pLoop, 0);
         6712  +    int bIntkey = sqlite3_column_int(pLoop, 1);
         6713  +    int nCol = sqlite3_column_int(pLoop, 2);
         6714  +    int bNoop = 0;
         6715  +    RecoverTable *pTab;
         6716  +
         6717  +    pTab = recoverFindTable(pState, &rc, iRoot, bIntkey, nCol, &bNoop);
         6718  +    if( bNoop || rc ) continue;
         6719  +    if( pTab==0 ) pTab = pOrphan;
         6720  +
         6721  +    if( 0==sqlite3_stricmp(pTab->zQuoted, "'sqlite_sequence'") ){
         6722  +      raw_printf(pState->out, "DELETE FROM sqlite_sequence;\n");
         6723  +    }
         6724  +    sqlite3_bind_int(pPages, 1, iRoot);
         6725  +    sqlite3_bind_int(pCells, 2, pTab->iPk);
         6726  +
         6727  +    while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPages) ){
         6728  +      int iPgno = sqlite3_column_int(pPages, 0);
         6729  +      sqlite3_bind_int(pCells, 1, iPgno);
         6730  +      while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pCells) ){
         6731  +        int nField = sqlite3_column_int(pCells, 0);
         6732  +        const char *zVal = (const char*)sqlite3_column_text(pCells, 1);
         6733  +
         6734  +        nField = nField+1;
         6735  +        if( pTab==pOrphan ){
         6736  +          raw_printf(pState->out, 
         6737  +              "INSERT INTO %s VALUES(%d, %d, %d, %s%s%s);\n",
         6738  +              pTab->zQuoted, iRoot, iPgno, nField, 
         6739  +              bIntkey ? "" : "NULL, ", zVal, pTab->azlCol[nField]
         6740  +          );
         6741  +        }else{
         6742  +          raw_printf(pState->out, "INSERT INTO %s(%s) VALUES( %s );\n", 
         6743  +              pTab->zQuoted, pTab->azlCol[nField], zVal
         6744  +          );
         6745  +        }
         6746  +      }
         6747  +      shellReset(&rc, pCells);
         6748  +    }
         6749  +    shellReset(&rc, pPages);
         6750  +    if( pTab!=pOrphan ) recoverFreeTable(pTab);
         6751  +  }
         6752  +  shellFinalize(&rc, pLoop);
         6753  +  shellFinalize(&rc, pPages);
         6754  +  shellFinalize(&rc, pCells);
         6755  +  recoverFreeTable(pOrphan);
         6756  +
         6757  +  /* The rest of the schema */
         6758  +  if( rc==SQLITE_OK ){
         6759  +    sqlite3_stmt *pStmt = 0;
         6760  +    shellPrepare(pState->db, &rc, 
         6761  +        "SELECT sql, name FROM recovery.schema "
         6762  +        "WHERE sql NOT LIKE 'create table%'", &pStmt
         6763  +    );
         6764  +    while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
         6765  +      const char *zSql = (const char*)sqlite3_column_text(pStmt, 0);
         6766  +      if( sqlite3_strnicmp(zSql, "create virt", 11)==0 ){
         6767  +        const char *zName = (const char*)sqlite3_column_text(pStmt, 1);
         6768  +        char *zPrint = shellMPrintf(&rc, 
         6769  +          "INSERT INTO sqlite_master VALUES('table', %Q, %Q, 0, %Q)",
         6770  +          zName, zName, zSql
         6771  +        );
         6772  +        raw_printf(pState->out, "%s;\n", zPrint);
         6773  +        sqlite3_free(zPrint);
         6774  +      }else{
         6775  +        raw_printf(pState->out, "%s;\n", zSql);
         6776  +      }
         6777  +    }
         6778  +    shellFinalize(&rc, pStmt);
         6779  +  }
         6780  +
         6781  +  if( rc==SQLITE_OK ){
         6782  +    raw_printf(pState->out, "PRAGMA writable_schema = off;\n");
         6783  +    raw_printf(pState->out, "COMMIT;\n");
         6784  +  }
         6785  +  sqlite3_exec(pState->db, "DETACH recovery", 0, 0, 0);
         6786  +  return rc;
         6787  +}
         6788  +#endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */
         6789  +
  6029   6790   
  6030   6791   /*
  6031   6792   ** If an input line begins with "." then invoke this routine to
  6032   6793   ** process that line.
  6033   6794   **
  6034   6795   ** Return 1 on error, 2 to exit, and 0 otherwise.
  6035   6796   */
................................................................................
  6309   7070       }   
  6310   7071     }else
  6311   7072   
  6312   7073     if( c=='d' && n>=3 && strncmp(azArg[0], "dbinfo", n)==0 ){
  6313   7074       rc = shell_dbinfo_command(p, nArg, azArg);
  6314   7075     }else
  6315   7076   
         7077  +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
         7078  +  if( c=='r' && strncmp(azArg[0], "recover", n)==0 ){
         7079  +    open_db(p, 0);
         7080  +    rc = recoverDatabaseCmd(p, nArg, azArg);
         7081  +  }else
         7082  +#endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */
         7083  +
  6316   7084     if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
  6317   7085       const char *zLike = 0;
  6318   7086       int i;
  6319   7087       int savedShowHeader = p->showHeader;
  6320   7088       int savedShellFlags = p->shellFlgs;
  6321   7089       ShellClearFlag(p, SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo);
  6322   7090       for(i=1; i<nArg; i++){
................................................................................
  6346   7114                              "?--newlines? ?LIKE-PATTERN?\n");
  6347   7115           rc = 1;
  6348   7116           goto meta_command_exit;
  6349   7117         }else{
  6350   7118           zLike = azArg[i];
  6351   7119         }
  6352   7120       }
         7121  +
  6353   7122       open_db(p, 0);
         7123  +
  6354   7124       /* When playing back a "dump", the content might appear in an order
  6355   7125       ** which causes immediate foreign key constraints to be violated.
  6356   7126       ** So disable foreign-key constraint enforcement to prevent problems. */
  6357   7127       raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n");
  6358   7128       raw_printf(p->out, "BEGIN TRANSACTION;\n");
  6359   7129       p->writableSchema = 0;
  6360   7130       p->showHeader = 0;
................................................................................
  6394   7164       }
  6395   7165       if( p->writableSchema ){
  6396   7166         raw_printf(p->out, "PRAGMA writable_schema=OFF;\n");
  6397   7167         p->writableSchema = 0;
  6398   7168       }
  6399   7169       sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
  6400   7170       sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
  6401         -    raw_printf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");
         7171  +    raw_printf(p->out, p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n");
  6402   7172       p->showHeader = savedShowHeader;
  6403   7173       p->shellFlgs = savedShellFlags;
  6404   7174     }else
  6405   7175   
  6406   7176     if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){
  6407   7177       if( nArg==2 ){
  6408   7178         setOrClearFlag(p, SHFLG_Echo, azArg[1]);

Added test/dbdata.test.

            1  +# 2019-04-11
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# This file implements regression tests for SQLite library.  The
           12  +# focus of this file is testing the sqlite_dbpage virtual table.
           13  +#
           14  +
           15  +set testdir [file dirname $argv0]
           16  +source $testdir/tester.tcl
           17  +set testprefix dbdata
           18  +
           19  +ifcapable !vtab||!compound {
           20  +  finish_test
           21  +  return
           22  +}
           23  +db enable_load_extension 1
           24  +if { [catch { db eval { SELECT load_extension('../dbdata') } }] } {
           25  +  finish_test
           26  +  return
           27  +}
           28  +
           29  +do_execsql_test 1.0 {
           30  +  CREATE TABLE T1(a, b);
           31  +  INSERT INTO t1(rowid, a ,b) VALUES(5, 'v', 'five');
           32  +  INSERT INTO t1(rowid, a, b) VALUES(10, 'x', 'ten');
           33  +}
           34  +
           35  +do_execsql_test 1.1 {
           36  +  SELECT pgno, cell, field, quote(value) FROM sqlite_dbdata WHERE pgno=2;
           37  +} {
           38  +  2 0 -1 5 
           39  +  2 0  0 'v' 
           40  +  2 0  1 'five' 
           41  +  2 1 -1 10 
           42  +  2 1  0 'x' 
           43  +  2 1  1 'ten'
           44  +}
           45  +
           46  +breakpoint
           47  +do_execsql_test 1.2 {
           48  +  SELECT pgno, cell, field, quote(value) FROM sqlite_dbdata;
           49  +} {
           50  +  1 0 -1 1 
           51  +  1 0 0 'table' 
           52  +  1 0 1 'T1' 
           53  +  1 0 2 'T1' 
           54  +  1 0 3 2 
           55  +  1 0 4 {'CREATE TABLE T1(a, b)'}
           56  +  2 0 -1 5 
           57  +  2 0  0 'v' 
           58  +  2 0  1 'five' 
           59  +  2 1 -1 10 
           60  +  2 1  0 'x' 
           61  +  2 1  1 'ten'
           62  +}
           63  +
           64  +set big [string repeat big 2000]
           65  +do_execsql_test 1.3 {
           66  +  INSERT INTO t1 VALUES(NULL, $big);
           67  +  SELECT value FROM sqlite_dbdata WHERE pgno=2 AND cell=2 AND field=1;
           68  +} $big
           69  +
           70  +do_execsql_test 1.4 {
           71  +  DELETE FROM t1;
           72  +  INSERT INTO t1 VALUES(NULL, randomblob(5050));
           73  +}
           74  +do_test 1.5 {
           75  +  execsql {
           76  +    SELECT quote(value) FROM sqlite_dbdata WHERE pgno=2 AND cell=0 AND field=1;
           77  +  }
           78  +} [db one {SELECT quote(b) FROM t1}]
           79  +
           80  +#-------------------------------------------------------------------------
           81  +reset_db
           82  +db enable_load_extension 1
           83  +db eval { SELECT load_extension('../dbdata') }
           84  +
           85  +do_execsql_test 2.0 {
           86  +  CREATE TABLE t1(a);
           87  +  CREATE INDEX i1 ON t1(a);
           88  +  WITH s(i) AS (
           89  +    SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<10
           90  +  )
           91  +  INSERT INTO t1 SELECT randomblob(900) FROM s;
           92  +}
           93  +
           94  +do_execsql_test 2.1 {
           95  +  SELECT * FROM sqlite_dbptr WHERE pgno=2;
           96  +} {
           97  +  2 25   2 6   2 7   2 9   2 11   2 13   2 15   2 17   2 19   2 21
           98  +}
           99  +
          100  +do_execsql_test 2.2 {
          101  +  SELECT * FROM sqlite_dbptr WHERE pgno=3;
          102  +} {
          103  +  3 24   3 23
          104  +}
          105  +
          106  +do_execsql_test 2.3 {
          107  +  SELECT * FROM sqlite_dbptr
          108  +} {
          109  +  2 25   2 6   2 7   2 9   2 11   2 13   2 15   2 17   2 19   2 21
          110  +  3 24   3 23
          111  +}
          112  +
          113  +
          114  +finish_test

Added test/recover.test.

            1  +# 2019 April 23
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +#
           12  +# Test the shell tool ".ar" command.
           13  +#
           14  +
           15  +set testdir [file dirname $argv0]
           16  +source $testdir/tester.tcl
           17  +set testprefix recover
           18  +
           19  +ifcapable !vtab {
           20  +  finish_test; return
           21  +}
           22  +set CLI [test_find_cli]
           23  +
           24  +proc compare_result {db1 db2 sql} {
           25  +  set r1 [$db1 eval $sql]
           26  +  set r2 [$db2 eval $sql]
           27  +  if {$r1 != $r2} {
           28  +  puts "r1: $r1"
           29  +  puts "r2: $r2"
           30  +    error "mismatch for $sql"
           31  +  }
           32  +  return ""
           33  +}
           34  +
           35  +proc compare_dbs {db1 db2} {
           36  +  compare_result $db1 $db2 "SELECT sql FROM sqlite_master ORDER BY 1"
           37  +  foreach tbl [$db1 eval {SELECT name FROM sqlite_master WHERE type='table'}] {
           38  +    compare_result $db1 $db2 "SELECT * FROM $tbl"
           39  +  }
           40  +}
           41  +
           42  +proc do_recover_test {tn {tsql {}} {res {}}} {
           43  +  set fd [open "|$::CLI test.db .recover"]
           44  +  fconfigure $fd -encoding binary
           45  +  fconfigure $fd -translation binary
           46  +  set sql [read $fd]
           47  +  close $fd
           48  +
           49  +  forcedelete test.db2
           50  +  sqlite3 db2 test.db2
           51  +  execsql $sql db2
           52  +  if {$tsql==""} {
           53  +    uplevel [list do_test $tn [list compare_dbs db db2] {}]
           54  +  } else {
           55  +    uplevel [list do_execsql_test -db db2 $tn $tsql $res]
           56  +  }
           57  +  db2 close
           58  +}
           59  +
           60  +set doc {
           61  +  hello
           62  +  world
           63  +}
           64  +do_execsql_test 1.1.1 {
           65  +  CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
           66  +  INSERT INTO t1 VALUES(1, 4, X'1234567800');
           67  +  INSERT INTO t1 VALUES(2, 'test', 8.1);
           68  +  INSERT INTO t1 VALUES(3, $doc, 8.4);
           69  +}
           70  +do_recover_test 1.1.2
           71  +
           72  +do_execsql_test 1.2.1 "
           73  +  DELETE FROM t1;
           74  +  INSERT INTO t1 VALUES(13, 'hello\r\nworld', 13);
           75  +"
           76  +do_recover_test 1.2.2
           77  +
           78  +do_execsql_test 1.3.1 "
           79  +  CREATE TABLE t2(i INTEGER PRIMARY KEY AUTOINCREMENT, b, c);
           80  +  INSERT INTO t2 VALUES(NULL, 1, 2);
           81  +  INSERT INTO t2 VALUES(NULL, 3, 4);
           82  +  INSERT INTO t2 VALUES(NULL, 5, 6);
           83  +  CREATE TABLE t3(i INTEGER PRIMARY KEY AUTOINCREMENT, b, c);
           84  +  INSERT INTO t3 VALUES(NULL, 1, 2);
           85  +  INSERT INTO t3 VALUES(NULL, 3, 4);
           86  +  INSERT INTO t3 VALUES(NULL, 5, 6);
           87  +  DELETE FROM t2;
           88  +"
           89  +do_recover_test 1.3.2
           90  +
           91  +#-------------------------------------------------------------------------
           92  +reset_db
           93  +do_execsql_test 2.1.0 {
           94  +  CREATE TABLE t1(a, b, c, PRIMARY KEY(b, c)) WITHOUT ROWID;
           95  +  INSERT INTO t1 VALUES(1, 2, 3);
           96  +  INSERT INTO t1 VALUES(4, 5, 6);
           97  +  INSERT INTO t1 VALUES(7, 8, 9);
           98  +}
           99  +
          100  +do_recover_test 2.1.1
          101  +
          102  +do_execsql_test 2.2.0 {
          103  +  PRAGMA writable_schema = 1;
          104  +  DELETE FROM sqlite_master WHERE name='t1';
          105  +}
          106  +do_recover_test 2.2.1 {
          107  +  SELECT name FROM sqlite_master
          108  +} {lost_and_found}
          109  +
          110  +do_execsql_test 2.3.0 {
          111  +  CREATE TABLE lost_and_found(a, b, c);
          112  +}
          113  +do_recover_test 2.3.1 {
          114  +  SELECT name FROM sqlite_master
          115  +} {lost_and_found lost_and_found_0}
          116  +
          117  +do_execsql_test 2.4.0 {
          118  +  CREATE TABLE lost_and_found_0(a, b, c);
          119  +}
          120  +do_recover_test 2.4.1 {
          121  +  SELECT name FROM sqlite_master;
          122  +  SELECT * FROM lost_and_found_1;
          123  +} {lost_and_found lost_and_found_0 lost_and_found_1
          124  +  2 2 3 {} 2 3 1
          125  +  2 2 3 {} 5 6 4
          126  +  2 2 3 {} 8 9 7
          127  +}
          128  +
          129  +finish_test

Changes to tool/mkshellc.tcl.

    36     36       if {[info exists typedef_seen($line)]} {
    37     37         return "/* $line */"
    38     38       }
    39     39       set typedef_seen($line) 1
    40     40     }
    41     41     return $line
    42     42   }
           43  +set iLine 0
    43     44   while {1} {
    44     45     set lx [omit_redundant_typedefs [gets $in]]
    45     46     if {[eof $in]} break;
           47  +  incr iLine
    46     48     if {[regexp {^INCLUDE } $lx]} {
    47     49       set cfile [lindex $lx 1]
    48     50       puts $out "/************************* Begin $cfile ******************/"
           51  +#   puts $out "#line 1 \"$cfile\""
    49     52       set in2 [open $topdir/src/$cfile rb]
    50     53       while {![eof $in2]} {
    51     54         set lx [omit_redundant_typedefs [gets $in2]]
    52         -      if {[regexp {^#include "sqlite} $lx]} continue
           55  +      if {[regexp {^#include "sqlite} $lx]} {
           56  +        set lx "/* $lx */"
           57  +      }
    53     58         if {[regexp {^# *include "test_windirent.h"} $lx]} {
    54     59           set lx "/* $lx */"
    55     60         }
    56     61         set lx [string map [list __declspec(dllexport) {}] $lx]
    57     62         puts $out $lx
    58     63       }
    59     64       close $in2
    60     65       puts $out "/************************* End $cfile ********************/"
           66  +#   puts $out "#line [expr $iLine+1] \"shell.c.in\""
    61     67       continue
    62     68     }
    63     69     puts $out $lx
    64     70   }
    65     71   close $in
    66     72   close $out