/ Check-in [dbbcbf00]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Add test cases and minor fixes for the zonefile module.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | zonefile
Files: files | file ages | folders
SHA3-256: dbbcbf0066ef82c789981feff78d95861a836e6e23a22ad3bb698dd257062f75
User & Date: dan 2018-02-23 19:21:19
Context
2018-02-23
21:01
Fix a problem with handling "k >= ?" constraints in the zonefile module. check-in: 9a99afaf user: dan tags: zonefile
19:21
Add test cases and minor fixes for the zonefile module. check-in: dbbcbf00 user: dan tags: zonefile
14:09
Fix a problem causing SQLITE_HAVE_LZ4 builds of zonefile to fail unless SQLITE_HAVE_ZLIB is also defined. check-in: 994aa77d user: dan tags: zonefile
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ext/zonefile/zonefile.c.

342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
...
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
...
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
....
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
....
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622

1623
1624
1625
1626
1627
1628
1629
....
1680
1681
1682
1683
1684
1685
1686

1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
  const char **pzKey              /* OUT: Pointer to key buffer */
){
  if( pGlobal->nHash ){
    ZonefileKey *pKey;
    u32 iHash = zonefileKeyHash(zDb, zTab, iFileid);
    for(pKey=pGlobal->aHash[iHash%pGlobal->nHash]; pKey; pKey=pKey->pHashNext){
      if( pKey->iFileid==iFileid 
       && 0==sqlite3_stricmp(zDb, pKey->zDb)
       && 0==sqlite3_stricmp(zTab, pKey->zName)
      ){
        *pzKey = pKey->zKey;
        return pKey->nKey;
      }
    }
  }

................................................................................
** Return zero if the two SQL values passed as arguments are equal, or
** non-zero otherwise. Values with different types are considered unequal,
** even if they both contain the same numeric value (e.g. 2 and 2.0).
*/
static int zonefileCompareValue(sqlite3_value *p1, sqlite3_value *p2){
  int eType;
  assert( p1 );
  if( p2==0 ) return 1;
  eType = sqlite3_value_type(p1);
  if( sqlite3_value_type(p2)!=eType ) return 1;
  switch( eType ){
    case SQLITE_INTEGER:
      return sqlite3_value_int64(p1)!=sqlite3_value_int64(p2);
    case SQLITE_FLOAT:
      return sqlite3_value_double(p1)!=sqlite3_value_double(p2);
................................................................................
  for(i=0; i<sizeof(a)/sizeof(a[0]); i++){
    if( 0==sqlite3_stricmp(zName, a[i].zName) ){
      *peType = a[i].eType;
      return SQLITE_OK;
    }
  }

  *pzErr = sqlite3_mprintf("unknown encryption type: %s", zName);
  return SQLITE_ERROR;
}

static int zonefileGetParams(
  sqlite3_context *pCtx,          /* Leave any error message here */
  const char *zJson,              /* JSON configuration parameter (or NULL) */
  ZonefileParam *p                /* Populate this object before returning */
................................................................................
  ZonefileCompress *pMethod,      /* Compression method object */
  void *pCmp,                     /* Compression handle */
  ZonefileCodec *pCodec,          /* Compression method, if any */
  ZonefileBuffer *pTo,            /* Append new data here */
  ZonefileBuffer *pFrom           /* Input buffer */
){
  int rc = SQLITE_OK;
  if( pFrom->n ){
    int nNonce = pCodec ? zonefileCodecNonceSize(pCodec) : 0;
    int nOrig = pTo->n;
    if( pMethod->eType==ZONEFILE_COMPRESSION_NONE ){
      if( zonefileBufferGrow(pCtx, pTo, pFrom->n + nNonce) ){
        rc = SQLITE_ERROR;
      }else{
        zonefileAppendBlob(pTo, pFrom->a, pFrom->n);
      }
    }else{
      int nReq = pMethod->xCompressBound(pCmp, pFrom->n);
      if( zonefileBufferGrow(pCtx, pTo, nReq + nNonce) ) return SQLITE_ERROR;
      rc = pMethod->xCompress(pCmp, &pTo->a[pTo->n], &nReq, pFrom->a, pFrom->n);
      pTo->n += nReq;
      if( rc!=SQLITE_OK ){
        return rc;
      }
    }

    /* Encrypt the data just appended to buffer pTo. */
    if( pCodec ){
      zonefileCodecEncode(pCodec, &pTo->a[nOrig], pTo->n - nOrig);
      pTo->n += nNonce;
    }
  }
  return SQLITE_OK;
}

/*
** Append nByte bytes of garbage data to the file opened with pFd. Return
** SQLITE_OK if successful, or SQLITE_ERROR if an error occurs.
**
** Parameter nByte is only ever non-zero when running tests. So it doesn't
................................................................................
  }
  switch( i ){
    case 0: /* filename */
      sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pSelect, 0));
      break;
    case 1: /* ekey */
      break;
    case 2: { /* header */
      const char *zFile = (const char*)sqlite3_column_text(pCsr->pSelect, 0);
      zonefileJsonHeader(ctx, zFile);

      break;
    }
  }
  return SQLITE_OK;
}

/* 
................................................................................
  u8 *aOut = sqlite3_malloc(nOut);

  assert( pMethod->eType!=ZONEFILE_COMPRESSION_NONE );
  if( aOut==0 ){
    rc = SQLITE_NOMEM;
  }else{
    rc = pMethod->xUncompress(pCmp, aOut, nOut, aIn, nIn);

    if( rc ){
      sqlite3_free(aOut);
      aOut = 0;
    }
  }

  *paOut = aOut;
  *pnOut = nOut;
  return rc;
}








|
|







 







<







 







|







 







<
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
|
|
<
|
|
|
|
|
<
|







 







|


>







 







>
|
|
|
<







342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
...
811
812
813
814
815
816
817

818
819
820
821
822
823
824
...
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
....
1032
1033
1034
1035
1036
1037
1038

1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051


1052
1053

1054
1055
1056
1057
1058

1059
1060
1061
1062
1063
1064
1065
1066
....
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
....
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685

1686
1687
1688
1689
1690
1691
1692
  const char **pzKey              /* OUT: Pointer to key buffer */
){
  if( pGlobal->nHash ){
    ZonefileKey *pKey;
    u32 iHash = zonefileKeyHash(zDb, zTab, iFileid);
    for(pKey=pGlobal->aHash[iHash%pGlobal->nHash]; pKey; pKey=pKey->pHashNext){
      if( pKey->iFileid==iFileid 
       && 0==sqlite3_stricmp(zTab, pKey->zName)
       && 0==sqlite3_stricmp(zDb, pKey->zDb)
      ){
        *pzKey = pKey->zKey;
        return pKey->nKey;
      }
    }
  }

................................................................................
** Return zero if the two SQL values passed as arguments are equal, or
** non-zero otherwise. Values with different types are considered unequal,
** even if they both contain the same numeric value (e.g. 2 and 2.0).
*/
static int zonefileCompareValue(sqlite3_value *p1, sqlite3_value *p2){
  int eType;
  assert( p1 );

  eType = sqlite3_value_type(p1);
  if( sqlite3_value_type(p2)!=eType ) return 1;
  switch( eType ){
    case SQLITE_INTEGER:
      return sqlite3_value_int64(p1)!=sqlite3_value_int64(p2);
    case SQLITE_FLOAT:
      return sqlite3_value_double(p1)!=sqlite3_value_double(p2);
................................................................................
  for(i=0; i<sizeof(a)/sizeof(a[0]); i++){
    if( 0==sqlite3_stricmp(zName, a[i].zName) ){
      *peType = a[i].eType;
      return SQLITE_OK;
    }
  }

  *pzErr = sqlite3_mprintf("unknown encryption method: %s", zName);
  return SQLITE_ERROR;
}

static int zonefileGetParams(
  sqlite3_context *pCtx,          /* Leave any error message here */
  const char *zJson,              /* JSON configuration parameter (or NULL) */
  ZonefileParam *p                /* Populate this object before returning */
................................................................................
  ZonefileCompress *pMethod,      /* Compression method object */
  void *pCmp,                     /* Compression handle */
  ZonefileCodec *pCodec,          /* Compression method, if any */
  ZonefileBuffer *pTo,            /* Append new data here */
  ZonefileBuffer *pFrom           /* Input buffer */
){
  int rc = SQLITE_OK;

  int nNonce = pCodec ? zonefileCodecNonceSize(pCodec) : 0;
  int nOrig = pTo->n;
  if( pMethod->eType==ZONEFILE_COMPRESSION_NONE ){
    if( zonefileBufferGrow(pCtx, pTo, pFrom->n + nNonce) ){
      rc = SQLITE_ERROR;
    }else{
      zonefileAppendBlob(pTo, pFrom->a, pFrom->n);
    }
  }else{
    int nReq = pMethod->xCompressBound(pCmp, pFrom->n);
    if( zonefileBufferGrow(pCtx, pTo, nReq + nNonce) ) return SQLITE_ERROR;
    rc = pMethod->xCompress(pCmp, &pTo->a[pTo->n], &nReq, pFrom->a, pFrom->n);
    pTo->n += nReq;


  }


  /* Encrypt the data just appended to buffer pTo. */
  if( rc==SQLITE_OK && pCodec ){
    zonefileCodecEncode(pCodec, &pTo->a[nOrig], pTo->n - nOrig);
    pTo->n += nNonce;
  }

  return rc;
}

/*
** Append nByte bytes of garbage data to the file opened with pFd. Return
** SQLITE_OK if successful, or SQLITE_ERROR if an error occurs.
**
** Parameter nByte is only ever non-zero when running tests. So it doesn't
................................................................................
  }
  switch( i ){
    case 0: /* filename */
      sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pSelect, 0));
      break;
    case 1: /* ekey */
      break;
    default: {
      const char *zFile = (const char*)sqlite3_column_text(pCsr->pSelect, 0);
      zonefileJsonHeader(ctx, zFile);
      assert( i==2 );
      break;
    }
  }
  return SQLITE_OK;
}

/* 
................................................................................
  u8 *aOut = sqlite3_malloc(nOut);

  assert( pMethod->eType!=ZONEFILE_COMPRESSION_NONE );
  if( aOut==0 ){
    rc = SQLITE_NOMEM;
  }else{
    rc = pMethod->xUncompress(pCmp, aOut, nOut, aIn, nIn);
  }
  if( rc ){
    sqlite3_free(aOut);
    aOut = 0;

  }

  *paOut = aOut;
  *pnOut = nOut;
  return rc;
}

Changes to ext/zonefile/zonefile1.test.

105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
...
239
240
241
242
243
244
245




246




247








































































































































































248
249
  do_catchsql_test 2.1 {
    WITH p(n,v) AS (
        VALUES('compressionTypeIndexData', 'zstd_global_dict')
    )
    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
................................................................................
} {0 0 0}

do_execsql_test 3.3 {
  UPDATE cc_files SET ekey = '0123456789';
  SELECT quote(dd.v)==quote(cc.v) FROM cc JOIN dd USING (k)
} {1 1 1}



















































































































































































finish_test








<







 







>
>
>
>

>
>
>
>

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


105
106
107
108
109
110
111

112
113
114
115
116
117
118
...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
  do_catchsql_test 2.1 {
    WITH p(n,v) AS (
        VALUES('compressionTypeIndexData', 'zstd_global_dict')
    )
    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}}
}


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
................................................................................
} {0 0 0}

do_execsql_test 3.3 {
  UPDATE cc_files SET ekey = '0123456789';
  SELECT quote(dd.v)==quote(cc.v) FROM cc JOIN dd USING (k)
} {1 1 1}

close [open test.zonefile w+]
do_catchsql_test 3.4 {
  SELECT header FROM cc_files
} {1 {failed to read header from file: "test.zonefile"}}

forcedelete test.zonefile
do_catchsql_test 3.5 {
  SELECT header FROM cc_files
} {1 {failed to open file "test.zonefile" for reading}}

do_execsql_test 3.6 {
  SELECT ekey FROM cc_files
} {{}}

#-------------------------------------------------------------------------
# Check that a file that uses an unknown compression method is handled
# correctly (an error is returned).
#
reset_db
load_static_extension db zonefile
do_execsql_test 4.0 {
  CREATE TABLE dd(k INTEGER PRIMARY KEY, frame INTEGER, idx INTEGER, v BLOB);
  INSERT INTO dd VALUES(1000, 1, -1, randomblob(44));
  INSERT INTO dd VALUES(1001, 1, -1, randomblob(55));
  INSERT INTO dd VALUES(1002, 2, -1, randomblob(66));
  SELECT zonefile_write('test.zonefile', 'dd');
  CREATE VIRTUAL TABLE x1 USING zonefile;
} {{}}

do_test 4.1 {
  hexio_write test.zonefile 5 77
} {1}
do_execsql_test 4.2 {
  INSERT INTO x1_files(filename) VALUES('test.zonefile');
} {}
do_catchsql_test 4.3 {
  SELECT * FROM x1
} {1 {unsupported compression method: 119}}
do_test 4.4 {
  hexio_write test.zonefile 4 77
} {1}
do_catchsql_test 4.5 {
  DELETE FROM x1_files;
  INSERT INTO x1_files(filename) VALUES('test.zonefile');
} {1 {unsupported compression method: 119}}

do_test 4.6 {
  hexio_write test.zonefile 0 00
} {1}
do_catchsql_test 4.7 {
  INSERT INTO x1_files(filename) VALUES('test.zonefile');
} {1 {failed to read zonefile header from file "test.zonefile"}}

#-------------------------------------------------------------------------
# Test using various types in the "frame" field of an input table.
#
reset_db
load_static_extension db zonefile
if {[lsearch $COMPRESSION_METHODS zlib]>=0} {
  do_execsql_test 5.0 {
    CREATE TABLE "a b"(k INTEGER PRIMARY KEY,frame INTEGER,idx INTEGER,v BLOB);
    INSERT INTO "a b" VALUES(1, 0.5, -1, randomblob(44));
    INSERT INTO "a b" VALUES(2, 0.5, -1, randomblob(55));
    INSERT INTO "a b" VALUES(3, 1.5, -1, randomblob(55));
    INSERT INTO "a b" VALUES(4, 1.5, -1, randomblob(55));
    INSERT INTO "a b" VALUES(5,   2, -1, randomblob(55));
    INSERT INTO "a b" VALUES(6,   2, -1, randomblob(55));
    INSERT INTO "a b" VALUES(7, 200, -1, randomblob(55));
    INSERT INTO "a b" VALUES(8, 200, -1, randomblob(55));
    INSERT INTO "a b" VALUES(9, 300, -1, randomblob(55));
    INSERT INTO "a b" VALUES(10, 300, -1, randomblob(55));
    INSERT INTO "a b" VALUES(11, NULL, -1, randomblob(55));
    INSERT INTO "a b" VALUES(12, NULL, -1, randomblob(55));
    INSERT INTO "a b" VALUES(13, 'f1', -1, randomblob(55));
    INSERT INTO "a b" VALUES(14, 'f1', -1, randomblob(55));
    INSERT INTO "a b" VALUES(15, 'frame2', -1, randomblob(55));
    INSERT INTO "a b" VALUES(16, 'frame2', -1, randomblob(55));
    INSERT INTO "a b" VALUES(17, x'1234', -1, randomblob(55));
    INSERT INTO "a b" VALUES(18, x'1234', -1, randomblob(55));
    INSERT INTO "a b" VALUES(19, x'abcd', -1, randomblob(55));
    INSERT INTO "a b" VALUES(20, x'abcd', -1, randomblob(55));
  
    SELECT zonefile_write('test.zonefile', 'a b',
      '{"compressionTypeContent":"zlib"}'
    );
  } {{}}

  do_execsql_test 5.1 {
    CREATE VIRTUAL TABLE abc USING zonefile; 
    INSERT INTO abc_files(filename) VALUES('test.zonefile');
    SELECT group_concat(k) FROM abc_shadow_idx GROUP BY fofst
  } {
    11,12   1,2   3,4   5,6   7,8  
     9,10  13,14 15,16 17,18 19,20
  }
}

do_execsql_test 6.0 {
  CREATE TABLE "ab"(k INTEGER PRIMARY KEY,frame INTEGER,idx INTEGER,v BLOB);
  INSERT INTO "ab" VALUES(1, 0.5, -1, randomblob(44));
  INSERT INTO "ab" VALUES(2, 0.5, -1, randomblob(55));
  INSERT INTO "ab" VALUES(3, 1.5, -1, randomblob(55));
  INSERT INTO "ab" VALUES(4, 1.5, -1, randomblob(55));
}
do_catchsql_test 6.1.1 {
  SELECT zonefile_write('test.zonefile', 'ab',
      '{"debugExtendedHeaderSize":-1}'
  );
} {1 {debugExtendedHeaderSize value out of range: -1}}
do_catchsql_test 6.1.2 {
  SELECT zonefile_write('test.zonefile', 'ab',
      '{"debugExtendedHeaderSize":256}'
  );
} {1 {debugExtendedHeaderSize value out of range: 256}}

do_catchsql_test 6.2 {
  SELECT zonefile_write('test.zonefile', 'ab',
      '{"unknown":256}'
  );
} {1 {unknown parameter name: "unknown"}}

forcedelete test.dir
file mkdir test.dir
do_catchsql_test 6.3 {
  SELECT zonefile_write('test.dir', 'ab');
} {1 {failed to open file "test.dir" for writing}}

do_catchsql_test 6.4 {
  CREATE VIRTUAL TABLE zzz USING zonefile;
  INSERT INTO zzz_files(filename) VALUES('nosuchfile.zonefile');
} {1 {failed to open file "nosuchfile.zonefile" for reading}}

do_catchsql_test 6.4 {
  INSERT INTO zzz_files(filename) VALUES('test.dir');
} {1 {failed to read zonefile header from file "test.dir"}}

#-------------------------------------------------------------------------
# Check that errors generated when building a dictionary are handled.
# The zstd library routines for building a dictionary throw an error
# if they are provided with too little data.
#
# Also test that zstd_global_dict cannot be used to compress the zonefile
# index (as there is nowhere in the file format to store the dictionary
# for this compression).
#
reset_db
load_static_extension db zonefile
if {[lsearch $COMPRESSION_METHODS zstd_global_dict]>=0} {
  do_execsql_test 7.0 {
    CREATE TABLE "ab"(k INTEGER PRIMARY KEY,frame INTEGER,idx INTEGER,v BLOB);
    INSERT INTO "ab" VALUES(1, -1, -1, 'abc');
  }

  do_catchsql_test 7.1 {
    SELECT zonefile_write('test.zonefile', 'ab',
      '{"compressionTypeContent":"zstd_global_dict"}'
    );
  } {1 {error generating dictionary}}

  do_catchsql_test 7.2 {
    SELECT zonefile_write('test.zonefile', 'ab',
      '{"compressionTypeIndexData":"zstd_global_dict"}'
    );
  } {1 {compressor "zstd_global_dict" may not be used to compress the zonefile index}}
}

#-------------------------------------------------------------------------
#
reset_db
load_static_extension db zonefile
do_catchsql_test 8.1 {
  CREATE VIRTUAL TABLE one USING zonefile_files;
} {1 {do not create zonefile_files tables directly!}}
do_catchsql_test 8.2 {
  CREATE VIRTUAL TABLE onetwothree USING zonefile_files;
} {1 {do not create zonefile_files tables directly!}}


finish_test

Changes to ext/zonefile/zonefileenc.test.

48
49
50
51
52
53
54



55
56
57
58
59
60

61


62
63
64




65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
...
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131






































































































132
133
      SELECT zonefile_write('test' || $i || '.zonefile', 'zz', 
        json_group_object(n, v)
      ) FROM p;
    }
  }
} {}




do_test 1.2 {
  execsql {
    CREATE VIRTUAL TABLE gg USING zonefile;
  }
  for {set i 0} {$i < $nFile} {incr i} {
    execsql { 

      INSERT INTO gg_files(filename) VALUES('test' || $i || '.zonefile')


    }
  }
} {}





do_catchsql_test 1.3 {
  SELECT count(*) FROM rr JOIN gg USING(k) WHERE rr.v!=gg.v;
} {1 {missing encryption key for file "test0.zonefile"}}
do_execsql_test 1.4 {
  UPDATE gg_files SET ekey = 'braking' WHERE filename='test0.zonefile';
}
do_catchsql_test 1.5 {
  SELECT count(*) FROM rr JOIN gg USING(k) WHERE rr.v!=gg.v;
} {1 {missing encryption key for file "test1.zonefile"}}

proc k {i} {
  lindex $::K [expr $i % [llength $::K]]
}
db func k k
do_execsql_test 1.6 {
  UPDATE gg_files SET ekey = k(rowid-1);
}
do_execsql_test 1.7 {
  SELECT count(*) FROM rr JOIN gg USING(k) WHERE rr.v!=gg.v;
} {0}
do_execsql_test 1.8 {
................................................................................
}
foreach {tn alg id} {
  1 aes_128_ctr 1
  2 aes_128_cbc 2
  3 AES_256_CTR 3
  4 Aes_256_CBC 4
} {
  do_catchsql_test 2.$tn {
    WITH p(n,v) AS (
        VALUES('encryptionType', $alg) UNION ALL
        VALUES('encryptionKey', 'secret')
    )
    SELECT zonefile_write('test' || $i || '.zonefile', 'zz', 
          json_group_object(n, v)
    ) FROM p;
  } "1 {unsupported encryption method: $id}"
}







































































































finish_test








>
>
>
|
<
|
|
|
|
>
|
>
>
|
|
<
>
>
>
>











<
<
<
<







 







|










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


48
49
50
51
52
53
54
55
56
57
58

59
60
61
62
63
64
65
66
67
68

69
70
71
72
73
74
75
76
77
78
79
80
81
82
83




84
85
86
87
88
89
90
...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
      SELECT zonefile_write('test' || $i || '.zonefile', 'zz', 
        json_group_object(n, v)
      ) FROM p;
    }
  }
} {}

proc k {i} { lindex $::K [expr $i % [llength $::K]] }
db func k k

do_execsql_test 1.2 {

  CREATE VIRTUAL TABLE gg USING zonefile;
}
for {set i 0} {$i < $nFile} {incr i} {
  do_execsql_test 1.2.$i { 
    INSERT INTO gg_files(filename, ekey) 
    VALUES('test' || $i || '.zonefile', k($i));
    SELECT count(*) FROM rr JOIN gg USING(k) WHERE rr.v!=gg.v;
  } 0
}


db close
sqlite3 db test.db
load_static_extension db zonefile
db func k k

do_catchsql_test 1.3 {
  SELECT count(*) FROM rr JOIN gg USING(k) WHERE rr.v!=gg.v;
} {1 {missing encryption key for file "test0.zonefile"}}
do_execsql_test 1.4 {
  UPDATE gg_files SET ekey = 'braking' WHERE filename='test0.zonefile';
}
do_catchsql_test 1.5 {
  SELECT count(*) FROM rr JOIN gg USING(k) WHERE rr.v!=gg.v;
} {1 {missing encryption key for file "test1.zonefile"}}





do_execsql_test 1.6 {
  UPDATE gg_files SET ekey = k(rowid-1);
}
do_execsql_test 1.7 {
  SELECT count(*) FROM rr JOIN gg USING(k) WHERE rr.v!=gg.v;
} {0}
do_execsql_test 1.8 {
................................................................................
}
foreach {tn alg id} {
  1 aes_128_ctr 1
  2 aes_128_cbc 2
  3 AES_256_CTR 3
  4 Aes_256_CBC 4
} {
  do_catchsql_test 2.1.$tn {
    WITH p(n,v) AS (
        VALUES('encryptionType', $alg) UNION ALL
        VALUES('encryptionKey', 'secret')
    )
    SELECT zonefile_write('test' || $i || '.zonefile', 'zz', 
          json_group_object(n, v)
    ) FROM p;
  } "1 {unsupported encryption method: $id}"
}

foreach {tn alg} {
  1 nosuchmethod! 
} {
  do_catchsql_test 2.1.$tn {
    WITH p(n,v) AS (
        VALUES('encryptionType', $alg) UNION ALL
        VALUES('encryptionKey', 'secret')
    )
    SELECT zonefile_write('test' || $i || '.zonefile', 'zz', 
          json_group_object(n, v)
    ) FROM p;
  } "1 {unknown encryption method: $alg}"
}

#-------------------------------------------------------------------------
# Test some hash collisions in the encryption key table.
#

# This is the same hash function used internally to store keys.
#
proc hash {zDb zTab iFile} {
  binary scan $zDb c*  A
  binary scan $zTab c* B
  set h 0
  foreach i $A { set h [expr ($h + ($h << 3) + $i) & 0xFFFFFFFF] }
  foreach i $B { set h [expr ($h + ($h << 3) + $i) & 0xFFFFFFFF] }
  return [expr $h ^ $iFile]
}

do_test 3.0 {
  set h1 [expr [hash main zone 1] % 512]
  for {set i 0} {1} {incr i} {
    set h2 [expr [hash "aux$i" zone 1] % 512]
    if {$h1==$h2} break
  }
  set i
} 52

reset_db
load_static_extension db zonefile
forcedelete test.db2

do_execsql_test 3.1 {
  CREATE TABLE zz(k INTEGER PRIMARY KEY, frame INTEGER, idx INTEGER, v BLOB);
  INSERT INTO zz VALUES(222, -1, -1, randomblob(60));
  WITH p(n,v) AS (
      VALUES('encryptionType', 'xor') UNION ALL
      VALUES('encryptionKey', 'pass')
  )
  SELECT zonefile_write('test1.zonefile', 'zz', 
      json_group_object(n, v)
  ) FROM p;

  DELETE FROM zz;
  INSERT INTO zz VALUES(333, -1, -1, randomblob(80));
  WITH p(n,v) AS (
      VALUES('encryptionType', 'xor') UNION ALL
      VALUES('encryptionKey', 'pass')
  )
  SELECT zonefile_write('test2.zonefile', 'zz', 
      json_group_object(n, v)
  ) FROM p;
} {{} {}}

do_execsql_test 3.2 {
  ATTACH 'test.db2' AS aux52;
  CREATE VIRTUAL TABLE main.zone USING zonefile;
  CREATE VIRTUAL TABLE aux52.zone USING zonefile;
  INSERT INTO main.zone_files(filename, ekey) VALUES('test1.zonefile', 'pass');
  INSERT INTO aux52.zone_files(filename, ekey) VALUES('test2.zonefile', 'pass');
}

do_execsql_test 3.3 {
  SELECT v IS NULL FROM main.zone;
  SELECT v IS NULL FROM aux52.zone;
} {0 0}

do_test 3.4 {
  set h1 [expr [hash main zone 1] % 512]
  for {set i 0} {1} {incr i} {
    set h2 [expr [hash "aux$i" zone 2] % 512]
    if {$h1==$h2} break
  }
  set i
} 682

forcedelete test.db3
do_execsql_test 3.5 {
  ATTACH 'test.db3' AS aux682;
  CREATE VIRTUAL TABLE aux682.zone USING zonefile;
  INSERT INTO aux682.zone_files(filename, ekey) VALUES('test1.zonefile','pass');
  INSERT INTO aux682.zone_files(filename, ekey) VALUES('test2.zonefile','pass');
  INSERT INTO main.zone_files(filename, ekey) VALUES('test2.zonefile','pass');
}

do_execsql_test 3.6 {
  SELECT v IS NULL FROM main.zone;
  SELECT v IS NULL FROM aux682.zone;
  SELECT v IS NULL FROM main.zone;
} {0 0 0 0 0 0}


finish_test

Changes to ext/zonefile/zonefilefault.test.

58
59
60
61
62
63
64


















































65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82










83
84
85
      );
    }
  } -test {
    faultsim_test_result {0 {{}}}
  }
}



















































do_execsql_test 2.0 {
  SELECT zonefile_write('test.zonefile', 'tt',
      '{"encryptionType":"xor", "encryptionKey":"secret"}'
  );
  CREATE VIRTUAL TABLE zz USING zonefile;
} {{}}

faultsim_save_and_close
do_faultsim_test 2 -faults oom* -prep {
  faultsim_restore_and_reopen
  load_static_extension db zonefile
} -body {
  execsql {
    INSERT INTO zz_files(filename, ekey) VALUES('test.zonefile', 'secret')
  }
} -test {
  faultsim_test_result {0 {}}
}











finish_test








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








|









>
>
>
>
>
>
>
>
>
>



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
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
141
142
143
144
145
      );
    }
  } -test {
    faultsim_test_result {0 {{}}}
  }
}

do_execsql_test 1.3.0 { UPDATE tt SET frame = NULL; }
do_faultsim_test 1.3 -faults oom* -prep {
  sqlite3 db test.db
  load_static_extension db zonefile
} -body {
  execsql {
    SELECT zonefile_write('test.zonefile', 'tt');
  }
} -test {
  faultsim_test_result {0 {{}}}
}

do_execsql_test 1.4.0 {
  INSERT INTO tt VALUES(5, -1, -1, randomblob(100));
  INSERT INTO tt VALUES(6, -1, -1, randomblob(100));
  INSERT INTO tt VALUES(7, -1, -1, randomblob(100));
  INSERT INTO tt VALUES(8, -1, -1, randomblob(100));
  INSERT INTO tt VALUES(9, -1, -1, randomblob(100));
  CREATE VIRTUAL TABLE ttz USING zonefile;
}
if {[catch { db eval $sql }]==0} {
  faultsim_save_and_close
  do_faultsim_test 1.4 -faults oom* -prep {
    faultsim_restore_and_reopen
    load_static_extension db zonefile
  } -body {
    execsql {
      SELECT zonefile_write('test.zonefile', 'tt',
          '{"compressionTypeIndexData":"zstd"}'
      );
    }
  } -test {
    faultsim_test_result {0 {{}}}
  }

  faultsim_save_and_close
  do_faultsim_test 1.5 -faults oom* -prep {
    faultsim_restore_and_reopen
    load_static_extension db zonefile
  } -body {
    execsql {
      INSERT INTO ttz_files(filename) VALUES('test.zonefile');
    }
  } -test {
    faultsim_test_result {0 {}}
  }
}

#-------------------------------------------------------------------------
#
do_execsql_test 2.0 {
  SELECT zonefile_write('test.zonefile', 'tt',
      '{"encryptionType":"xor", "encryptionKey":"secret"}'
  );
  CREATE VIRTUAL TABLE zz USING zonefile;
} {{}}

faultsim_save_and_close
do_faultsim_test 2.1 -faults oom* -prep {
  faultsim_restore_and_reopen
  load_static_extension db zonefile
} -body {
  execsql {
    INSERT INTO zz_files(filename, ekey) VALUES('test.zonefile', 'secret')
  }
} -test {
  faultsim_test_result {0 {}}
}

faultsim_save_and_close
do_faultsim_test 2.2 -faults oom* -prep {
  faultsim_restore_and_reopen
  load_static_extension db zonefile
} -body {
  execsql { SELECT json_extract(header, '$.magicNumber') FROM zz_files }
} -test {
  faultsim_test_result {0 1179332920}
}

finish_test