SQLite

Check-in [883e7e75d6]
Login

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

Overview
Comment:Add an LRU cache of uncompressed frame content to the zonefile virtual table implementation.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | zonefile
Files: files | file ages | folders
SHA3-256: 883e7e75d65622e8d06c46e48b7cc756cc0e3345b8124a8038cab0a8d51d0458
User & Date: dan 2018-02-22 16:46:42.652
Context
2018-02-22
21:06
Add tests cases and fix some minor zonefile problems. (check-in: f4d42162fa user: dan tags: zonefile)
16:46
Add an LRU cache of uncompressed frame content to the zonefile virtual table implementation. (check-in: 883e7e75d6 user: dan tags: zonefile)
2018-02-21
21:15
Modifications to the zonefile module to make it easier to add a cache of uncompressed frame content. (check-in: d9d5cc62f1 user: dan tags: zonefile)
Changes
Unified Diff Ignore Whitespace Patch
Changes to ext/zonefile/zonefile.c.
1906
1907
1908
1909
1910
1911
1912













1913
1914
1915
1916
1917
1918
1919
1920
1921


1922





1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
      const char *zKey = (const char*)sqlite3_value_text(apVal[3]);
      rc = zonefileKeyStore(pTab->pGlobal, pTab->zDb, pTab->zBase,iFileid,zKey);
    }
  }

  return rc;
}














typedef struct ZonefileTab ZonefileTab;
struct ZonefileTab {
  sqlite3_vtab base;         /* Base class - must be first */
  sqlite3 *db;
  sqlite3_stmt *pIdToName;   /* Translate fileid to filename */
  ZonefileGlobal *pGlobal;
  char *zName;               /* Name of this table */
  char *zDb;                 /* Name of db containing this table */


  int nCacheSize;





};

typedef struct ZonefileCsr ZonefileCsr;
struct ZonefileCsr {
  sqlite3_vtab_cursor base;  /* Base class - must be first */
  sqlite3_stmt *pSelect;     /* SELECT on %_shadow_idx table */
};

typedef struct ZonefileFrame ZonefileFrame;
struct ZonefileFrame {
  i64 iFileid;               /* Fileid for this frame */
  i64 iFrameOff;             /* Offset of frame in file */
  int nBuf;                  /* Size of aBuf[] in bytes */
  u8 *aBuf;                  /* Buffer containing uncompressed frame data */
};

/*
** Attempt to interpret the contents of string z as an integer. If
** successful, set (*piVal) to the integer value and return SQLITE_OK.
** Otherwise, return SQLITE_ERROR.
*/
static int zonefileParseInteger(const char *z, int *piVal){
  *piVal = atoi(z);







>
>
>
>
>
>
>
>
>
>
>
>
>









>
>
|
>
>
>
>
>








<
<
<
<
<
<
<
<







1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950








1951
1952
1953
1954
1955
1956
1957
      const char *zKey = (const char*)sqlite3_value_text(apVal[3]);
      rc = zonefileKeyStore(pTab->pGlobal, pTab->zDb, pTab->zBase,iFileid,zKey);
    }
  }

  return rc;
}

/* Each entry in the frame-cache is represented by an instance of the
** following structure.  */
typedef struct ZonefileFrame ZonefileFrame;
struct ZonefileFrame {
  i64 iFileid;               /* Fileid for this frame */
  i64 iFrameOff;             /* Offset of frame in file */
  int nBuf;                  /* Size of aBuf[] in bytes */
  u8 *aBuf;                  /* Buffer containing uncompressed frame data */
  ZonefileFrame *pLruNext;   /* Next element in LRU list */
  ZonefileFrame *pLruPrev;   /* Previous element in LRU list */
  ZonefileFrame *pHashNext;  /* Next element in same hash bucket */
};

typedef struct ZonefileTab ZonefileTab;
struct ZonefileTab {
  sqlite3_vtab base;         /* Base class - must be first */
  sqlite3 *db;
  sqlite3_stmt *pIdToName;   /* Translate fileid to filename */
  ZonefileGlobal *pGlobal;
  char *zName;               /* Name of this table */
  char *zDb;                 /* Name of db containing this table */

  /* The following variables are used to implement the frame-cache */
  int nCacheSize;            /* Configured cache size */
  int nCacheEntry;           /* Current number of entries in cache */
  int nCacheBucket;          /* Number of buckets in frame cache hash table */
  ZonefileFrame **aCache;    /* Array of hash buckets */
  ZonefileFrame *pCacheFirst;/* Most recently used frame */
  ZonefileFrame *pCacheLast; /* Least recently used frame (first to discard) */
};

typedef struct ZonefileCsr ZonefileCsr;
struct ZonefileCsr {
  sqlite3_vtab_cursor base;  /* Base class - must be first */
  sqlite3_stmt *pSelect;     /* SELECT on %_shadow_idx table */
};









/*
** Attempt to interpret the contents of string z as an integer. If
** successful, set (*piVal) to the integer value and return SQLITE_OK.
** Otherwise, return SQLITE_ERROR.
*/
static int zonefileParseInteger(const char *z, int *piVal){
  *piVal = atoi(z);
2068
2069
2070
2071
2072
2073
2074

2075
2076
2077
2078
2079
2080
2081
    if( rc==SQLITE_OK ){
      rc = sqlite3_declare_vtab(db, ZONEFILE_SCHEMA);
    }

    for(i=3; i<argc && rc==SQLITE_OK; i++){
      zonefileParseOption(p, argv[i], pzErr);
    }

  }

  if( rc!=SQLITE_OK ){
    sqlite3_free(p);
    p = 0;
  }
  *ppVtab = (sqlite3_vtab*)p;







>







2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
    if( rc==SQLITE_OK ){
      rc = sqlite3_declare_vtab(db, ZONEFILE_SCHEMA);
    }

    for(i=3; i<argc && rc==SQLITE_OK; i++){
      zonefileParseOption(p, argv[i], pzErr);
    }
    if( rc==SQLITE_OK && p->nCacheSize<1 ) p->nCacheSize = 1;
  }

  if( rc!=SQLITE_OK ){
    sqlite3_free(p);
    p = 0;
  }
  *ppVtab = (sqlite3_vtab*)p;
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
  int argc, const char *const*argv,
  sqlite3_vtab **ppVtab,
  char **pzErr
){
  return zonefileCreateConnect(0, pAux, db, argc, argv, ppVtab, pzErr);
}

/* 
** zonefile virtual table module xDisconnect method.
*/
static int zonefileDisconnect(sqlite3_vtab *pVtab){
  ZonefileTab *pTab = (ZonefileTab*)pVtab;
  sqlite3_finalize(pTab->pIdToName);
  sqlite3_free(pTab);
  return SQLITE_OK;
}

/* 
** Zonefile virtual table module xBestIndex method.
**
** Equality and range constraints on either the rowid or column "k" (which
** are the same thing) are processed. Bits in the idxNum parameter are
** set to indicate the constraints present:
**







<
<
<
<
<
<
<
<
<
<







2117
2118
2119
2120
2121
2122
2123










2124
2125
2126
2127
2128
2129
2130
  int argc, const char *const*argv,
  sqlite3_vtab **ppVtab,
  char **pzErr
){
  return zonefileCreateConnect(0, pAux, db, argc, argv, ppVtab, pzErr);
}











/* 
** Zonefile virtual table module xBestIndex method.
**
** Equality and range constraints on either the rowid or column "k" (which
** are the same thing) are processed. Bits in the idxNum parameter are
** set to indicate the constraints present:
**
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226

  pInfo->idxNum = idxNum;
  pInfo->estimatedCost = cost;

  return SQLITE_OK;
}

/* 
** zonefile virtual table module xDestroy method.
*/
static int zonefileDestroy(sqlite3_vtab *pVtab){
  ZonefileTab *pTab = (ZonefileTab*)pVtab;
  int rc = SQLITE_OK;
  char *zSql = sqlite3_mprintf(
      "DROP TABLE IF EXISTS %Q.'%q_shadow_idx';"
      "DROP TABLE IF EXISTS %Q.'%q_shadow_file';"
      "DROP TABLE IF EXISTS %Q.'%q_shadow_frame';"
      "DROP TABLE IF EXISTS %Q.'%q_files';",
      pTab->zDb, pTab->zName, pTab->zDb, pTab->zName, pTab->zDb, pTab->zName
  );
  if( zSql==0 ){
    rc = SQLITE_NOMEM;
  }else{
    rc = sqlite3_exec(pTab->db, zSql, 0, 0, 0);
    sqlite3_free(zSql);
  }

  if( rc==SQLITE_OK ){
    zonefileDisconnect(pVtab);
  }
  return rc;
}

/* 
** zonefile virtual table module xOpen method.
*/
static int zonefileOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
  ZonefileCsr *pCsr;
  pCsr = (ZonefileCsr*)sqlite3_malloc(sizeof(ZonefileCsr));
  if( pCsr==0 ){







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







2190
2191
2192
2193
2194
2195
2196


























2197
2198
2199
2200
2201
2202
2203

  pInfo->idxNum = idxNum;
  pInfo->estimatedCost = cost;

  return SQLITE_OK;
}



























/* 
** zonefile virtual table module xOpen method.
*/
static int zonefileOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
  ZonefileCsr *pCsr;
  pCsr = (ZonefileCsr*)sqlite3_malloc(sizeof(ZonefileCsr));
  if( pCsr==0 ){
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
  return (pCsr->pSelect==0);
}

static void zonefileFree(void *p){
  sqlite3_free(p);
}

static int zonefileCtxUncompress(
  sqlite3_context *pCtx, 
  ZonefileCompress *pMethod, 
  void *pCmp, 
  u8 *aBuf, int nBuf,
  int iKeyOff, int nKey
){
  int rc;
  u8 *aUn = 0;
  int nUn = 0;
    
  rc = zonefileUncompress(pMethod, pCmp, aBuf, nBuf, &aUn, &nUn);
  if( rc==SQLITE_OK ){
    sqlite3_result_blob(pCtx, &aUn[iKeyOff], nKey, SQLITE_TRANSIENT);
  }else if( rc==SQLITE_ERROR ){
    zonefileCtxError(pCtx, "failed to uncompress frame");
  }

  sqlite3_free(aUn);
  return rc;
}

static int zonefileGetFile(
  sqlite3_context *pCtx,          /* Leave error message here */
  ZonefileCsr *pCsr,              /* Cursor object */
  const char **pzFile             /* OUT: Pointer to current file */
){
  ZonefileTab *pTab = (ZonefileTab*)pCsr->base.pVtab;
  int rc = SQLITE_OK;







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







2293
2294
2295
2296
2297
2298
2299






















2300
2301
2302
2303
2304
2305
2306
  return (pCsr->pSelect==0);
}

static void zonefileFree(void *p){
  sqlite3_free(p);
}























static int zonefileGetFile(
  sqlite3_context *pCtx,          /* Leave error message here */
  ZonefileCsr *pCsr,              /* Cursor object */
  const char **pzFile             /* OUT: Pointer to current file */
){
  ZonefileTab *pTab = (ZonefileTab*)pCsr->base.pVtab;
  int rc = SQLITE_OK;
2419
2420
2421
2422
2423
2424
2425























2426
2427
2428
2429
2430






























2431
2432
2433







































































2434
2435
2436


2437


2438
2439
2440
2441
2442
2443
2444
  }

  zonefileFileClose(pFd);
  sqlite3_free(aBuf);
  return rc;
}
























static ZonefileFrame *zonefileCacheFind(
  ZonefileTab *pTab, 
  i64 iFile, 
  i64 iFrameOff
){






























  return 0;
}








































































static void zonefileCacheStore(
  ZonefileTab *pTab,
  ZonefileFrame *pFrame


){


}

static int zonefileValueReadCache(sqlite3_context *pCtx, ZonefileCsr *pCsr){
  int rc = SQLITE_OK;
  ZonefileTab *pTab = (ZonefileTab*)pCsr->base.pVtab;
  ZonefileFrame *pFrame = 0;
  i64 iFile = sqlite3_column_int64(pCsr->pSelect, 1);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
>
>
|
>
>







2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
  }

  zonefileFileClose(pFd);
  sqlite3_free(aBuf);
  return rc;
}

#ifndef NDEBUG
static void zonefileCacheCheck(ZonefileTab *pTab){
  ZonefileFrame *p;
  int n = 0;
  for(p=pTab->pCacheFirst; p; p=p->pLruNext){
    assert( p!=pTab->pCacheFirst || p->pLruPrev==0 );
    assert( p!=pTab->pCacheLast || p->pLruNext==0 );
    assert( p==pTab->pCacheFirst || p->pLruPrev->pLruNext==p );
    assert( p==pTab->pCacheLast || p->pLruNext->pLruPrev==p );
    n++;
  }
  assert( n==pTab->nCacheEntry );
}
#else
# define zonefileCacheCheck(x)
#endif

/*
** Search the frame-cache belonging to virtual table pTab for an entry
** corresponding to the frame at byte offset iFrameOff of the file with
** file id iFile. If such an entry is found, return a pointer to it.
** Otherwise, if no such entry exists, return NULL.
*/
static ZonefileFrame *zonefileCacheFind(
  ZonefileTab *pTab, 
  i64 iFile, 
  i64 iFrameOff
){
  ZonefileFrame *pFrame;
  for(pFrame=pTab->pCacheFirst; pFrame; pFrame=pFrame->pLruNext){
    if( pFrame->iFileid==iFile && pFrame->iFrameOff==iFrameOff ){
      /* Found a match. Move it to the front of the LRU list and return
      ** a pointer to it. */
      assert( (pFrame->pLruPrev==0)==(pFrame==pTab->pCacheFirst) );
      assert( (pFrame->pLruNext==0)==(pFrame==pTab->pCacheLast) );
      if( pFrame->pLruPrev ){
        assert( pFrame==pFrame->pLruPrev->pLruNext );
        pFrame->pLruPrev->pLruNext = pFrame->pLruNext;

        if( pFrame->pLruNext ){
          assert( pFrame==pFrame->pLruNext->pLruPrev );
          pFrame->pLruNext->pLruPrev = pFrame->pLruPrev;
        }else{
          assert( pFrame==pTab->pCacheLast );
          pTab->pCacheLast = pFrame->pLruPrev;
          pTab->pCacheLast->pLruNext = 0;
        }

        pFrame->pLruPrev = 0;
        pFrame->pLruNext = pTab->pCacheFirst;
        pTab->pCacheFirst->pLruPrev = pFrame;
        pTab->pCacheFirst = pFrame;
      }

      zonefileCacheCheck(pTab);
      return pFrame;
    }
  }
  return 0;
}

/*
** Return the index of the hash bucket that iFileid/iFrameOff belongs to.
*/
int zonefileCacheHash(ZonefileTab *pTab, i64 iFileid, i64 iFrameOff){
  u32 h;
  h = (iFileid & 0xFFFFFFFF) ^ (iFrameOff & 0xFFFFFFFF);
  return (h % pTab->nCacheBucket);
}

/*
** Store the frame object passed as the second argument in the frame
** cache belonging to table pTab.
*/
static int zonefileCacheStore(ZonefileTab *pTab, ZonefileFrame *pFrame){
  int h;

  /* Allocate the hash table if it has not already been allocated. */
  if( pTab->aCache==0 ){
    int nByte = pTab->nCacheSize * 2 * sizeof(ZonefileFrame*);
    pTab->aCache = (ZonefileFrame**)sqlite3_malloc(nByte);
    if( pTab->aCache==0 ){
      sqlite3_free(pFrame);
      return SQLITE_NOMEM;
    }
    memset(pTab->aCache, 0, nByte);
    pTab->nCacheBucket = pTab->nCacheSize * 2;
  }

  /* Add the new entry to the hash table */
  h = zonefileCacheHash(pTab, pFrame->iFileid, pFrame->iFrameOff);
  assert( h>=0 && h<pTab->nCacheBucket );
  pFrame->pHashNext = pTab->aCache[h];
  pTab->aCache[h] = pFrame;

  /* Add the new entry to the LRU list */
  pFrame->pLruPrev = 0;
  pFrame->pLruNext = pTab->pCacheFirst;
  pTab->pCacheFirst = pFrame;
  if( pFrame->pLruNext==0 ){
    pTab->pCacheLast = pFrame;
  }else{
    pFrame->pLruNext->pLruPrev = pFrame;
  }
  pTab->nCacheEntry++;

  if( pTab->nCacheEntry>pTab->nCacheSize ){
    ZonefileFrame **pp;

    /* Remove the oldest entry from the LRU list. */
    ZonefileFrame *pLast = pTab->pCacheLast;
    assert( pTab->pCacheLast );
    assert( pTab->nCacheEntry>1 );
    pTab->pCacheLast = pLast->pLruPrev;
    pTab->pCacheLast->pLruNext = 0;
    pTab->nCacheEntry--;

    /* Remove the same entry from the hash table. */
    h = zonefileCacheHash(pTab, pLast->iFileid, pLast->iFrameOff);
    assert( h>=0 && h<pTab->nCacheBucket );
    for(pp=&pTab->aCache[h]; *pp!=pLast; pp=&((*pp)->pHashNext));
    *pp = pLast->pHashNext;
    sqlite3_free(pLast);
  }
  zonefileCacheCheck(pTab);

  return SQLITE_OK;
}

/*
** Delete all resources associated with the frame-cache for table pTab.
*/
static void zonefileCacheDelete(ZonefileTab *pTab){
  ZonefileFrame *p;
  ZonefileFrame *pNext;
  for(p=pTab->pCacheFirst; p; p=pNext){
    pNext = p->pLruNext;
    sqlite3_free(p);
  }
  sqlite3_free(pTab->aCache);
}

static int zonefileValueReadCache(sqlite3_context *pCtx, ZonefileCsr *pCsr){
  int rc = SQLITE_OK;
  ZonefileTab *pTab = (ZonefileTab*)pCsr->base.pVtab;
  ZonefileFrame *pFrame = 0;
  i64 iFile = sqlite3_column_int64(pCsr->pSelect, 1);
2533
2534
2535
2536
2537
2538
2539

2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554



2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
      ZonefileFrame *p = 0;
      int nOut = pCmpMethod->xUncompressSize(pCmp, pFrame->aBuf, pFrame->nBuf);

      p = (ZonefileFrame*)sqlite3_malloc(nOut + sizeof(ZonefileFrame));
      if( p==0 ){
        rc = SQLITE_NOMEM;
      }else{

        p->aBuf = (u8*)&p[1];
        p->nBuf = nOut;
        p->iFrameOff = iFrameOff;
        p->iFileid = iFile;
        rc = pCmpMethod->xUncompress(
            pCmp, p->aBuf, p->nBuf, pFrame->aBuf, pFrame->nBuf
        );
        sqlite3_free(pFrame);
        pFrame = p;
      }
    }

    if( rc!=SQLITE_OK ){
      sqlite3_free(pFrame);
      pFrame = 0;



    }
    zonefileReleaseFile(pCsr);
    zonefileFileClose(pFd);
    zonefileCodecDestroy(pCodec);
    if( pCmpMethod ) pCmpMethod->xClose(pCmp);

    if( zErr ){
      assert( rc!=SQLITE_OK );
      sqlite3_result_error(pCtx, zErr, -1);
      sqlite3_free(zErr);
    }
  }

  if( pFrame ){
    assert( rc==SQLITE_OK );
    sqlite3_result_blob(pCtx, &pFrame->aBuf[iKeyOff], nKeySz, SQLITE_TRANSIENT);
    sqlite3_free(pFrame);
  }

  return rc;
}

/* 
** zonefile virtual table module xColumn method.







>















>
>
>
















<







2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657

2658
2659
2660
2661
2662
2663
2664
      ZonefileFrame *p = 0;
      int nOut = pCmpMethod->xUncompressSize(pCmp, pFrame->aBuf, pFrame->nBuf);

      p = (ZonefileFrame*)sqlite3_malloc(nOut + sizeof(ZonefileFrame));
      if( p==0 ){
        rc = SQLITE_NOMEM;
      }else{
        memset(p, 0, sizeof(ZonefileFrame));
        p->aBuf = (u8*)&p[1];
        p->nBuf = nOut;
        p->iFrameOff = iFrameOff;
        p->iFileid = iFile;
        rc = pCmpMethod->xUncompress(
            pCmp, p->aBuf, p->nBuf, pFrame->aBuf, pFrame->nBuf
        );
        sqlite3_free(pFrame);
        pFrame = p;
      }
    }

    if( rc!=SQLITE_OK ){
      sqlite3_free(pFrame);
      pFrame = 0;
    }else{
      rc = zonefileCacheStore(pTab, pFrame);
      if( rc!=SQLITE_OK ) pFrame = 0;
    }
    zonefileReleaseFile(pCsr);
    zonefileFileClose(pFd);
    zonefileCodecDestroy(pCodec);
    if( pCmpMethod ) pCmpMethod->xClose(pCmp);

    if( zErr ){
      assert( rc!=SQLITE_OK );
      sqlite3_result_error(pCtx, zErr, -1);
      sqlite3_free(zErr);
    }
  }

  if( pFrame ){
    assert( rc==SQLITE_OK );
    sqlite3_result_blob(pCtx, &pFrame->aBuf[iKeyOff], nKeySz, SQLITE_TRANSIENT);

  }

  return rc;
}

/* 
** zonefile virtual table module xColumn method.
2607
2608
2609
2610
2611
2612
2613





































2614
2615
2616
2617
2618
2619
2620
      }
      sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pSelect, iCol));
      break;
    }
  }
  return rc;
}






































/* 
** zonefile virtual table module xRowid method.
*/
static int zonefileRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
  ZonefileCsr *pCsr = (ZonefileCsr*)cur;
  *pRowid = sqlite3_column_int64(pCsr->pSelect, 0);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
      }
      sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pSelect, iCol));
      break;
    }
  }
  return rc;
}

/* 
** zonefile virtual table module xDisconnect method.
*/
static int zonefileDisconnect(sqlite3_vtab *pVtab){
  ZonefileTab *pTab = (ZonefileTab*)pVtab;
  zonefileCacheDelete(pTab);
  sqlite3_finalize(pTab->pIdToName);
  sqlite3_free(pTab);
  return SQLITE_OK;
}

/* 
** zonefile virtual table module xDestroy method.
*/
static int zonefileDestroy(sqlite3_vtab *pVtab){
  ZonefileTab *pTab = (ZonefileTab*)pVtab;
  int rc = SQLITE_OK;
  char *zSql = sqlite3_mprintf(
      "DROP TABLE IF EXISTS %Q.'%q_shadow_idx';"
      "DROP TABLE IF EXISTS %Q.'%q_shadow_file';"
      "DROP TABLE IF EXISTS %Q.'%q_shadow_frame';"
      "DROP TABLE IF EXISTS %Q.'%q_files';",
      pTab->zDb, pTab->zName, pTab->zDb, pTab->zName, pTab->zDb, pTab->zName
  );
  if( zSql==0 ){
    rc = SQLITE_NOMEM;
  }else{
    rc = sqlite3_exec(pTab->db, zSql, 0, 0, 0);
    sqlite3_free(zSql);
  }

  if( rc==SQLITE_OK ){
    zonefileDisconnect(pVtab);
  }
  return rc;
}

/* 
** zonefile virtual table module xRowid method.
*/
static int zonefileRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
  ZonefileCsr *pCsr = (ZonefileCsr*)cur;
  *pRowid = sqlite3_column_int64(pCsr->pSelect, 0);
Changes to ext/zonefile/zonefile1.test.
104
105
106
107
108
109
110

111
112
113
114
115
116
117

118
119
120
121
122
123
124
125
126
127
128




129
130
131
132
133
134
135
    )
    SELECT zonefile_write('test.zonefile', 'bb', json_group_object(n,v)) FROM p;
  } {1 {compressor "zstd_global_dict" may not be used to compress the zonefile index}}
}
# puts $COMPRESSION_METHODS

set extra_header 0

foreach cmp $COMPRESSION_METHODS { foreach cmpidx $COMPRESSION_METHODS {
  if {$cmpidx == "zstd_global_dict"} continue
  reset_db
  load_static_extension db zonefile

  set tn "$cmp/$cmpidx"
  set extra_header [expr {$extra_header ? 0 : 100}]


  do_execsql_test 2.$tn.0 {
    CREATE TABLE zz(
      k INTEGER PRIMARY KEY, 
      frame INTEGER DEFAULT -1, 
      idx INTEGER DEFAULT -1, 
      v BLOB
    );
    CREATE TABLE rt(k INTEGER PRIMARY KEY, v BLOB);
    CREATE VIRTUAL TABLE zone USING zonefile;
  }




  
  set nMinByte   0
  set nMaxByte 444
  foreach {zonefile lKey} {
    test1.zonefile {195 1238 298 405 297}
    test2.zonefile {124 1624 82 1929}
    test3.zonefile {932 683 1751 410 41}







>







>

|







<

>
>
>
>







104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128

129
130
131
132
133
134
135
136
137
138
139
140
    )
    SELECT zonefile_write('test.zonefile', 'bb', json_group_object(n,v)) FROM p;
  } {1 {compressor "zstd_global_dict" may not be used to compress the zonefile index}}
}
# puts $COMPRESSION_METHODS

set extra_header 0
set cachesize 0
foreach cmp $COMPRESSION_METHODS { foreach cmpidx $COMPRESSION_METHODS {
  if {$cmpidx == "zstd_global_dict"} continue
  reset_db
  load_static_extension db zonefile

  set tn "$cmp/$cmpidx"
  set extra_header [expr {$extra_header ? 0 : 100}]
  set cachesize [expr {$cachesize ? 0 : 10}]

  do_execsql_test 2.$tn.0.1 {
    CREATE TABLE zz(
      k INTEGER PRIMARY KEY, 
      frame INTEGER DEFAULT -1, 
      idx INTEGER DEFAULT -1, 
      v BLOB
    );
    CREATE TABLE rt(k INTEGER PRIMARY KEY, v BLOB);

  }

  do_execsql_test 2.$tn.0.2 "
    CREATE VIRTUAL TABLE zone USING zonefile(cachesize = $cachesize)
  " {}
  
  set nMinByte   0
  set nMaxByte 444
  foreach {zonefile lKey} {
    test1.zonefile {195 1238 298 405 297}
    test2.zonefile {124 1624 82 1929}
    test3.zonefile {932 683 1751 410 41}