modernc.org/cc@v1.0.1/v2/testdata/_sqlite/src/dbpage.c (about)

     1  /*
     2  ** 2017-10-11
     3  **
     4  ** The author disclaims copyright to this source code.  In place of
     5  ** a legal notice, here is a blessing:
     6  **
     7  **    May you do good and not evil.
     8  **    May you find forgiveness for yourself and forgive others.
     9  **    May you share freely, never taking more than you give.
    10  **
    11  ******************************************************************************
    12  **
    13  ** This file contains an implementation of the "sqlite_dbpage" virtual table.
    14  **
    15  ** The sqlite_dbpage virtual table is used to read or write whole raw
    16  ** pages of the database file.  The pager interface is used so that 
    17  ** uncommitted changes and changes recorded in the WAL file are correctly
    18  ** retrieved.
    19  **
    20  ** Usage example:
    21  **
    22  **    SELECT data FROM sqlite_dbpage('aux1') WHERE pgno=123;
    23  **
    24  ** This is an eponymous virtual table so it does not need to be created before
    25  ** use.  The optional argument to the sqlite_dbpage() table name is the
    26  ** schema for the database file that is to be read.  The default schema is
    27  ** "main".
    28  **
    29  ** The data field of sqlite_dbpage table can be updated.  The new
    30  ** value must be a BLOB which is the correct page size, otherwise the
    31  ** update fails.  Rows may not be deleted or inserted.
    32  */
    33  
    34  #include "sqliteInt.h"   /* Requires access to internal data structures */
    35  #if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
    36      && !defined(SQLITE_OMIT_VIRTUALTABLE)
    37  
    38  typedef struct DbpageTable DbpageTable;
    39  typedef struct DbpageCursor DbpageCursor;
    40  
    41  struct DbpageCursor {
    42    sqlite3_vtab_cursor base;       /* Base class.  Must be first */
    43    int pgno;                       /* Current page number */
    44    int mxPgno;                     /* Last page to visit on this scan */
    45  };
    46  
    47  struct DbpageTable {
    48    sqlite3_vtab base;              /* Base class.  Must be first */
    49    sqlite3 *db;                    /* The database */
    50    Pager *pPager;                  /* Pager being read/written */
    51    int iDb;                        /* Index of database to analyze */
    52    int szPage;                     /* Size of each page in bytes */
    53    int nPage;                      /* Number of pages in the file */
    54  };
    55  
    56  /*
    57  ** Connect to or create a dbpagevfs virtual table.
    58  */
    59  static int dbpageConnect(
    60    sqlite3 *db,
    61    void *pAux,
    62    int argc, const char *const*argv,
    63    sqlite3_vtab **ppVtab,
    64    char **pzErr
    65  ){
    66    DbpageTable *pTab = 0;
    67    int rc = SQLITE_OK;
    68    int iDb;
    69  
    70    if( argc>=4 ){
    71      Token nm;
    72      sqlite3TokenInit(&nm, (char*)argv[3]);
    73      iDb = sqlite3FindDb(db, &nm);
    74      if( iDb<0 ){
    75        *pzErr = sqlite3_mprintf("no such schema: %s", argv[3]);
    76        return SQLITE_ERROR;
    77      }
    78    }else{
    79      iDb = 0;
    80    }
    81    rc = sqlite3_declare_vtab(db, 
    82            "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
    83    if( rc==SQLITE_OK ){
    84      pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable));
    85      if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
    86    }
    87  
    88    assert( rc==SQLITE_OK || pTab==0 );
    89    if( rc==SQLITE_OK ){
    90      Btree *pBt = db->aDb[iDb].pBt;
    91      memset(pTab, 0, sizeof(DbpageTable));
    92      pTab->db = db;
    93      pTab->iDb = iDb;
    94      pTab->pPager = pBt ? sqlite3BtreePager(pBt) : 0;
    95    }
    96  
    97    *ppVtab = (sqlite3_vtab*)pTab;
    98    return rc;
    99  }
   100  
   101  /*
   102  ** Disconnect from or destroy a dbpagevfs virtual table.
   103  */
   104  static int dbpageDisconnect(sqlite3_vtab *pVtab){
   105    sqlite3_free(pVtab);
   106    return SQLITE_OK;
   107  }
   108  
   109  /*
   110  ** idxNum:
   111  **
   112  **     0     full table scan
   113  **     1     pgno=?1
   114  */
   115  static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
   116    int i;
   117    pIdxInfo->estimatedCost = 1.0e6;  /* Initial cost estimate */
   118    for(i=0; i<pIdxInfo->nConstraint; i++){
   119      struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
   120      if( p->usable && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
   121        pIdxInfo->estimatedRows = 1;
   122        pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
   123        pIdxInfo->estimatedCost = 1.0;
   124        pIdxInfo->idxNum = 1;
   125        pIdxInfo->aConstraintUsage[i].argvIndex = 1;
   126        pIdxInfo->aConstraintUsage[i].omit = 1;
   127        break;
   128      }
   129    }
   130    if( pIdxInfo->nOrderBy>=1
   131     && pIdxInfo->aOrderBy[0].iColumn<=0
   132     && pIdxInfo->aOrderBy[0].desc==0
   133    ){
   134      pIdxInfo->orderByConsumed = 1;
   135    }
   136    return SQLITE_OK;
   137  }
   138  
   139  /*
   140  ** Open a new dbpagevfs cursor.
   141  */
   142  static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
   143    DbpageCursor *pCsr;
   144  
   145    pCsr = (DbpageCursor *)sqlite3_malloc64(sizeof(DbpageCursor));
   146    if( pCsr==0 ){
   147      return SQLITE_NOMEM_BKPT;
   148    }else{
   149      memset(pCsr, 0, sizeof(DbpageCursor));
   150      pCsr->base.pVtab = pVTab;
   151      pCsr->pgno = -1;
   152    }
   153  
   154    *ppCursor = (sqlite3_vtab_cursor *)pCsr;
   155    return SQLITE_OK;
   156  }
   157  
   158  /*
   159  ** Close a dbpagevfs cursor.
   160  */
   161  static int dbpageClose(sqlite3_vtab_cursor *pCursor){
   162    DbpageCursor *pCsr = (DbpageCursor *)pCursor;
   163    sqlite3_free(pCsr);
   164    return SQLITE_OK;
   165  }
   166  
   167  /*
   168  ** Move a dbpagevfs cursor to the next entry in the file.
   169  */
   170  static int dbpageNext(sqlite3_vtab_cursor *pCursor){
   171    int rc = SQLITE_OK;
   172    DbpageCursor *pCsr = (DbpageCursor *)pCursor;
   173    pCsr->pgno++;
   174    return rc;
   175  }
   176  
   177  static int dbpageEof(sqlite3_vtab_cursor *pCursor){
   178    DbpageCursor *pCsr = (DbpageCursor *)pCursor;
   179    return pCsr->pgno > pCsr->mxPgno;
   180  }
   181  
   182  static int dbpageFilter(
   183    sqlite3_vtab_cursor *pCursor, 
   184    int idxNum, const char *idxStr,
   185    int argc, sqlite3_value **argv
   186  ){
   187    DbpageCursor *pCsr = (DbpageCursor *)pCursor;
   188    DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
   189    int rc = SQLITE_OK;
   190    Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
   191  
   192    pTab->szPage = sqlite3BtreeGetPageSize(pBt);
   193    pTab->nPage = sqlite3BtreeLastPage(pBt);
   194    if( idxNum==1 ){
   195      pCsr->pgno = sqlite3_value_int(argv[0]);
   196      if( pCsr->pgno<1 || pCsr->pgno>pTab->nPage ){
   197        pCsr->pgno = 1;
   198        pCsr->mxPgno = 0;
   199      }else{
   200        pCsr->mxPgno = pCsr->pgno;
   201      }
   202    }else{
   203      pCsr->pgno = 1;
   204      pCsr->mxPgno = pTab->nPage;
   205    }
   206    return rc;
   207  }
   208  
   209  static int dbpageColumn(
   210    sqlite3_vtab_cursor *pCursor, 
   211    sqlite3_context *ctx, 
   212    int i
   213  ){
   214    DbpageCursor *pCsr = (DbpageCursor *)pCursor;
   215    DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
   216    int rc = SQLITE_OK;
   217    switch( i ){
   218      case 0: {           /* pgno */
   219        sqlite3_result_int(ctx, pCsr->pgno);
   220        break;
   221      }
   222      case 1: {           /* data */
   223        DbPage *pDbPage = 0;
   224        rc = sqlite3PagerGet(pTab->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
   225        if( rc==SQLITE_OK ){
   226          sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pTab->szPage,
   227                              SQLITE_TRANSIENT);
   228        }
   229        sqlite3PagerUnref(pDbPage);
   230        break;
   231      }
   232      default: {          /* schema */
   233        sqlite3 *db = sqlite3_context_db_handle(ctx);
   234        sqlite3_result_text(ctx, db->aDb[pTab->iDb].zDbSName, -1, SQLITE_STATIC);
   235        break;
   236      }
   237    }
   238    return SQLITE_OK;
   239  }
   240  
   241  static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
   242    DbpageCursor *pCsr = (DbpageCursor *)pCursor;
   243    *pRowid = pCsr->pgno;
   244    return SQLITE_OK;
   245  }
   246  
   247  static int dbpageUpdate(
   248    sqlite3_vtab *pVtab,
   249    int argc,
   250    sqlite3_value **argv,
   251    sqlite_int64 *pRowid
   252  ){
   253    DbpageTable *pTab = (DbpageTable *)pVtab;
   254    int pgno;
   255    DbPage *pDbPage = 0;
   256    int rc = SQLITE_OK;
   257    char *zErr = 0;
   258  
   259    if( argc==1 ){
   260      zErr = "cannot delete";
   261      goto update_fail;
   262    }
   263    pgno = sqlite3_value_int(argv[0]);
   264    if( pgno<1 || pgno>pTab->nPage ){
   265      zErr = "bad page number";
   266      goto update_fail;
   267    }
   268    if( sqlite3_value_int(argv[1])!=pgno ){
   269      zErr = "cannot insert";
   270      goto update_fail;
   271    }
   272    if( sqlite3_value_type(argv[3])!=SQLITE_BLOB 
   273     || sqlite3_value_bytes(argv[3])!=pTab->szPage 
   274    ){
   275      zErr = "bad page value";
   276      goto update_fail;
   277    }
   278    rc = sqlite3PagerGet(pTab->pPager, pgno, (DbPage**)&pDbPage, 0);
   279    if( rc==SQLITE_OK ){
   280      rc = sqlite3PagerWrite(pDbPage);
   281      if( rc==SQLITE_OK ){
   282        memcpy(sqlite3PagerGetData(pDbPage),
   283               sqlite3_value_blob(argv[3]),
   284               pTab->szPage);
   285      }
   286    }
   287    sqlite3PagerUnref(pDbPage);
   288    return rc;
   289  
   290  update_fail:
   291    sqlite3_free(pVtab->zErrMsg);
   292    pVtab->zErrMsg = sqlite3_mprintf("%s", zErr);
   293    return SQLITE_ERROR;
   294  }
   295  
   296  /*
   297  ** Invoke this routine to register the "dbpage" virtual table module
   298  */
   299  int sqlite3DbpageRegister(sqlite3 *db){
   300    static sqlite3_module dbpage_module = {
   301      0,                            /* iVersion */
   302      dbpageConnect,                /* xCreate */
   303      dbpageConnect,                /* xConnect */
   304      dbpageBestIndex,              /* xBestIndex */
   305      dbpageDisconnect,             /* xDisconnect */
   306      dbpageDisconnect,             /* xDestroy */
   307      dbpageOpen,                   /* xOpen - open a cursor */
   308      dbpageClose,                  /* xClose - close a cursor */
   309      dbpageFilter,                 /* xFilter - configure scan constraints */
   310      dbpageNext,                   /* xNext - advance a cursor */
   311      dbpageEof,                    /* xEof - check for end of scan */
   312      dbpageColumn,                 /* xColumn - read data */
   313      dbpageRowid,                  /* xRowid - read data */
   314      dbpageUpdate,                 /* xUpdate */
   315      0,                            /* xBegin */
   316      0,                            /* xSync */
   317      0,                            /* xCommit */
   318      0,                            /* xRollback */
   319      0,                            /* xFindMethod */
   320      0,                            /* xRename */
   321      0,                            /* xSavepoint */
   322      0,                            /* xRelease */
   323      0,                            /* xRollbackTo */
   324    };
   325    return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
   326  }
   327  #elif defined(SQLITE_ENABLE_DBPAGE_VTAB)
   328  int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; }
   329  #endif /* SQLITE_ENABLE_DBSTAT_VTAB */