/ Check-in [0b7bd169]
Login

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

Overview
Comment:Add start of "zonefile" virtual table.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | zonefile
Files: files | file ages | folders
SHA3-256: 0b7bd1694bf50a5afed22ed3026cefe53c5e7ec334167244e2caa9c56185ff43
User & Date: dan 2018-02-10 21:04:12
Context
2018-02-12
20:04
Add support for reading simple (no compression, no encryption) zonefile files. check-in: dba42f0e user: dan tags: zonefile
2018-02-10
21:04
Add start of "zonefile" virtual table. check-in: 0b7bd169 user: dan tags: zonefile
17:41
Add the start of the "zonefile" extension. check-in: c125b4c3 user: dan tags: zonefile
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/zonefile/zonefile.c.

    39     39   
    40     40   #define ZONEFILE_SZ_HEADER 26
    41     41   
    42     42   #define ZONEFILE_DEFAULT_MAXAUTOFRAMESIZE (64*1024)
    43     43   #define ZONEFILE_DEFAULT_ENCRYPTION       0
    44     44   #define ZONEFILE_DEFAULT_COMPRESSION      0
    45     45   
           46  +
           47  +#define ZONEFILE_SCHEMA          \
           48  +  "CREATE TABLE z1("             \
           49  +  "  k INTEGER PRIMARY KEY,"     \
           50  +  "  v BLOB,"                    \
           51  +  "  fileid INTEGER,"            \
           52  +  "  frame INTEGER,"             \
           53  +  "  ofst INTEGER,"              \
           54  +  "  sz INTEGER"                 \
           55  +  ")"
           56  +
           57  +#define ZONEFILE_FILES_SCHEMA    \
           58  +  "CREATE TABLE z2("             \
           59  +  "  filename TEXT,"             \
           60  +  "  priority INTEGER,"          \
           61  +  "  ekey BLOB,"                 \
           62  +  "  header JSON HIDDEN"         \
           63  +  ")"
           64  +
    46     65   
    47     66   #include <stdio.h>
    48     67   #include <string.h>
    49     68   #include <assert.h>
    50     69   
    51     70   typedef struct ZonefileWrite ZonefileWrite;
    52     71   struct ZonefileWrite {
    53     72     int compressionTypeIndexData;
    54     73     int compressionTypeContent;
    55     74     int encryptionType;
    56     75     int maxAutoFrameSize;
    57     76   };
           77  +
           78  +typedef struct ZonefileHeader ZonefileHeader;
           79  +struct ZonefileHeader {
           80  +  u32 magicNumber;
           81  +  u8 compressionTypeIndexData;
           82  +  u8 compressionTypeContent;
           83  +  u32 byteOffsetDictionary;
           84  +  u32 byteOffsetFrames;
           85  +  u32 numFrames;
           86  +  u32 numKeys;
           87  +  u8 encryptionType;
           88  +  u8 encryptionKeyIdx;
           89  +  u8 extendedHeaderVersion;
           90  +  u8 extendedHeaderSize;
           91  +};
    58     92   
    59     93   typedef struct ZonefileBuffer ZonefileBuffer;
    60     94   struct ZonefileBuffer {
    61     95     u8 *a;
    62     96     int n;
    63     97     int nAlloc;
    64     98   };
................................................................................
    79    113   
    80    114   static void zonefileTransferError(sqlite3_context *pCtx){
    81    115     sqlite3 *db = sqlite3_context_db_handle(pCtx);
    82    116     const char *zErr = sqlite3_errmsg(db);
    83    117     sqlite3_result_error(pCtx, zErr, -1);
    84    118   }
    85    119   
    86         -static sqlite3_stmt *zonefilePrepare(
          120  +static int zonefilePrepare(
          121  +  sqlite3 *db,
          122  +  sqlite3_stmt **ppStmt,
          123  +  char **pzErr,
          124  +  const char *zFmt,
          125  +  ...
          126  +){
          127  +  int rc;
          128  +  va_list ap;
          129  +  char *zSql;
          130  +  va_start(ap, zFmt);
          131  +  zSql = sqlite3_vmprintf(zFmt, ap);
          132  +  *ppStmt = 0;
          133  +  if( zSql ){
          134  +    rc = sqlite3_prepare(db, zSql, -1, ppStmt, 0);
          135  +    if( rc!=SQLITE_OK ){
          136  +      *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
          137  +    }
          138  +    sqlite3_free(zSql);
          139  +  }else{
          140  +    rc = SQLITE_NOMEM;
          141  +  }
          142  +  return rc;
          143  +}
          144  +
          145  +
          146  +static sqlite3_stmt *zonefileCtxPrepare(
    87    147     sqlite3_context *pCtx,
    88    148     const char *zFmt,
    89    149     ...
    90    150   ){
    91    151     sqlite3_stmt *pRet = 0;
    92    152     va_list ap;
    93    153     char *zSql;
................................................................................
    95    155     zSql = sqlite3_vmprintf(zFmt, ap);
    96    156     if( zSql ){
    97    157       sqlite3 *db = sqlite3_context_db_handle(pCtx);
    98    158       int rc = sqlite3_prepare(db, zSql, -1, &pRet, 0);
    99    159       if( rc!=SQLITE_OK ){
   100    160         zonefileTransferError(pCtx);
   101    161       }
          162  +    sqlite3_free(zSql);
   102    163     }else{
   103    164       sqlite3_result_error_nomem(pCtx);
   104    165     }
   105    166     return pRet;
   106    167   }
   107    168   
   108    169   /*
................................................................................
   114    175     int eType;
   115    176     assert( p1 );
   116    177     if( p2==0 ) return 1;
   117    178     eType = sqlite3_value_type(p1);
   118    179     if( sqlite3_value_type(p2)!=eType ) return 1;
   119    180     switch( eType ){
   120    181       case SQLITE_INTEGER:
   121         -      return sqlite3_value_int64(p1)==sqlite3_value_int64(p2);
          182  +      return sqlite3_value_int64(p1)!=sqlite3_value_int64(p2);
   122    183       case SQLITE_FLOAT:
   123         -      return sqlite3_value_double(p1)==sqlite3_value_double(p2);
          184  +      return sqlite3_value_double(p1)!=sqlite3_value_double(p2);
   124    185       case SQLITE_TEXT:
   125    186       case SQLITE_BLOB: {
   126    187         int n1 = sqlite3_value_bytes(p1);
   127    188         int n2 = sqlite3_value_bytes(p2);
   128    189         if( n1!=n2 ) return 1;
   129    190         return memcmp(sqlite3_value_blob(p1), sqlite3_value_blob(p2), n1);
   130    191       }
................................................................................
   187    248   
   188    249   static void zonefilePut32(u8 *aBuf, u32 v){
   189    250     aBuf[0] = (v >> 24) & 0xFF;
   190    251     aBuf[1] = (v >> 16) & 0xFF;
   191    252     aBuf[2] = (v >>  8) & 0xFF;
   192    253     aBuf[3] = v & 0xFF;
   193    254   }
          255  +
          256  +static u32 zonefileGet32(u8 *aBuf){
          257  +  return (((u32)aBuf[0]) << 24)
          258  +       + (((u32)aBuf[1]) << 16)
          259  +       + (((u32)aBuf[2]) <<  8)
          260  +       + (((u32)aBuf[3]) <<  0);
          261  +}
   194    262   
   195    263   static void zonefileAppend32(ZonefileBuffer *pBuf, u32 v){
   196    264     zonefilePut32(&pBuf->a[pBuf->n], v);
   197    265     pBuf->n += 4;
   198    266   }
   199    267   
   200    268   static void zonefileAppend64(ZonefileBuffer *pBuf, u64 v){
................................................................................
   207    275     pBuf->n += n;
   208    276   }
   209    277   
   210    278   static int zonefileWrite(FILE *pFd, const u8 *aBuf, int nBuf){
   211    279     size_t res = fwrite(aBuf, 1, nBuf, pFd);
   212    280     return res!=nBuf ? SQLITE_ERROR : SQLITE_OK;
   213    281   }
          282  +
          283  +static int zonefileRead(FILE *pFd, u8 *aBuf, int nBuf, i64 iOff){
          284  +  int rc = fseek(pFd, iOff, SEEK_SET);
          285  +  if( rc==0 ){
          286  +    rc = fread(aBuf, 1, nBuf, pFd);
          287  +    rc = (rc==nBuf) ? SQLITE_OK : SQLITE_ERROR;
          288  +  }
          289  +  return rc;
          290  +}
   214    291   
   215    292   /*
   216    293   ** Function:     zonefile_write(F,T[,J])
   217    294   */
   218    295   static void zonefileWriteFunc(
   219    296     sqlite3_context *pCtx,       /* Context object */
   220    297     int objc,                       /* Number of SQL arguments */
................................................................................
   243    320     if( objc==3 ){
   244    321       zJson = (const char*)sqlite3_value_text(objv[2]);
   245    322     }
   246    323     if( zonefileGetParams(pCtx, zJson, &sWrite) ) return;
   247    324   
   248    325     /* Prepare the SQL statement used to read data from the source table. This
   249    326     ** also serves to verify the suitability of the source table schema. */
   250         -  pStmt = zonefilePrepare(pCtx, 
          327  +  pStmt = zonefileCtxPrepare(pCtx, 
   251    328         "SELECT k, frame, v FROM %Q ORDER BY frame, idx, k", zTbl
   252    329     );
   253    330     if( pStmt==0 ) return;
   254    331   
   255    332     /* Open a file-handle used to write out the zonefile */ 
   256    333     pFd = fopen(zFile, "w");
   257    334     if( pFd==0 ){
................................................................................
   292    369   
   293    370       /* Add data for new entry to sFrames */
   294    371       if( zonefileBufferGrow(pCtx, &sFrames, nBlob) ) goto zone_write_out;
   295    372       zonefileAppendBlob(&sFrames, pBlob, nBlob);
   296    373       szFrame += nBlob;
   297    374       nKey++;
   298    375     }
          376  +  sqlite3_value_free(pPrev);
          377  +  pPrev = 0;
   299    378   
   300    379     /* Create the zonefile header in the in-memory buffer */
   301    380     zonefilePut32(&aHdr[0], ZONEFILE_MAGIC_NUMBER);
   302    381     aHdr[4] = sWrite.compressionTypeIndexData;
   303    382     aHdr[5] = sWrite.compressionTypeContent;
   304    383     zonefilePut32(&aHdr[6], 0);     /* Compression dictionary byte offset */
   305    384     zonefilePut32(&aHdr[10], ZONEFILE_SZ_HEADER + sFrameIdx.n + sKeyIdx.n); 
................................................................................
   328    407    zone_write_out:
   329    408     if( pFd ) fclose(pFd);
   330    409     sqlite3_finalize(pStmt);
   331    410     zonefileBufferFree(&sFrameIdx);
   332    411     zonefileBufferFree(&sKeyIdx);
   333    412     zonefileBufferFree(&sFrames);
   334    413   }
          414  +
          415  +typedef struct ZonefileFilesTab ZonefileFilesTab;
          416  +struct ZonefileFilesTab {
          417  +  sqlite3_vtab base;              /* Base class - must be first */
          418  +  sqlite3 *db;
          419  +  char *zBase;                    /* Name of this table */
          420  +  char *zDb;                      /* Database containing this table */
          421  +  sqlite3_stmt *pInsert;          /* Insert into the %_shadow_file table */
          422  +  sqlite3_stmt *pDelete;          /* Delete by rowid from %_shadow_file table */
          423  +};
          424  +
          425  +typedef struct ZonefileFilesCsr ZonefileFilesCsr;
          426  +struct ZonefileFilesCsr {
          427  +  sqlite3_vtab_cursor base;       /* Base class - must be first */
          428  +  sqlite3_stmt *pSelect;
          429  +};
          430  +
          431  +/*
          432  +** This function does the work of xCreate (if bCreate!=0) or xConnect
          433  +** (if bCreate==0) for the zonefile_files module.
          434  +*/
          435  +static int zffCreateConnect(
          436  +  int bCreate,
          437  +  sqlite3 *db,
          438  +  int argc, const char *const*argv,
          439  +  sqlite3_vtab **ppVtab,
          440  +  char **pzErr
          441  +){
          442  +  ZonefileFilesTab *p;
          443  +  const char *zName = argv[2];
          444  +  const char *zDb = argv[1];
          445  +  int nName = strlen(zName);
          446  +  int nDb = strlen(zDb);
          447  +  int rc = SQLITE_OK;
          448  +
          449  +  if( nName<6 || memcmp(&zName[nName-6], "_files", 6)!=0 ){
          450  +    *pzErr = sqlite3_mprintf("do not create zonefile_files tables directly!");
          451  +    *ppVtab = 0;
          452  +    return SQLITE_ERROR;
          453  +  }
          454  +
          455  +  p = (ZonefileFilesTab*)sqlite3_malloc(sizeof(ZonefileFilesTab)+nName+1+nDb+1);
          456  +  if( !p ){
          457  +    rc = SQLITE_NOMEM;
          458  +  }else{
          459  +    memset(p, 0, sizeof(ZonefileFilesTab));
          460  +    p->zBase = (char*)&p[1];
          461  +    memcpy(p->zBase, zName, nName-6);
          462  +    p->zBase[nName-6] = '\0';
          463  +    p->zDb = &p->zBase[nName+1];
          464  +    memcpy(p->zDb, zDb, nDb+1);
          465  +    p->db = db;
          466  +    rc = sqlite3_declare_vtab(db, ZONEFILE_FILES_SCHEMA);
          467  +  }
          468  +
          469  +  if( rc!=SQLITE_OK ){
          470  +    sqlite3_free(p);
          471  +    p = 0;
          472  +  }
          473  +  *ppVtab = (sqlite3_vtab*)p;
          474  +  return rc;
          475  +}
          476  +
          477  +/* 
          478  +** zonefile_files virtual table module xCreate method.
          479  +*/
          480  +static int zffCreate(
          481  +  sqlite3 *db,
          482  +  void *pAux,
          483  +  int argc, const char *const*argv,
          484  +  sqlite3_vtab **ppVtab,
          485  +  char **pzErr
          486  +){
          487  +  return zffCreateConnect(1, db, argc, argv, ppVtab, pzErr);
          488  +}
          489  +
          490  +/* 
          491  +** zonefile_files virtual table module xConnect method.
          492  +*/
          493  +static int zffConnect(
          494  +  sqlite3 *db,
          495  +  void *pAux,
          496  +  int argc, const char *const*argv,
          497  +  sqlite3_vtab **ppVtab,
          498  +  char **pzErr
          499  +){
          500  +  return zffCreateConnect(0, db, argc, argv, ppVtab, pzErr);
          501  +}
          502  +
          503  +/* 
          504  +** zonefile_files virtual table module xDisconnect method.
          505  +*/
          506  +static int zffDisconnect(sqlite3_vtab *pVtab){
          507  +  ZonefileFilesTab *pTab = (ZonefileFilesTab*)pVtab;
          508  +  sqlite3_finalize(pTab->pInsert);
          509  +  sqlite3_finalize(pTab->pDelete);
          510  +  sqlite3_free(pTab);
          511  +  return SQLITE_OK;
          512  +}
          513  +
          514  +/* 
          515  +** zonefile_files virtual table module xBestIndex method.
          516  +*/
          517  +static int zffBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
          518  +  return SQLITE_OK;
          519  +}
          520  +
          521  +/* 
          522  +** zonefile_files virtual table module xOpen method.
          523  +*/
          524  +static int zffOpen(sqlite3_vtab *pVtab, sqlite3_vtab_cursor **ppCursor){
          525  +  ZonefileFilesCsr *pCsr;
          526  +  pCsr = (ZonefileFilesCsr*)sqlite3_malloc(sizeof(ZonefileFilesCsr));
          527  +  if( pCsr==0 ){
          528  +    return SQLITE_NOMEM;
          529  +  }
          530  +  memset(pCsr, 0, sizeof(ZonefileFilesCsr));
          531  +  *ppCursor = (sqlite3_vtab_cursor*)pCsr;
          532  +  return SQLITE_OK;
          533  +}
          534  +
          535  +static void zffCursorReset(ZonefileFilesCsr *pCsr){
          536  +  sqlite3_finalize(pCsr->pSelect);
          537  +  pCsr->pSelect = 0;
          538  +}
          539  +
          540  +/* 
          541  +** zonefile_files virtual table module xClose method.
          542  +*/
          543  +static int zffClose(sqlite3_vtab_cursor *cur){
          544  +  ZonefileFilesCsr *pCsr = (ZonefileFilesCsr*)cur;
          545  +  zffCursorReset(pCsr);
          546  +  sqlite3_free(pCsr);
          547  +  return SQLITE_OK;
          548  +}
          549  +
          550  +/* 
          551  +** zonefile_files virtual table module xNext method.
          552  +*/
          553  +static int zffNext(sqlite3_vtab_cursor *cur){
          554  +  ZonefileFilesCsr *pCsr = (ZonefileFilesCsr*)cur;
          555  +  int rc;
          556  +  if( SQLITE_ROW==sqlite3_step(pCsr->pSelect) ){
          557  +    rc = SQLITE_OK;
          558  +  }else{
          559  +    rc = sqlite3_finalize(pCsr->pSelect);
          560  +    pCsr->pSelect = 0;
          561  +  }
          562  +  return rc;
          563  +}
          564  +
          565  +/* 
          566  +** zonefile_files virtual table module xFilter method.
          567  +*/
          568  +static int zffFilter(
          569  +  sqlite3_vtab_cursor *cur, 
          570  +  int idxNum, const char *idxStr,
          571  +  int argc, sqlite3_value **argv
          572  +){
          573  +  ZonefileFilesCsr *pCsr = (ZonefileFilesCsr*)cur;
          574  +  ZonefileFilesTab *pTab = (ZonefileFilesTab*)(pCsr->base.pVtab);
          575  +  int rc;
          576  +  zffCursorReset(pCsr);
          577  +
          578  +  rc = zonefilePrepare(pTab->db, &pCsr->pSelect, &pTab->base.zErrMsg,
          579  +      "SELECT filename, fileid FROM %Q.'%q_shadow_file'",
          580  +      pTab->zDb, pTab->zBase
          581  +  );
          582  +  if( rc==SQLITE_OK ){
          583  +    rc = zffNext(cur);
          584  +  }
          585  +  return rc;
          586  +}
          587  +
          588  +/*
          589  +** zonefile_files virtual table module xEof method.
          590  +*/
          591  +static int zffEof(sqlite3_vtab_cursor *cur){
          592  +  ZonefileFilesCsr *pCsr = (ZonefileFilesCsr*)cur;
          593  +  return pCsr->pSelect==0;
          594  +}
          595  +
          596  +static FILE *zonefileOpenFile(sqlite3_context *pCtx, const char *zFile){
          597  +  FILE *pFd = fopen(zFile, "r");
          598  +  if( pFd==0 ){
          599  +    zonefileCtxError(pCtx, "failed to open file for reading: \"%s\"", zFile);
          600  +  }
          601  +  return pFd;
          602  +}
          603  +
          604  +static void zonefileHeaderDeserialize(u8 *aBuf, ZonefileHeader *pHdr){
          605  +  pHdr->magicNumber = zonefileGet32(&aBuf[0]);
          606  +  pHdr->compressionTypeIndexData = aBuf[4];
          607  +  pHdr->compressionTypeContent = aBuf[5];
          608  +  pHdr->byteOffsetDictionary = zonefileGet32(&aBuf[6]);
          609  +  pHdr->byteOffsetFrames = zonefileGet32(&aBuf[10]);
          610  +  pHdr->numFrames = zonefileGet32(&aBuf[14]);
          611  +  pHdr->numKeys = zonefileGet32(&aBuf[18]);
          612  +  pHdr->encryptionType = aBuf[22];
          613  +  pHdr->encryptionKeyIdx = aBuf[23];
          614  +  pHdr->extendedHeaderVersion = aBuf[24];
          615  +  pHdr->extendedHeaderSize = aBuf[25];
          616  +}
          617  +
          618  +static void zonefileJsonHeader(sqlite3_context *pCtx, const char *zFile){
          619  +  FILE *pFd = zonefileOpenFile(pCtx, zFile);
          620  +  if( pFd ){
          621  +    int rc;
          622  +    ZonefileHeader hdr;
          623  +    u8 aBuf[ZONEFILE_SZ_HEADER];
          624  +
          625  +    rc = zonefileRead(pFd, aBuf, ZONEFILE_SZ_HEADER, 0);
          626  +    if( rc==SQLITE_OK ){
          627  +      zonefileHeaderDeserialize(aBuf, &hdr);
          628  +    }
          629  +
          630  +    if( rc!=SQLITE_OK ){
          631  +      zonefileCtxError(pCtx, "failed to read header from file: \"%s\"", zFile);
          632  +    }else{
          633  +      char *zJson = sqlite3_mprintf("{"
          634  +          "\"magicNumber\":%u,"
          635  +          "\"compressionTypeIndexData\":%u,"
          636  +          "\"compressionTypeContent\":%u,"
          637  +          "\"byteOffsetDictionary\":%u,"
          638  +          "\"byteOffsetFrames\":%u,"
          639  +          "\"numFrames\":%u,"
          640  +          "\"numKeys\":%u,"
          641  +          "\"encryptionType\":%u,"
          642  +          "\"encryptionKeyIdx\":%u,"
          643  +          "\"extendedHeaderVersion\":%u,"
          644  +          "\"extendedHeaderSize\":%u}",
          645  +          (u32)hdr.magicNumber,
          646  +          (u32)hdr.compressionTypeIndexData,
          647  +          (u32)hdr.compressionTypeContent,
          648  +          (u32)hdr.byteOffsetDictionary,
          649  +          (u32)hdr.byteOffsetFrames,
          650  +          (u32)hdr.numFrames,
          651  +          (u32)hdr.numKeys,
          652  +          (u32)hdr.encryptionType,
          653  +          (u32)hdr.encryptionKeyIdx,
          654  +          (u32)hdr.extendedHeaderVersion,
          655  +          (u32)hdr.extendedHeaderSize
          656  +      );
          657  +      if( zJson ){
          658  +        sqlite3_result_text(pCtx, zJson, -1, SQLITE_TRANSIENT);
          659  +        sqlite3_free(zJson);
          660  +      }else{
          661  +        sqlite3_result_error_nomem(pCtx);
          662  +      }
          663  +    }
          664  +    fclose(pFd);
          665  +  }
          666  +}
          667  +
          668  +/* 
          669  +** zonefile_files virtual table module xColumn method.
          670  +*/
          671  +static int zffColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
          672  +  ZonefileFilesCsr *pCsr = (ZonefileFilesCsr*)cur;
          673  +  switch( i ){
          674  +    case 0: /* filename */
          675  +      sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pSelect, 0));
          676  +      break;
          677  +    case 1: /* priority */
          678  +      break;
          679  +    case 2: /* ekey */
          680  +      break;
          681  +    case 3: { /* header */
          682  +      const char *zFile = (const char*)sqlite3_column_text(pCsr->pSelect, 0);
          683  +      zonefileJsonHeader(ctx, zFile);
          684  +      break;
          685  +    }
          686  +  }
          687  +  return SQLITE_OK;
          688  +}
          689  +
          690  +/* 
          691  +** zonefile_files virtual table module xRowid method.
          692  +*/
          693  +static int zffRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
          694  +  ZonefileFilesCsr *pCsr = (ZonefileFilesCsr*)cur;
          695  +  *pRowid = sqlite3_column_int64(pCsr->pSelect, 1);
          696  +  return SQLITE_OK;
          697  +}
          698  +
          699  +/*
          700  +** zonefile_files virtual table module xUpdate method.
          701  +**
          702  +** A delete specifies a single argument - the rowid of the row to remove.
          703  +** 
          704  +** Update and insert operations pass:
          705  +**
          706  +**   1. The "old" rowid, or NULL.
          707  +**   2. The "new" rowid.
          708  +**   3. Values for each of the 4 columns: (filename,priority,ekey,header)
          709  +*/
          710  +static int zffUpdate(
          711  +  sqlite3_vtab *pVtab, 
          712  +  int nVal, 
          713  +  sqlite3_value **apVal, 
          714  +  sqlite_int64 *pRowid
          715  +){
          716  +  int rc = SQLITE_OK;
          717  +  ZonefileFilesTab *pTab = (ZonefileFilesTab*)pVtab;
          718  +
          719  +  if( sqlite3_value_type(apVal[0])==SQLITE_INTEGER ){
          720  +    if( pTab->pDelete==0 ){
          721  +      rc = zonefilePrepare(pTab->db, &pTab->pInsert, &pVtab->zErrMsg,
          722  +          "DELETE FROM %Q.'%q_shadow_file WHERE fileid=?",
          723  +          pTab->zDb, pTab->zBase
          724  +      );
          725  +    }
          726  +    if( rc==SQLITE_OK ){
          727  +      sqlite3_bind_value(pTab->pDelete, 1, apVal[0]);
          728  +      sqlite3_step(pTab->pDelete);
          729  +      rc = sqlite3_reset(pTab->pDelete);
          730  +    }
          731  +  }
          732  +  if( nVal>1 ){
          733  +    if( pTab->pInsert==0 ){
          734  +      rc = zonefilePrepare(pTab->db, &pTab->pInsert, &pVtab->zErrMsg,
          735  +          "INSERT INTO %Q.'%q_shadow_file'(filename) VALUES(?)",
          736  +          pTab->zDb, pTab->zBase
          737  +      );
          738  +    }
          739  +
          740  +    if( rc==SQLITE_OK ){
          741  +      const char *zFile = (const char*)sqlite3_value_text(apVal[2]);
          742  +      sqlite3_bind_text(pTab->pInsert, 1, zFile, -1, SQLITE_TRANSIENT);
          743  +      sqlite3_step(pTab->pInsert);
          744  +      rc = sqlite3_reset(pTab->pInsert);
          745  +    }
          746  +  }
          747  +
          748  +  return SQLITE_OK;
          749  +}
          750  +
          751  +typedef struct ZonefileTab ZonefileTab;
          752  +struct ZonefileTab {
          753  +  sqlite3_vtab base;         /* Base class - must be first */
          754  +  sqlite3 *db;
          755  +  char *zName;               /* Name of this table */
          756  +  char *zDb;                 /* Name of db containing this table */
          757  +};
          758  +
          759  +/*
          760  +** This function does the work of xCreate (if bCreate!=0) or xConnect
          761  +** (if bCreate==0) for the zonefile module.
          762  +**
          763  +**   argv[0]   -> module name  ("zonefile")
          764  +**   argv[1]   -> database name
          765  +**   argv[2]   -> table name
          766  +*/
          767  +static int zonefileCreateConnect(
          768  +  int bCreate,
          769  +  sqlite3 *db,
          770  +  int argc, const char *const*argv,
          771  +  sqlite3_vtab **ppVtab,
          772  +  char **pzErr
          773  +){
          774  +  ZonefileTab *p;
          775  +  const char *zName = argv[2];
          776  +  const char *zDb = argv[1];
          777  +  int nName = strlen(zName);
          778  +  int nDb = strlen(zDb);
          779  +  int rc = SQLITE_OK;
          780  +
          781  +  p = (ZonefileTab*)sqlite3_malloc(sizeof(ZonefileTab) + nName+1 + nDb+1);
          782  +  if( !p ){
          783  +    rc = SQLITE_NOMEM;
          784  +  }else{
          785  +    memset(p, 0, sizeof(ZonefileTab));
          786  +    p->zName = (char*)&p[1];
          787  +    memcpy(p->zName, zName, nName+1);
          788  +    p->zDb = &p->zName[nName+1];
          789  +    memcpy(p->zDb, zDb, nDb+1);
          790  +    p->db = db;
          791  +  
          792  +    if( bCreate ){
          793  +      char *zSql = sqlite3_mprintf(
          794  +          "CREATE TABLE %Q.'%q_shadow_idx'(" 
          795  +          "  k INTEGER PRIMARY KEY,"
          796  +          "  fileid INTEGER,"
          797  +          "  frame INTEGER,"
          798  +          "  ofst INTEGER,"
          799  +          "  sz INTEGER"
          800  +          ");"
          801  +          "CREATE TABLE %Q.'%q_shadow_file'(" 
          802  +          "  filename TEXT,"
          803  +          "  priority INTEGER,"
          804  +          "  fileid INTEGER PRIMARY KEY"
          805  +          ");" 
          806  +          "CREATE VIRTUAL TABLE %Q.'%q_files' USING zonefile_files;",
          807  +          zDb, zName, zDb, zName, zDb, zName
          808  +      );
          809  +  
          810  +      if( zSql==0 ){
          811  +        rc = SQLITE_NOMEM;
          812  +      }else{
          813  +        rc = sqlite3_exec(db, zSql, 0, 0, pzErr);
          814  +        sqlite3_free(zSql);
          815  +      }
          816  +    }
          817  +    
          818  +    if( rc==SQLITE_OK ){
          819  +      rc = sqlite3_declare_vtab(db, ZONEFILE_SCHEMA);
          820  +    }
          821  +  }
          822  +
          823  +  if( rc!=SQLITE_OK ){
          824  +    sqlite3_free(p);
          825  +    p = 0;
          826  +  }
          827  +  *ppVtab = (sqlite3_vtab*)p;
          828  +  return rc;
          829  +}
          830  +
          831  +/* 
          832  +** zonefile virtual table module xCreate method.
          833  +*/
          834  +static int zonefileCreate(
          835  +  sqlite3 *db,
          836  +  void *pAux,
          837  +  int argc, const char *const*argv,
          838  +  sqlite3_vtab **ppVtab,
          839  +  char **pzErr
          840  +){
          841  +  return zonefileCreateConnect(1, db, argc, argv, ppVtab, pzErr);
          842  +}
          843  +
          844  +/* 
          845  +** zonefile virtual table module xConnect method.
          846  +*/
          847  +static int zonefileConnect(
          848  +  sqlite3 *db,
          849  +  void *pAux,
          850  +  int argc, const char *const*argv,
          851  +  sqlite3_vtab **ppVtab,
          852  +  char **pzErr
          853  +){
          854  +  return zonefileCreateConnect(0, db, argc, argv, ppVtab, pzErr);
          855  +}
          856  +
          857  +/* 
          858  +** zonefile virtual table module xDisconnect method.
          859  +*/
          860  +static int zonefileDisconnect(sqlite3_vtab *pVtab){
          861  +  ZonefileTab *pTab = (ZonefileTab*)pVtab;
          862  +  sqlite3_free(pTab);
          863  +  return SQLITE_OK;
          864  +}
          865  +
          866  +/* 
          867  +** zonefile virtual table module xBestIndex method.
          868  +*/
          869  +static int zonefileBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
          870  +  return SQLITE_OK;
          871  +}
          872  +
          873  +/* 
          874  +** zonefile virtual table module xDestroy method.
          875  +*/
          876  +static int zonefileDestroy(sqlite3_vtab *pVtab){
          877  +  ZonefileTab *pTab = (ZonefileTab*)pVtab;
          878  +  int rc = SQLITE_OK;
          879  +  char *zSql = sqlite3_mprintf(
          880  +      "DROP TABLE IF EXISTS %Q.'%q_shadow_idx';"
          881  +      "DROP TABLE IF EXISTS %Q.'%q_shadow_file';"
          882  +      "DROP TABLE IF EXISTS %Q.'%q_files';",
          883  +      pTab->zDb, pTab->zName, pTab->zDb, pTab->zName, pTab->zDb, pTab->zName
          884  +  );
          885  +  if( zSql==0 ){
          886  +    rc = SQLITE_NOMEM;
          887  +  }else{
          888  +    rc = sqlite3_exec(pTab->db, zSql, 0, 0, 0);
          889  +  }
          890  +
          891  +  if( rc==SQLITE_OK ){
          892  +    zonefileDisconnect(pVtab);
          893  +  }
          894  +  return rc;
          895  +}
          896  +
          897  +/* 
          898  +** zonefile virtual table module xOpen method.
          899  +*/
          900  +static int zonefileOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
          901  +  return SQLITE_OK;
          902  +}
          903  +
          904  +/* 
          905  +** zonefile virtual table module xClose method.
          906  +*/
          907  +static int zonefileClose(sqlite3_vtab_cursor *cur){
          908  +  return SQLITE_OK;
          909  +}
          910  +
          911  +/* 
          912  +** zonefile virtual table module xFilter method.
          913  +*/
          914  +static int zonefileFilter(
          915  +  sqlite3_vtab_cursor *pVtabCursor, 
          916  +  int idxNum, const char *idxStr,
          917  +  int argc, sqlite3_value **argv
          918  +){
          919  +  return SQLITE_OK;
          920  +}
          921  +
          922  +/* 
          923  +** zonefile virtual table module xNext method.
          924  +*/
          925  +static int zonefileNext(sqlite3_vtab_cursor *pVtabCursor){
          926  +  return SQLITE_OK;
          927  +}
          928  +
          929  +/*
          930  +** zonefile virtual table module xEof method.
          931  +*/
          932  +static int zonefileEof(sqlite3_vtab_cursor *cur){
          933  +  return SQLITE_OK;
          934  +}
          935  +
          936  +/* 
          937  +** zonefile virtual table module xColumn method.
          938  +*/
          939  +static int zonefileColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
          940  +  return SQLITE_OK;
          941  +}
          942  +
          943  +/* 
          944  +** zonefile virtual table module xRowid method.
          945  +*/
          946  +static int zonefileRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){
          947  +  return SQLITE_OK;
          948  +}
          949  +
   335    950   
   336    951   /*
   337    952   ** Register the "zonefile" extensions.
   338    953   */
   339    954   static int zonefileRegister(sqlite3 *db){
          955  +  static sqlite3_module filesModule = {
          956  +    0,                            /* iVersion */
          957  +    zffCreate,                    /* xCreate - create a table */
          958  +    zffConnect,                   /* xConnect - connect to an existing table */
          959  +    zffBestIndex,                 /* xBestIndex - Determine search strategy */
          960  +    zffDisconnect,                /* xDisconnect - Disconnect from a table */
          961  +    zffDisconnect,                /* xDestroy - Drop a table */
          962  +    zffOpen,                      /* xOpen - open a cursor */
          963  +    zffClose,                     /* xClose - close a cursor */
          964  +    zffFilter,                    /* xFilter - configure scan constraints */
          965  +    zffNext,                      /* xNext - advance a cursor */
          966  +    zffEof,                       /* xEof */
          967  +    zffColumn,                    /* xColumn - read data */
          968  +    zffRowid,                     /* xRowid - read data */
          969  +    zffUpdate,                    /* xUpdate - write data */
          970  +    0,                            /* xBegin - begin transaction */
          971  +    0,                            /* xSync - sync transaction */
          972  +    0,                            /* xCommit - commit transaction */
          973  +    0,                            /* xRollback - rollback transaction */
          974  +    0,                            /* xFindFunction - function overloading */
          975  +    0,                            /* xRename - rename the table */
          976  +    0,                            /* xSavepoint */
          977  +    0,                            /* xRelease */
          978  +    0                             /* xRollbackTo */
          979  +  };
          980  +
          981  +  static sqlite3_module zonefileModule = {
          982  +    0,                            /* iVersion */
          983  +    zonefileCreate,               /* xCreate - create a table */
          984  +    zonefileConnect,              /* xConnect - connect to an existing table */
          985  +    zonefileBestIndex,            /* xBestIndex - Determine search strategy */
          986  +    zonefileDisconnect,           /* xDisconnect - Disconnect from a table */
          987  +    zonefileDestroy,              /* xDestroy - Drop a table */
          988  +    zonefileOpen,                 /* xOpen - open a cursor */
          989  +    zonefileClose,                /* xClose - close a cursor */
          990  +    zonefileFilter,               /* xFilter - configure scan constraints */
          991  +    zonefileNext,                 /* xNext - advance a cursor */
          992  +    zonefileEof,                  /* xEof */
          993  +    zonefileColumn,               /* xColumn - read data */
          994  +    zonefileRowid,                /* xRowid - read data */
          995  +    0,                            /* xUpdate - write data */
          996  +    0,                            /* xBegin - begin transaction */
          997  +    0,                            /* xSync - sync transaction */
          998  +    0,                            /* xCommit - commit transaction */
          999  +    0,                            /* xRollback - rollback transaction */
         1000  +    0,                            /* xFindFunction - function overloading */
         1001  +    0,                            /* xRename - rename the table */
         1002  +    0,                            /* xSavepoint */
         1003  +    0,                            /* xRelease */
         1004  +    0                             /* xRollbackTo */
         1005  +  };
         1006  +
   340   1007     struct Func {
   341   1008       const char *z;
   342   1009       int n;
   343   1010       void (*x)(sqlite3_context*,int,sqlite3_value**);
   344   1011     } aFunc[] = {
   345   1012       { "zonefile_write", 2, zonefileWriteFunc },
   346   1013       { "zonefile_write", 3, zonefileWriteFunc },
   347   1014     };
         1015  +
   348   1016     int rc = SQLITE_OK;
   349   1017     int i;
   350   1018   
   351   1019     for(i=0; rc==SQLITE_OK && i<sizeof(aFunc)/sizeof(aFunc[0]); i++){
   352   1020       struct Func *p = &aFunc[i];
   353   1021       rc = sqlite3_create_function(db, p->z, p->n, SQLITE_ANY, 0, p->x, 0, 0);
   354   1022     }
         1023  +
         1024  +  if( rc==SQLITE_OK ){
         1025  +    rc = sqlite3_create_module(db, "zonefile_files", &filesModule, 0);
         1026  +  }
         1027  +  if( rc==SQLITE_OK ){
         1028  +    rc = sqlite3_create_module(db, "zonefile", &zonefileModule, 0);
         1029  +  }
   355   1030   
   356   1031     return rc;
   357   1032   }
   358   1033   
   359   1034   #else         /* SQLITE_OMIT_VIRTUALTABLE */
   360   1035   # define zonefileRegister(x) SQLITE_OK
   361   1036   #endif

Changes to ext/zonefile/zonefile1.test.

    15     15   if {![info exists testdir]} {
    16     16     set testdir [file join [file dirname [info script]] .. .. test]
    17     17   }
    18     18   source [file join $testdir tester.tcl]
    19     19   set testprefix zonefile1
    20     20   load_static_extension db zonefile
    21     21   
    22         -
    23     22   do_execsql_test 1.0 {
    24     23     CREATE TABLE zz(k INTEGER PRIMARY KEY, frame INTEGER, idx INTEGER, v BLOB);
    25     24     INSERT INTO zz VALUES(1, -1, -1, randomblob(100));
    26     25     INSERT INTO zz VALUES(2, -1, -1, randomblob(100));
    27     26     INSERT INTO zz VALUES(3, -1, -1, randomblob(100));
    28     27   }
           28  +
    29     29   
    30     30   do_execsql_test 1.1 {
    31     31     SELECT zonefile_write('test.zonefile', 'zz');
    32         -}
           32  +} {{}}
           33  +
           34  +do_execsql_test 2.0 {
           35  +  CREATE VIRTUAL TABLE z1 USING zonefile;
           36  +  SELECT name FROM sqlite_master WHERE name LIKE 'z1%' ORDER BY 1;
           37  +} {z1 z1_files z1_shadow_file z1_shadow_idx}
           38  +
           39  +do_execsql_test 2.1 {
           40  +  INSERT INTO z1_files(filename) VALUES('test.zonefile');
           41  +  SELECT filename, 
           42  +         json_extract(header, '$.magicNumber'),
           43  +         json_extract(header, '$.numFrames'),
           44  +         json_extract(header, '$.numKeys')
           45  +         FROM z1_files;
           46  +} {test.zonefile 1179332920 1 3}
    33     47   
    34     48   finish_test