aboutsummaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/fts3/fts3Int.h2
-rw-r--r--ext/fts5/fts5Int.h3
-rw-r--r--ext/fts5/fts5_index.c175
-rw-r--r--ext/fts5/fts5_main.c3
-rw-r--r--ext/fts5/fts5_storage.c23
-rw-r--r--ext/fts5/test/fts5aa.test2
-rw-r--r--ext/fts5/test/fts5corrupt.test7
-rw-r--r--ext/fts5/test/fts5corrupt2.test12
-rw-r--r--ext/fts5/test/fts5corrupt3.test297
-rw-r--r--ext/fts5/test/fts5corrupt5.test8
-rw-r--r--ext/fts5/test/fts5corrupt7.test2
-rw-r--r--ext/fts5/test/fts5corrupt8.test2
-rw-r--r--ext/fts5/test/fts5faultI.test20
-rw-r--r--ext/fts5/test/fts5integrity.test6
-rw-r--r--ext/fts5/test/fts5rebuild.test2
-rw-r--r--ext/fts5/test/fts5unicode4.test30
-rw-r--r--ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java4
-rw-r--r--ext/misc/fileio.c147
-rw-r--r--ext/misc/vtablog.c59
-rw-r--r--ext/misc/windirent.h163
-rw-r--r--ext/rtree/rtree.c6
-rw-r--r--ext/session/sessionchange.test16
-rw-r--r--ext/session/sqlite3session.c22
-rw-r--r--ext/session/test_session.c30
-rw-r--r--ext/wasm/GNUmakefile11
-rw-r--r--ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-extras31
-rw-r--r--ext/wasm/api/sqlite3-api-glue.c-pp.js9
-rw-r--r--ext/wasm/api/sqlite3-api-oo1.c-pp.js400
-rw-r--r--ext/wasm/api/sqlite3-api-prologue.js17
-rw-r--r--ext/wasm/api/sqlite3-wasm.c7
-rw-r--r--ext/wasm/fiddle.make3
-rw-r--r--ext/wasm/mkwasmbuilds.c2
-rw-r--r--ext/wasm/speedtest1-worker.html2
-rw-r--r--ext/wasm/speedtest1.html2
-rw-r--r--ext/wasm/tester1.c-pp.js288
35 files changed, 1408 insertions, 405 deletions
diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h
index d438549de..bd4666253 100644
--- a/ext/fts3/fts3Int.h
+++ b/ext/fts3/fts3Int.h
@@ -213,7 +213,7 @@ typedef sqlite3_int64 i64; /* 8-byte signed integer */
** Macros needed to provide flexible arrays in a portable way
*/
#ifndef offsetof
-# define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD))
+# define offsetof(ST,M) ((size_t)((char*)&((ST*)0)->M - (char*)0))
#endif
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
# define FLEXARRAY
diff --git a/ext/fts5/fts5Int.h b/ext/fts5/fts5Int.h
index 2da347862..dbab6546c 100644
--- a/ext/fts5/fts5Int.h
+++ b/ext/fts5/fts5Int.h
@@ -20,6 +20,7 @@ SQLITE_EXTENSION_INIT1
#include <string.h>
#include <assert.h>
+#include <stddef.h>
#ifndef SQLITE_AMALGAMATION
@@ -79,7 +80,7 @@ typedef sqlite3_uint64 u64;
** Macros needed to provide flexible arrays in a portable way
*/
#ifndef offsetof
-# define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD))
+# define offsetof(ST,M) ((size_t)((char*)&((ST*)0)->M - (char*)0))
#endif
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
# define FLEXARRAY
diff --git a/ext/fts5/fts5_index.c b/ext/fts5/fts5_index.c
index 63840de1f..7036e57f5 100644
--- a/ext/fts5/fts5_index.c
+++ b/ext/fts5/fts5_index.c
@@ -554,6 +554,36 @@ struct Fts5SegIter {
u8 bDel; /* True if the delete flag is set */
};
+static int fts5IndexCorruptRowid(Fts5Index *pIdx, i64 iRowid){
+ pIdx->rc = FTS5_CORRUPT;
+ sqlite3Fts5ConfigErrmsg(pIdx->pConfig,
+ "fts5: corruption found reading blob %lld from table \"%s\"",
+ iRowid, pIdx->pConfig->zName
+ );
+ return SQLITE_CORRUPT_VTAB;
+}
+#define FTS5_CORRUPT_ROWID(pIdx, iRowid) fts5IndexCorruptRowid(pIdx, iRowid)
+
+static int fts5IndexCorruptIter(Fts5Index *pIdx, Fts5SegIter *pIter){
+ pIdx->rc = FTS5_CORRUPT;
+ sqlite3Fts5ConfigErrmsg(pIdx->pConfig,
+ "fts5: corruption on page %d, segment %d, table \"%s\"",
+ pIter->iLeafPgno, pIter->pSeg->iSegid, pIdx->pConfig->zName
+ );
+ return SQLITE_CORRUPT_VTAB;
+}
+#define FTS5_CORRUPT_ITER(pIdx, pIter) fts5IndexCorruptIter(pIdx, pIter)
+
+static int fts5IndexCorruptIdx(Fts5Index *pIdx){
+ pIdx->rc = FTS5_CORRUPT;
+ sqlite3Fts5ConfigErrmsg(pIdx->pConfig,
+ "fts5: corruption in table \"%s\"", pIdx->pConfig->zName
+ );
+ return SQLITE_CORRUPT_VTAB;
+}
+#define FTS5_CORRUPT_IDX(pIdx) fts5IndexCorruptIdx(pIdx)
+
+
/*
** Array of tombstone pages. Reference counted.
*/
@@ -843,7 +873,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
** All the reasons those functions might return SQLITE_ERROR - missing
** table, missing row, non-blob/text in block column - indicate
** backing store corruption. */
- if( rc==SQLITE_ERROR ) rc = FTS5_CORRUPT;
+ if( rc==SQLITE_ERROR ) rc = FTS5_CORRUPT_ROWID(p, iRowid);
if( rc==SQLITE_OK ){
u8 *aOut = 0; /* Read blob data into this buffer */
@@ -893,7 +923,7 @@ static Fts5Data *fts5LeafRead(Fts5Index *p, i64 iRowid){
Fts5Data *pRet = fts5DataRead(p, iRowid);
if( pRet ){
if( pRet->nn<4 || pRet->szLeaf>pRet->nn ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_ROWID(p, iRowid);
fts5DataRelease(pRet);
pRet = 0;
}
@@ -1252,8 +1282,14 @@ static Fts5Structure *fts5StructureReadUncached(Fts5Index *p){
/* TODO: Do we need this if the leaf-index is appended? Probably... */
memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING);
p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet);
- if( p->rc==SQLITE_OK && (pConfig->pgsz==0 || pConfig->iCookie!=iCookie) ){
- p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie);
+ if( p->rc==SQLITE_OK ){
+ if( (pConfig->pgsz==0 || pConfig->iCookie!=iCookie) ){
+ p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie);
+ }
+ }else if( p->rc==SQLITE_CORRUPT_VTAB ){
+ sqlite3Fts5ConfigErrmsg(p->pConfig,
+ "fts5: corrupt structure record for table \"%s\"", p->pConfig->zName
+ );
}
fts5DataRelease(pData);
if( p->rc!=SQLITE_OK ){
@@ -1876,7 +1912,7 @@ static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){
while( iOff>=pIter->pLeaf->szLeaf ){
fts5SegIterNextPage(p, pIter);
if( pIter->pLeaf==0 ){
- if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT;
+ if( p->rc==SQLITE_OK ) FTS5_CORRUPT_ITER(p, pIter);
return;
}
iOff = 4;
@@ -1908,7 +1944,7 @@ static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){
iOff += fts5GetVarint32(&a[iOff], nNew);
if( iOff+nNew>pIter->pLeaf->szLeaf || nKeep>pIter->term.n || nNew==0 ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_ITER(p, pIter);
return;
}
pIter->term.n = nKeep;
@@ -2103,7 +2139,7 @@ static void fts5SegIterReverseNewPage(Fts5Index *p, Fts5SegIter *pIter){
iRowidOff = fts5LeafFirstRowidOff(pNew);
if( iRowidOff ){
if( iRowidOff>=pNew->szLeaf ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_ITER(p, pIter);
}else{
pIter->pLeaf = pNew;
pIter->iLeafOffset = iRowidOff;
@@ -2337,7 +2373,7 @@ static void fts5SegIterNext(
}
assert_nc( iOff<pLeaf->szLeaf );
if( iOff>pLeaf->szLeaf ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_ITER(p, pIter);
return;
}
}
@@ -2445,18 +2481,20 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){
fts5DataRelease(pIter->pLeaf);
pIter->pLeaf = pLast;
pIter->iLeafPgno = pgnoLast;
- iOff = fts5LeafFirstRowidOff(pLast);
- if( iOff>pLast->szLeaf ){
- p->rc = FTS5_CORRUPT;
- return;
- }
- iOff += fts5GetVarint(&pLast->p[iOff], (u64*)&pIter->iRowid);
- pIter->iLeafOffset = iOff;
+ if( p->rc==SQLITE_OK ){
+ iOff = fts5LeafFirstRowidOff(pLast);
+ if( iOff>pLast->szLeaf ){
+ FTS5_CORRUPT_ITER(p, pIter);
+ return;
+ }
+ iOff += fts5GetVarint(&pLast->p[iOff], (u64*)&pIter->iRowid);
+ pIter->iLeafOffset = iOff;
- if( fts5LeafIsTermless(pLast) ){
- pIter->iEndofDoclist = pLast->nn+1;
- }else{
- pIter->iEndofDoclist = fts5LeafFirstTermOff(pLast);
+ if( fts5LeafIsTermless(pLast) ){
+ pIter->iEndofDoclist = pLast->nn+1;
+ }else{
+ pIter->iEndofDoclist = fts5LeafFirstTermOff(pLast);
+ }
}
}
@@ -2526,7 +2564,7 @@ static void fts5LeafSeek(
iPgidx += fts5GetVarint32(&a[iPgidx], iTermOff);
iOff = iTermOff;
if( iOff>n ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_ITER(p, pIter);
return;
}
@@ -2569,7 +2607,7 @@ static void fts5LeafSeek(
iOff = iTermOff;
if( iOff>=n ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_ITER(p, pIter);
return;
}
@@ -2591,7 +2629,7 @@ static void fts5LeafSeek(
iPgidx = (u32)pIter->pLeaf->szLeaf;
iPgidx += fts5GetVarint32(&pIter->pLeaf->p[iPgidx], iOff);
if( iOff<4 || (i64)iOff>=pIter->pLeaf->szLeaf ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_ITER(p, pIter);
return;
}else{
nKeep = 0;
@@ -2606,7 +2644,7 @@ static void fts5LeafSeek(
search_success:
if( (i64)iOff+nNew>n || nNew<1 ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_ITER(p, pIter);
return;
}
pIter->iLeafOffset = iOff + nNew;
@@ -3071,7 +3109,7 @@ static void fts5SegIterGotoPage(
assert( iLeafPgno>pIter->iLeafPgno );
if( iLeafPgno>pIter->pSeg->pgnoLast ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_IDX(p);
}else{
fts5DataRelease(pIter->pNextLeaf);
pIter->pNextLeaf = 0;
@@ -3086,7 +3124,7 @@ static void fts5SegIterGotoPage(
u8 *a = pIter->pLeaf->p;
int n = pIter->pLeaf->szLeaf;
if( iOff<4 || iOff>=n ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_IDX(p);
}else{
iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid);
pIter->iLeafOffset = iOff;
@@ -3565,7 +3603,7 @@ static void fts5ChunkIterate(
if( nRem<=0 ){
break;
}else if( pSeg->pSeg==0 ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_IDX(p);
return;
}else{
pgno++;
@@ -4668,7 +4706,7 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){
** a single page has been assigned to more than one segment. In
** this case a prior iteration of this loop may have corrupted the
** segment currently being trimmed. */
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_ROWID(p, iLeafRowid);
}else{
fts5BufferZero(&buf);
fts5BufferGrow(&p->rc, &buf, pData->nn);
@@ -5135,7 +5173,7 @@ static void fts5SecureDeleteOverflow(
}else if( bDetailNone ){
break;
}else if( iNext>=pLeaf->szLeaf || pLeaf->nn<pLeaf->szLeaf || iNext<4 ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_ROWID(p, iRowid);
break;
}else{
int nShift = iNext - 4;
@@ -5155,7 +5193,7 @@ static void fts5SecureDeleteOverflow(
i1 += fts5GetVarint32(&aPg[i1], iFirst);
if( iFirst<iNext ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_ROWID(p, iRowid);
break;
}
aIdx = sqlite3Fts5MallocZero(&p->rc, (pLeaf->nn-pLeaf->szLeaf)+2);
@@ -5378,14 +5416,14 @@ static void fts5DoSecureDelete(
nSuffix = (nPrefix2 + nSuffix2) - nPrefix;
if( (iKeyOff+nSuffix)>iPgIdx || (iNextOff+nSuffix2)>iPgIdx ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_IDX(p);
}else{
if( iKey!=1 ){
iOff += sqlite3Fts5PutVarint(&aPg[iOff], nPrefix);
}
iOff += sqlite3Fts5PutVarint(&aPg[iOff], nSuffix);
if( nPrefix2>pSeg->term.n ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_IDX(p);
}else if( nPrefix2>nPrefix ){
memcpy(&aPg[iOff], &pSeg->term.p[nPrefix], nPrefix2-nPrefix);
iOff += (nPrefix2-nPrefix);
@@ -5809,7 +5847,7 @@ static Fts5Structure *fts5IndexOptimizeStruct(
}
nByte += (((i64)pStruct->nLevel)+1) * sizeof(Fts5StructureLevel);
- assert( nByte==SZ_FTS5STRUCTURE(pStruct->nLevel+2) );
+ assert( nByte==(i64)SZ_FTS5STRUCTURE(pStruct->nLevel+2) );
pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte);
if( pNew ){
@@ -6178,7 +6216,7 @@ static void fts5MergePrefixLists(
}
if( pHead==0 || pHead->pNext==0 ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_IDX(p);
break;
}
@@ -6215,7 +6253,7 @@ static void fts5MergePrefixLists(
assert_nc( tmp.n+nTail<=nTmp );
assert( tmp.n+nTail<=nTmp+nMerge*10 );
if( tmp.n+nTail>nTmp-FTS5_DATA_ZERO_PADDING ){
- if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT;
+ if( p->rc==SQLITE_OK ) FTS5_CORRUPT_IDX(p);
break;
}
fts5BufferSafeAppendVarint(&out, (tmp.n+nTail) * 2);
@@ -8248,19 +8286,27 @@ static int fts5TestUtf8(const char *z, int n){
/*
** This function is also purely an internal test. It does not contribute to
** FTS functionality, or even the integrity-check, in any way.
+**
+** This function sets output variable (*pbFail) to true if the test fails. Or
+** leaves it unchanged if the test succeeds.
*/
static void fts5TestTerm(
Fts5Index *p,
Fts5Buffer *pPrev, /* Previous term */
const char *z, int n, /* Possibly new term to test */
u64 expected,
- u64 *pCksum
+ u64 *pCksum,
+ int *pbFail
){
int rc = p->rc;
if( pPrev->n==0 ){
fts5BufferSet(&rc, pPrev, n, (const u8*)z);
}else
- if( rc==SQLITE_OK && (pPrev->n!=n || memcmp(pPrev->p, z, n)) ){
+ if( *pbFail==0
+ && rc==SQLITE_OK
+ && (pPrev->n!=n || memcmp(pPrev->p, z, n))
+ && (p->pHash==0 || p->pHash->nEntry==0)
+ ){
u64 cksum3 = *pCksum;
const char *zTerm = (const char*)&pPrev->p[1]; /* term sans prefix-byte */
int nTerm = pPrev->n-1; /* Size of zTerm in bytes */
@@ -8310,7 +8356,7 @@ static void fts5TestTerm(
fts5BufferSet(&rc, pPrev, n, (const u8*)z);
if( rc==SQLITE_OK && cksum3!=expected ){
- rc = FTS5_CORRUPT;
+ *pbFail = 1;
}
*pCksum = cksum3;
}
@@ -8319,7 +8365,7 @@ static void fts5TestTerm(
#else
# define fts5TestDlidxReverse(x,y,z)
-# define fts5TestTerm(u,v,w,x,y,z)
+# define fts5TestTerm(t,u,v,w,x,y,z)
#endif
/*
@@ -8344,14 +8390,17 @@ static void fts5IndexIntegrityCheckEmpty(
for(i=iFirst; p->rc==SQLITE_OK && i<=iLast; i++){
Fts5Data *pLeaf = fts5DataRead(p, FTS5_SEGMENT_ROWID(pSeg->iSegid, i));
if( pLeaf ){
- if( !fts5LeafIsTermless(pLeaf) ) p->rc = FTS5_CORRUPT;
- if( i>=iNoRowid && 0!=fts5LeafFirstRowidOff(pLeaf) ) p->rc = FTS5_CORRUPT;
+ if( !fts5LeafIsTermless(pLeaf)
+ || (i>=iNoRowid && 0!=fts5LeafFirstRowidOff(pLeaf))
+ ){
+ FTS5_CORRUPT_ROWID(p, FTS5_SEGMENT_ROWID(pSeg->iSegid, i));
+ }
}
fts5DataRelease(pLeaf);
}
}
-static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){
+static void fts5IntegrityCheckPgidx(Fts5Index *p, i64 iRowid, Fts5Data *pLeaf){
i64 iTermOff = 0;
int ii;
@@ -8369,12 +8418,12 @@ static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){
iOff = iTermOff;
if( iOff>=pLeaf->szLeaf ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_ROWID(p, iRowid);
}else if( iTermOff==nIncr ){
int nByte;
iOff += fts5GetVarint32(&pLeaf->p[iOff], nByte);
if( (iOff+nByte)>pLeaf->szLeaf ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_ROWID(p, iRowid);
}else{
fts5BufferSet(&p->rc, &buf1, nByte, &pLeaf->p[iOff]);
}
@@ -8383,7 +8432,7 @@ static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){
iOff += fts5GetVarint32(&pLeaf->p[iOff], nKeep);
iOff += fts5GetVarint32(&pLeaf->p[iOff], nByte);
if( nKeep>buf1.n || (iOff+nByte)>pLeaf->szLeaf ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_ROWID(p, iRowid);
}else{
buf1.n = nKeep;
fts5BufferAppendBlob(&p->rc, &buf1, nByte, &pLeaf->p[iOff]);
@@ -8391,7 +8440,7 @@ static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){
if( p->rc==SQLITE_OK ){
res = fts5BufferCompare(&buf1, &buf2);
- if( res<=0 ) p->rc = FTS5_CORRUPT;
+ if( res<=0 ) FTS5_CORRUPT_ROWID(p, iRowid);
}
}
fts5BufferSet(&p->rc, &buf2, buf1.n, buf1.p);
@@ -8452,7 +8501,7 @@ static void fts5IndexIntegrityCheckSegment(
** entry even if all the terms are removed from it by secure-delete
** operations. */
}else{
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_ROWID(p, iRow);
}
}else{
@@ -8464,15 +8513,15 @@ static void fts5IndexIntegrityCheckSegment(
iOff = fts5LeafFirstTermOff(pLeaf);
iRowidOff = fts5LeafFirstRowidOff(pLeaf);
if( iRowidOff>=iOff || iOff>=pLeaf->szLeaf ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_ROWID(p, iRow);
}else{
iOff += fts5GetVarint32(&pLeaf->p[iOff], nTerm);
res = fts5Memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm));
if( res==0 ) res = nTerm - nIdxTerm;
- if( res<0 ) p->rc = FTS5_CORRUPT;
+ if( res<0 ) FTS5_CORRUPT_ROWID(p, iRow);
}
- fts5IntegrityCheckPgidx(p, pLeaf);
+ fts5IntegrityCheckPgidx(p, iRow, pLeaf);
}
fts5DataRelease(pLeaf);
if( p->rc ) break;
@@ -8502,7 +8551,7 @@ static void fts5IndexIntegrityCheckSegment(
iKey = FTS5_SEGMENT_ROWID(iSegid, iPg);
pLeaf = fts5DataRead(p, iKey);
if( pLeaf ){
- if( fts5LeafFirstRowidOff(pLeaf)!=0 ) p->rc = FTS5_CORRUPT;
+ if( fts5LeafFirstRowidOff(pLeaf)!=0 ) FTS5_CORRUPT_ROWID(p, iKey);
fts5DataRelease(pLeaf);
}
}
@@ -8517,12 +8566,12 @@ static void fts5IndexIntegrityCheckSegment(
int iRowidOff = fts5LeafFirstRowidOff(pLeaf);
ASSERT_SZLEAF_OK(pLeaf);
if( iRowidOff>=pLeaf->szLeaf ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_ROWID(p, iKey);
}else if( bSecureDelete==0 || iRowidOff>0 ){
i64 iDlRowid = fts5DlidxIterRowid(pDlidx);
fts5GetVarint(&pLeaf->p[iRowidOff], (u64*)&iRowid);
if( iRowid<iDlRowid || (bSecureDelete==0 && iRowid!=iDlRowid) ){
- p->rc = FTS5_CORRUPT;
+ FTS5_CORRUPT_ROWID(p, iKey);
}
}
fts5DataRelease(pLeaf);
@@ -8574,6 +8623,7 @@ int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum){
/* Used by extra internal tests only run if NDEBUG is not defined */
u64 cksum3 = 0; /* Checksum based on contents of indexes */
Fts5Buffer term = {0,0,0}; /* Buffer used to hold most recent term */
+ int bTestFail = 0;
#endif
const int flags = FTS5INDEX_QUERY_NOOUTPUT;
@@ -8616,7 +8666,7 @@ int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum){
char *z = (char*)fts5MultiIterTerm(pIter, &n);
/* If this is a new term, query for it. Update cksum3 with the results. */
- fts5TestTerm(p, &term, z, n, cksum2, &cksum3);
+ fts5TestTerm(p, &term, z, n, cksum2, &cksum3, &bTestFail);
if( p->rc ) break;
if( eDetail==FTS5_DETAIL_NONE ){
@@ -8634,15 +8684,26 @@ int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum){
}
}
}
- fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3);
+ fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3, &bTestFail);
fts5MultiIterFree(pIter);
- if( p->rc==SQLITE_OK && bUseCksum && cksum!=cksum2 ) p->rc = FTS5_CORRUPT;
-
- fts5StructureRelease(pStruct);
+ if( p->rc==SQLITE_OK && bUseCksum && cksum!=cksum2 ){
+ p->rc = FTS5_CORRUPT;
+ sqlite3Fts5ConfigErrmsg(p->pConfig,
+ "fts5: checksum mismatch for table \"%s\"", p->pConfig->zName
+ );
+ }
#ifdef SQLITE_DEBUG
+ /* In SQLITE_DEBUG builds, expensive extra checks were run as part of
+ ** the integrity-check above. If no other errors were detected, but one
+ ** of these tests failed, set the result to SQLITE_CORRUPT_VTAB here. */
+ if( p->rc==SQLITE_OK && bTestFail ){
+ p->rc = FTS5_CORRUPT;
+ }
fts5BufferFree(&term);
#endif
+
+ fts5StructureRelease(pStruct);
fts5BufferFree(&poslist);
return fts5IndexReturn(p);
}
diff --git a/ext/fts5/fts5_main.c b/ext/fts5/fts5_main.c
index e888abf21..4efc53219 100644
--- a/ext/fts5/fts5_main.c
+++ b/ext/fts5/fts5_main.c
@@ -3701,8 +3701,9 @@ static int fts5IntegrityMethod(
" FTS5 table %s.%s: %s",
zSchema, zTabname, sqlite3_errstr(rc));
}
+ }else if( (rc&0xff)==SQLITE_CORRUPT ){
+ rc = SQLITE_OK;
}
-
sqlite3Fts5IndexCloseReader(pTab->p.pIndex);
pTab->p.pConfig->pzErrmsg = 0;
diff --git a/ext/fts5/fts5_storage.c b/ext/fts5/fts5_storage.c
index 2b43016be..76820e85b 100644
--- a/ext/fts5/fts5_storage.c
+++ b/ext/fts5/fts5_storage.c
@@ -539,6 +539,7 @@ static int fts5StorageDeleteFromIndex(
for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
if( pConfig->abUnindexed[iCol-1]==0 ){
sqlite3_value *pVal = 0;
+ sqlite3_value *pFree = 0;
const char *pText = 0;
int nText = 0;
const char *pLoc = 0;
@@ -555,11 +556,22 @@ static int fts5StorageDeleteFromIndex(
if( pConfig->bLocale && sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
}else{
- pText = (const char*)sqlite3_value_text(pVal);
- nText = sqlite3_value_bytes(pVal);
- if( pConfig->bLocale && pSeek ){
- pLoc = (const char*)sqlite3_column_text(pSeek, iCol + pConfig->nCol);
- nLoc = sqlite3_column_bytes(pSeek, iCol + pConfig->nCol);
+ if( sqlite3_value_type(pVal)!=SQLITE_TEXT ){
+ /* Make a copy of the value to work with. This is because the call
+ ** to sqlite3_value_text() below forces the type of the value to
+ ** SQLITE_TEXT, and we may need to use it again later. */
+ pFree = pVal = sqlite3_value_dup(pVal);
+ if( pVal==0 ){
+ rc = SQLITE_NOMEM;
+ }
+ }
+ if( rc==SQLITE_OK ){
+ pText = (const char*)sqlite3_value_text(pVal);
+ nText = sqlite3_value_bytes(pVal);
+ if( pConfig->bLocale && pSeek ){
+ pLoc = (const char*)sqlite3_column_text(pSeek, iCol+pConfig->nCol);
+ nLoc = sqlite3_column_bytes(pSeek, iCol + pConfig->nCol);
+ }
}
}
@@ -575,6 +587,7 @@ static int fts5StorageDeleteFromIndex(
}
sqlite3Fts5ClearLocale(pConfig);
}
+ sqlite3_value_free(pFree);
}
}
if( rc==SQLITE_OK && p->nTotalRow<1 ){
diff --git a/ext/fts5/test/fts5aa.test b/ext/fts5/test/fts5aa.test
index bcad9e724..184cb77b8 100644
--- a/ext/fts5/test/fts5aa.test
+++ b/ext/fts5/test/fts5aa.test
@@ -428,7 +428,7 @@ do_execsql_test 15.1 {
}
do_catchsql_test 15.2 {
INSERT INTO t1(t1) VALUES('integrity-check');
-} {1 {database disk image is malformed}}
+} {1 {fts5: checksum mismatch for table "t1"}}
#-------------------------------------------------------------------------
#
diff --git a/ext/fts5/test/fts5corrupt.test b/ext/fts5/test/fts5corrupt.test
index 0abd8b86d..8788bc2ed 100644
--- a/ext/fts5/test/fts5corrupt.test
+++ b/ext/fts5/test/fts5corrupt.test
@@ -47,11 +47,10 @@ do_test 1.3 {
DELETE FROM t1_data WHERE rowid = fts5_rowid('segment', $segid, 4);
}
catchsql { INSERT INTO t1(t1) VALUES('integrity-check') }
-} {1 {database disk image is malformed}}
+} {1 {fts5: corruption found reading blob 137438953476 from table "t1"}}
do_execsql_test 1.3b {
PRAGMA integrity_check(t1);
-} {{malformed inverted index for FTS5 table main.t1}}
-
+} {{fts5: corruption found reading blob 137438953476 from table "t1"}}
do_test 1.4 {
db_restore_and_reopen
@@ -61,7 +60,7 @@ do_test 1.4 {
rowid = fts5_rowid('segment', $segid, 4);
}
catchsql { INSERT INTO t1(t1) VALUES('integrity-check') }
-} {1 {database disk image is malformed}}
+} {1 {fts5: corruption found reading blob 137438953476 from table "t1"}}
db_restore_and_reopen
#db eval {SELECT rowid, fts5_decode(rowid, block) aS r FROM t1_data} {puts $r}
diff --git a/ext/fts5/test/fts5corrupt2.test b/ext/fts5/test/fts5corrupt2.test
index 6b4d6d411..fd2a841c7 100644
--- a/ext/fts5/test/fts5corrupt2.test
+++ b/ext/fts5/test/fts5corrupt2.test
@@ -109,12 +109,12 @@ for {set i [expr $nbyte-2]} {$i>=0} {incr i -1} {
do_catchsql_test 2.$i.2 {
INSERT INTO t1(t1) VALUES('integrity-check');
- } {1 {database disk image is malformed}}
+ } {/1.*fts5: corruption.*/}
do_test 2.$i.3 {
set res [catchsql {SELECT rowid FROM t1 WHERE t1 MATCH 'x*'}]
expr {
- $res=="1 {database disk image is malformed}"
+ [string match {*fts5: corruption*} $res]
|| $res=="0 {$all}"
}
} 1
@@ -160,17 +160,17 @@ foreach {tn hdr} {
close $fd
set res [catchsql {SELECT rowid FROM x3 WHERE x3 MATCH 'x AND a'}]
- if {$res == "1 {database disk image is malformed}"} {incr nCorrupt}
+ if {[string match {*fts5: corruption*} $res]} {incr nCorrupt}
set {} 1
} {1}
if {($tn2 % 10)==0 && $existing != $hdr} {
do_test 3.$tn.$tn2.2 {
catchsql { INSERT INTO x3(x3) VALUES('integrity-check') }
- } {1 {database disk image is malformed}}
+ } {/.*fts5: corruption.*/}
do_execsql_test 3.$tn.$tn2.3 {
PRAGMA integrity_check(x3);
- } {{malformed inverted index for FTS5 table main.x3}}
+ } {/.*fts5: corruption.*/}
}
execsql ROLLBACK
@@ -209,7 +209,7 @@ foreach {tn nCut} {
set res [catchsql {
SELECT rowid FROM x4 WHERE x4 MATCH 'a' ORDER BY 1 DESC
}]
- if {$res == "1 {database disk image is malformed}"} {incr nCorrupt}
+ if {[string match {*fts5: corruption*} $res]} {incr nCorrupt}
set {} 1
} {1}
diff --git a/ext/fts5/test/fts5corrupt3.test b/ext/fts5/test/fts5corrupt3.test
index 437c4842c..eab4c3c91 100644
--- a/ext/fts5/test/fts5corrupt3.test
+++ b/ext/fts5/test/fts5corrupt3.test
@@ -102,7 +102,7 @@ proc do_3_test {tn} {
list [
catch { db eval {SELECT rowid FROM t1 WHERE t1 MATCH 'x*'} } msg
] $msg
- } {1 {database disk image is malformed}}
+ } {/.*fts5: corruption.*/}
catch { db eval ROLLBACK }
}
}
@@ -273,7 +273,7 @@ do_execsql_test 6.1.1 {
}
do_catchsql_test 6.1.2 {
INSERT INTO t1(t1) VALUES('integrity-check');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corruption.*/}
#-------
reset_db
@@ -289,7 +289,7 @@ do_execsql_test 6.2.1 {
}
do_catchsql_test 6.2.2 {
INSERT INTO t1(t1) VALUES('integrity-check');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corruption.*/}
#-------
reset_db
@@ -308,7 +308,7 @@ do_execsql_test 6.3.1 {
}
do_catchsql_test 6.3.2 {
INSERT INTO t1(t1) VALUES('integrity-check');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corruption.*/}
do_execsql_test 6.3.3 {
ROLLBACK;
BEGIN;
@@ -319,7 +319,7 @@ do_execsql_test 6.3.3 {
}
do_catchsql_test 6.3.3 {
INSERT INTO t1(t1) VALUES('integrity-check');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corruption.*/}
do_execsql_test 6.3.4 {
ROLLBACK;
BEGIN;
@@ -330,7 +330,7 @@ do_execsql_test 6.3.4 {
}
do_catchsql_test 6.3.5 {
INSERT INTO t1(t1) VALUES('integrity-check');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corruption.*/}
do_execsql_test 6.3.6 {
ROLLBACK;
BEGIN;
@@ -341,7 +341,7 @@ do_execsql_test 6.3.6 {
}
do_catchsql_test 6.3.5 {
INSERT INTO t1(t1) VALUES('integrity-check');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corruption.*/}
#------------------------------------------------------------------------
@@ -374,7 +374,7 @@ do_test 7.1 {
db eval BEGIN
db eval {DELETE FROM t5_data WHERE rowid = $i}
set r [catchsql { INSERT INTO t5(t5) VALUES('integrity-check')} ]
- if {$r != "1 {database disk image is malformed}"} { error $r }
+ if {![string match {*fts5: corruption*} $r]} { error $r }
db eval ROLLBACK
}
} {}
@@ -399,7 +399,7 @@ do_test 9.1.1 {
} {}
do_catchsql_test 9.1.2 {
SELECT * FROM t1('one AND two');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
do_test 9.2.1 {
set blob "12345678" ;# cookie
@@ -411,7 +411,7 @@ do_test 9.2.1 {
} {}
do_catchsql_test 9.2.2 {
SELECT * FROM t1('one AND two');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#-------------------------------------------------------------------------
reset_db
@@ -497,7 +497,7 @@ do_test 10.0 {
} {}
do_catchsql_test 10.1 {
SELECT * FROM t1 WHERE t1 MATCH 'abandon';
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#-------------------------------------------------------------------------
#
@@ -678,13 +678,13 @@ do_test 12.0 {
| end c2.db
}]} {}
-do_catchsql_test 11.1 {
+do_catchsql_test 12.1 {
SELECT * FROM t1 WHERE t1 MATCH 'abandon';
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
-do_catchsql_test 11.2 {
+do_catchsql_test 12.2 {
INSERT INTO t1(t1, rank) VALUES('merge', 500);
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#-------------------------------------------------------------------------
#
@@ -870,7 +870,7 @@ do_test 14.0 {
do_catchsql_test 14.1 {
INSERT INTO t1(t1) VALUES('optimize');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#---------------------------------------------------------------------------
#
@@ -1040,7 +1040,7 @@ do_test 16.0 {
do_catchsql_test 16.1 {
INSERT INTO t1(t1) VALUES('integrity-check');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#--------------------------------------------------------------------------
reset_db
@@ -1126,7 +1126,7 @@ do_test 17.0 {
do_catchsql_test 17.1 {
SELECT * FROM t1 WHERE t1 MATCH 'abandon';
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#--------------------------------------------------------------------------
reset_db
@@ -1435,7 +1435,7 @@ do_test 18.0 {
do_catchsql_test 18.1 {
INSERT INTO t1(t1) VALUES('optimize');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#--------------------------------------------------------------------------
reset_db
@@ -1546,7 +1546,7 @@ do_test 19.0 {
do_catchsql_test 19.1 {
INSERT INTO t1(t1) VALUES('optimize');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#--------------------------------------------------------------------------
reset_db
@@ -1630,7 +1630,7 @@ do_test 20.0 {
do_catchsql_test 20.1 {
SELECT * FROM t1 WHERE t1 MATCH 'abandon';
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#-------------------------------------------------------------------------
reset_db
@@ -1764,7 +1764,7 @@ do_test 21.0 {
do_catchsql_test 21.1 {
DELETE FROM t1 WHERE t1 MATCH 'ab*ndon';
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#-------------------------------------------------------------------------
#
@@ -2100,7 +2100,7 @@ do_test 22.0 {
do_catchsql_test 22.1 {
INSERT INTO t1(t1) VALUES('optimize');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#--------------------------------------------------------------------------
reset_db
@@ -2211,7 +2211,7 @@ do_test 23.0 {
do_catchsql_test 23.1 {
INSERT INTO t1(t1) VALUES('optimize');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#--------------------------------------------------------------------------
reset_db
@@ -2429,7 +2429,7 @@ do_test 24.0 {
do_catchsql_test 24.1 {
UPDATE t1 SET b=quote(zeroblob(200)) WHERE a MATCH 'thread*';
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
do_catchsql_test 24.2 {
INSERT INTO t1(t1) VALUES('integrity-check');
@@ -2518,7 +2518,7 @@ do_test 25.0 {
do_catchsql_test 25.1 {
INSERT INTO t1(t1) VALUES('rebuild');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
do_execsql_test 25.2 {
PRAGMA page_size=512;
@@ -3011,7 +3011,7 @@ do_test 27.0 {
do_catchsql_test 27.1 {
DELETE FROM t1 WHERE a MATCH 'fts*';
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#-------------------------------------------------------------------------
reset_db
@@ -3700,7 +3700,7 @@ do_catchsql_test 32.1 {
highlight(t1, 2, '[', ']')
FROM t1('g + h')
WHERE rank MATCH 'bm25(1.0, 1.0)' ORDER BY rank;
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
do_catchsql_test 32.2 {
SELECT * FROM t3;
@@ -5351,7 +5351,7 @@ do_execsql_test 41.0 {
do_catchsql_test 41.1 {
INSERT INTO t1(t1) VALUES('optimize');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
do_catchsql_test 41.2 {
INSERT INTO t1(t1) VALUES('integrity-check');
@@ -5573,7 +5573,7 @@ do_test 42.0 {
do_catchsql_test 42.1 {
INSERT INTO t1(t1) VALUES('integrity-check');
-} {1 {database disk image is malformed}}
+} {1 {fts5: checksum mismatch for table "t1"}}
#-------------------------------------------------------------------------
reset_db
@@ -5813,7 +5813,7 @@ do_execsql_test 44.1 {
do_catchsql_test 44.2 {
INSERT INTO t1(t1) VALUES('integrity-check');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
do_catchsql_test 44.3 {
SELECT snippet(t1, -1, '.', '..', '', 2 ) FROM t1('g h') ORDER BY rank;
@@ -6644,7 +6644,7 @@ do_test 48.0 {
do_catchsql_test 48.1 {
INSERT INTO t1(t1) VALUES('integrity-check');
-} {1 {database disk image is malformed}}
+} {1 {fts5: corruption on page 1, segment 1, table "t1"}}
#--------------------------------------------------------------------------
reset_db
@@ -6917,7 +6917,6 @@ REPLACE INTO t1_data VALUES(1,X'2eb1182424');
REPLACE INTO t1_data VALUES(10,X'000000000102080002010101020107');
INSERT INTO t1_data VALUES(137438953473,X'0000032b0230300102060102060102061f0203010203010203010832303136303630390102070102070102070101340102050102050102050101350102040102040102040207303030303030301c023d010204010204010662696e6172790306010202030601020203060102020306010202030601020203060102020306010202030601020203060102020306010202030601020203060102020108636f6d70696c657201020201020201020201066462737461740702030102030102030204656275670402020102020102020107656e61626c6507020201020201020201020201020201020201020201020201020201020201020201020201020201020201020201020201020201020201020201020201020202087874656e73696f6e1f02040102040102040104667473340a02030102030102030401350d020301020301020301036763630102030102030102030206656f706f6c7910020301020301020301056a736f6e3113020301020301020301046c6f61641f020301020301020301036d61781c02020102020102020205656d6f72791c020301020301020304047379733516020301020301020301066e6f6361736502060102020306010202030601020213060102020306010202030601020203060102020306010202030601020203060102020306010202030601020201046f6d69741f0202010202010202010572747265651902030102030102030402696d010601020203060102020306010202030601020203060102020306010202030601020203060102020306010202030601020203060102020306010202010a7468726561647361666522020201020201020201047674616207020401020401020401017801060101020106010102010601010201060101020106010102010601010201060101020106010102010601010201060101020106010102010601010201060101020106010102010601010201060101020106010102010601010201060101020106010102ad060101020106010102010601010201060101020106010101010601010201060101020106010102010601010201060101020106010102010601010201060101020106010102010601010201060101020415130c0c124413110f47130efc0e11100f0e100f440f1040150f');
INSERT INTO t1_data VALUES(274877906945,X'00000e96023030011a042319320d3b123d812b5a31120110446e581b66814a05010a4537814274010e8102815c810f3d0104846d01081581204401103741043c59416b44010a404655265301103f73811a11114213010a821235820f020135030484320201360104816a020162020484550302390301710a04824a020166030483690201670704837d0201690404822602016a0504825c02026b620504817502016f0904810d0303e79c88060482760201700a04826302017204048155020373c2be050481130201770204846202027962050482710202c2ba010482140203e58496070483330204e8b2b879010483710101310110545c0c814b0e3a6501082c815d5b011a2a0e2f0d765c3d686014061d0d0112810733112c2e82141101048313010e5c6f632e813e42010c811882370548010e19158146822f1f01104d364a708146135a010a237b0a55210201610904841703027678090481270201620304810002026374060484660202657a0704827602016601048351090483540301660704814b02016b03025f0304c582caba0204816602016c01025f0302cebc0904843e02016e0804821802016f0a04817503016f070483100201720304822c020484380201740404842e0102460201770104812f0204836c02027a6f040483110202cebc02048267040161020484650205d5bd62cebc0604845b0204f2a580880204842a0206f38184a179670502750204f696a3aa0a04814601013201063330390110812281378114600d010c03716c5e822d010e81226b542a814d010a72740f83000108813a1e0b010c5681046f812c010c07814a777328011664244219531b1a2f811e4a010c4d81557c7f1b0201300704810702013307048230010484050202367807048175020239710804832502016204026b0204814d020363306108048262020265650504817602026667070483150201690704832f0301360a04814d02016c08024702016d0304843e0303cfb2630204814002016e0804837503016203048416030370c2be0304821b02016f0604834b0201700504816b030175070210020273660604841c020676c2bac2b2640604830a02017704027d02017808048141010482700201790504811d0202c2ba0502470206ca8d73ecbab9010483340204f09e9ab504048367010133010c3e04814f82250114812e814b2e0411811305010c811337811e6e010c82085e2b0e5d010c61812054811c01148122451b0781050c813d010c17823762643e011e080c1720814a10364306143b0d33260112810f0c2a810c816b13010a8163810e470201370404811102056176c2aa36050481530202646e0904846202026a730404827402016b0a020c02036f616b0404830a0201750504820d02017605025e0201770a04820702027a73050482460202c2ba0604824a020483330203cba434040483200203cebc790304847e01013401124181442c1d091f81580108601d8336011081320a2b8125820001123b0b81158116811f070110078112817a817308010e6682410d810e2601122d0d6413378147351e01105081021d3525812d01128246510a622204054101105c1b620e81302b05020130020483480104822702013102027e020132030483270201350304844802023770030207020261710604823f0201640802570204830a020265770304831f020168070483210201690204825b02016f020481280704835402057037e18b8d0904810802017304048439030172020481440303c2bd6b0a02630201760202490804815e0201770304816e050483550201780704816902017a070483280207c2b2f093aabc780a0482240301b303024e0301bc0604837a0202cb800204834a0202cebc04048201040484410203d3ad770a04814f0202d5a508048371010135011630817e0f81040d2c041552010c813d3b7e8115010c40692182693a01121f810d810d0a32814701101d1d1f642281742e01068229240110811231810a387f4c01100f50810f8165810d0114811f26443152593c104a010e641e1a3357820e020132030481540201340204815402023778040207020163060481020204815b020164020483010201670a0481540304f0948f870904811a0201690704835502016d0604832203027b01022803017a0a025102016e020484260404816002026f690502680301720104834e02017208024f02021d020475e69c8e0504814c0202767602025f0302de870a04837b020178090483200104835003026a72090484400201790504837204022302017a0104836b0202c2aa0a0481070303bcc2b3090484370203c7866403027501013601087c158303011212814305813e7b0e090118141a1c49713a211e0c74630f010a59826d8113011203328166037781561a01101d7f1d2a1f822533010e820e070f7b40160110811f40292c813226010a2d20824a32010a81418158670201300304840a0201660404817d02016d0804826902016e080626817f0104820b02016f0404825a02017003023b020272750804840c0301760a04844d02017403025b020175080484200202766e060482360303c2ba6c030482220202c2aa0204810e0301b20204835703048421040484240301bc0802410202d2a1010482630204e1b18f3704048354010137010c08816337812f01101382211532424d39010881248123010e7724810267815f011081236029813e273301101b7b29812a5b813b01128150810324814b220b01060c8417010e165b6c81708117010a1782346f6c0201380804816803016b0604840102013908023f0201610204816c0201630302760201640304832604023e0204833902016502048203020266770804821a0201670a04830002026964080484500304f29e9eb70802250201700204811b0201710904832d0201730304826b05048403020174010481000205776a62c2b2050482630201790202260206c2b2eaaeb464050485020301b3080482480303bac7af0a0484550203c695650804822a0202ceb90a0481170202dbae05023f010138011819814a2703390a61090c6912011a21181304812523811b5f164e050114110f35128123423f810c010c817573817c03010e7182590c812b0401142503597e6e0e2f3a3759011252813a811a2b75091a010882162a31010e17450a81048279010858658208020231670a048205020361c2b906023b02016301048236020164050482520201650904833d0201670904811b0201690604825002026a7a0604837c02016e0204832002017002026d0302c789010481020201720504835e0201740604810002017502020a0702630302676306025f0303e4a0a70102640203786a75010484440201790104841402047ac2be72070481340207c2ba3766673576090482790301bd07048142010481600202c7b309027a0401740604823b0202d2bf0304830f0204e989a6300a02600204f4bd91b60702120101390106518369010e19254641823711010c258267288121010e817c810d2b17250110810a578133812f4c0110415681067b288121010e0881208119347101140b8131543c8100343d1101088203813e01100d742e3230820f3802013006048107020134080481440202356501021a02013808048147020162020482230201630304833c030162050483390206656cf093b5bd070484140202677303048502020769e3ad9669c2b90304847402016b0804836402016c0404841f02016d010481250904825202016e06025402016f0704842a0201700a04834a0201720a0483530201750304822e020676f097b18374030482140201780604833d0202c2b9010481550301be070483720204826f0202ca80060481630202d5a80504833f0101610114551047810e130a78660c011a364611206c0b13080705733d5501240f08070c090b0c20813d1471042e4351131e011204412d814f0913104201263036110d060b1f811a301b0f4e1a29092f181c012808071e221a2a81075b320503065a0f140c1a0a26011c07231d0e6f3715063b760c6b091501121111303e3a71566d6d010e0867814d816a0c01181e18240d41724d221b3f384b0201300204830b060483080302c2b30204837f0201310a026e020134050481560301730902690201360406827c0f0201370204825d06020a0201390904815b0304f3bfb2a70a04822c0201610404810e020262660604841a03017608025b02016309088112825f020164090482310201650a0484480302396f01025d02026774010482090302df9b06048321020168070661813303016f03048248020169030483610504814001048401010483460301300704824203016a0204824402016a0504813303021d03017209048412030277380804824502016c0104814c02036ec2ba0804835702016f0204811d030176020238020270360a04840d02017107048201030469ca99690602350201720304812d0104845e02017304022c02017409022b020175050484140302caaf0402410201760404831f020177010484180704845203026f6d04024b02017a030482660202c2aa0204810a0301b30a04817b0302bd76020483780302be6a0302440202c58207025e0202c69901027a0302ad77010483200206c993f099b183070484270203caa1660204841a0204f29788ac0804831d0204f4ba9f950504843c010162011c0e33810216341c2413042130780501184d373e53131f2f052907423e010c830e3781390e011c1320461f81041b811b041e15243d011e241b10816c310b130c3133033b0741011a11816d3139100c13140b395848011c580e411a06304306810a3138330d011a441707092c70140c1643813920010c73653581374f010c826c81210f0402013803024f07048172020161020481650204810c020162030483470301370404813602016307048379020483280201640304815501048176010481060201650104812a0104841f0201660504821f0201670302700201680804846403016b0a04831d0301700904845502016908025c02016a010483560904827602026b6306023402016c0404832602016d040484410204825702016e0504831603027831020482160302c2be0504827d02026f6a05048121020171030232020483220304845402023a0201720204845c0304846e03013607048224020174060484480201780704844303016f0604814f045807070a0707070707080709070709070808090a5c07080708080b07060a06080707070b0a0b0808070b0a0b0a55070b08080a0908080707060709070709070706080c060b07070c0a66070b08080609070607080c0909660b06070707080a0807070b0b0707080a0b07070d0607080c0908630707070b07070a070d060b0707090a07080b080a070809085f0707070c0706080706070809080f06080a5807070607060e070807080907070b070b060c0709090807690808070707070708070608070709070809070a0d0b07070809095b070707070707070c080d07070b06070707070c07080b0808811a0b08060706080a070a07080609070707080808071307070a0708070907060807090b06060707070b0707080708070707080c090a0a81080a0b07070b0f0b0706070707060b07070b07080808110b070707');
-INSERT INTO t1_data VALUES(274877906946,X'00000e880330627a020482240202c2aa0a04833f0301b30704844b0302b9650704824f0301ba0204845f0202c9820a0483640202d194060482300203e19cbd0904844b0203e691b4050483510205e78dadde9b0104821201016301142a6c033b8151085c094601140b813d49313f81110e1c011681163611221527257f5d38011c150f22811a0a3c12350631238117011c3e26420b402c1d81080c40150b2f01181c3143382640273d60132e070118663b1d162a1b0e2e8111393e0110821117310e52811c01141a2f49810181391f2b130112323c0305812a6f2e390201320204842702023334020481340201350202610201360304844603023362040484470203376a360a04826b02013808026203016f0704830d02013902025502016106088170827a0301320a04820403016c0404831502016204048327050484030201630a04814302016401048349020484760302430301640204845d02016504048249020367c2bd07020a0302cebc0902150201680a02500201690204846102016a06024c0301770504842b02016b0104830e0704811803023370040483580301710404845f02016c0504844f0204820d0204837f0302c2aa0104833702016d0104844c02016e0804834f03026c6a07025702046fecbd9a01023a020270330204830a0301740304837c020271350204811e0201720706833b310206736ef09289b70104832b020174070483290301320204827c02017608022802017806025b0302c2b30904835202027978080483040303c9b56f0904846a0202c2aa04048127050482120301b30504813a0301b901024204016a0704840c0202c5820704823c0202c999010482470202cebc0602400203db91670602730202dca7050482760203e1a3950304817e0203e786a702048273010164011a0612105b292b817c1211080d5a01147c1d420b35451c36811a011e0e168117081c0c2e051d474055192d011e02050a1c81180420250f815f300f21011c02316a37143321443a10042d54230112761428810e4750054101101805072b8215294e0116680f0f5381445a3e0b070901224e4a41210c361c281b101c43051325130f01185a1e19108106300f2e3f4538020130060481370202327305022002013405048168020335377a03021802013704027b02013804048260020161030882118101030263650904814d0201620604822502016303048419030135090483240201640602280301380404817e0201650404823c0304f097ac9f010482680201660a0267030566e2b6936f0104821c0201680704813302016b0604832002016c01026a0301610204843202016d0804845e03026d6d03023c020270730a04817f0304c2be797a0804832e020271710504835f02017203021b0201740204825a02017706027202017805048451010683572e03016e0a04814c0201790304811702017a080484450302c2b90204837b0202c2aa0604825b0303b273630104841c0301b9050485040301bc0a027b0303bd37680502670202c98b0204826b0203cfa1740504823a0203d199610202350203e3bf87040483570204f1baaba90504817301016501120b8104392d0d20180f011645213f292e4d0d082f8165011e0b400c07341b2329307f193338173a012055292409050c560a272a0f4403245718011a1c3a183f1c43264c3126060829012081208102043a044d0621650b180e150e011a066c030e513d7d265e1313130c0118171953040457347b114d191901261b1c060c26090d6f0d332a1519096e03101d1d012207342f1f2c7e2517251d0f310d2a17081e02013005020a02013308048247020135030483660201380704841b030132030482180201610102600604825f0304c2bdc2ba02023a02016209021f0201630604813002056663cebc610604841e0201670504816a0104842703037177310604833f03027872080482350201680604825e02016a040483320104840d02016b0304813f02026c6408020602016d070481590104837d03016c08020d02016e060484630301780404815c02016f0104826b0804825e02017008027b0302c2aa0504847c0201710404836d0201730402510302cebc08048338020375c7bf05048344020177010482660304822303026479070481630204786ec2ba0204814f0202796a0a04834f02017a01048407030484660604810603026561020483180204c2b278390504813d0301b304024f04026536010483110302b9330604813e0301be0304840b040484560202c4a702022d0206c6a5f7ada9990402350202c79f090481180202caa60502140204cebcc2bd080483320202db900a0481250205f4b5aa9079040484360204f7b985bd0204835e01016601128101285c096981190e01121f813f0d431a8135530114698102813228492f190a011260161881328101812601188155780d813257050c0b04060114161681340772811b5e25011c4505810e13290b253a0c0c0a1a4b011a3714133e1235812b136b062c0b011a6b591356810c3c240906250b1001148127810d413e0e81090d020231680504822c0302c2bc0204830c0201360104840c0303656a740902110302d1950504824f0201370902130201390a0482530303e0a9ae0904844c0201610804810d0201620a04810c03023039030481330302356902048268020163060483470201650504822d02016706048200030483560302713509025002026a79010484410804825902016c0504822002016e07020d0304843a02016f0204842d0201710304837604048361030482430201720904840f020173020482520804810b02017406068425320201760202420201780804845d02037979650704814802017a080481110301780804812c0202c2bd070484600202cebc0508813082410102770401610202250202ddb40302310205f19e9a937a030482410101670118365558195a0a062d0581260a011881068143330844041f0a1851011a2025141e1081204f550e077521011a193b1f58351912265681220821011812070528472f4e2f407f204a01124d1e1f811b810d7b4d01180f1d3481034a35580a12811f011c2303340d1470150778070c812331011620411939703c032915143f01104281116a3d323c6a0201350604842902013703023f0201390a04816e0201610604826402016202023f0201630a04843302016409048258020165020482620404814702016602061b833f0201670404827d03026369020227020169040483490301670604847602016a0604845d0404840902016c04024601088150822b010482350204830a0301690304844902016d0202710704820002016f03048509020482380304836603026e74010483580201700504817a020171020481080204826a0201720304837b0202410302160302c2b3080484550201730904816e020174040248010484280304834e020275730404836e020176060484720104815c02017709026a020178060275040483790201790504821501026c030170080483770304cfb269710704815102017a0204813303016f090483160202c2aa050481400301ba0804810b0401630804830d0301be0604844d0202c8a30a02110203cba0640204816a0202cebf060482420204e487856e030481080204ec97bd6d080484080205f09eb3a0770502260208f687999931ed878703048424010168011a12460e090c036e151b812e065501161708411982151738471f35011a2d1c0678340c1f04425c21200c010c2a087f255d4a011a0d0b6c33814a212c3a0a401b1e011c501f2381010a0481201c0c6012280118150b5228520e0a036c1c8123011a15810a060408030a81563f381601185b1b06212a143f332a60160e011a221b1e62411d2048090e0b0f5502033072350804826a020131020482530201320304823b0201330104814502033677380204813102026174020483540304dbbf6f620404835d0201620504846a0104831803017103048323020164060483740201660a02410201690102130104821402016a0504823f02016c0404832e02016d09022602026e640a04822702016f070482000301750402670201710304813106020d0202726304048220020173060484530201750504831e020483400302c2bd0704843a020177020483470203786371030483740201790904810002017a0302300202c2b9080483280301bc010481700303bd33720304825e0205c99973c2bd040483160203d5a6330a04842b0204e7b3b3300904813c0205f099a68f72090209010169011c21101d4b2d0e0e066b4253074c140118070a0910447556030833541d01163733816837402b3909122501183c5b1139102e2d430c662334011e27050f21621230323503332b6a0332011e1e07031843202e6e3c2850094d410c01163955220b16812d24521212011681250b0a3505460481176f011a2c09266b162968051c0a1481170116022e1e820c352037263a070201310104825d0602110303696869020484070201320204826e0201610304832203016f040232020162050642843f03048336020484540301370804833c03026c6105027a0203636165090483120201640502770304833e03017107022f0301780702470201650a04811e020167080238020168040481160102230404826b030170040483000201690304836f0302766c0304811402016b0504812e02026c6108027702016d0308827d81530604837302026e790904842602016f06048208020170060481680302320201710204812902017307048255020274320104822a02017506026803016e0a04821303017207025f0302c2b90504834a020177020483130201780604836b0402210301320604847302017a010483130202c2aa0804823c0301b9030482600301ba0104845304016c0504837e0202c3b8080484600204cf9d6379020483660202d3860704812e0203e3a4be0402560203e58784010481210204f09e95ac0102580204f5aea5890a023301016a01123428131a1f6c81445601141e227c1a7b5f1918810301182318812e17455605460d811c011a28820221311a6e12093f050a0c0120082c0b0f1362074457460c3b070d5132011c2143052a20133d160a358117591f01103136813b136e6247011c100e4c28060d16815a320a3e11070124462c03582e262d45110804113326040808070807080809090b81050708060708090607060907070b070e07070807060706070b08070f0807070709080708080c070706060808090c07060708080708080909811307070708060709080707070607070a060b070706070707080a080607060c070707080809070608080908090a812406070707070a0906070b0b0908070b07070b0607070b0608070608090b080a080f080a0608080b070b08070a080b0a810408080708080607090707080807070b070c070a070f070b080607090707080d06070b810b070607070607070b08070707070b14070a0f08070b0d08070e080b060a0a070a0707080707070709080a0a0a0e810f0907070709080a0b0707060a0707060807060a08070b08070907060807090b090a0a81140a09070706100707090a060607060e07070807070d08070a07070806070608070a070708070707080a0808090909');
INSERT INTO t1_data VALUES(274877906947,X'00080e7f073c23110a1a18392f66090524183704276d6703306a320404824e030164080483520305c2bd7ac2bc0604815a0201360704833202016106021f020482400201630304822a0708817e8204030173040483500201640404824803016d0804824a03017709023002016606048367020268680a04815802016902088339811804027f0302656e0704834e0303d5a5370604816702036a3366090484470303c2ba660904826e02016b0904837c02016c07021403026c610604835802016d0204816802016e0104831202016f0104822f020270720602060201710704822202017206048174020273690204824602017409020c020175090482140201760a0482720301660404824403016a090484290201790404845703025d0203c2bc33040484620301bd0304824c020484540202c78607022403019a010482380202ca87070484390202d39d030485050203e184940404831b0203e6a881060483480203e8b18c0a04816d0203ee8d850104814801016b0110467257393c81272c011a053e815d3b190517064524521f011c3823590a8115372004313b1f3216011a5a20780b102d0804426916112c011a182f810781082d12137026161501221a180516811611051c131207811515173501180320112581062e05621c1407011c2d0e0617811522062208065a21520114582841621e6c203f1e2001161647411a272533815b1c2602013009048309020232630104835a0301720104817f0201330604836f0302ddb5080482560202347a07048102020135020483460104827b02043678ca800a04835f0201370404814b0104846002016103048246010482220301700204833f0201620404824d060481150201650304824f02016606088110834c0201670604821d0303c2be66010481790201680404843b030176050482270201690a04830e02016e0904844202016f040481010301630304822f020270640204822f03016e0704845802027177090482710206736ec2b2796a0104832e0306dab1d485377004048304020174050481700201750a0212020378627604048164030173080483190201790704833d0204823a02017a0506820e67030178070484530202c2b2060481500104823f020483030301b3020484310301bc04027e0402caaf0a026a0301be040482590204842e0202540202c79f0804824d0202cfa30804815a0204f29a92970204823301016c01140f63351a0a653b650d22011c09117a3e1538123537046a15043101141310082f49052f772b0c011c11121781583c2a5010133228241301287f3e0a2b1244080503060a100f413b4f0d070e2a01103e4e1f04814e7b1601183d0404052877111f230f811d01123a100f053e5c076910011a031732102381243d1b1727507301180e5d273e810803812e0f192a02013301048271070481330204821d020134080263020135060481280201610104830a0201640604826d020165060483050201670204841c0504841c0304841b0201680a04845602016a0104811c01024f030481080204813102016b0204837008024502016d0404836c04068207780301670704842302016f0404821203016d040484490301720404837e0201700104821d03048407030165050483050201720a04811602017307023502017407020503016f080484240302c2b90504821b020175090484090201770a088119822503026d6905048300020178030482680604812a0201790104830c0204833a0303d9a06806022002017a060482600203c2aa33030481560301b904020a0301bd0504820f0202d0b90904817c0202d3820202200202daa9080482030203de966e02024b0202df9d080484350204f098b0a20604845e01016d01220304456608322258060a031d4c38340f090112310c070e4238626e6601124a318109030513812f0118240d561e533742188113101b01160b24444b224d44814d4806011c05774e483410330d23541b28090401141f29062581131e221b6d011e81053a037a03320b0e4c24360d2310011a0e321d3c141825111d54637a1c0114093d3c2e58571a35293a0201350104840a03017701048330020136060217020138030483370201610a0482650201620504815e0201630704827701048201020164080483690201660804846703016904048113020167070483080201680504837d05022c0302cdb10a04815f0201690104833a0404824302026a360a04823b02016b0a04813502016d0504831a0204833803021a02026e360404825e02016f080484140201720304844b0404816603056ff09d899b0304823f020275390204816e0301780a04824202017604088308812703027902027770050482040201790104827e040482750204812902017a060483030304c2bdc2b30104836f0203c2aa62040484040301b903021c0302bd6b090484300301be0704814d0202c99402025603049a65656b090484020202ca92090482060203d19a730504844a0203d49f690804836e0202dfa8020482710204f09180860704822901016e011a0c0b8104243647521f43231f36011a2e1b33432c3d0b414905054d17011010573a6c0a816c1801160e063582340a5239050b06011a4481063d1b67250f2044200839012044591d1857291214135814101a1b361d011225067e8147111a4a4301166b13362e17195f3812186f01141c465b032b290406373301182a152a2281300f8107054e3f02023274080481770305c2bacf8168020481450201340604832f0201350704842e02013605020e0201380404841d0201610404810d020483750201620304812b020484230301610804834503026c6a0304816d0201630102380305613577337405048359020165040482720201660904826202066736f094b0af0a0482250201680104811f02016b0304847202016c0404822403016f0904822c0302c2b301025002016d0504817b01023f02016e020483090802040303e7bda10804832d02036f6b740404811402017005048419020484220202716506026303026b760904830a020172080482430304706c73620504825f02017308048413020174080481070201760104827f0204836e020477e7b89a0104840e02017a030483700206c2aa35657065050482740301b30804842b04046cc2be78090481040301b903020d0301bc010484260904813f0203c7a5620302330203c99f36050481010301a30704815b0202ca8b090483250202cdbb0604820a0202cebc0102170401380304842b0207eca2a6f29c87950904824001016f01221d17052b58101241060e3a201f1021633a0114816919811c142443100801280426080e2620042a812c531a490e121707131710011273432e493347811a340112195f671f46721c325e0118380c052b812822478107600b0116021c21821b2019263433040126021b05351b2a286b05181f071b5628111a330a012014533e073d0c0e5469141d1e2734050901220318051b44412803632e0642370e0a3a2b020131070481770201320a04812f0202346e04022b020136030483590304f09a81b60404834702016105048210020162030205030167010268020163010481540604820202048300020264310902420201650804834b02016703048247030365c6b602048205030573f098b890030481450201690204832802016a0a04826703016c0104825e02016b0604815e03016c03048334030677c2aa74c2bc09023d02016c0304823903027777060484540303df866c0104815b02016d0204811f0303796f7704020302016e0204814d07024a02016f0902680201700604840a0104831a0204835a020172070484440201730a023703026b660604830e030278790304815b0201750904822402017704025b020178030482350307f4b2a3896a343407026b0201790902720302633409020402017a020484590302dea004025f0202c2b20204816b050481200202de900402160204ee85a5770204822c0101700114143a0d391a60812d4e09011a2f313104201c372c3a3411321b011a268140144226334145050d1c4d01164e081f20671f088107237901186b123c1f6d07261e2b732e210116511116342a3d32376e083001106882257a0a17141101163039192b0c05812d735f3b01262a3e0841030b17181411051e0a18530e272b6d01182f322b260e24581d5381050f02013104048353020132050482370301690204843e02013302020d0201340104841f0201350a048139020137050482770201380204833a02016105025a0504832f0201620304836d020163050484100304832003016c030481290201640304837e020482490304822b010482290201660a04827002046964dc960204833102016c0704814502016d010482000201700104817e02037176760904821f020473eb91a708048152020174090482770201750404831e01063a825d03017a0904826a020276730a0254020177080260030277630104815c020178070481220202020301720804841202017a0204834c0202c2aa040484010301ba080482580202c6a3020481320203cdbf690502790202ce90070483140301bc030481470205d1a371cebc060481590203d2976a0404830c0203dfba6e0604814b01017101163732393b8120422f054b0e010e030b211d815d1c01165641757c080d81311d090e0112816581542d2313054301224e07121706516606080e39102d231c4b39010a2d81402d5e011a132527428114080d6e1111721c011a814a1a341538251023100d1c4c011e22182622623712411e38162a182d3b01142b67611981470f1f1f250201310a04824e0202336207048217020238730204815a0303cf886d06025a02033962620404833803016f0a04814e020161060483140302726d050483450301790904810c02036376690504811c02016403024d020165010483280802550301650904827f0304ebb8b561070482340201670302670301660804810e020168040482340201690704844d0302616404020f02016a030481060301700704827802016b070481240104814b0302c2bd0504816102016c0604837f03017a0404837902036dc2b90804810002016e0904821602016f0304812c03016401024b02017103048233060483600303e5848e04023a020172040481050305f3978aa06c070481151708070b070a0d0707070607080c080909090706080707070707070806070707070a090b070708080909090981140708070708080b0a0b0b070b070907090707070707070807080c0c070609070b0807100706070e08080a81110f06070707070f07120a0c070707070b0707060607080709080b0b080709060708070808080a810f0707060707070b070707070a080b08070e08070b0b08070c080f070a09060807070a080909080a810b080b070706070b0b0708060b07070c07070707070a0a09090b0708070a07070b0a070c070a060b080907080807070d8123070707070a0706060f070707090b07070707070b07080907080a060f070608080706070c060707070c070a810f07070706070707070a070b0713070a070707090a070c070706080a07070807080808070b0909810607080808090707080709060a070a060707070707070b080707090707060b0807');
INSERT INTO t1_data VALUES(274877906948,X'00000e8a0330717304048359030134050481100203756371070482190201760704817b0301770804821d0201770204844d0201780204836c0404826103017504026a0202c2aa020482420301b305022c040267390602570301b9080481540301bc0102290206c99cf6b5aa80080481430202cebc02026e02048120010172011a1c2f15158108048125463f251d010811811539011412423105812181171549011847284a30234e5b33042632120118351e8113817d0f2b220d111901264f104a211004061d0a2a0b35121a0a2118341f011c81160a1b030d2a0610243e445f0c011c6f0c1e3b1768141e322717500b140110537f810169811625011a492847203e210f532c16480627020135020481780302caae0104811a020261330904846c0201620804812d0201630404814a0201650704837503017301048276020168050213020169010484540604842b0302796f0504833302016a0304831b02016b0604701302016d0604815302016e070483630204815202027071020481520201710104835b02037266700704843002027362040481490201740904817d020175020481040304f59e9c9407048218020176060484060204776dc2aa020483070201780504812503016601048159020279790704840502027a730904826c030178030482740202c2aa04023d010483540301bd06026b0203cab877010483290202cdbf060482410202cebc04025c0401690204827f04016c0904840e0202cf880104835d0203dfbe6c01025b0204f0aeb7b2030481680205f1a7b5bb390504826a010173011a22810d12415003071f81181839011a3220221511546d810012052b57011a0c4274300d154e81111f041e10011e293f4213051b2276560817312811170120092136122418370e4e782b3912080f3201262b3b340f222b0c09142a0822116a135c1c130c0114320c4e385a0d0415075f01163543340f06362381133c0c012224180981742048191d110e180e180d310f011a20632450281f043027114b034e0203316a61030482160201360104826e0201380a0484570201610104844d0504814a0201620904820f020164010481630304810403027761040258020165080481550302c9b70204827a0204677367690102660201680104831b020169020483760301720a04814502016a04020c02016b04023405023c030269630504840502016c08048463020170030482670202716d080482000201720304835c03016507024d020174030482520504821503016505048207020175040208030137060481710201760a04833d0201780404832302027a6f080481200202c2ba0204812c0301bd0404821e0205c3a66865730702540202c7890804816f0205cebcc7af730504815c0202d2930202540202db89020481160203e8b8a00304825d0205f0958db331070481620305989b8569780a04813d0204f69299a5020210010174011a7b3829100a4e511f1a281c17140114812626032c372634234c01140a520e815a810815200501123e4f3531042d57615b011a041f3e64070f1f1913274a20770114811d0f5d743e0634161c01162c2782130c1b810520280d01164a513110480b402b810d13011e522d08042c1146137012201e810512011a290903182c05301e5d811944290201390a04836d0301610104836e02016208027803036cc2bc07048261020263640a0481480301730704813602016408022b020165050484310301720702260301780402500203666d73070484470201670104825b02016a040481590304836702016c0304835601025e02016d060484110301340204813702016f04021802017006068336280201710304813507025902017201026508022903016d0604812f0201740304827e03016a010482440201750404834b02017604021a010484150504836a02057773c2b2380602520201780204823e0302cebc080484040303d2956403048171020179020484240204813c0202c2b303048307020484410301be0204816f030484250203c798680104843d03019c030482570204e19ea86a020482350302a0950a0482280204e5a4bc780304810e0101750126090a35030a03220a1731630f31252f0c4b1e31011e39200e3715282a03103b56090f6b1501121d4916246e6d460d6501162609380406361e816d203f011a22166008124f58202e182025150114390f3a25713f0e3f715c011a5a11191123466025710c313312011e3c191326811c1444055f1f5109051201143b106f1181000d068155012043381381020d81080d0603171824260a0201300404844a02013207024203026b390204833803066eeebabb35660604842102013308020302023f02013503048243020436716b66040481440201380a04843d020261690704836002016203048209030484670201630a04841d020264790104822b0201650502340302c2bd060484300201670202620201680704810d020169010484430104843402026b67040481540306eea3ad77c2aa0a04836702016c020258040482270104830a02016d0404824102036e716a0604843e02016f0104832a04020c0204836803036530650a04817402017005025b0301630604843d020171070275020273720404827002017504048133010484120301370102270201760104814f03026203016d0904844802017701048375080481220301660202330301700a04827f020378c2b2030484710202796806023c0301730704813d02017a0404815f0104817202048407010483390202c2b204026802048254040266640204831e0301b3090482230302b963060482010401750a0483290306ba35f2999dac09020f0203ca926e090483350203cdb4780302350202cebc0a020f0204d7a7696d010483100206f097bc996d71040481480101760114185b2258291610821c0e01160272173107154f5b813722011a81020c200e1826250d39811f07011a7911152a2a45131504422c81070120050d3f5b23342e3e4139032a3813042d0116592d1c15630c0c0a814649011c1a362f5c4a35511f0804033e372b01102981262a352e8205010e0b4b6282388106011e26810a2d125f361a12170d1721311e0201300204832b0201320104811b050483790201350204832202016404024c0202657a090483710202666307022703016c07048362030277750604842f0201670304843d0104844c0203686f7a07027202016a0102430204847502046ce0a2b20704810302016d0204827b02026e330804826c02016f0104835502017102027606026c020172060483490202736505048371020174030484130302387602025d02017502048345020376346b0904825c0201770904814b0303c2bd720804812b020178040483600201790804816402017a08026e0202c2b90704811c0301bd0504821e0204cdbcc7a108021a0202cfb8080481490204f09f96a50204842101017701180207232d37812d0c045c4a0a011a06163b3408171c52213a26592201206d08581605811a171e0c0a1347104914011282181324082b73320f01122f6e811d2c3d410a44011e551414206a092f133f333d150a3e0f011e235b170e37060627471b13373b3e27011a0e1e816b270c10102d53381045011a060e1e254d044932651234691e011a158138300a04810c0a8121071802013003027707048214020131080481370201320a04835502013304048271020538ceb369650802310201390a0481440202616c0502570302c7a104026c0201620804811c02016301048168020241020164040481560104820b020165080484460102400202686c060232020269670604827302016a0108810c826e0704824e02026b6c0604816902016c0304831c02016d0304811903016407022b02016e01022e0604845a030237780702040301710804815102016f0104842903017a0704826902017003048445020482080202713002024e0201720804822003016202022302017303048111010482790204812d03067479c39f66700a0210020174020229020175090484430301690604820402017606020202017a01021b0104843a0202c2b90604842b0301bd030484570202c69b0504815d0202c8a30a02240202ceb8090484690301bc0404832f0202df85020481230101780116812b0a16810e4b045a3b2a01205b1305811134092f62072343100f0f05011e5734152612030b4c4134123009361601121781653207780a6a0d01164a25210824138107738139011481341f088158060c8133010e5920193a4c2331011a0510358101231a1b3609702732011a2f07631610033436810256174c011a1342040a58110721378139101602033067750802720201320604834303017109048244020133090481700203366f79010483520201390404810902016301048411050483420201640a048432020265310704832b02026774040481000302d5b2010259020369756c0504832902016c07048365030233700904824102016d010482670404834c0504830c02016e0104831604048120030169090481750303eba6990104835f02016f0604834c030379c2ba0a0481560201700404815e06048256020174040482370201760a04820d0201770604811c02017a0404812e06020b0202c2b9030481660301bd0a04816c0301be030483620206c99b6d7777750304835b0206ceb0646b66610402490202d8bf030482250206e8bfbc626964080482510204f09c9a9e0404830f010179010e2081335661371c01220e4e2718124f0d0649812b0b0a063b040b011402741d1235810805211a011409161d732b8106325f6a01182e330325068107703728302b011e3723081c0d0a3f810c183e061b067f0106834a12011a044030185a1e810704220a0541011245602b0e421441817801144b03811a1a29614e224b02013003048139020132050485050304f09caba6010482230201350104822708048413020138020483430201610402230201620902440108812181070301300304815e020263710404831002016403048226010483660604823c020165010484510201670104816407048418030334c2b20a0481120201690404814c02016a010481500904810f02036b75610304836402016d01027902016f0304817b03056f6373cebc0a0483010201700104817d020171050482680104843b0302383203048128040807090707070b0608060707060c0b810e07080807070707060b080707070b0807090807070a070a07070808070b06090807070708080a0b81230907070b070b0707080907070706090807070807060b07060707070808070a080b0708090b0b09810a0707060908070607060609070b0a070706080a09070707070e0a0708090b0c0b09070a080a811a0706080c09070a07080b0708060806070b080c0e07090e09060706080b060a070b0607090707130b080708070b0908070a0c810d070b0706080707080b080a0a070807090708070707090709070706080709080a81170a0707070a070707070a0b0a07080d080707060a070707070b0707060f0b060707060a08070807080708810d0807070709070b070808070907080f0b070907090b0707070a0807070c0b080c0a810107070a0b07060c07080f070b09070b0906070b070b');
INSERT INTO t1_data VALUES(274877906949,X'00000e5c033079720404826c0404833002021b03026f6b020482100201740904842e010484150303c2b36f0204840e0201760704826b02017708048273020578f48ba5b50a0481400201790904845902017a050483280304c2bac2bd0404841e0203c2aa680904843a0301bc070481100301be0304820304016a050481630202ca8103027b0202cb860604840d0204ceb56e370204832e0302bc740202520202cf8d07027e0205d8ae39c2aa0104813c0204e887b3770404816a0204f1bfb0970204832f01017a0118101e282f07045961813a193e011e69162f0d2b051c060f084460063053011e06810c20330d0733815c220515220c011210290a7e07810c3a18011a1f2f064a19155212472781047c010a123e45825501166c6062182718167131092f0112331b812c0b6e81470b01184f3a230d45261e271c36111701140a8128456b291248391a0201300104840d0204812502013401048318020137070483070201380904823b03016704026402013907023403016e060481380201610204812f0404824504045243020162050481150104824003016a0804827a020163070484590204817903017a02048209020164020484200203653077030482610302737601048424020166070481730201670304841e0504840e03016b0504825302016901048235010484400404841002016a010483680404845f02046bc2b97407023302026c7a0704812d02027161070209030378cebc0a021f020172040483750404815f0201730304813c030131020482040201740704824d0302793901027502017604048423020177040620813103048313020179030484540204833c04022503017a0904826302017a050483530203c2b2660404840f0307ba6272f397bd92010483070301be020482760202c6b9050482410203c9a3650604812c0202cbae020482180202d38c0704812f0204f096adb7070483490204f6a69c8b030484390102c2aa010c815e81147969010c811c827f0417010e81077a4c03815f010a2e8100820c010a810d148140010c0a7481201a13010c0b831525323d010a8206358129010c21637a33812701083c8340390301300504820a0304326939770404841c03016107048334030165030484150302696c0704810103016c0704812a03027178090481620301730504830e0301750504846303017802021c0301790304836803017a0604834e040135030482650302cdbf010483330304ceb23169070484090303e4849a0504817d0201b201088219744601082210832c010629846001121c8137182211816232010a81668122690108817281080110816a433581102f3e010e7481001b3481190106814e1b010e3646823a810e070301310504840b030161010481720301660604822f0301680804821003016a0704844803016b0104845b03016c0504823403026f700802340301710804826004026d3106024a03017509068458070301770a04836c04016b01021f0301790a0482790302c2b20a02270401b3040482130303ceae6e010484330302df9e040482100201b3010881656e750106820b50010e81434a27048153010a812b068122010843810c0401048211010a50817d812e010c811a8163810801061e832c010c811f81418101030163030481210301640504831102048104030482440301680a048202040271300404841303066b6576cebc6a0104843603026f7a08026d0303756a7808023e030176040483610301770704814403027973020484360302c2b906020c0401bc010484490401bd0804835c0302d38c0304846f0304eaae96750a0484020201b9010c3b824018322d010e0468315a5c817901067d583401060b810e010865118169010c0e07826b813a01066f8265010c3b8239633852010e61161e7030821b01068241210301350804843d0301620302480301690402610403e7a1910704812103016d080269030673c2bac2b36c090483070301760504821d02048454030278350702620302c2ba010483320304ca897a750804813b0401b5070482350303cebc6d050483120302d199020483020402ad660604840c0302d2a1010482550302daa30202340201ba01026d01085119826a010c2f5e82008110010882028221010481090108821b812d01068128460208810b8264010c810971812d440301310304820e0301320504825e05048221030333756d010482720301340502700301640604813d03016607020c0301690204823a03016b0104812203016c0704842103016d0304835f03016e0a04813c03016f0304834d030173060482660401710604810f0301740104843c0303d48174040482690201bc010482690108813c83290114090f816045242e148111010a810616822701048456010e2c81167a638115010a3a3b83204001067a8367010c8114127a2265010a824f7f5c230301300604833e0302616f020483560301640104827d090481280301650502150301660804841a03016804048221030169030481120301720104827803017606023d04016e020481700302c2aa0904836c0401ba090484100201bd01088240224f010843813674020a81185068620106822a44010e14154a8101825e010c19814a1b826c010c81221f81651b010a815a4d812c01082d7281160301300804843c030231300304836703013509048353030365c2bc0304814d0302667504027a0301670604831503016c09025d03016d03048178030172020483620301730104816b0402c2b30404823203017401027204016a08048451030175090237040177090481690301770302190301780a04823d03027a350a0481260302c2aa060481620401b3090481090304f098a1a30a04825d0201be010a0d730b816f010c821d81236c2b010c6f8208358119010681236801087d4e831e0108823c8235010667794b010683165e010e05812e3d3c820d010c81148123817403043531c2ba0204824c03083875c2bceba7957a03020803016302020804036dcebc0304814e0301640304843704033379790504823203016b08023603016d070481090304825804013707027a03016f080484530301710a04842203017809025e0304c2aa6135010481460401b90a04836b0401bc0704814f0306c6ab66e3afb9080482660103c39f350304821f0201b0050481110301680602030201b8040481310604810403016c0a024803017108024b0201be06048323030482650301300504812d0304f48990ae060482740103c491680a0483700301760a0481290201a7010484090202b177020482380201b3030482280102c5800602090301360104826a02018202048173040483780301370104814102018b090482730201930504810f0102c680020483790404830c020183020228020185030484400704820b02028d7a0a04821c0201920404835e02019507048437010484070301760204836102019a020214080483100303d795680504820602019e030481050201a30404820a05048436030177070484290201a50704843b0201a8060482690304816f03027735020483630202ab79050484430201b6060481050201b904024003016d070481130201bd090484350201bf06048361030163020481580102c781040484560201830604833a020286650404842a0301750a04821a020189070483370303e0b9b30904836602018c0104816c04020602021d030171050484570201960a04842d03016b0204821903016c04021e03016e0204845002019a0a04844402019d0704835103013103021702039f77750704827e0201a1090483340201a301022b0404831d0304616363750502520302cfb2040483720201a50a0481530202ad760902310201af0104811d0908816281390301640404843c0201b3080483240201bb030483480201bd040484290304840a0203bf646a0404843f03017a040482450102c89d05020f0201a1090483550201a3060483550201ab0904813203017a04024a0201ad030482210201b10204824302025d0303656577030483600202b46e010482240201b6090484410204bce39f9d020484570102c9870604813202018b0804843603017a06027102018d080481130204840c02018f0104836309026202029164020484430201930504816d0201970304843402039c6c73070483700201a0070483470201a203048262030364d7960a0484010201a80304832a060484390202a96a080481170303c69532090481440201ac040214020481180202ae770604832c0201b0090482300201b40804845a0201b5070482110302716f010482160201ba0504837b0201bb02048149030165050483250201bc07088105833002067f824d0302d19f0402330201bd04024d03017a0904814f0102ca800a048321020181040481580201820604821e020383693707048417020287630704840002018a0904834c0104835c02018b06022f02018c0704814702018d0704810a0104831a020490e7b38308048423020191020482510201920304832f030135030483710201950304833207026802019902026b02019b0904832a02019d09024c02019f0802210201a4010484080202a5710a0481680203a777670804831e0301790902100201ae0402700104834e0201af040484650202b673080484190201b705048221010483520201b808048465030167010484400104cb81cab90104834802018602048317020689777568cf920804842602018b0404817b020191050484200202a0720304833e0201a3040625827f0201a4030485080102cdb1070881408205020483700201b30404840e0202b735080482640201b80504815a0201b90a0482370206bb31cebc6c730304842f030133070483010103ce80370304826d0201900202770201ae0504844e0201b1050484080201b20904815f0201b3040483430201b40702600201b50804823b0201b90304846e0302c9a1070483300201ba0404844d0104847e0201bb050482780201bc010882378223010e811105814d8134010a8142823f2d0106811c52010a6e1814816b02088168824b010a438137812d011019060c6b812f811c010a81314e811b03033366660404825503013502048263030238620904820703016303048120040f080b0907070b07070a0907070707080a07070b0a0a81060b0707070606070f0b070b07070908070b070f0b090807080b07070707070c0e0707090d07080908080a0a50070a0707080708070706070707080a094d07070707070707070707080706070707090844070f07080c0708070708070707080a4707060609060c0b07080a07090808080737070b09060706070707070707070707094807080b0607070707060708074107080709070706070707080607060706070808070a460a0d06090709060b060707060a07070c0907060b06060b070a090707080707070b0707070c060b08070b070a09070b07070b08080706070707070807080707090d070707060707070609070a090807070d0707070b09070707070706070a0908070a0807060b0a080707090707090b08090a08070707080707070e07060708070709080b06070b0a0707070a06070606070809060a07080b07070a070c07070808070e070807070c07090607070707060707080b0743090708');
@@ -6976,7 +6975,7 @@ COMMIT;
do_catchsql_test 51.1 {
SELECT max(rowid)==0 FROM t1('e*');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#--------------------------------------------------------------------------
reset_db
@@ -8752,7 +8751,7 @@ do_test 60.0 {
do_catchsql_test 60.2 {
SELECT (matchinfo(t1,591)) FROM t1 WHERE t1 MATCH 'e*eŸ'
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#-------------------------------------------------------------------------
do_test 61.0 {
@@ -9773,7 +9772,7 @@ do_test 66.0 {
do_catchsql_test 66.1 {
INSERT INTO t1(t1) VALUES('integrity-check');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#-------------------------------------------------------------------------
#
@@ -10107,7 +10106,7 @@ do_test 68.0 {
do_catchsql_test 68.1 {
PRAGMA reverse_unordered_selects=ON;
INSERT INTO t1(t1) SELECT x FROM t2;
-} {1 {database disk image is malformed}}
+} {1 {fts5: corruption on page 1, segment 1, table "t1"}}
#-------------------------------------------------------------------------
reset_db
@@ -10323,7 +10322,7 @@ do_test 69.0 {
do_catchsql_test 69.2 {
SELECT * FROM t1 WHERE a MATCH 'fx*'
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#-------------------------------------------------------------------------
reset_db
@@ -10506,7 +10505,7 @@ do_test 71.0 {
do_catchsql_test 71.2 {
INSERT INTO t1(t1) VALUES('integrity-check');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#-------------------------------------------------------------------------
reset_db
@@ -10633,9 +10632,9 @@ do_catchsql_test 72.1 {
INSERT INTO ttt(ttt) VALUES('integrity-check');
} {1 {database disk image is malformed}}
-do_catchsql_test 72.1 {
+do_catchsql_test 72.2 {
SELECT 1 FROM ttt('e* NOT ee*');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#-------------------------------------------------------------------------
reset_db
@@ -10761,7 +10760,7 @@ do_test 73.0 {
do_catchsql_test 73.1 {
SELECT snippet(ttt,ttt, NOT 54 ),
* FROM ttt('e* NOT ee*e* NOT ee* NOT ee*e* NOT e*') ;
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#-------------------------------------------------------------------------
reset_db
@@ -15910,8 +15909,220 @@ do_catchsql_test 82.4 {
SAVEPOINT b;
} {1 {database disk image is malformed}}
+#-------------------------------------------------------------------------
+reset_db
+do_test 83.0 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+.open --hexdb
+| size 24576 pagesize 4096 filename crash-c4a4c5492615bd.db
+| page 1 offset 0
+| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
+| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 06 .....@ ........
+| 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 00 ................
+| 96: 00 00 00 00 0d 00 00 00 06 0e 0f 00 0f aa 0f 53 ...............S
+| 112: 0e e8 0e 8b 0e 33 0e 0f 00 01 00 00 00 00 00 00 .....3..........
+| 3584: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 22 ................
+| 3600: 06 06 17 11 11 01 31 74 61 62 6c 65 62 62 62 62 ......1tablebbbb
+| 3616: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 62 62 .CREATE TABLE bb
+| 3632: 28 61 29 56 05 06 17 1f 1f 01 7d 74 61 62 6c 65 (a)V.......table
+| 3648: 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 6f 6e 66 t1_configt1_conf
+| 3664: 69 67 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 ig.CREATE TABLE
+| 3680: 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b 20 50 52 't1_config'(k PR
+| 3696: 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 20 57 49 IMARY KEY, v) WI
+| 3712: 54 48 4f 55 54 20 52 4f 57 49 44 5b 04 07 17 21 THOUT ROWID[...!
+| 3728: 21 01 81 01 74 61 62 6c 65 74 31 5f 64 6f 63 73 !...tablet1_docs
+| 3744: 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 04 43 52 izet1_docsize.CR
+| 3760: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 64 EATE TABLE 't1_d
+| 3776: 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 54 45 47 ocsize'(id INTEG
+| 3792: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY,
+| 3808: 73 7a 20 42 4c 4f 42 29 69 03 07 17 19 19 01 81 sz BLOB)i.......
+| 3824: 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 31 5f 69 -tablet1_idxt1_i
+| 3840: 64 78 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 dx.CREATE TABLE
+| 3856: 27 74 31 5f 69 64 78 27 28 73 65 67 69 64 2c 20 't1_idx'(segid,
+| 3872: 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 52 49 4d term, pgno, PRIM
+| 3888: 41 52 59 20 4b 45 59 28 73 65 67 69 64 2c 20 74 ARY KEY(segid, t
+| 3904: 65 72 6d 29 29 20 57 49 54 48 4f 55 54 20 52 4f erm)) WITHOUT RO
+| 3920: 57 49 44 55 02 07 17 1b 1b 01 81 01 74 61 62 6c WIDU........tabl
+| 3936: 65 74 31 5f 64 61 74 61 74 31 5f 64 61 74 61 02 et1_datat1_data.
+| 3952: 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 CREATE TABLE 't1
+| 3968: 5f 64 61 74 61 27 28 69 64 20 49 4e 54 45 47 45 _data'(id INTEGE
+| 3984: 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 R PRIMARY KEY, b
+| 4000: 6c 6f 63 6b 20 42 4c 4f 42 29 54 01 07 17 11 11 lock BLOB)T.....
+| 4016: 08 81 15 74 61 62 6c 65 74 31 74 31 43 52 45 41 ...tablet1t1CREA
+| 4032: 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 4c 45 TE VIRTUAL TABLE
+| 4048: 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 28 61 t1 USING fts5(a
+| 4064: 2c 62 2c 70 72 65 66 69 78 3d 22 31 2c 32 2c 33 ,b,prefix=.1,2,3
+| 4080: 2c 34 22 2c 20 63 6f 6e 74 65 6e 74 3d 22 22 29 ,4., content=..)
+| page 2 offset 4096
+| 0: 0d 0b 6a 00 37 09 4c 02 0f e7 09 4c 0f c6 0f a4 ..j.7.L....L....
+| 16: 0f 88 0f 6d 0f 4b 0f 2c 0f 0e 0e ec 0e cd 0e ad ...m.K.,........
+| 32: 0e 8e 0e 6c 0e 4b 0e 29 0e 08 0d e6 0d c4 0d b5 ...l.K.)........
+| 48: 0d 97 0d 76 0d 54 0d 31 0d 15 0c f3 0c d3 0c b5 ...v.T.1........
+| 64: 0c 95 0c 73 0c 54 0c 32 0c 10 0b ee 0b cc 0b b0 ...s.T.2........
+| 80: 0b 8d 0b 7e 0b 48 0b 2e 0b 00 4a ef fa cc 0a ad ...~.H....J.....
+| 96: 0a 8c 0a 6d 0a 4d 0a 2b 0a 0c 09 00 00 00 00 00 ...m.M.+........
+| 2368: 00 00 00 00 00 00 00 00 00 00 00 00 15 0a 03 00 ................
+| 2384: 30 00 00 00 01 01 03 35 00 03 01 01 12 02 01 12 0......5........
+| 2400: 03 01 11 1c 8c 80 80 80 80 10 03 00 3e 00 00 00 ............>...
+| 2416: 17 01 05 05 34 74 61 62 6c 03 02 03 01 04 77 68 ....4tabl.....wh
+| 2432: 65 72 03 02 06 09 1b 8c 80 80 80 80 0f 03 00 3c er.............<
+| 2448: 00 00 00 16 05 34 66 74 73 34 03 02 02 01 04 6e .....4fts4.....n
+| 2464: 75 6d 62 03 07 01 04 09 1b 8c 80 80 80 80 0e 03 umb.............
+| 2480: 00 3c 00 00 00 16 04 33 74 68 65 03 06 01 01 04 .<.....3the.....
+| 2496: 01 03 77 68 65 03 02 04 04 0a 1b 8c 80 80 80 80 ..whe...........
+| 2512: 0d 03 00 3c 00 00 00 16 04 33 6e 75 6d 03 06 01 ...<.....3num...
+| 2528: 01 05 01 03 74 61 62 03 02 03 04 0a 19 8c 80 80 ....tab.........
+| 2544: 80 80 0c 03 00 38 00 00 00 14 03 32 77 68 03 02 .....8.....2wh..
+| 2560: 04 00 04 33 66 74 73 03 02 02 04 07 18 8c 80 80 ...3fts.........
+| 2576: 80 80 0b 03 00 36 00 00 00 13 03 32 74 61 03 02 .....6.....2ta..
+| 2592: 03 02 01 68 03 06 01 01 04 04 07 1b 8c 80 80 80 ...h............
+| 2608: 80 0a 03 00 3c 00 00 00 16 03 32 6e 75 03 06 01 ....<.....2nu...
+| 2624: 01 05 01 02 6f 66 03 06 01 01 06 04 09 19 8c 80 ....of..........
+| 2640: 80 80 80 09 03 00 38 00 00 00 14 03 32 66 74 03 ......8.....2ft.
+| 2656: 02 02 01 02 69 73 02 06 01 01 03 04 07 18 8c 80 ....is..........
+| 2672: 80 80 22 08 03 00 36 00 00 00 13 02 31 74 03 08 ......6.....1t..
+| 2688: 03 01 01 04 01 01 77 03 02 04 04 09 1a 8c 80 80 ......w.........
+| 2704: 80 80 07 03 00 3a 00 00 00 15 02 31 6e 03 08 01 .....:.....1n...
+| 2720: 01 02 05 01 01 6f 03 06 01 01 06 04 09 18 8c 80 .....o..........
+| 2736: 80 80 80 06 03 00 36 00 00 00 13 04 02 31 66 03 ......6......1f.
+| 2752: 02 02 01 01 69 03 06 01 01 03 05 06 1c 8c 80 80 ....i...........
+| 2768: 80 80 05 03 00 3e 00 00 00 17 04 30 74 68 65 03 .....>.....0the.
+| 2784: 06 01 01 04 01 05 77 68 65 72 65 03 02 04 0a 15 ......where.....
+| 2800: 8c 80 80 80 80 04 03 00 30 00 00 00 11 01 01 06 ........0.......
+| 2816: 06 30 74 61 62 6c 65 03 01 f3 07 1c 8c 80 80 80 .0table.........
+| 2832: 80 03 03 00 3e 00 00 00 17 07 30 6e 75 6d 62 65 ....>.....0numbe
+| 2848: 72 03 06 01 01 05 01 02 6f 66 03 06 04 0d 13 8c r.......of......
+| 2864: 80 80 80 80 02 03 00 2c 00 00 00 0f 01 01 03 02 .......,........
+| 2880: 30 6e 03 06 01 01 02 07 1b 8c 80 80 80 80 01 03 0n..............
+| 2896: 00 3c 00 00 00 16 08 30 66 74 73 34 61 75 78 03 .<.....0fts4aux.
+| 2912: 02 02 01 02 69 73 03 06 04 0c 00 00 00 14 2a 00 ....is........*.
+| 2928: 00 00 01 01 02 24 00 02 01 01 12 02 01 12 08 88 .....$..........
+| 2944: 80 80 80 80 12 03 00 16 00 00 00 05 02 1c 88 80 ................
+| 2960: 80 80 80 11 03 00 3e 00 00 00 17 05 34 72 6f 77 ......>.....4row
+| 2976: 73 02 06 01 01 05 01 04 74 68 65 72 02 02 04 0b s.......ther....
+| 2992: 15 88 80 80 80 80 10 03 00 30 00 00 00 11 02 01 .........0......
+| 3008: 01 07 05 34 62 65 74 77 02 02 04 08 1b 88 80 80 ...4betw........
+| 3024: 80 80 0f 03 00 3c 00 00 00 16 04 04 33 72 6f 77 .....<......3row
+| 3040: 02 06 01 01 05 01 03 74 68 65 02 08 05 0a 1b 88 .......the......
+| 3056: 80 80 80 80 0e 03 00 3c 00 00 00 16 01 01 02 04 .......<........
+| 3072: 33 61 72 65 02 02 b3 01 03 62 65 74 02 02 07 08 3are.....bet....
+| 3088: 1b 88 80 80 80 80 0d 03 00 3c 00 00 00 16 03 32 .........<.....2
+| 3104: 74 68 02 08 02 01 01 07 00 04 33 61 6e 64 02 06 th........3and..
+| 3120: 04 0a 1b 88 80 80 80 80 0c 03 00 3c 00 00 00 16 ...........<....
+| 3136: 03 32 69 6e 02 06 01 01 06 01 02 72 6f 02 06 01 .2in.......ro...
+| 3152: 01 05 04 09 18 88 80 80 80 80 0b 03 00 36 00 0f .............6..
+| 3168: f0 13 02 03 32 61 72 02 02 03 01 02 62 65 02 02 ....2ar.....be..
+| 3184: 03 05 07 1b 88 80 80 80 80 0a 03 00 3c dd 00 00 ............<...
+| 3200: 18 c2 31 74 02 08 02 01 01 07 00 03 32 61 6e 02 ..1t........2an.
+| 3216: 06 01 01 04 09 19 88 80 80 80 80 09 03 00 38 00 ..............8.
+| 3232: 00 00 14 02 31 6e 02 06 01 01 03 01 01 72 02 06 ....1n.......r..
+| 3248: 01 01 05 04 08 17 88 80 80 80 80 08 03 00 34 00 ..............4.
+| 3264: 00 00 12 02 31 62 02 02 04 01 01 69 02 06 01 01 ....1b.....i....
+| 3280: 06 04 06 19 88 80 90 80 80 07 03 00 38 00 00 00 ............8...
+| 3296: 14 04 02 31 32 02 02 05 01 01 61 02 08 03 01 01 ...12.....a.....
+| 3312: 02 05 06 1b 88 80 80 80 80 06 03 00 3c 00 00 00 ............<...
+| 3328: 16 06 30 74 68 65 72 65 02 02 02 00 02 31 31 02 ..0there.....11.
+| 3344: 06 01 01 04 0a 15 88 80 80 80 80 05 03 00 30 00 ..............0.
+| 3360: 00 00 11 01 01 05 04 30 74 68 65 02 06 01 01 07 .......0the.....
+| 3376: 07 1c 88 80 80 80 80 04 03 00 3e 00 00 00 17 01 ..........>.....
+| 3392: 01 06 02 30 6e 02 06 01 01 03 01 04 72 6f 77 73 ...0n.......rows
+| 3408: 02 06 07 08 1b 88 80 80 80 80 03 03 00 3c 00 00 .............<..
+| 3424: 00 16 08 30 62 65 74 77 65 65 6e 02 02 04 01 02 ...0between.....
+| 3440: 69 6e 02 06 04 0c 1a 88 80 80 80 80 02 03 00 3a in.............:
+| 3456: 00 00 00 15 04 30 61 6e 64 02 06 01 01 02 02 02 .....0and.......
+| 3472: 72 65 02 02 03 04 0a 17 88 80 80 80 80 01 03 00 re..............
+| 3488: 34 00 00 0c 52 02 30 31 02 06 01 01 04 01 01 32 4...R.01.......2
+| 3504: 02 02 05 04 08 08 84 80 80 80 80 12 03 00 16 00 ................
+| 3520: 00 00 05 04 1b 84 80 80 80 80 11 03 00 3c 00 00 .............<..
+| 3536: 00 16 05 34 74 61 62 6c 01 06 00 f1 05 02 03 65 ...4tabl.......e
+| 3552: 72 6d 01 02 04 0b 1b 84 80 80 80 80 10 03 00 3c rm.............<
+| 3568: 00 00 00 16 05 34 65 61 63 68 01 02 03 01 04 70 .....4each.....p
+| 3584: 72 65 73 01 02 05 04 09 1a 84 80 80 80 80 0f 03 res.............
+| 3600: 00 3a 00 00 00 15 04 33 74 65 72 01 02 04 02 02 .:.....3ter.....
+| 3616: 68 65 01 06 01 01 03 04 08 1b 84 80 80 80 80 0e he..............
+| 3632: 03 00 3c 00 00 00 16 04 33 70 72 65 01 02 05 01 ..<.....3pre....
+| 3648: 03 74 61 62 01 06 01 01 05 04 08 1a 84 80 80 80 .tab............
+| 3664: 80 0d 03 00 3a 00 00 00 15 04 33 66 6f 72 01 02 ....:.....3for..
+| 3680: 02 02 02 74 73 01 06 01 01 04 04 08 1b 84 80 80 ...ts...........
+| 3696: 80 80 0c 03 00 3c 00 00 00 16 03 32 74 68 01 06 .....<.....2th..
+| 3712: 01 01 03 00 04 33 65 61 63 01 02 03 04 09 18 74 .....3eac......t
+| 3728: 80 80 80 80 0b 03 00 36 00 00 00 13 03 32 74 61 .......6.....2ta
+| 3744: 01 06 01 01 05 02 01 65 01 02 04 04 09 19 84 80 .......e........
+| 3760: 80 80 80 0a 03 00 38 00 00 00 14 03 32 69 6e 01 ......8.....2in.
+| 3776: 06 01 01 02 11 02 70 62 01 02 05 04 09 18 84 80 ......pb........
+| 3792: 80 80 80 09 03 00 36 00 00 00 13 03 32 66 6f 01 ......6.....2fo.
+| 3808: 02 02 02 01 74 01 06 01 01 04 04 07 1b 84 80 80 ....t...........
+| 3824: 80 80 08 03 00 3c 0d c0 00 16 12 31 74 01 0a 04 .....<.....1t...
+| 3840: 01 01 03 04 00 03 32 65 61 01 02 03 04 0a 17 84 ......2ea.......
+| 3856: 80 80 80 80 07 03 00 34 00 00 00 12 02 31 69 01 .......4.....1i.
+| 3872: 06 01 01 02 01 01 70 01 02 05 04 08 18 84 80 80 ......p.........
+| 3888: 80 80 06 03 00 36 00 00 00 13 02 31 65 01 02 03 .....6.....1e...
+| 3904: 01 01 66 01 08 02 5b 01 04 04 06 1b 84 80 80 80 ..f...[.........
+| 3920: 80 05 03 00 3c 00 00 00 16 05 30 74 65 72 6d 01 ....<.....0term.
+| 3936: 02 04 02 02 68 65 01 06 01 01 03 04 09 14 84 80 ....he..........
+| 3952: 80 80 80 04 03 00 2e 00 00 00 10 06 30 74 61 62 ............0tab
+| 3968: 6c 65 01 06 01 01 05 04 15 84 80 80 80 80 03 03 le..............
+| 3984: 00 30 00 00 00 11 01 f8 30 70 72 65 73 65 6e 74 .0......0present
+| 4000: 01 02 05 05 1b 84 80 80 80 80 02 03 00 3c 00 00 .............<..
+| 4016: 00 16 04 30 66 74 73 01 06 01 01 04 01 02 69 6e ...0fts.......in
+| 4032: 01 06 01 01 04 0a 1a 84 80 80 80 80 01 03 00 3a ...............:
+| 4048: 00 00 00 15 05 30 65 61 63 68 01 02 03 01 03 66 .....0each.....f
+| 4064: 6f 72 01 02 02 04 09 06 01 03 00 12 03 0b 0f 00 or..............
+| 4080: 00 08 8c 80 80 80 80 11 03 00 16 00 00 00 05 04 ................
+| page 3 offset 8192
+| 0: 0a 00 00 00 32 0e 4f 00 0f fa 0f f1 0f e9 0f e1 ....2.O.........
+| 16: 0f d8 0f d1 0f c9 0f c1 0f b9 0f b1 0f a9 0f a0 ................
+| 32: 0f 98 0f 90 0f 87 0f 80 0f 78 0f 71 0f 68 0f 5f .........x.q.h._
+| 48: 0f 56 0f 4d 0f 41 0f 38 0f 2f 0f 26 0f 1d 0f 13 .V.M.A.8./.&....
+| 64: 0f 0a 0f 01 0e f7 0e ee 0e e6 0e dd 0e d6 0e cd ................
+| 80: 0e c3 0e ba 0e b0 0e a8 0e 9f 0e 96 0e 00 00 00 ................
+| 3648: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 ................
+| 3664: 04 01 10 01 03 34 74 20 07 04 02 4e 01 03 34 1e .....4t ...N..4.
+| 3680: 09 04 01 12 01 03 33 74 68 1c 08 04 01 10 01 03 ......3th.......
+| 3696: 33 6e 1a 08 04 01 10 01 03 32 77 18 08 04 01 10 3n.......2w.....
+| 3712: 01 03 32 74 16 08 04 01 10 01 03 32 6e 14 07 04 ..2t.......2n...
+| 3728: 01 0e 01 03 32 12 08 04 01 10 01 03 31 74 10 08 ....2.......1t..
+| 3744: 04 01 10 01 03 31 6e 0e 07 04 01 0e 01 03 31 0c .....1n.......1.
+| 3760: 09 04 01 12 01 03 30 74 68 0a 08 04 01 10 01 03 ......0th.......
+| 3776: 30 74 08 19 04 01 12 01 03 30 6e 75 06 08 04 01 0t.......0nu....
+| 3792: 10 01 03 30 6e 04 06 04 01 0c 01 03 02 08 04 01 ...0n...........
+| 3808: 10 01 02 34 72 22 07 04 01 0e 01 02 34 20 08 04 ...4r.......4 ..
+| 3824: 01 10 01 02 33 72 1e 09 04 01 12 01 02 33 61 72 ....3r.......3ar
+| 3840: 1c 08 04 01 10 01 02 32 74 1a 08 04 01 10 01 02 .......2t.......
+| 3856: 32 69 18 09 04 01 12 01 02 32 60 82 16 08 04 01 2i.......2`.....
+| 3872: 10 01 02 31 74 14 08 04 01 10 01 02 31 6e 12 08 ...1t.......1n..
+| 3888: 04 01 10 01 02 31 62 10 08 04 01 10 01 02 31 32 .....1b.......12
+| 3904: 0e 0b 04 01 16 01 02 30 74 68 65 72 0c 08 04 01 .......0ther....
+| 3920: 10 01 02 30 74 0a 08 04 01 10 01 02 30 6e 08 08 ...0t.......0n..
+| 3936: 04 01 10 01 02 30 62 06 08 04 01 10 01 02 30 61 .....0b.......0a
+| 3952: 04 06 04 01 0c 01 02 02 07 04 09 10 01 34 74 22 .............4t.
+| 3968: 06 04 09 0e 01 34 20 08 04 09 12 01 33 74 65 1e .....4 .....3te.
+| 3984: 07 04 09 10 01 33 70 1c 07 04 09 10 01 33 66 1a .....3p......3f.
+| 4000: 08 04 09 12 01 32 74 68 18 07 04 09 10 01 32 74 .....2th......2t
+| 4016: 16 07 04 09 10 01 32 69 14 07 04 09 10 01 32 66 ......2i......2f
+| 4032: 12 07 04 09 10 01 31 74 10 07 04 09 10 01 31 69 ......1t......1i
+| 4048: 0e 06 04 09 0e 01 31 0c 08 04 09 12 01 30 74 65 ......1......0te
+| 4064: 0a 07 04 09 10 01 30 74 08 07 04 09 10 01 30 70 ......0t......0p
+| 4080: 06 08 04 09 12 01 30 66 74 04 05 04 09 0c 01 02 ......0ft.......
+| page 4 offset 12288
+| 0: 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+| 4064: 00 00 00 00 00 00 00 00 00 00 00 05 03 03 00 10 ................
+| 4080: 03 05 05 02 03 00 10 04 06 05 01 03 00 10 04 04 ................
+| page 5 offset 16384
+| 0: 0a 00 00 00 02 0f eb 00 0f eb 0f f4 00 00 00 00 ................
+| 4064: 00 00 00 00 00 00 00 00 00 00 00 08 03 15 01 70 ...............p
+| 4080: 67 83 7a 18 0b 03 1b 01 76 65 72 73 69 6f 6e 04 g.z.....version.
+| page 6 offset 20480
+| 0: 0d 00 00 00 03 0f f2 00 0f fc 0f 00 00 00 00 00 ................
+| 4080: 00 00 03 03 02 01 03 03 02 02 01 02 02 01 02 09 ................
+| end crash-c4a4c5492615bd.db
+}]} {}
+
+do_catchsql_test 83.1 {
+ SELECT * FROM t1('R*R*R*R*R*R*R*R*') WHERE (a,b)<=(current_date,0 BETWEEN 'a'<>11 AND '') ORDER BY rowid DESC;
+} {/.*fts5: corruption found/}
sqlite3_fts5_may_be_corrupt 0
finish_test
-
diff --git a/ext/fts5/test/fts5corrupt5.test b/ext/fts5/test/fts5corrupt5.test
index 6a70fc7e4..4b21a9ff7 100644
--- a/ext/fts5/test/fts5corrupt5.test
+++ b/ext/fts5/test/fts5corrupt5.test
@@ -237,7 +237,7 @@ do_test 1.0 {
do_catchsql_test 1.1 {
SELECT * FROM t1('R*') WHERE (a,b)<=(current_date,0) ORDER BY rowid DESC;
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#-------------------------------------------------------------------------
#
@@ -450,7 +450,7 @@ do_test 2.0 {
do_catchsql_test 2.1 {
SELECT * FROM t1('R*R*R*R*') WHERE (a,b)<=(current_date,0) ORDER BY rowid DESC;
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#-------------------------------------------------------------------------
reset_db
@@ -569,7 +569,7 @@ do_test 3.0 {
do_catchsql_test 3.1 {
UPDATE t1 SET b=quote(zeroblob(200)) WHERE a MATCH 'thra*T';
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#-------------------------------------------------------------------------
reset_db
@@ -878,7 +878,7 @@ do_execsql_test 5.1 {
}
do_catchsql_test 5.4 {
UPDATE t1 SET content=randomblob(500);
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
#-------------------------------------------------------------------------
reset_db
diff --git a/ext/fts5/test/fts5corrupt7.test b/ext/fts5/test/fts5corrupt7.test
index 41e359f42..23061a1cb 100644
--- a/ext/fts5/test/fts5corrupt7.test
+++ b/ext/fts5/test/fts5corrupt7.test
@@ -123,6 +123,6 @@ do_execsql_test 2.2 {
do_catchsql_test 2.3 {
DELETE FROM t1 WHERE rowid = 1
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
finish_test
diff --git a/ext/fts5/test/fts5corrupt8.test b/ext/fts5/test/fts5corrupt8.test
index d642920e4..a43bbaa03 100644
--- a/ext/fts5/test/fts5corrupt8.test
+++ b/ext/fts5/test/fts5corrupt8.test
@@ -32,7 +32,7 @@ sqlite3 db test.db
do_catchsql_test 1.2 {
SELECT * FROM t1
-} {1 {database disk image is malformed}}
+} {1 {fts5: corrupt structure record for table "t1"}}
do_catchsql_test 1.3 {
DROP TABLE t1
} {0 {}}
diff --git a/ext/fts5/test/fts5faultI.test b/ext/fts5/test/fts5faultI.test
index ab84d37de..a2b04af8f 100644
--- a/ext/fts5/test/fts5faultI.test
+++ b/ext/fts5/test/fts5faultI.test
@@ -325,5 +325,25 @@ ifcapable foreignkey {
}
}
+#-------------------------------------------------------------------------
+reset_db
+
+do_execsql_test 13.0 {
+ CREATE VIRTUAL TABLE t1 USING fts5(a, b);
+ INSERT INTO t1 VALUES('abc def', X'123456');
+}
+faultsim_save_and_close
+
+
+do_faultsim_test 13 -faults oom* -prep {
+ faultsim_restore_and_reopen
+} -body {
+ execsql {
+ UPDATE t1 SET a='def abc'
+ }
+} -test {
+ faultsim_test_result {0 {}}
+}
+
finish_test
diff --git a/ext/fts5/test/fts5integrity.test b/ext/fts5/test/fts5integrity.test
index 5c4002180..4bf120c44 100644
--- a/ext/fts5/test/fts5integrity.test
+++ b/ext/fts5/test/fts5integrity.test
@@ -37,6 +37,12 @@ do_execsql_test 2.1 {
INSERT INTO yy(yy) VALUES('integrity-check');
}
+db close
+sqlite3 db test.db
+do_execsql_test 2.1 {
+ INSERT INTO yy(yy) VALUES('integrity-check');
+}
+
#--------------------------------------------------------------------
#
do_execsql_test 3.0 {
diff --git a/ext/fts5/test/fts5rebuild.test b/ext/fts5/test/fts5rebuild.test
index d74b148fb..065d16b91 100644
--- a/ext/fts5/test/fts5rebuild.test
+++ b/ext/fts5/test/fts5rebuild.test
@@ -46,7 +46,7 @@ do_execsql_test 1.5 {
do_catchsql_test 1.6 {
INSERT INTO f1(f1) VALUES('integrity-check');
-} {1 {database disk image is malformed}}
+} {/.*fts5: corrupt.*/}
do_execsql_test 1.7 {
INSERT INTO f1(f1) VALUES('rebuild');
diff --git a/ext/fts5/test/fts5unicode4.test b/ext/fts5/test/fts5unicode4.test
index dc225cb5e..f006d6c0a 100644
--- a/ext/fts5/test/fts5unicode4.test
+++ b/ext/fts5/test/fts5unicode4.test
@@ -28,4 +28,34 @@ do_execsql_test 1.1 {
INSERT INTO sss VALUES('まりや');
}
+foreach {tn enc tok} {
+ 1 utf-8 ascii
+ 2 utf-16 ascii
+ 3 utf-8 unicode61
+ 4 utf-16 unicode61
+} {
+ reset_db
+
+ do_execsql_test 1.$tn.0 "
+ PRAGMA encoding = '$enc';
+ CREATE VIRTUAL TABLE vt2 USING fts5(c0, c1, tokenize=$tok);
+ "
+
+ do_execsql_test 1.$tn.1 {
+ INSERT INTO vt2(c0, c1) VALUES ('bhal', x'17db');
+ }
+
+ do_execsql_test 1.$tn.2 {
+ UPDATE vt2 SET c0='bhal';
+ }
+
+ do_execsql_test 1.$tn.3 {
+ INSERT INTO vt2(vt2) VALUES('integrity-check')
+ }
+
+ do_execsql_test 1.$tn.4 {
+ SELECT quote(c1) FROM vt2
+ } {X'17DB'}
+}
+
finish_test
diff --git a/ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java b/ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java
index 1fa6c6b80..912f6ed5b 100644
--- a/ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java
+++ b/ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java
@@ -120,7 +120,7 @@ public abstract class AggregateFunction<T> implements SQLFunction {
argument, the context is set to the given initial value. On all other
calls, the 2nd argument is ignored.
- @see SQLFunction.PerContextState#getAggregateState
+ @see AggregateFunction.PerContextState#getAggregateState
*/
protected final ValueHolder<T> getAggregateState(sqlite3_context cx, T initialValue){
return map.getAggregateState(cx, initialValue);
@@ -130,7 +130,7 @@ public abstract class AggregateFunction<T> implements SQLFunction {
To be called from the implementation's xFinal() method to fetch
the final state of the UDF and remove its mapping.
- see SQLFunction.PerContextState#takeAggregateState
+ see AggregateFunction.PerContextState#takeAggregateState
*/
protected final T takeAggregateState(sqlite3_context cx){
return map.takeAggregateState(cx);
diff --git a/ext/misc/fileio.c b/ext/misc/fileio.c
index 96a7f82bd..22d61df61 100644
--- a/ext/misc/fileio.c
+++ b/ext/misc/fileio.c
@@ -67,6 +67,7 @@
** data: For a regular file, a blob containing the file data. For a
** symlink, a text value containing the text of the link. For a
** directory, NULL.
+** level: Directory hierarchy level. Topmost is 1.
**
** If a non-NULL value is specified for the optional $dir parameter and
** $path is a relative path, then $path is interpreted relative to $dir.
@@ -92,13 +93,11 @@ SQLITE_EXTENSION_INIT1
# include <dirent.h>
# include <utime.h>
# include <sys/time.h>
+# define STRUCT_STAT struct stat
#else
-# include "windows.h"
-# include <io.h>
+# include "windirent.h"
# include <direct.h>
-# include "test_windirent.h"
-# define dirent DIRENT
-# define stat _stat
+# define STRUCT_STAT struct _stat
# define chmod(path,mode) fileio_chmod(path,mode)
# define mkdir(path,mode) fileio_mkdir(path)
#endif
@@ -116,14 +115,16 @@ SQLITE_EXTENSION_INIT1
/*
** Structure of the fsdir() table-valued function
*/
- /* 0 1 2 3 4 5 */
-#define FSDIR_SCHEMA "(name,mode,mtime,data,path HIDDEN,dir HIDDEN)"
+ /* 0 1 2 3 4 5 6 */
+#define FSDIR_SCHEMA "(name,mode,mtime,data,level,path HIDDEN,dir HIDDEN)"
+
#define FSDIR_COLUMN_NAME 0 /* Name of the file */
#define FSDIR_COLUMN_MODE 1 /* Access mode */
#define FSDIR_COLUMN_MTIME 2 /* Last modification time */
#define FSDIR_COLUMN_DATA 3 /* File content */
-#define FSDIR_COLUMN_PATH 4 /* Path to top of search */
-#define FSDIR_COLUMN_DIR 5 /* Path is relative to this directory */
+#define FSDIR_COLUMN_LEVEL 4 /* Level. Topmost is 1 */
+#define FSDIR_COLUMN_PATH 5 /* Path to top of search */
+#define FSDIR_COLUMN_DIR 6 /* Path is relative to this directory */
/*
** UTF8 chmod() function for Windows
@@ -289,7 +290,7 @@ LPWSTR utf8_to_utf16(const char *z){
*/
static void statTimesToUtc(
const char *zPath,
- struct stat *pStatBuf
+ STRUCT_STAT *pStatBuf
){
HANDLE hFindFile;
WIN32_FIND_DATAW fd;
@@ -317,7 +318,7 @@ static void statTimesToUtc(
*/
static int fileStat(
const char *zPath,
- struct stat *pStatBuf
+ STRUCT_STAT *pStatBuf
){
#if defined(_WIN32)
sqlite3_int64 sz = strlen(zPath);
@@ -341,7 +342,7 @@ static int fileStat(
*/
static int fileLinkStat(
const char *zPath,
- struct stat *pStatBuf
+ STRUCT_STAT *pStatBuf
){
#if defined(_WIN32)
return fileStat(zPath, pStatBuf);
@@ -374,7 +375,7 @@ static int makeDirectory(
int i = 1;
while( rc==SQLITE_OK ){
- struct stat sStat;
+ STRUCT_STAT sStat;
int rc2;
for(; zCopy[i]!='/' && i<nCopy; i++);
@@ -424,7 +425,7 @@ static int writeFile(
** be an error though - if there is already a directory at the same
** path and either the permissions already match or can be changed
** to do so using chmod(), it is not an error. */
- struct stat sStat;
+ STRUCT_STAT sStat;
if( errno!=EEXIST
|| 0!=fileStat(zFile, &sStat)
|| !S_ISDIR(sStat.st_mode)
@@ -620,13 +621,14 @@ struct fsdir_cursor {
sqlite3_vtab_cursor base; /* Base class - must be first */
int nLvl; /* Number of entries in aLvl[] array */
+ int mxLvl; /* Maximum level */
int iLvl; /* Index of current entry */
FsdirLevel *aLvl; /* Hierarchy of directories being traversed */
const char *zBase;
int nBase;
- struct stat sStat; /* Current lstat() results */
+ STRUCT_STAT sStat; /* Current lstat() results */
char *zPath; /* Path to current entry */
sqlite3_int64 iRowid; /* Current rowid */
};
@@ -738,7 +740,7 @@ static int fsdirNext(sqlite3_vtab_cursor *cur){
mode_t m = pCur->sStat.st_mode;
pCur->iRowid++;
- if( S_ISDIR(m) ){
+ if( S_ISDIR(m) && pCur->iLvl+3<pCur->mxLvl ){
/* Descend into this directory */
int iNew = pCur->iLvl + 1;
FsdirLevel *pLvl;
@@ -846,7 +848,11 @@ static int fsdirColumn(
}else{
readFileContents(ctx, pCur->zPath);
}
+ break;
}
+ case FSDIR_COLUMN_LEVEL:
+ sqlite3_result_int(ctx, pCur->iLvl+2);
+ break;
case FSDIR_COLUMN_PATH:
default: {
/* The FSDIR_COLUMN_PATH and FSDIR_COLUMN_DIR are input parameters.
@@ -880,8 +886,11 @@ static int fsdirEof(sqlite3_vtab_cursor *cur){
/*
** xFilter callback.
**
-** idxNum==1 PATH parameter only
-** idxNum==2 Both PATH and DIR supplied
+** idxNum bit Meaning
+** 0x01 PATH=N
+** 0x02 DIR=N
+** 0x04 LEVEL<N
+** 0x08 LEVEL<=N
*/
static int fsdirFilter(
sqlite3_vtab_cursor *cur,
@@ -890,6 +899,7 @@ static int fsdirFilter(
){
const char *zDir = 0;
fsdir_cursor *pCur = (fsdir_cursor*)cur;
+ int i;
(void)idxStr;
fsdirResetCursor(pCur);
@@ -898,14 +908,24 @@ static int fsdirFilter(
return SQLITE_ERROR;
}
- assert( argc==idxNum && (argc==1 || argc==2) );
+ assert( (idxNum & 0x01)!=0 && argc>0 );
zDir = (const char*)sqlite3_value_text(argv[0]);
if( zDir==0 ){
fsdirSetErrmsg(pCur, "table function fsdir requires a non-NULL argument");
return SQLITE_ERROR;
}
- if( argc==2 ){
- pCur->zBase = (const char*)sqlite3_value_text(argv[1]);
+ i = 1;
+ if( (idxNum & 0x02)!=0 ){
+ assert( argc>i );
+ pCur->zBase = (const char*)sqlite3_value_text(argv[i++]);
+ }
+ if( (idxNum & 0x0c)!=0 ){
+ assert( argc>i );
+ pCur->mxLvl = sqlite3_value_int(argv[i++]);
+ if( idxNum & 0x08 ) pCur->mxLvl++;
+ if( pCur->mxLvl<=0 ) pCur->mxLvl = 1000000000;
+ }else{
+ pCur->mxLvl = 1000000000;
}
if( pCur->zBase ){
pCur->nBase = (int)strlen(pCur->zBase)+1;
@@ -934,10 +954,11 @@ static int fsdirFilter(
** In this implementation idxNum is used to represent the
** query plan. idxStr is unused.
**
-** The query plan is represented by values of idxNum:
+** The query plan is represented by bits in idxNum:
**
-** (1) The path value is supplied by argv[0]
-** (2) Path is in argv[0] and dir is in argv[1]
+** 0x01 The path value is supplied by argv[0]
+** 0x02 dir is in argv[1]
+** 0x04 maxdepth is in argv[1] or [2]
*/
static int fsdirBestIndex(
sqlite3_vtab *tab,
@@ -946,6 +967,9 @@ static int fsdirBestIndex(
int i; /* Loop over constraints */
int idxPath = -1; /* Index in pIdxInfo->aConstraint of PATH= */
int idxDir = -1; /* Index in pIdxInfo->aConstraint of DIR= */
+ int idxLevel = -1; /* Index in pIdxInfo->aConstraint of LEVEL< or <= */
+ int idxLevelEQ = 0; /* 0x08 for LEVEL<= or LEVEL=. 0x04 for LEVEL< */
+ int omitLevel = 0; /* omit the LEVEL constraint */
int seenPath = 0; /* True if an unusable PATH= constraint is seen */
int seenDir = 0; /* True if an unusable DIR= constraint is seen */
const struct sqlite3_index_constraint *pConstraint;
@@ -953,25 +977,48 @@ static int fsdirBestIndex(
(void)tab;
pConstraint = pIdxInfo->aConstraint;
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
- if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
- switch( pConstraint->iColumn ){
- case FSDIR_COLUMN_PATH: {
- if( pConstraint->usable ){
- idxPath = i;
- seenPath = 0;
- }else if( idxPath<0 ){
- seenPath = 1;
+ if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){
+ switch( pConstraint->iColumn ){
+ case FSDIR_COLUMN_PATH: {
+ if( pConstraint->usable ){
+ idxPath = i;
+ seenPath = 0;
+ }else if( idxPath<0 ){
+ seenPath = 1;
+ }
+ break;
}
- break;
- }
- case FSDIR_COLUMN_DIR: {
- if( pConstraint->usable ){
- idxDir = i;
- seenDir = 0;
- }else if( idxDir<0 ){
- seenDir = 1;
+ case FSDIR_COLUMN_DIR: {
+ if( pConstraint->usable ){
+ idxDir = i;
+ seenDir = 0;
+ }else if( idxDir<0 ){
+ seenDir = 1;
+ }
+ break;
+ }
+ case FSDIR_COLUMN_LEVEL: {
+ if( pConstraint->usable && idxLevel<0 ){
+ idxLevel = i;
+ idxLevelEQ = 0x08;
+ omitLevel = 0;
+ }
+ break;
}
- break;
+ }
+ }else
+ if( pConstraint->iColumn==FSDIR_COLUMN_LEVEL
+ && pConstraint->usable
+ && idxLevel<0
+ ){
+ if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE ){
+ idxLevel = i;
+ idxLevelEQ = 0x08;
+ omitLevel = 1;
+ }else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ){
+ idxLevel = i;
+ idxLevelEQ = 0x04;
+ omitLevel = 1;
}
}
}
@@ -988,14 +1035,20 @@ static int fsdirBestIndex(
}else{
pIdxInfo->aConstraintUsage[idxPath].omit = 1;
pIdxInfo->aConstraintUsage[idxPath].argvIndex = 1;
+ pIdxInfo->idxNum = 0x01;
+ pIdxInfo->estimatedCost = 1.0e9;
+ i = 2;
if( idxDir>=0 ){
pIdxInfo->aConstraintUsage[idxDir].omit = 1;
- pIdxInfo->aConstraintUsage[idxDir].argvIndex = 2;
- pIdxInfo->idxNum = 2;
- pIdxInfo->estimatedCost = 10.0;
- }else{
- pIdxInfo->idxNum = 1;
- pIdxInfo->estimatedCost = 100.0;
+ pIdxInfo->aConstraintUsage[idxDir].argvIndex = i++;
+ pIdxInfo->idxNum |= 0x02;
+ pIdxInfo->estimatedCost /= 1.0e4;
+ }
+ if( idxLevel>=0 ){
+ pIdxInfo->aConstraintUsage[idxLevel].omit = omitLevel;
+ pIdxInfo->aConstraintUsage[idxLevel].argvIndex = i++;
+ pIdxInfo->idxNum |= idxLevelEQ;
+ pIdxInfo->estimatedCost /= 1.0e4;
}
}
diff --git a/ext/misc/vtablog.c b/ext/misc/vtablog.c
index 2cc29c285..44acc32e6 100644
--- a/ext/misc/vtablog.c
+++ b/ext/misc/vtablog.c
@@ -14,6 +14,13 @@
** on stdout when its key interfaces are called. This is intended for
** interactive analysis and debugging of virtual table interfaces.
**
+** To build this extension as a separately loaded shared library or
+** DLL, use compiler command-lines similar to the following:
+**
+** (linux) gcc -fPIC -shared vtablog.c -o vtablog.so
+** (mac) clang -fPIC -dynamiclib vtablog.c -o vtablog.dylib
+** (windows) cl vtablog.c -link -dll -out:vtablog.dll
+**
** Usage example:
**
** .load ./vtablog
@@ -240,7 +247,7 @@ static int vtablogConnect(
/*
-** This method is the destructor for vtablog_cursor objects.
+** This method is the destructor for vtablog_vtab objects.
*/
static int vtablogDisconnect(sqlite3_vtab *pVtab){
vtablog_vtab *pTab = (vtablog_vtab*)pVtab;
@@ -252,7 +259,7 @@ static int vtablogDisconnect(sqlite3_vtab *pVtab){
}
/*
-** This method is the destructor for vtablog_cursor objects.
+** This method is (also) the destructor for vtablog_vtab objects.
*/
static int vtablogDestroy(sqlite3_vtab *pVtab){
vtablog_vtab *pTab = (vtablog_vtab*)pVtab;
@@ -436,6 +443,39 @@ static int vtablogFilter(
}
/*
+** Return an sqlite3_index_info operator name in static space.
+** The name is possibly overwritten on subsequent calls.
+*/
+static char *vtablogOpName(unsigned char op){
+ static char zUnknown[30];
+ char *zOut;
+ switch( op ){
+ case SQLITE_INDEX_CONSTRAINT_EQ: zOut = "EQ"; break;
+ case SQLITE_INDEX_CONSTRAINT_GT: zOut = "GT"; break;
+ case SQLITE_INDEX_CONSTRAINT_LE: zOut = "LE"; break;
+ case SQLITE_INDEX_CONSTRAINT_LT: zOut = "LT"; break;
+ case SQLITE_INDEX_CONSTRAINT_GE: zOut = "GE"; break;
+ case SQLITE_INDEX_CONSTRAINT_MATCH: zOut = "MATCH"; break;
+ case SQLITE_INDEX_CONSTRAINT_LIKE: zOut = "LIKE"; break;
+ case SQLITE_INDEX_CONSTRAINT_GLOB: zOut = "GLOB"; break;
+ case SQLITE_INDEX_CONSTRAINT_REGEXP: zOut = "REGEXP"; break;
+ case SQLITE_INDEX_CONSTRAINT_NE: zOut = "NE"; break;
+ case SQLITE_INDEX_CONSTRAINT_ISNOT: zOut = "ISNOT"; break;
+ case SQLITE_INDEX_CONSTRAINT_ISNOTNULL: zOut = "ISNOTNULL"; break;
+ case SQLITE_INDEX_CONSTRAINT_ISNULL: zOut = "ISNULL"; break;
+ case SQLITE_INDEX_CONSTRAINT_IS: zOut = "IS"; break;
+ case SQLITE_INDEX_CONSTRAINT_LIMIT: zOut = "LIMIT"; break;
+ case SQLITE_INDEX_CONSTRAINT_OFFSET: zOut = "OFFSET"; break;
+ case SQLITE_INDEX_CONSTRAINT_FUNCTION: zOut = "FUNCTION"; break;
+ default:
+ sqlite3_snprintf(sizeof(zUnknown),zUnknown,"%d",op);
+ zOut = zUnknown;
+ break;
+ }
+ return zOut;
+}
+
+/*
** SQLite will invoke this method one or more times while planning a query
** that uses the vtablog virtual table. This routine needs to create
** a query plan for each invocation and compute an estimated cost for that
@@ -451,14 +491,23 @@ static int vtablogBestIndex(
printf(" colUsed: 0x%016llx\n", p->colUsed);
printf(" nConstraint: %d\n", p->nConstraint);
for(i=0; i<p->nConstraint; i++){
+ sqlite3_value *pVal = 0;
+ int rc = sqlite3_vtab_rhs_value(p, i, &pVal);
printf(
- " constraint[%d]: col=%d termid=%d op=%d usabled=%d collseq=%s\n",
+ " constraint[%d]: col=%d termid=%d op=%s usabled=%d coll=%s rhs=",
i,
p->aConstraint[i].iColumn,
p->aConstraint[i].iTermOffset,
- p->aConstraint[i].op,
+ vtablogOpName(p->aConstraint[i].op),
p->aConstraint[i].usable,
- sqlite3_vtab_collation(p,i));
+ sqlite3_vtab_collation(p,i)
+ );
+ if( rc==SQLITE_OK ){
+ vtablogQuote(pVal);
+ printf("\n");
+ }else{
+ printf("N/A\n");
+ }
}
printf(" nOrderBy: %d\n", p->nOrderBy);
for(i=0; i<p->nOrderBy; i++){
diff --git a/ext/misc/windirent.h b/ext/misc/windirent.h
new file mode 100644
index 000000000..f84491e46
--- /dev/null
+++ b/ext/misc/windirent.h
@@ -0,0 +1,163 @@
+/*
+** 2025-06-05
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** An implementation of opendir(), readdir(), and closedir() for Windows,
+** based on the FindFirstFile(), FindNextFile(), and FindClose() APIs
+** of Win32.
+**
+** #include this file inside any C-code module that needs to use
+** opendir()/readdir()/closedir(). This file is a no-op on non-Windows
+** machines. On Windows, static functions are defined that implement
+** those standard interfaces.
+*/
+#if defined(_WIN32) && defined(_MSC_VER) && !defined(SQLITE_WINDIRENT_H)
+#define SQLITE_WINDIRENT_H
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <io.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#ifndef FILENAME_MAX
+# define FILENAME_MAX (260)
+#endif
+#ifndef S_ISREG
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+#ifndef S_ISDIR
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+#ifndef S_ISLNK
+#define S_ISLNK(m) (0)
+#endif
+typedef unsigned short mode_t;
+
+/* The dirent object for Windows is abbreviated. The only field really
+** usable by applications is d_name[].
+*/
+struct dirent {
+ int d_ino; /* Inode number (synthesized) */
+ unsigned d_attributes; /* File attributes */
+ char d_name[FILENAME_MAX]; /* Null-terminated filename */
+};
+
+/* The internals of DIR are opaque according to standards. So it
+** does not matter what we put here. */
+typedef struct DIR DIR;
+struct DIR {
+ intptr_t d_handle; /* Handle for findfirst()/findnext() */
+ struct dirent cur; /* Current entry */
+};
+
+/* Ignore hidden and system files */
+#define WindowsFileToIgnore(a) \
+ ((((a).attrib)&_A_HIDDEN) || (((a).attrib)&_A_SYSTEM))
+
+/*
+** Close a previously opened directory
+*/
+static int closedir(DIR *pDir){
+ int rc = 0;
+ if( pDir==0 ){
+ return EINVAL;
+ }
+ if( pDir->d_handle!=0 && pDir->d_handle!=(-1) ){
+ rc = _findclose(pDir->d_handle);
+ }
+ sqlite3_free(pDir);
+ return rc;
+}
+
+/*
+** Open a new directory. The directory name should be UTF-8 encoded.
+** appropriate translations happen automatically.
+*/
+static DIR *opendir(const char *zDirName){
+ DIR *pDir;
+ wchar_t *b1;
+ sqlite3_int64 sz;
+ struct _wfinddata_t data;
+
+ pDir = sqlite3_malloc64( sizeof(DIR) );
+ if( pDir==0 ) return 0;
+ memset(pDir, 0, sizeof(DIR));
+ memset(&data, 0, sizeof(data));
+ sz = strlen(zDirName);
+ b1 = sqlite3_malloc64( (sz+3)*sizeof(b1[0]) );
+ if( b1==0 ){
+ closedir(pDir);
+ return NULL;
+ }
+ sz = MultiByteToWideChar(CP_UTF8, 0, zDirName, sz, b1, sz);
+ b1[sz++] = '\\';
+ b1[sz++] = '*';
+ b1[sz] = 0;
+ if( sz+1>sizeof(data.name)/sizeof(data.name[0]) ){
+ closedir(pDir);
+ sqlite3_free(b1);
+ return NULL;
+ }
+ memcpy(data.name, b1, (sz+1)*sizeof(b1[0]));
+ sqlite3_free(b1);
+ pDir->d_handle = _wfindfirst(data.name, &data);
+ if( pDir->d_handle<0 ){
+ closedir(pDir);
+ return NULL;
+ }
+ while( WindowsFileToIgnore(data) ){
+ memset(&data, 0, sizeof(data));
+ if( _wfindnext(pDir->d_handle, &data)==-1 ){
+ closedir(pDir);
+ return NULL;
+ }
+ }
+ pDir->cur.d_ino = 0;
+ pDir->cur.d_attributes = data.attrib;
+ WideCharToMultiByte(CP_UTF8, 0, data.name, -1,
+ pDir->cur.d_name, FILENAME_MAX, 0, 0);
+ return pDir;
+}
+
+/*
+** Read the next entry from a directory.
+**
+** The returned struct-dirent object is managed by DIR. It is only
+** valid until the next readdir() or closedir() call. Only the
+** d_name[] field is meaningful. The d_name[] value has been
+** translated into UTF8.
+*/
+static struct dirent *readdir(DIR *pDir){
+ struct _wfinddata_t data;
+ if( pDir==0 ) return 0;
+ if( (pDir->cur.d_ino++)==0 ){
+ return &pDir->cur;
+ }
+ do{
+ memset(&data, 0, sizeof(data));
+ if( _wfindnext(pDir->d_handle, &data)==-1 ){
+ return NULL;
+ }
+ }while( WindowsFileToIgnore(data) );
+ pDir->cur.d_attributes = data.attrib;
+ WideCharToMultiByte(CP_UTF8, 0, data.name, -1,
+ pDir->cur.d_name, FILENAME_MAX, 0, 0);
+ return &pDir->cur;
+}
+
+#endif /* defined(_WIN32) && defined(_MSC_VER) */
diff --git a/ext/rtree/rtree.c b/ext/rtree/rtree.c
index 5e9fa6996..f7d3bda01 100644
--- a/ext/rtree/rtree.c
+++ b/ext/rtree/rtree.c
@@ -64,6 +64,8 @@
#endif
int sqlite3GetToken(const unsigned char*,int*); /* In the SQLite core */
+#include <stddef.h>
+
/*
** If building separately, we will need some setup that is normally
** found in sqliteInt.h
@@ -95,7 +97,7 @@ typedef unsigned int u32;
# define NEVER(X) (X)
#endif
#ifndef offsetof
-#define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD))
+# define offsetof(ST,M) ((size_t)((char*)&((ST*)0)->M - (char*)0))
#endif
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
# define FLEXARRAY
@@ -2848,7 +2850,7 @@ static int deleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell, int iHeight){
return rc;
}
-
+
/*
** Insert cell pCell into node pNode. Node pNode is the head of a
** subtree iHeight high (leaf nodes have iHeight==0).
diff --git a/ext/session/sessionchange.test b/ext/session/sessionchange.test
index c1c28622e..6e2cb0e82 100644
--- a/ext/session/sessionchange.test
+++ b/ext/session/sessionchange.test
@@ -96,6 +96,22 @@ do_test 1.5 {
$iter finalize
grp delete
+do_test 1.6 {
+ set C [changeset_from_sql {
+ INSERT INTO t1 VALUES(1001, hex(randomblob(10000)), hex(randomblob(10000)));
+ INSERT INTO t1 VALUES(2001, hex(randomblob(10000)), hex(randomblob(10000)));
+ INSERT INTO t1 VALUES(3001, hex(randomblob(10000)), hex(randomblob(10000)));
+ }]
+
+ sqlite3changegroup grp
+ set iter [sqlite3changeset_start $C]
+ while {[$iter next]=="SQLITE_ROW"} {
+ grp add_change $iter
+ }
+ $iter finalize
+} SQLITE_OK
+
+grp delete
finish_test
diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c
index a8dd1d9be..175cacbe8 100644
--- a/ext/session/sqlite3session.c
+++ b/ext/session/sqlite3session.c
@@ -3396,14 +3396,15 @@ int sqlite3changeset_start_v2_strm(
** object and the buffer is full, discard some data to free up space.
*/
static void sessionDiscardData(SessionInput *pIn){
- if( pIn->xInput && pIn->iNext>=sessions_strm_chunk_size ){
- int nMove = pIn->buf.nBuf - pIn->iNext;
+ if( pIn->xInput && pIn->iCurrent>=sessions_strm_chunk_size ){
+ int nMove = pIn->buf.nBuf - pIn->iCurrent;
assert( nMove>=0 );
if( nMove>0 ){
- memmove(pIn->buf.aBuf, &pIn->buf.aBuf[pIn->iNext], nMove);
+ memmove(pIn->buf.aBuf, &pIn->buf.aBuf[pIn->iCurrent], nMove);
}
- pIn->buf.nBuf -= pIn->iNext;
- pIn->iNext = 0;
+ pIn->buf.nBuf -= pIn->iCurrent;
+ pIn->iNext -= pIn->iCurrent;
+ pIn->iCurrent = 0;
pIn->nData = pIn->buf.nBuf;
}
}
@@ -3757,8 +3758,8 @@ static int sessionChangesetNextOne(
p->rc = sessionInputBuffer(&p->in, 2);
if( p->rc!=SQLITE_OK ) return p->rc;
- sessionDiscardData(&p->in);
p->in.iCurrent = p->in.iNext;
+ sessionDiscardData(&p->in);
/* If the iterator is already at the end of the changeset, return DONE. */
if( p->in.iNext>=p->in.nData ){
@@ -6117,14 +6118,19 @@ int sqlite3changegroup_add_change(
sqlite3_changegroup *pGrp,
sqlite3_changeset_iter *pIter
){
+ int rc = SQLITE_OK;
+
if( pIter->in.iCurrent==pIter->in.iNext
|| pIter->rc!=SQLITE_OK
|| pIter->bInvert
){
/* Iterator does not point to any valid entry or is an INVERT iterator. */
- return SQLITE_ERROR;
+ rc = SQLITE_ERROR;
+ }else{
+ pIter->in.bNoDiscard = 1;
+ rc = sessionOneChangeToHash(pGrp, pIter, 0);
}
- return sessionOneChangeToHash(pGrp, pIter, 0);
+ return rc;
}
/*
diff --git a/ext/session/test_session.c b/ext/session/test_session.c
index e167cb8fb..f28604abc 100644
--- a/ext/session/test_session.c
+++ b/ext/session/test_session.c
@@ -1459,6 +1459,9 @@ struct TestChangegroup {
typedef struct TestChangeIter TestChangeIter;
struct TestChangeIter {
sqlite3_changeset_iter *pIter;
+
+ /* If this iter uses streaming. */
+ TestStreamInput in;
};
@@ -1681,6 +1684,7 @@ static int SQLITE_TCLAPI test_sqlite3changeset_start(
sqlite3_changeset_iter *pIter = 0;
int flags = 0;
int rc = SQLITE_OK;
+ int nAlloc = 0; /* Bytes of space to allocate */
static int iCmd = 1;
char zCmd[64];
@@ -1696,18 +1700,36 @@ static int SQLITE_TCLAPI test_sqlite3changeset_start(
return TCL_ERROR;
}
- flags = isInvert ? SQLITE_CHANGESETSTART_INVERT : 0;
pChangeset = (void *)Tcl_GetByteArrayFromObj(objv[objc-1], &nChangeset);
- rc = sqlite3changeset_start_v2(&pIter, (int)nChangeset, pChangeset, flags);
+ flags = isInvert ? SQLITE_CHANGESETSTART_INVERT : 0;
+
+ nAlloc = sizeof(TestChangeIter);
+ if( test_tcl_integer(interp, SESSION_STREAM_TCL_VAR) ){
+ nAlloc += nChangeset;
+ }
+ pNew = (TestChangeIter*)ckalloc(nAlloc);
+ memset(pNew, 0, nAlloc);
+ if( test_tcl_integer(interp, SESSION_STREAM_TCL_VAR) ){
+ pNew->in.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
+ pNew->in.nData = nChangeset;
+ pNew->in.aData = (unsigned char*)&pNew[1];
+ memcpy(pNew->in.aData, pChangeset, nChangeset);
+ }
+
+ if( pNew->in.nStream ){
+ void *pCtx = (void*)&pNew->in;
+ rc = sqlite3changeset_start_v2_strm(&pIter, testStreamInput, pCtx, flags);
+ }else{
+ rc = sqlite3changeset_start_v2(&pIter, (int)nChangeset, pChangeset, flags);
+ }
if( rc!=SQLITE_OK ){
char *zErr = sqlite3_mprintf(
"error in sqlite3changeset_start_v2() - %d", rc
);
Tcl_AppendResult(interp, zErr, (char*)0);
+ ckfree(pNew);
return TCL_ERROR;
}
-
- pNew = (TestChangeIter*)ckalloc(sizeof(TestChangeIter));
pNew->pIter = pIter;
sprintf(zCmd, "csiter%d", iCmd++);
diff --git a/ext/wasm/GNUmakefile b/ext/wasm/GNUmakefile
index ec258099f..51a6bf965 100644
--- a/ext/wasm/GNUmakefile
+++ b/ext/wasm/GNUmakefile
@@ -260,7 +260,8 @@ SQLITE_OPT.full-featured := \
-DSQLITE_ENABLE_RTREE \
-DSQLITE_ENABLE_SESSION \
-DSQLITE_ENABLE_STMTVTAB \
- -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
+ -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION \
+ -DSQLITE_ENABLE_COLUMN_METADATA
ifeq (0,$(wasm-bare-bones))
# The so-called canonical build is full-featured:
@@ -410,7 +411,7 @@ DISTCLEAN_FILES += $(bin.stripccomments)
# -D... flags which should be included in all invocations should be
# appended to $(SQLITE.CALL.C-PP.FILTER.global).
bin.c-pp := ./c-pp
-$(bin.c-pp): c-pp.c $(sqlite3.c) $(MAKEFILE)
+$(bin.c-pp): c-pp.c $(sqlite3.c) # $(MAKEFILE)
$(CC) -O0 -o $@ c-pp.c $(sqlite3.c) '-DCMPP_DEFAULT_DELIM="//#"' -I$(dir.top) \
-DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_UTF16 \
-DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_WAL -DSQLITE_THREADSAFE=0 \
@@ -428,7 +429,7 @@ define SQLITE.CALL.C-PP.FILTER
$(2): $(1) $$(MAKEFILE_LIST) $$(bin.c-pp)
@mkdir -p $$(dir $$@)
$$(bin.c-pp) -f $(1) -o $$@ $(3) $(SQLITE.CALL.C-PP.FILTER.global)
-#CLEAN_FILES += $(2)
+CLEAN_FILES += $(2)
endef
# /end SQLITE.CALL.C-PP.FILTER
########################################################################
@@ -597,6 +598,7 @@ emcc.flags += -v
# -v is _very_ loud but also informative about what it's doing
endif
+
########################################################################
# emcc flags for .c/.o.
emcc.cflags :=
@@ -616,7 +618,8 @@ emcc.jsflags += -sNO_POLYFILL
emcc.jsflags += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.api)
emcc.exportedRuntimeMethods := \
-sEXPORTED_RUNTIME_METHODS=wasmMemory
- # wasmMemory ==> required by our code for use with -sIMPORTED_MEMORY
+# wasmMemory ==> required by our code for use with -sIMPORTED_MEMORY
+# Emscripten 4.0.7 (2025-04-15) stops exporting HEAP* by default.
emcc.jsflags += $(emcc.exportedRuntimeMethods)
emcc.jsflags += -sUSE_CLOSURE_COMPILER=0
emcc.jsflags += -sIMPORTED_MEMORY
diff --git a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-extras b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-extras
index e635d93b3..01dad072e 100644
--- a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-extras
+++ b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-extras
@@ -1,12 +1,27 @@
+_sqlite3_column_database_name
+_sqlite3_column_origin_name
+_sqlite3_column_table_name
+_sqlite3_create_module
+_sqlite3_create_module_v2
_sqlite3_create_window_function
-_sqlite3_progress_handler
-_sqlite3_set_authorizer
+_sqlite3_declare_vtab
+_sqlite3_drop_modules
_sqlite3_preupdate_blobwrite
_sqlite3_preupdate_count
_sqlite3_preupdate_depth
_sqlite3_preupdate_hook
_sqlite3_preupdate_new
_sqlite3_preupdate_old
+_sqlite3_progress_handler
+_sqlite3_set_authorizer
+_sqlite3_vtab_collation
+_sqlite3_vtab_distinct
+_sqlite3_vtab_in
+_sqlite3_vtab_in_first
+_sqlite3_vtab_in_next
+_sqlite3_vtab_nochange
+_sqlite3_vtab_on_conflict
+_sqlite3_vtab_rhs_value
_sqlite3changegroup_add
_sqlite3changegroup_add_strm
_sqlite3changegroup_delete
@@ -49,15 +64,3 @@ _sqlite3session_object_config
_sqlite3session_patchset
_sqlite3session_patchset_strm
_sqlite3session_table_filter
-_sqlite3_create_module
-_sqlite3_create_module_v2
-_sqlite3_declare_vtab
-_sqlite3_drop_modules
-_sqlite3_vtab_collation
-_sqlite3_vtab_distinct
-_sqlite3_vtab_in
-_sqlite3_vtab_in_first
-_sqlite3_vtab_in_next
-_sqlite3_vtab_nochange
-_sqlite3_vtab_on_conflict
-_sqlite3_vtab_rhs_value
diff --git a/ext/wasm/api/sqlite3-api-glue.c-pp.js b/ext/wasm/api/sqlite3-api-glue.c-pp.js
index a38b9cb5e..8d2d4a589 100644
--- a/ext/wasm/api/sqlite3-api-glue.c-pp.js
+++ b/ext/wasm/api/sqlite3-api-glue.c-pp.js
@@ -20,7 +20,6 @@
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
'use strict';
const toss = (...args)=>{throw new Error(args.join(' '))};
- const toss3 = sqlite3.SQLite3Error.toss;
const capi = sqlite3.capi, wasm = sqlite3.wasm, util = sqlite3.util;
globalThis.WhWasmUtilInstaller(wasm);
delete globalThis.WhWasmUtilInstaller;
@@ -368,6 +367,14 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
);
}/* sqlite3_set_authorizer() */
+ if( !!wasm.exports.sqlite3_column_origin_name ){
+ wasm.bindingSignatures.push(
+ ["sqlite3_column_database_name","string", "sqlite3_stmt*", "int"],
+ ["sqlite3_column_origin_name","string", "sqlite3_stmt*", "int"],
+ ["sqlite3_column_table_name","string", "sqlite3_stmt*", "int"]
+ );
+ }
+
if(false && wasm.compileOptionUsed('SQLITE_ENABLE_NORMALIZE')){
/* ^^^ "the problem" is that this is an optional feature and the
build-time function-export list does not currently take
diff --git a/ext/wasm/api/sqlite3-api-oo1.c-pp.js b/ext/wasm/api/sqlite3-api-oo1.c-pp.js
index 3d6a24c77..62c44fa9d 100644
--- a/ext/wasm/api/sqlite3-api-oo1.c-pp.js
+++ b/ext/wasm/api/sqlite3-api-oo1.c-pp.js
@@ -16,7 +16,6 @@
and it installs its deliverable as globalThis.sqlite3.oo1.
*/
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
- const toss = (...args)=>{throw new Error(args.join(' '))};
const toss3 = (...args)=>{throw new sqlite3.SQLite3Error(...args)};
const capi = sqlite3.capi, wasm = sqlite3.wasm, util = sqlite3.util;
@@ -39,6 +38,21 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
*/
const __ptrMap = new WeakMap();
/**
+ A Set of oo1.DB or oo1.Stmt objects which are proxies for
+ (sqlite3*) resp. (sqlite3_stmt*) pointers which themselves are
+ owned elsewhere. Objects in this Set do not own their underlying
+ handle and that handle must be guaranteed (by the client) to
+ outlive the proxy. DB.close()/Stmt.finalize() methods will remove
+ the object from this Set _instead_ of closing/finalizing the
+ pointer. These proxies are primarily intended as a way to briefly
+ wrap an (sqlite3[_stmt]*) object as an oo1.DB/Stmt without taking
+ over ownership, to take advantage of simplifies usage compared to
+ the C API while not imposing any change of ownership.
+
+ See DB.wrapHandle() and Stmt.wrapHandle().
+ */
+ const __doesNotOwnHandle = new Set();
+ /**
Map of DB instances to objects, each object being a map of Stmt
wasm pointers to Stmt objects.
*/
@@ -235,73 +249,89 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
};
}
const opt = ctor.normalizeArgs(...args);
- let fn = opt.filename, vfsName = opt.vfs, flagsStr = opt.flags;
- if(('string'!==typeof fn && 'number'!==typeof fn)
- || 'string'!==typeof flagsStr
- || (vfsName && ('string'!==typeof vfsName && 'number'!==typeof vfsName))){
- sqlite3.config.error("Invalid DB ctor args",opt,arguments);
- toss3("Invalid arguments for DB constructor.");
- }
- let fnJs = ('number'===typeof fn) ? wasm.cstrToJs(fn) : fn;
- const vfsCheck = ctor._name2vfs[fnJs];
- if(vfsCheck){
- vfsName = vfsCheck.vfs;
- fn = fnJs = vfsCheck.filename(fnJs);
- }
- let pDb, oflags = 0;
- if( flagsStr.indexOf('c')>=0 ){
- oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
- }
- if( flagsStr.indexOf('w')>=0 ) oflags |= capi.SQLITE_OPEN_READWRITE;
- if( 0===oflags ) oflags |= capi.SQLITE_OPEN_READONLY;
- oflags |= capi.SQLITE_OPEN_EXRESCODE;
- const stack = wasm.pstack.pointer;
- try {
- const pPtr = wasm.pstack.allocPtr() /* output (sqlite3**) arg */;
- let rc = capi.sqlite3_open_v2(fn, pPtr, oflags, vfsName || 0);
- pDb = wasm.peekPtr(pPtr);
- checkSqlite3Rc(pDb, rc);
- capi.sqlite3_extended_result_codes(pDb, 1);
- if(flagsStr.indexOf('t')>=0){
- capi.sqlite3_trace_v2(pDb, capi.SQLITE_TRACE_STMT,
- __dbTraceToConsole, pDb);
+ //sqlite3.config.debug("DB ctor",opt);
+ let pDb;
+ if( (pDb = opt['sqlite3*']) ){
+ /* This property ^^^^^ is very specifically NOT DOCUMENTED and
+ NOT part of the public API. This is a back door for functions
+ like DB.wrapDbHandle(). */
+ //sqlite3.config.debug("creating proxy db from",opt);
+ if( !opt['sqlite3*:takeOwnership'] ){
+ /* This is object does not own its handle. */
+ __doesNotOwnHandle.add(this);
}
- }catch( e ){
- if( pDb ) capi.sqlite3_close_v2(pDb);
- throw e;
- }finally{
- wasm.pstack.restore(stack);
+ this.filename = capi.sqlite3_db_filename(pDb,'main');
+ }else{
+ let fn = opt.filename, vfsName = opt.vfs, flagsStr = opt.flags;
+ if(('string'!==typeof fn && 'number'!==typeof fn)
+ || 'string'!==typeof flagsStr
+ || (vfsName && ('string'!==typeof vfsName && 'number'!==typeof vfsName))){
+ sqlite3.config.error("Invalid DB ctor args",opt,arguments);
+ toss3("Invalid arguments for DB constructor.");
+ }
+ let fnJs = ('number'===typeof fn) ? wasm.cstrToJs(fn) : fn;
+ const vfsCheck = ctor._name2vfs[fnJs];
+ if(vfsCheck){
+ vfsName = vfsCheck.vfs;
+ fn = fnJs = vfsCheck.filename(fnJs);
+ }
+ let oflags = 0;
+ if( flagsStr.indexOf('c')>=0 ){
+ oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
+ }
+ if( flagsStr.indexOf('w')>=0 ) oflags |= capi.SQLITE_OPEN_READWRITE;
+ if( 0===oflags ) oflags |= capi.SQLITE_OPEN_READONLY;
+ oflags |= capi.SQLITE_OPEN_EXRESCODE;
+ const stack = wasm.pstack.pointer;
+ try {
+ const pPtr = wasm.pstack.allocPtr() /* output (sqlite3**) arg */;
+ let rc = capi.sqlite3_open_v2(fn, pPtr, oflags, vfsName || 0);
+ pDb = wasm.peekPtr(pPtr);
+ checkSqlite3Rc(pDb, rc);
+ capi.sqlite3_extended_result_codes(pDb, 1);
+ if(flagsStr.indexOf('t')>=0){
+ capi.sqlite3_trace_v2(pDb, capi.SQLITE_TRACE_STMT,
+ __dbTraceToConsole, pDb);
+ }
+ }catch( e ){
+ if( pDb ) capi.sqlite3_close_v2(pDb);
+ throw e;
+ }finally{
+ wasm.pstack.restore(stack);
+ }
+ this.filename = fnJs;
}
- this.filename = fnJs;
__ptrMap.set(this, pDb);
__stmtMap.set(this, Object.create(null));
- try{
+ if( !opt['sqlite3*'] ){
+ try{
//#if enable-see
- dbCtorApplySEEKey(this,opt);
+ dbCtorApplySEEKey(this,opt);
//#endif
- // Check for per-VFS post-open SQL/callback...
- const pVfs = capi.sqlite3_js_db_vfs(pDb)
- || toss3("Internal error: cannot get VFS for new db handle.");
- const postInitSql = __vfsPostOpenCallback[pVfs];
- if(postInitSql){
- /**
- Reminder: if this db is encrypted and the client did _not_ pass
- in the key, any init code will fail, causing the ctor to throw.
- We don't actually know whether the db is encrypted, so we cannot
- sensibly apply any heuristics which skip the init code only for
- encrypted databases for which no key has yet been supplied.
- */
- if(postInitSql instanceof Function){
- postInitSql(this, sqlite3);
- }else{
- checkSqlite3Rc(
- pDb, capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0)
- );
+ // Check for per-VFS post-open SQL/callback...
+ const pVfs = capi.sqlite3_js_db_vfs(pDb)
+ || toss3("Internal error: cannot get VFS for new db handle.");
+ const postInitSql = __vfsPostOpenCallback[pVfs];
+ if(postInitSql){
+ /**
+ Reminder: if this db is encrypted and the client did _not_ pass
+ in the key, any init code will fail, causing the ctor to throw.
+ We don't actually know whether the db is encrypted, so we cannot
+ sensibly apply any heuristics which skip the init code only for
+ encrypted databases for which no key has yet been supplied.
+ */
+ if(postInitSql instanceof Function){
+ postInitSql(this, sqlite3);
+ }else{
+ checkSqlite3Rc(
+ pDb, capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0)
+ );
+ }
}
+ }catch(e){
+ this.close();
+ throw e;
}
- }catch(e){
- this.close();
- throw e;
}
};
@@ -404,7 +434,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
- `vfs`: the VFS fname
//#if enable-see
-
SEE-capable builds optionally support ONE of the following
additional options:
@@ -430,7 +459,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
is supplied and the database is encrypted, execution of the
post-initialization SQL will fail, causing the constructor to
throw.
-
//#endif enable-see
The `filename` and `vfs` arguments may be either JS strings or
@@ -458,8 +486,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/**
Internal-use enum for mapping JS types to DB-bindable types.
These do not (and need not) line up with the SQLITE_type
- values. All values in this enum must be truthy and distinct
- but they need not be numbers.
+ values. All values in this enum must be truthy and (mostly)
+ distinct but they need not be numbers.
*/
const BindTypes = {
null: 1,
@@ -468,7 +496,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
boolean: 4,
blob: 5
};
- BindTypes['undefined'] == BindTypes.null;
if(wasm.bigIntEnabled){
BindTypes.bigint = BindTypes.number;
}
@@ -487,26 +514,30 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
- `db`: the DB object which created the statement.
- `columnCount`: the number of result columns in the query, or 0
- for queries which cannot return results. This property is a proxy
- for sqlite3_column_count() and its use in loops should be avoided
- because of the call overhead associated with that. The
- `columnCount` is not cached when the Stmt is created because a
- schema change made via a separate db connection between this
- statement's preparation and when it is stepped may invalidate it.
+ for queries which cannot return results. This property is a
+ read-only proxy for sqlite3_column_count() and its use in loops
+ should be avoided because of the call overhead associated with
+ that. The `columnCount` is not cached when the Stmt is created
+ because a schema change made between this statement's preparation
+ and when it is stepped may invalidate it.
- - `parameterCount`: the number of bindable parameters in the query.
+ - `parameterCount`: the number of bindable parameters in the
+ query. Like `columnCount`, this property is ready-only and is a
+ proxy for a C API call.
As a general rule, most methods of this class will throw if
called on an instance which has been finalized. For brevity's
sake, the method docs do not all repeat this warning.
*/
- const Stmt = function(){
+ const Stmt = function(/*oo1db, stmtPtr, BindTypes [,takeOwnership=true] */){
if(BindTypes!==arguments[2]){
toss3(capi.SQLITE_MISUSE, "Do not call the Stmt constructor directly. Use DB.prepare().");
}
this.db = arguments[0];
__ptrMap.set(this, arguments[1]);
- this.parameterCount = capi.sqlite3_bind_parameter_count(this.pointer);
+ if( arguments.length>3 && !arguments[3] ){
+ __doesNotOwnHandle.add(this);
+ }
};
/** Throws if the given DB has been closed, else it is returned. */
@@ -699,10 +730,10 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
},
/**
Finalizes all open statements and closes this database
- connection. This is a no-op if the db has already been
- closed. After calling close(), `this.pointer` will resolve to
- `undefined`, so that can be used to check whether the db
- instance is still opened.
+ connection (with one exception noted below). This is a no-op if
+ the db has already been closed. After calling close(),
+ `this.pointer` will resolve to `undefined`, and that can be
+ used to check whether the db instance is still opened.
If this.onclose.before is a function then it is called before
any close-related cleanup.
@@ -722,14 +753,19 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
all, will never trigger close(), so onclose handlers are not a
reliable way to implement close-time cleanup or maintenance of
a db.
+
+ If this instance was created using DB.wrapHandle() and does not
+ own this.pointer then it does not close the db handle but it
+ does perform all other work, such as calling onclose callbacks
+ and disassociating this object from this.pointer.
*/
close: function(){
- if(this.pointer){
+ const pDb = this.pointer;
+ if(pDb){
if(this.onclose && (this.onclose.before instanceof Function)){
try{this.onclose.before(this)}
catch(e){/*ignore*/}
}
- const pDb = this.pointer;
Object.keys(__stmtMap.get(this)).forEach((k,s)=>{
if(s && s.pointer){
try{s.finalize()}
@@ -738,7 +774,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
});
__ptrMap.delete(this);
__stmtMap.delete(this);
- capi.sqlite3_close_v2(pDb);
+ if( !__doesNotOwnHandle.delete(this) ){
+ capi.sqlite3_close_v2(pDb);
+ }
if(this.onclose && (this.onclose.after instanceof Function)){
try{this.onclose.after(this)}
catch(e){/*ignore*/}
@@ -1061,18 +1099,18 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const cbArgCache = Object.create(null)
/* 2nd arg for arg.cbArg, used by (at least) row-to-object
converter */;
- for(; stmt.step(); stmt._lockedByExec = false){
+ for( ; stmt.step(); __execLock.delete(stmt) ){
if(0===gotColNames++){
stmt.getColumnNames(cbArgCache.columnNames = (opt.columnNames || []));
}
- stmt._lockedByExec = true;
+ __execLock.add(stmt);
const row = arg.cbArg(stmt,cbArgCache);
if(resultRows) resultRows.push(row);
if(callback && false === callback.call(opt, row, stmt)){
break;
}
}
- stmt._lockedByExec = false;
+ __execLock.delete(stmt);
}
if(0===gotColNames){
/* opt.columnNames was provided but we visited no result rows */
@@ -1094,7 +1132,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}*/finally{
wasm.scopedAllocPop(stack);
if(stmt){
- delete stmt._lockedByExec;
+ __execLock.delete(stmt);
stmt.finalize();
}
}
@@ -1388,7 +1426,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/**
Starts a transaction, calls the given callback, and then either
- rolls back or commits the savepoint, depending on whether the
+ rolls back or commits the transaction, depending on whether the
callback throws. The callback is passed this db object as its
only argument. On success, returns the result of the
callback. Throws on error.
@@ -1451,9 +1489,63 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
*/
checkRc: function(resultCode){
return checkSqlite3Rc(this, resultCode);
- }
+ },
}/*DB.prototype*/;
+ /**
+ Returns a new oo1.DB instance which wraps the given (sqlite3*)
+ WASM pointer, optionally with or without taking over ownership of
+ that pointer.
+
+ The first argument must be either a non-NULL (sqlite3*) WASM
+ pointer.
+
+ The second argument, defaulting to false, specifies ownership of
+ the first argument. If it is truthy, the returned object will
+ pass that pointer to sqlite3_close() when its close() method is
+ called, otherwise it will not.
+
+ Throws if pDb is not a non-0 WASM pointer.
+
+ The caller MUST GUARANTEE that the passed-in handle will outlive
+ the returned object, i.e. that it will not be closed. If it is closed,
+ this object will hold a stale pointer and results are undefined.
+
+ Aside from its lifetime, the proxy is to be treated as any other
+ DB instance, including the requirement of calling close() on
+ it. close() will free up internal resources owned by the proxy
+ and disassociate the proxy from that handle but will not
+ actually close the proxied db handle unless this function is
+ passed a thruthy second argument.
+
+ To stress:
+
+ - DO NOT call sqlite3_close() (or similar) on the being-proxied
+ pointer while a proxy is active.
+
+ - ALWAYS eventually call close() on the returned object. If the
+ proxy does not own the underlying handle then its MUST be
+ closed BEFORE the being-proxied handle is closed.
+
+ Design notes:
+
+ - wrapHandle() "could" accept a DB object instance as its first
+ argument and proxy thatDb.pointer but there is currently no use
+ case where doing so would be useful, so it does not allow
+ that. That restriction may be lifted in a future version.
+ */
+ DB.wrapHandle = function(pDb, takeOwnership=false){
+ if( !pDb || !wasm.isPtr(pDb) ){
+ throw new sqlite3.SQLite3Error(capi.SQLITE_MISUSE,
+ "Argument must be a WASM sqlite3 pointer");
+ }
+ return new DB({
+ /* This ctor call style is very specifically internal-use-only.
+ It is not documented and may change at any time. */
+ "sqlite3*": pDb,
+ "sqlite3*:takeOwnership": !!takeOwnership
+ });
+ };
/** Throws if the given Stmt has been finalized, else stmt is
returned. */
@@ -1475,8 +1567,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
case BindTypes.string:
return t;
case BindTypes.bigint:
- if(wasm.bigIntEnabled) return t;
- /* else fall through */
+ return wasm.bigIntEnabled ? t : undefined;
default:
return util.isBindableTypedArray(v) ? BindTypes.blob : undefined;
}
@@ -1511,7 +1602,30 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
};
/**
- If stmt._lockedByExec is truthy, this throws an exception
+ Each Stmt object which is "locked" by DB.exec() gets an entry
+ here to note that "lock".
+
+ The reason this is in place is because exec({callback:...})'s
+ callback gets access to the Stmt objects created internally by
+ exec() but it must not use certain Stmt APIs.
+ */
+ const __execLock = new Set();
+ /**
+ This is a Stmt.get() counterpart of __execLock. Each time
+ Stmt.step() returns true, the statement is added to this set,
+ indicating that Stmt.get() is legal. Stmt APIs which invalidate
+ that status remove the Stmt object from this set, which will
+ cause Stmt.get() to throw with a descriptive error message
+ instead of a more generic "API misuse" if we were to allow that
+ call to reach the C API.
+ */
+ const __stmtMayGet = new Set();
+
+ /**
+ Stmt APIs which are prohibited on locked objects must call
+ affirmNotLockedByExec() before doing any work.
+
+ If __execLock.has(stmt) is truthy, this throws an exception
complaining that the 2nd argument (an operation name,
e.g. "bind()") is not legal while the statement is "locked".
Locking happens before an exec()-like callback is passed a
@@ -1519,7 +1633,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
finalize the statement. If it does not throw, it returns stmt.
*/
const affirmNotLockedByExec = function(stmt,currentOpName){
- if(stmt._lockedByExec){
+ if(__execLock.has(stmt)){
toss3("Operation is illegal when statement is locked:",currentOpName);
}
return stmt;
@@ -1604,7 +1718,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
toss3("Unsupported bind() argument type: "+(typeof val));
}
if(rc) DB.checkRc(stmt.db.pointer, rc);
- stmt._mayGet = false;
return stmt;
};
@@ -1620,16 +1733,23 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
This method always throws if called when it is illegal to do
so. Namely, when triggered via a per-row callback handler of a
DB.exec() call.
+
+ If Stmt does not own its underlying (sqlite3_stmt*) (see
+ Stmt.wrapHandle()) then this function will not pass it to
+ sqlite3_finalize().
*/
finalize: function(){
- if(this.pointer){
+ const ptr = this.pointer;
+ if(ptr){
affirmNotLockedByExec(this,'finalize()');
- const rc = capi.sqlite3_finalize(this.pointer);
- delete __stmtMap.get(this.db)[this.pointer];
+ const rc = (__doesNotOwnHandle.delete(this)
+ ? 0
+ : capi.sqlite3_finalize(ptr));
+ delete __stmtMap.get(this.db)[ptr];
__ptrMap.delete(this);
- delete this._mayGet;
+ __execLock.delete(this);
+ __stmtMayGet.delete(this);
delete this.parameterCount;
- delete this._lockedByExec;
delete this.db;
return rc;
}
@@ -1643,7 +1763,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
clearBindings: function(){
affirmNotLockedByExec(affirmStmtOpen(this), 'clearBindings()')
capi.sqlite3_clear_bindings(this.pointer);
- this._mayGet = false;
+ __stmtMayGet.delete(this);
return this;
},
/**
@@ -1669,7 +1789,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
affirmNotLockedByExec(this,'reset()');
if(alsoClearBinds) this.clearBindings();
const rc = capi.sqlite3_reset(affirmStmtOpen(this).pointer);
- this._mayGet = false;
+ __stmtMayGet.delete(this);
checkSqlite3Rc(this.db, rc);
return this;
},
@@ -1756,7 +1876,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}else if(!this.parameterCount){
toss3("This statement has no bindable parameters.");
}
- this._mayGet = false;
+ __stmtMayGet.delete(this);
if(null===arg){
/* bind NULL */
return bindOne(this, ndx, BindTypes.null, arg);
@@ -1821,14 +1941,18 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
affirmNotLockedByExec(this, 'step()');
const rc = capi.sqlite3_step(affirmStmtOpen(this).pointer);
switch(rc){
- case capi.SQLITE_DONE: return this._mayGet = false;
- case capi.SQLITE_ROW: return this._mayGet = true;
- default:
- this._mayGet = false;
- sqlite3.config.warn("sqlite3_step() rc=",rc,
- capi.sqlite3_js_rc_str(rc),
- "SQL =", capi.sqlite3_sql(this.pointer));
- DB.checkRc(this.db.pointer, rc);
+ case capi.SQLITE_DONE:
+ __stmtMayGet.delete(this);
+ return false;
+ case capi.SQLITE_ROW:
+ __stmtMayGet.add(this);
+ return true;
+ default:
+ __stmtMayGet.delete(this);
+ sqlite3.config.warn("sqlite3_step() rc=",rc,
+ capi.sqlite3_js_rc_str(rc),
+ "SQL =", capi.sqlite3_sql(this.pointer));
+ DB.checkRc(this.db.pointer, rc);
}
},
/**
@@ -1913,7 +2037,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
getJSON() can be used for that.
*/
get: function(ndx,asType){
- if(!affirmStmtOpen(this)._mayGet){
+ if(!__stmtMayGet.has(affirmStmtOpen(this))){
toss3("Stmt.step() has not (recently) returned true.");
}
if(Array.isArray(ndx)){
@@ -2109,6 +2233,64 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
set: ()=>toss3("The columnCount property is read-only.")
});
+ Object.defineProperty(Stmt.prototype, 'parameterCount', {
+ enumerable: false,
+ get: function(){return capi.sqlite3_bind_parameter_count(this.pointer)},
+ set: ()=>toss3("The parameterCount property is read-only.")
+ });
+
+ /**
+ The Stmt counterpart of oo1.DB.wrapHandle(), this creates a Stmt
+ instance which wraps a WASM (sqlite3_stmt*) in the oo1 API,
+ optionally with or without taking over ownership of that pointer.
+
+ The first argument must be an oo1.DB instance[^1].
+
+ The second argument must be a valid WASM (sqlite3_stmt*), as
+ produced by sqlite3_prepare_v2() and sqlite3_prepare_v3().
+
+ The third argument, defaulting to false, specifies whether the
+ returned Stmt object takes over ownership of the underlying
+ (sqlite3_stmt*). If true, the returned object's finalize() method
+ will finalize that handle, else it will not. If it is false,
+ ownership of pStmt is unchanged and pStmt MUST outlive the
+ returned object or results are undefined.
+
+ This function throws if the arguments are invalid. On success it
+ returns a new Stmt object which wraps the given statement
+ pointer.
+
+ Like all Stmt objects, the finalize() method must eventually be
+ called on the returned object to free up internal resources,
+ regardless of whether this function's third argument is true or
+ not.
+
+ [^1]: The first argument cannot be a (sqlite3*) because the
+ resulting Stmt object requires a parent DB object. It is not yet
+ determined whether it would be of general benefit to refactor the
+ DB/Stmt pair internals to communicate in terms of the underlying
+ (sqlite3*) rather than a DB object. If so, we could laxen the
+ first argument's requirement and allow an (sqlite3*). Because
+ DB.wrapHandle() enables multiple DB objects to proxy the same
+ (sqlite3*), we cannot unambiguously translate the first arugment
+ from (sqlite3*) to DB instances for us with this function's first
+ argument.
+ */
+ Stmt.wrapHandle = function(oo1db, pStmt, takeOwnership=false){
+ let ctor = Stmt;
+ if( !(oo1db instanceof DB) || !oo1db.pointer ){
+ throw new sqlite3.SQLite3Error(sqlite3.SQLITE_MISUSE,
+ "First argument must be an opened "+
+ "sqlite3.oo1.DB instance");
+ }
+ if( !pStmt || !wasm.isPtr(pStmt) ){
+ throw new sqlite3.SQLite3Error(sqlite3.SQLITE_MISUSE,
+ "Second argument must be a WASM "+
+ "sqlite3_stmt pointer");
+ }
+ return new Stmt(oo1db, pStmt, BindTypes, !!takeOwnership);
+ }
+
/** The OO API's public namespace. */
sqlite3.oo1 = {
DB,
diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js
index 7e128a3fa..e3807a314 100644
--- a/ext/wasm/api/sqlite3-api-prologue.js
+++ b/ext/wasm/api/sqlite3-api-prologue.js
@@ -134,22 +134,7 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
const config = Object.assign(Object.create(null),{
exports: undefined,
memory: undefined,
- bigIntEnabled: (()=>{
- if('undefined'!==typeof Module){
- /* Emscripten module will contain HEAPU64 when built with
- -sWASM_BIGINT=1, else it will not.
-
- As of emsdk 3.1.55, when building in strict mode, HEAPxyz
- are only available if _explicitly_ included in the exports,
- else they are not. We do not (as of 2024-03-04) use -sSTRICT
- for the canonical builds.
- */
- if( !!Module.HEAPU64 ) return true;
- /* Else fall through and hope for the best. Nobody _really_
- builds this without BigInt support, do they? */
- }
- return !!globalThis.BigInt64Array;
- })(),
+ bigIntEnabled: !!globalThis.BigInt64Array,
debug: console.debug.bind(console),
warn: console.warn.bind(console),
error: console.error.bind(console),
diff --git a/ext/wasm/api/sqlite3-wasm.c b/ext/wasm/api/sqlite3-wasm.c
index d9f0f08eb..ee8a10209 100644
--- a/ext/wasm/api/sqlite3-wasm.c
+++ b/ext/wasm/api/sqlite3-wasm.c
@@ -135,9 +135,12 @@
/*
** If SQLITE_WASM_BARE_BONES is defined, undefine most of the ENABLE
-** macros.
+** macros. This will, when using the canonical makefile, also elide
+** any C functions from the WASM exports which are listed in
+** ./EXPORT_FUNCTIONS.sqlite3-extras.
*/
#ifdef SQLITE_WASM_BARE_BONES
+# undef SQLITE_ENABLE_COLUMN_METADATA
# undef SQLITE_ENABLE_DBPAGE_VTAB
# undef SQLITE_ENABLE_DBSTAT_VTAB
# undef SQLITE_ENABLE_EXPLAIN_COMMENTS
@@ -1157,7 +1160,7 @@ const char * sqlite3__wasm_enum_json(void){
{ /* Validate that the above struct sizeof()s match
** expectations. We could improve upon this by
** checking the offsetof() for each member. */
- const sqlite3_index_info siiCheck;
+ const sqlite3_index_info siiCheck = {0};
#define IndexSzCheck(T,M) \
(sizeof(T) == sizeof(*siiCheck.M))
if(!IndexSzCheck(sqlite3_index_constraint,aConstraint)
diff --git a/ext/wasm/fiddle.make b/ext/wasm/fiddle.make
index 8110384a6..5b1eb5e77 100644
--- a/ext/wasm/fiddle.make
+++ b/ext/wasm/fiddle.make
@@ -40,9 +40,8 @@ fiddle.emcc-flags = \
-sWASM_BIGINT=$(emcc.WASM_BIGINT) \
-sEXPORT_NAME=$(sqlite3.js.init-func) \
-Wno-limited-postlink-optimizations \
- $(emcc.exportedRuntimeMethods) \
+ $(emcc.exportedRuntimeMethods),FS \
-sEXPORTED_FUNCTIONS=@$(abspath $(EXPORTED_FUNCTIONS.fiddle)) \
- -sEXPORTED_RUNTIME_METHODS=FS,wasmMemory \
$(SQLITE_OPT.full-featured) \
$(SQLITE_OPT.common) \
$(SHELL_OPT) \
diff --git a/ext/wasm/mkwasmbuilds.c b/ext/wasm/mkwasmbuilds.c
index d13302769..8aa29c0fe 100644
--- a/ext/wasm/mkwasmbuilds.c
+++ b/ext/wasm/mkwasmbuilds.c
@@ -328,7 +328,7 @@ static void mk_lib_mode(const char *zName /* build name */,
pf("\t\t$(cflags.common) $(SQLITE_OPT) \\\n"
"\t\t$(cflags.%s) $(cflags.%s.%s) \\\n"
"\t\t$(cflags.wasm_extra_init) $(sqlite3-wasm.cfiles)\n", zName, zNM);
- if( LIBMODE_ESM & flags ){
+ if( (LIBMODE_ESM & flags) || (LIBMODE_NODEJS & flags) ){
/* TODO? Replace this $(call) with the corresponding makefile
** code. OTOH, we also use this $(call) in the speedtest1-wasmfs
** build, which is not part of the rules emitted by this
diff --git a/ext/wasm/speedtest1-worker.html b/ext/wasm/speedtest1-worker.html
index 8c9a77dc5..ba0d22fb6 100644
--- a/ext/wasm/speedtest1-worker.html
+++ b/ext/wasm/speedtest1-worker.html
@@ -279,7 +279,7 @@
opt.innerHTML = lbl;
opt.value = f;
if(preselectedFlags.indexOf(f) >= 0) opt.selected = true;
- });
+ });
const cbReverseLog = E('#cb-reverse-log-order');
const lblReverseLog = E('#lbl-reverse-log-order');
if(cbReverseLog.checked){
diff --git a/ext/wasm/speedtest1.html b/ext/wasm/speedtest1.html
index 9cc20924e..3bad62006 100644
--- a/ext/wasm/speedtest1.html
+++ b/ext/wasm/speedtest1.html
@@ -118,7 +118,7 @@
argv.push("--vfs", vfs);
log2('',"Using VFS:",vfs);
if('kvvfs' === vfs){
- forceSize = 4 /* 5 uses approx. 4.96mb */;
+ forceSize = 2 /* 5 uses approx. 4.96mb */;
dbFile = 'session';
log2('warning',"kvvfs VFS: forcing --size",forceSize,
"and filename '"+dbFile+"'.");
diff --git a/ext/wasm/tester1.c-pp.js b/ext/wasm/tester1.c-pp.js
index d30e59e38..dd70024ab 100644
--- a/ext/wasm/tester1.c-pp.js
+++ b/ext/wasm/tester1.c-pp.js
@@ -41,7 +41,7 @@
ES6 worker module build:
- ./c-pp -f tester1.c-pp.js -o tester1-esm.js -Dtarget=es6-module
+ ./c-pp -f tester1.c-pp.js -o tester1-esm.mjs -Dtarget=es6-module
*/
//#if target=es6-module
import {default as sqlite3InitModule} from './jswasm/sqlite3.mjs';
@@ -221,7 +221,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
else if(filter instanceof Function) pass = filter(err);
else if('string' === typeof filter) pass = (err.message === filter);
if(!pass){
- throw new Error(msg || ("Filter rejected this exception: "+err.message));
+ throw new Error(msg || ("Filter rejected this exception: <<"+err.message+">>"));
}
return this;
},
@@ -1209,6 +1209,104 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
}
}
})
+
+ ////////////////////////////////////////////////////////////////////
+ .t({
+ name: "oo1.DB/Stmt.wrapDbHandle()",
+ test: function(sqlite3){
+ /* Maintenance reminder: this function is early in the list to
+ demonstrate that the wrappers for this.db created by this
+ function do not interfere with downstream tests, e.g. by
+ closing this.db.pointer. */
+ //sqlite3.config.debug("Proxying",this.db);
+ const misuseMsg = "SQLITE_MISUSE: Argument must be a WASM sqlite3 pointer";
+ T.mustThrowMatching(()=>sqlite3.oo1.DB.wrapHandle(this.db), misuseMsg)
+ .mustThrowMatching(()=>sqlite3.oo1.DB.wrapHandle(0), misuseMsg);
+ let dw = sqlite3.oo1.DB.wrapHandle(this.db.pointer);
+ //sqlite3.config.debug('dw',dw);
+ T.assert( dw, '!!dw' )
+ .assert( dw instanceof sqlite3.oo1.DB, 'dw is-a oo1.DB' )
+ .assert( dw.pointer, 'dw.pointer' )
+ .assert( dw.pointer === this.db.pointer, 'dw.pointer===db.pointer' )
+ .assert( dw.filename === this.db.filename, 'dw.filename===db.filename' );
+
+ T.assert( dw === dw.exec("select 1") );
+ let q;
+ try {
+ q = dw.prepare("select 1");
+ T.assert( q.step() )
+ .assert( !q.step() );
+ }finally{
+ if( q ) q.finalize();
+ }
+ dw.close();
+ T.assert( !dw.pointer )
+ .assert( this.db === this.db.exec("select 1") );
+ dw = undefined;
+
+ let pDb = 0, pStmt = 0;
+ const stack = wasm.pstack.pointer;
+ try {
+ const ppOut = wasm.pstack.allocPtr();
+ T.assert( 0===wasm.peekPtr(ppOut) );
+ let rc = capi.sqlite3_open_v2( ":memory:", ppOut,
+ capi.SQLITE_OPEN_CREATE
+ | capi.SQLITE_OPEN_READWRITE,
+ 0);
+ T.assert( 0===rc, 'open_v2()' );
+ pDb = wasm.peekPtr(ppOut);
+ wasm.pokePtr(ppOut, 0);
+ T.assert( pDb>0, 'pDb>0' );
+ const pTmp = pDb;
+ dw = sqlite3.oo1.DB.wrapHandle(pDb, true);
+ pDb = 0;
+ //sqlite3.config.debug("dw",dw);
+ T.assert( pTmp===dw.pointer, 'pDb===dw.pointer' );
+ T.assert( dw.filename === "", "dw.filename == "+dw.filename );
+ let q = dw.prepare("select 1");
+ try {
+ T.assert( q.step(), "step()" );
+ T.assert( !q.step(), "!step()" );
+ }finally{
+ q.finalize();
+ q = undefined;
+ }
+ T.assert( dw===dw.exec("select 1") );
+ dw.affirmOpen();
+ const select1 = "select 1";
+ rc = capi.sqlite3_prepare_v2( dw, select1, -1, ppOut, 0 );
+ T.assert( 0===rc, 'prepare_v2() rc='+rc );
+ pStmt = wasm.peekPtr(ppOut);
+ T.assert( pStmt && wasm.isPtr(pStmt), 'pStmt is valid?' );
+ try {
+ //log( "capi.sqlite3_sql() =",capi.sqlite3_sql(pStmt));
+ T.assert( select1 === capi.sqlite3_sql(pStmt), 'SQL mismatch' );
+ q = sqlite3.oo1.Stmt.wrapHandle(dw, pStmt, false);
+ //log("q@"+pStmt+" does not own handle");
+ T.assert( q.step(), "step()" )
+ .assert( !q.step(), "!step()" );
+ q.finalize();
+ q = undefined;
+ T.assert( select1 === capi.sqlite3_sql(pStmt), 'SQL mismatch'
+ /* This will fail if we've mismanaged pStmt's lifetime */);
+ q = sqlite3.oo1.Stmt.wrapHandle(dw, pStmt, true);
+ pStmt = 0;
+ q.reset();
+ T.assert( q.step(), "step()" )
+ .assert( !q.step(), "!step()" );
+ }finally{
+ if( pStmt ) capi.sqlite3_finalize(pStmt)
+ if( q ) q.finalize();
+ }
+
+ }finally{
+ wasm.pstack.restore(stack);
+ if( pDb ){ capi.sqlite3_close_v2(pDb); }
+ else if( dw ){ dw.close(); }
+ }
+ }
+ })/*oo1.DB/Stmt.wrapHandle()*/
+
////////////////////////////////////////////////////////////////////
.t('sqlite3_db_config() and sqlite3_db_status()', function(sqlite3){
let rc = capi.sqlite3_db_config(this.db, capi.SQLITE_DBCONFIG_LEGACY_ALTER_TABLE, 0, 0);
@@ -1263,12 +1361,12 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
capi.sqlite3_stmt_status(
st, capi.SQLITE_STMTSTATUS_RUN, 0
) === 0)
- .assert(!st._mayGet)
.assert('a' === st.getColumnName(0))
.mustThrowMatching(()=>st.columnCount=2,
/columnCount property is read-only/)
.assert(1===st.columnCount)
.assert(0===st.parameterCount)
+ .assert(0===capi.sqlite3_bind_parameter_count(st))
.mustThrow(()=>st.bind(1,null))
.assert(true===st.step())
.assert(3 === st.get(0))
@@ -1287,9 +1385,9 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
.assert(1===st.get(0,capi.SQLITE_BLOB).length)
.assert(st.getBlob(0) instanceof Uint8Array)
.assert('3'.charCodeAt(0) === st.getBlob(0)[0])
- .assert(st._mayGet)
.assert(false===st.step())
- .assert(!st._mayGet)
+ .mustThrowMatching(()=>st.get(0),
+ "Stmt.step() has not (recently) returned true.")
.assert(
capi.sqlite3_stmt_status(
st, capi.SQLITE_STMTSTATUS_RUN, 0
@@ -1297,11 +1395,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
T.assert(this.progressHandlerCount>0
|| wasm.compileOptionUsed('OMIT_PROGRESS_CALLBACK'),
- "Expecting progress callback.").
- assert(0===capi.sqlite3_strglob("*.txt", "foo.txt")).
- assert(0!==capi.sqlite3_strglob("*.txt", "foo.xtx")).
- assert(0===capi.sqlite3_strlike("%.txt", "foo.txt", 0)).
- assert(0!==capi.sqlite3_strlike("%.txt", "foo.xtx", 0));
+ "Expecting progress callback.");
}finally{
rc = st.finalize();
}
@@ -1350,7 +1444,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
.assert(pVfsDb > 0)
.assert(pVfsMem !== pVfsDflt
/* memdb lives on top of the default vfs */)
- .assert(pVfsDb === pVfsDflt || pVfsdb === pVfsMem)
+ .assert(pVfsDb === pVfsDflt || pVfsDb === pVfsMem)
;
/*const vMem = new capi.sqlite3_vfs(pVfsMem),
vDflt = new capi.sqlite3_vfs(pVfsDflt),
@@ -1495,6 +1589,8 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
let st = db.prepare("update t set b=:b where a='blob'");
try {
T.assert(0===st.columnCount)
+ .assert(1===st.parameterCount)
+ .assert(1===capi.sqlite3_bind_parameter_count(st))
.assert( false===st.isReadOnly() );
const ndx = st.getParamIndex(':b');
T.assert(1===ndx);
@@ -2193,7 +2289,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
"back into JS because of the lack of 64-bit integer support.");
}
}finally{
- const x = w.scopedAlloc(1), y = w.scopedAlloc(1), z = w.scopedAlloc(1);
+ //const x = w.scopedAlloc(1), y = w.scopedAlloc(1), z = w.scopedAlloc(1);
//log("x=",x,"y=",y,"z=",z); // just looking at the alignment
w.scopedAllocPop(stack);
}
@@ -2673,50 +2769,70 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|| "Only available in main thread."),
test: function(sqlite3){
this.kvvfsUnlink();
- let db;
- const encOpt1 = 1
- ? {textkey: 'foo'}
- : {key: 'foo'};
- const encOpt2 = encOpt1.textkey
- ? encOpt1
- : {hexkey: new Uint8Array([0x66,0x6f,0x6f]/*==>"foo"*/)}
- try{
- db = new this.JDb({
- filename: this.kvvfsDbFile,
- ...encOpt1
- });
- db.exec([
- "create table t(a,b);",
- "insert into t(a,b) values(1,2),(3,4)"
- ]);
- db.close();
- let err;
- try{
- db = new this.JDb({
- filename: this.kvvfsDbFile,
- flags: 'ct'
+ let initDb = true;
+ const tryKey = function(keyKey, key, expectCount){
+ let db;
+ //console.debug('tryKey()',arguments);
+ const ctoropt = {
+ filename: this.kvvfsDbFile
+ //vfs: 'kvvfs'
+ //,flags: 'ct'
+ };
+ try {
+ if (initDb) {
+ initDb = false;
+ db = new this.JDb({
+ ...ctoropt,
+ [keyKey]: key
+ });
+ db.exec([
+ "drop table if exists t;",
+ "create table t(a);"
+ ]);
+ db.close();
+ // Ensure that it's actually encrypted...
+ let err;
+ try {
+ db = new this.JDb(ctoropt);
+ T.assert(db, 'db opened') /* opening is fine, but... */;
+ db.exec("select 1 from sqlite_schema");
+ console.warn("(should not be reached) sessionStorage =", sessionStorage);
+ } catch (e) {
+ err = e;
+ } finally {
+ db.close()
+ }
+ T.assert(err, "Expecting an exception")
+ .assert(sqlite3.capi.SQLITE_NOTADB == err.resultCode,
+ "Expecting NOTADB");
+ }/*initDb*/
+ //console.debug('tryKey()',arguments);
+ db = new sqlite3.oo1.DB({
+ ...ctoropt,
+ vfs: 'kvvfs',
+ [keyKey]: key
});
- T.assert(db) /* opening is fine, but... */;
- db.exec("select 1 from sqlite_schema");
- console.warn("sessionStorage =",sessionStorage);
- }catch(e){
- err = e;
- }finally{
- db.close();
+ db.exec("insert into t(a) values (1),(2)");
+ T.assert(expectCount === db.selectValue('select sum(a) from t'));
+ } finally {
+ if (db) db.close();
}
- T.assert(err,"Expecting an exception")
- .assert(sqlite3.capi.SQLITE_NOTADB==err.resultCode,
- "Expecting NOTADB");
- db = new sqlite3.oo1.DB({
- filename: this.kvvfsDbFile,
- vfs: 'kvvfs',
- ...encOpt2
- });
- T.assert( 4===db.selectValue('select sum(a) from t') );
- }finally{
- if( db ) db.close();
- this.kvvfsUnlink();
- }
+ }.bind(this);
+ const hexFoo = new Uint8Array([0x66,0x6f,0x6f]/*=="foo"*/);
+ tryKey('textkey', 'foo', 3);
+ T.assert( !initDb );
+ tryKey('textkey', 'foo', 6);
+ this.kvvfsUnlink();
+ initDb = true;
+ tryKey('key', 'foo', 3);
+ T.assert( !initDb );
+ tryKey('key', hexFoo, 6);
+ this.kvvfsUnlink();
+ initDb = true;
+ tryKey('hexkey', hexFoo, 3);
+ T.assert( !initDb );
+ tryKey('hexkey', hexFoo, 6);
+ this.kvvfsUnlink();
}
})/*kvvfs with SEE*/
//#endif enable-see
@@ -2836,6 +2952,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
},
9
);
+ T.assert( 0==rc );
db.transaction((d)=>{
d.exec([
"create table t(a);",
@@ -2849,8 +2966,10 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
.assert(2 === countHook[capi.SQLITE_UPDATE])
.assert(1 === countHook[capi.SQLITE_DELETE]);
//wasm.xWrap.FuncPtrAdapter.debugFuncInstall = true;
- db.close();
+ T.assert( !!capi.sqlite3_preupdate_hook(db, 0, 0) );
//wasm.xWrap.FuncPtrAdapter.debugFuncInstall = false;
+ T.assert( !capi.sqlite3_preupdate_hook(db, 0, 0) );
+ db.close();
}
})/*pre-update hooks*/
;/*end hook API tests*/
@@ -3051,7 +3170,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
T.assert(6 === db.selectValue('select count(*) from p')).
assert( this.opfsImportSize == exp.byteLength );
db.close();
- const unlink = this.opfsUnlink =
+ this.opfsUnlink =
(fn=filename)=>sqlite3.util.sqlite3__wasm_vfs_unlink("opfs",fn);
this.opfsUnlink(filename);
T.assert(!(await sqlite3.opfs.entryExists(filename)));
@@ -3302,7 +3421,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
.assert(true === await u3.removeVfs())
.assert(false === await P3b.removeVfs());
}
- }/*OPFS SAH Pool sanity checks*/)
+ }/*OPFS SAH Pool sanity checks*/);
////////////////////////////////////////////////////////////////////////
T.g('Misc. APIs')
@@ -3311,6 +3430,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
db.exec("create table t(a)");
const stmt = db.prepare("insert into t(a) values($a)");
T.assert( 1===capi.sqlite3_bind_parameter_count(stmt) )
+ .assert( 1===stmt.parameterCount )
.assert( 1===capi.sqlite3_bind_parameter_index(stmt, "$a") )
.assert( 0===capi.sqlite3_bind_parameter_index(stmt, ":a") )
.assert( 1===stmt.getParamIndex("$a") )
@@ -3323,6 +3443,44 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
db.close();
})
+ /**
+ Ensure that certain Stmt members throw when called
+ via DB.exec().
+ */
+ .t('locked-by-exec() APIs', function(sqlite3){
+ const db = new sqlite3.oo1.DB();
+ db.exec("create table t(a);insert into t(a) values(1);");
+ let checkCount = 0;
+ const checkOp = function(op){
+ ++checkCount;
+ T.mustThrowMatching(() => {
+ db.exec({
+ sql: "select ?1",
+ bind: op,
+ callback: (row, stmt) => {
+ switch (row[0]) {
+ case 'bind': stmt.bind(1); break;
+ case 'finalize':
+ case 'clearBindings':
+ case 'reset':
+ case 'step': stmt[op](); break;
+ }
+ }
+ });
+ }, /^Operation is illegal when statement is locked.*/)
+ };
+ try{
+ checkOp('bind');
+ checkOp('finalize');
+ checkOp('clearBindings');
+ checkOp('reset');
+ checkOp('step');
+ T.assert(5===checkCount);
+ }finally{
+ db.close();
+ }
+ })
+
////////////////////////////////////////////////////////////////////
.t("Misc. stmt_...", function(sqlite3){
const db = new sqlite3.oo1.DB();
@@ -3353,6 +3511,16 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
T.assert( 1===n )
.assert( 0===capi.sqlite3_stmt_busy(stmt) )
.assert( !stmt.isBusy() );
+
+ if( wasm.exports.sqlite3_column_origin_name ){
+ log("Column metadata APIs enabled");
+ T.assert( "t" === capi.sqlite3_column_table_name(stmt, 0))
+ .assert("a" === capi.sqlite3_column_origin_name(stmt, 0))
+ .assert("main" === capi.sqlite3_column_database_name(stmt, 0))
+ }else{
+ log("Column metadata APIs not enabled");
+ } // column metadata APIs
+
stmt.finalize();
db.close();
})
@@ -3364,7 +3532,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
capi.sqlite3_interrupt(db);
T.assert( 0!==capi.sqlite3_is_interrupted(db) );
db.close();
- })
+ });
////////////////////////////////////////////////////////////////////////
T.g('Bug Reports')
@@ -3384,10 +3552,10 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
sql: "SELECT * FROM f order by path",
rowMode: 'array'
});
- const dump = function(lbl){
+ /*const dump = function(lbl){
let rc = fetchEm();
log((lbl ? (lbl+' results') : ''),rc);
- };
+ };*/
//dump('Full fts table');
let rc = fetchEm();
T.assert(3===rc.length);