1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Merge all of the trunk enchancements into the bedrock branch.

FossilOrigin-Name: ba2174bdca7d1d1aadf0a4de1e01aeba3d95b6656cb9ecdff88b00cfbef8f3a9
This commit is contained in:
drh
2025-07-17 15:31:16 +00:00
66 changed files with 3879 additions and 973 deletions

View File

@@ -1986,9 +1986,9 @@ static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){
** leave an error in the Fts5Index object.
*/
static void fts5SegIterAllocTombstone(Fts5Index *p, Fts5SegIter *pIter){
const int nTomb = pIter->pSeg->nPgTombstone;
const i64 nTomb = (i64)pIter->pSeg->nPgTombstone;
if( nTomb>0 ){
int nByte = SZ_FTS5TOMBSTONEARRAY(nTomb+1);
i64 nByte = SZ_FTS5TOMBSTONEARRAY(nTomb+1);
Fts5TombstoneArray *pNew;
pNew = (Fts5TombstoneArray*)sqlite3Fts5MallocZero(&p->rc, nByte);
if( pNew ){
@@ -2481,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 ){
FTS5_CORRUPT_ITER(p, pIter);
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);
}
}
}
@@ -5845,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 ){
@@ -8284,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 */
@@ -8346,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;
}
@@ -8355,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
/*
@@ -8613,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;
@@ -8655,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 ){
@@ -8673,7 +8684,7 @@ 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 ){
@@ -8682,11 +8693,17 @@ int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum){
"fts5: checksum mismatch for table \"%s\"", p->pConfig->zName
);
}
fts5StructureRelease(pStruct);
#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);
}

View File

@@ -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
@@ -10106,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
@@ -15909,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

View File

@@ -90,5 +90,58 @@ do_execsql_test 3.7 {
SELECT * FROM sqlite_schema
}
#-------------------------------------------------------------------------
reset_db
proc hex_to_blob {hex} {
binary encode hex $hex
}
db func hex_to_blob hex_to_blob
do_execsql_test 4.0 {
CREATE VIRTUAL TABLE x1 USING fts5(x, content='', contentless_delete=1);
BEGIN;
INSERT INTO x1(rowid, x) VALUES(1, 'a b c d e f g h');
INSERT INTO x1(rowid, x) VALUES(2, 'a b c d e f g h');
COMMIT;
DELETE FROM x1 WHERE rowid=1;
}
do_execsql_test 4.1 {
SELECT hex(block) FROM x1_data WHERE id=10
} {
00000000FF00000101010200010101010101010102
}
do_execsql_test 4.2.1 {
UPDATE x1_data SET block=
X'00000000FF00000101010200010101010101819C9B95A8000102'
WHERE id=10;
}
do_catchsql_test 4.2.2 {
SELECT * FROM x1('c d e');
} {1 {out of memory}}
do_execsql_test 4.3.1 {
UPDATE x1_data SET block=
X'00000000FF000001010102000101010101019282AFF9A0000102'
WHERE id=10;
}
do_catchsql_test 4.3.2 {
SELECT * FROM x1('c d e');
} {1 {out of memory}}
do_execsql_test 4.4.1 {
UPDATE x1_data SET block=
X'00000000FF000001010102000101010101018181808080130102'
WHERE id=10;
}
do_catchsql_test 4.3.2 {
SELECT * FROM x1('c d e');
} {1 {out of memory}}
finish_test

View File

@@ -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 {

View File

@@ -40,4 +40,53 @@ do_execsql_test 1.2 {
SELECT * FROM t1 LEFT JOIN vt ON (vt MATCH 'abc')
} {1 abc 2 abc}
do_execsql_test 1.3 {
DELETE FROM t1;
INSERT INTO t1 VALUES(14);
}
do_execsql_test 1.4 {
SELECT * FROM vt LEFT JOIN t1 ON vt.rowid = 1;
} {
abc 14
xyz {}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE t0 USING fts5(a,b);
INSERT INTO t0(a,b)VALUES(1,0);
CREATE TABLE t1(x);
}
do_execsql_test 2.1 {
SELECT * FROM t0 LEFT JOIN t1;
} {1 0 {}}
breakpoint
do_catchsql_test 2.2 {
SELECT * FROM t0 LEFT JOIN t1 ON t0.b MATCH '1';
} {1 {no query solution}}
do_execsql_test 2.3 {
SELECT * FROM t0 LEFT JOIN t1 ON +b MATCH '1';
} {1 0 {}}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 3.0 {
CREATE VIRTUAL TABLE t0 USING fts5(c0, c1);
INSERT INTO t0(c0,c1) VALUES (1,0);
}
do_catchsql_test 3.1 {
SELECT * FROM t0
LEFT JOIN ( SELECT 0 AS col_0 )
ON ((((t0.c1 MATCH '1')AND(CASE WHEN t0.c0 THEN CAST(t0.c1 AS INTEGER) ELSE 1 END))));
} {1 {no query solution}}
finish_test

View File

@@ -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
@@ -435,6 +442,39 @@ static int vtablogFilter(
return SQLITE_OK;
}
/*
** 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
@@ -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++){

View File

@@ -1135,6 +1135,12 @@ static void resetCursor(RtreeCursor *pCsr){
pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
pCsr->pReadAux = pStmt;
/* The following will only fail if the previous sqlite3_step() call failed,
** in which case the error has already been caught. This statement never
** encounters an error within an sqlite3_column_xxx() function, as it
** calls sqlite3_column_value(), which does not use malloc(). So it is safe
** to ignore the error code here. */
sqlite3_reset(pStmt);
}
/*

View File

@@ -99,5 +99,24 @@ do_execsql_test rtreeH-300 {
ORDER BY id;
} {box-48,48 box-49,48 box-48,49 xbox-49,49}
#-------------------------------------------------------------------------
reset_db
do_execsql_test rtreeH-300 {
CREATE TABLE t0(c0);
INSERT INTO t0(c0) VALUES (NULL);
INSERT INTO t0(c0) VALUES (1);
CREATE VIRTUAL TABLE t1 USING rtree(c0, c1, c2, +c3 BLOB );
INSERT INTO t1(c2, c3, c0) VALUES (1, 2, 1);
}
do_execsql_test rtreeH-310 {
SELECT 1 FROM t1 WHERE t1.c3;
} {1}
do_execsql_test rtreeH-320 {
SELECT * FROM t0 WHERE NOT EXISTS (
SELECT 1 FROM t1 WHERE t1.c3 OR t0.c0 ISNULL
);
} {}
finish_test

88
ext/session/sessionI.test Normal file
View File

@@ -0,0 +1,88 @@
# 2015 July 14
#
# 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.
#
#***********************************************************************
#
#
if {![info exists testdir]} {
set testdir [file join [file dirname [info script]] .. .. test]
}
source [file join [file dirname [info script]] session_common.tcl]
source $testdir/tester.tcl
ifcapable !session {finish_test; return}
set testprefix sessionI
forcedelete test.db2
sqlite3 db2 test.db2
do_test 1.0 {
do_common_sql {
CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
}
} {}
set C [changeset_from_sql {
INSERT INTO t1 VALUES(1, 'one');
INSERT INTO t1 VALUES(2, 'two');
INSERT INTO t1 VALUES(3, 'three');
INSERT INTO t1 VALUES(4, 'four');
INSERT INTO t1 VALUES(5, 'five');
INSERT INTO t1 VALUES(6, 'six');
}]
do_execsql_test 1.1 {
SELECT * FROM t1
} {
1 one 2 two 3 three 4 four 5 five 6 six
}
proc xFilter {data} {
foreach {op tname flag pk old new} $data {}
if {$op=="INSERT"} {
set ipk [lindex $new 1]
return [expr $ipk % 2]
}
return 1
}
proc xConflict {args} {
}
sqlite3changeset_apply_v3 db2 $C xConflict xFilter
do_execsql_test -db db2 1.2 {
SELECT * FROM t1
} {
1 one 3 three 5 five
}
do_execsql_test -db db2 1.3 {
DELETE FROM t1
}
sqlite3changeset_apply_v3 db2 $C xConflict
do_execsql_test -db db2 1.4 {
SELECT * FROM t1
} {
1 one 2 two 3 three 4 four 5 five 6 six
}
proc xFilter2 {data} {
return 0
}
do_execsql_test -db db2 1.5 {
DELETE FROM t1
}
sqlite3changeset_apply_v3 db2 $C xConflict xFilter2
do_execsql_test -db db2 1.6 {
SELECT * FROM t1
} { }
finish_test

View File

@@ -5213,6 +5213,10 @@ static int sessionChangesetApply(
void *pCtx, /* Copy of sixth arg to _apply() */
const char *zTab /* Table name */
),
int(*xFilterIter)(
void *pCtx, /* Copy of sixth arg to _apply() */
sqlite3_changeset_iter *p
),
int(*xConflict)(
void *pCtx, /* Copy of fifth arg to _apply() */
int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
@@ -5353,6 +5357,9 @@ static int sessionChangesetApply(
** next change. A log message has already been issued. */
if( schemaMismatch ) continue;
/* If this is a call to apply_v3(), invoke xFilterIter here. */
if( xFilterIter && 0==xFilterIter(pCtx, pIter) ) continue;
rc = sessionApplyOneWithRetry(db, pIter, &sApply, xConflict, pCtx);
}
@@ -5420,6 +5427,87 @@ static int sessionChangesetApply(
return rc;
}
/*
** This function is called by all six sqlite3changeset_apply() variants:
**
** + sqlite3changeset_apply()
** + sqlite3changeset_apply_v2()
** + sqlite3changeset_apply_v3()
** + sqlite3changeset_apply_strm()
** + sqlite3changeset_apply_strm_v2()
** + sqlite3changeset_apply_strm_v3()
**
** Arguments passed to this function are as follows:
**
** db:
** Database handle to apply changeset to main database of.
**
** nChangeset/pChangeset:
** These are both passed zero for the streaming variants. For the normal
** apply() functions, these are passed the size of and the buffer containing
** the changeset, respectively.
**
** xInput/pIn:
** These are both passed zero for the normal variants. For the streaming
** apply() functions, these are passed the input callback and context
** pointer, respectively.
**
** xFilter:
** The filter function as passed to apply() or apply_v2() (to filter by
** table name), if any. This is always NULL for apply_v3() calls.
**
** xFilterIter:
** The filter function as passed to apply_v3(), if any.
**
** xConflict:
** The conflict handler callback (must not be NULL).
**
** pCtx:
** The context pointer passed to the xFilter and xConflict handler callbacks.
**
** ppRebase, pnRebase:
** Zero for apply(). The rebase changeset output pointers, if any, for
** apply_v2() and apply_v3().
**
** flags:
** Zero for apply(). The flags parameter for apply_v2() and apply_v3().
*/
static int sessionChangesetApplyV23(
sqlite3 *db, /* Apply change to "main" db of this handle */
int nChangeset, /* Size of changeset in bytes */
void *pChangeset, /* Changeset blob */
int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
void *pIn, /* First arg for xInput */
int(*xFilter)(
void *pCtx, /* Copy of sixth arg to _apply() */
const char *zTab /* Table name */
),
int(*xFilterIter)(
void *pCtx, /* Copy of sixth arg to _apply() */
sqlite3_changeset_iter *p /* Handle describing current change */
),
int(*xConflict)(
void *pCtx, /* Copy of sixth arg to _apply() */
int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
sqlite3_changeset_iter *p /* Handle describing change and conflict */
),
void *pCtx, /* First argument passed to xConflict */
void **ppRebase, int *pnRebase,
int flags
){
sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
int rc = sessionChangesetStart(
&pIter, xInput, pIn, nChangeset, pChangeset, bInverse, 1
);
if( rc==SQLITE_OK ){
rc = sessionChangesetApply(db, pIter,
xFilter, xFilterIter, xConflict, pCtx, ppRebase, pnRebase, flags
);
}
return rc;
}
/*
** Apply the changeset passed via pChangeset/nChangeset to the main
** database attached to handle "db".
@@ -5441,17 +5529,39 @@ int sqlite3changeset_apply_v2(
void **ppRebase, int *pnRebase,
int flags
){
sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
int bInv = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset, bInv, 1);
return sessionChangesetApplyV23(db,
nChangeset, pChangeset, 0, 0,
xFilter, 0, xConflict, pCtx,
ppRebase, pnRebase, flags
);
}
if( rc==SQLITE_OK ){
rc = sessionChangesetApply(
db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
);
}
return rc;
/*
** Apply the changeset passed via pChangeset/nChangeset to the main
** database attached to handle "db".
*/
int sqlite3changeset_apply_v3(
sqlite3 *db, /* Apply change to "main" db of this handle */
int nChangeset, /* Size of changeset in bytes */
void *pChangeset, /* Changeset blob */
int(*xFilter)(
void *pCtx, /* Copy of sixth arg to _apply() */
sqlite3_changeset_iter *p /* Handle describing current change */
),
int(*xConflict)(
void *pCtx, /* Copy of sixth arg to _apply() */
int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
sqlite3_changeset_iter *p /* Handle describing change and conflict */
),
void *pCtx, /* First argument passed to xConflict */
void **ppRebase, int *pnRebase,
int flags
){
return sessionChangesetApplyV23(db,
nChangeset, pChangeset, 0, 0,
0, xFilter, xConflict, pCtx,
ppRebase, pnRebase, flags
);
}
/*
@@ -5474,8 +5584,10 @@ int sqlite3changeset_apply(
),
void *pCtx /* First argument passed to xConflict */
){
return sqlite3changeset_apply_v2(
db, nChangeset, pChangeset, xFilter, xConflict, pCtx, 0, 0, 0
return sessionChangesetApplyV23(db,
nChangeset, pChangeset, 0, 0,
xFilter, 0, xConflict, pCtx,
0, 0, 0
);
}
@@ -5484,6 +5596,29 @@ int sqlite3changeset_apply(
** attached to handle "db". Invoke the supplied conflict handler callback
** to resolve any conflicts encountered while applying the change.
*/
int sqlite3changeset_apply_v3_strm(
sqlite3 *db, /* Apply change to "main" db of this handle */
int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
void *pIn, /* First arg for xInput */
int(*xFilter)(
void *pCtx, /* Copy of sixth arg to _apply() */
sqlite3_changeset_iter *p
),
int(*xConflict)(
void *pCtx, /* Copy of sixth arg to _apply() */
int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
sqlite3_changeset_iter *p /* Handle describing change and conflict */
),
void *pCtx, /* First argument passed to xConflict */
void **ppRebase, int *pnRebase,
int flags
){
return sessionChangesetApplyV23(db,
0, 0, xInput, pIn,
0, xFilter, xConflict, pCtx,
ppRebase, pnRebase, flags
);
}
int sqlite3changeset_apply_v2_strm(
sqlite3 *db, /* Apply change to "main" db of this handle */
int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
@@ -5501,15 +5636,11 @@ int sqlite3changeset_apply_v2_strm(
void **ppRebase, int *pnRebase,
int flags
){
sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
int rc = sessionChangesetStart(&pIter, xInput, pIn, 0, 0, bInverse, 1);
if( rc==SQLITE_OK ){
rc = sessionChangesetApply(
db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
);
}
return rc;
return sessionChangesetApplyV23(db,
0, 0, xInput, pIn,
xFilter, 0, xConflict, pCtx,
ppRebase, pnRebase, flags
);
}
int sqlite3changeset_apply_strm(
sqlite3 *db, /* Apply change to "main" db of this handle */
@@ -5526,8 +5657,10 @@ int sqlite3changeset_apply_strm(
),
void *pCtx /* First argument passed to xConflict */
){
return sqlite3changeset_apply_v2_strm(
db, xInput, pIn, xFilter, xConflict, pCtx, 0, 0, 0
return sessionChangesetApplyV23(db,
0, 0, xInput, pIn,
xFilter, 0, xConflict, pCtx,
0, 0, 0
);
}

View File

@@ -1145,13 +1145,22 @@ void sqlite3changegroup_delete(sqlite3_changegroup*);
** the changeset passed via the second and third arguments.
**
** The fourth argument (xFilter) passed to these functions is the "filter
** callback". If it is not NULL, then for each table affected by at least one
** change in the changeset, the filter callback is invoked with
** the table name as the second argument, and a copy of the context pointer
** passed as the sixth argument as the first. If the "filter callback"
** returns zero, then no attempt is made to apply any changes to the table.
** Otherwise, if the return value is non-zero or the xFilter argument to
** is NULL, all changes related to the table are attempted.
** callback". This may be passed NULL, in which case all changes in the
** changeset are applied to the database. For sqlite3changeset_apply() and
** sqlite3_changeset_apply_v2(), if it is not NULL, then it is invoked once
** for each table affected by at least one change in the changeset. In this
** case the table name is passed as the second argument, and a copy of
** the context pointer passed as the sixth argument to apply() or apply_v2()
** as the first. If the "filter callback" returns zero, then no attempt is
** made to apply any changes to the table. Otherwise, if the return value is
** non-zero, all changes related to the table are attempted.
**
** For sqlite3_changeset_apply_v3(), the xFilter callback is invoked once
** per change. The second argument in this case is an sqlite3_changeset_iter
** that may be queried using the usual APIs for the details of the current
** change. If the "filter callback" returns zero in this case, then no attempt
** is made to apply the current change. If it returns non-zero, the change
** is applied.
**
** For each table that is not excluded by the filter callback, this function
** tests that the target database contains a compatible table. A table is
@@ -1172,11 +1181,11 @@ void sqlite3changegroup_delete(sqlite3_changegroup*);
** one such warning is issued for each table in the changeset.
**
** For each change for which there is a compatible table, an attempt is made
** to modify the table contents according to the UPDATE, INSERT or DELETE
** change. If a change cannot be applied cleanly, the conflict handler
** function passed as the fifth argument to sqlite3changeset_apply() may be
** invoked. A description of exactly when the conflict handler is invoked for
** each type of change is below.
** to modify the table contents according to each UPDATE, INSERT or DELETE
** change that is not excluded by a filter callback. If a change cannot be
** applied cleanly, the conflict handler function passed as the fifth argument
** to sqlite3changeset_apply() may be invoked. A description of exactly when
** the conflict handler is invoked for each type of change is below.
**
** Unlike the xFilter argument, xConflict may not be passed NULL. The results
** of passing anything other than a valid function pointer as the xConflict
@@ -1327,6 +1336,23 @@ int sqlite3changeset_apply_v2(
void **ppRebase, int *pnRebase, /* OUT: Rebase data */
int flags /* SESSION_CHANGESETAPPLY_* flags */
);
int sqlite3changeset_apply_v3(
sqlite3 *db, /* Apply change to "main" db of this handle */
int nChangeset, /* Size of changeset in bytes */
void *pChangeset, /* Changeset blob */
int(*xFilter)(
void *pCtx, /* Copy of sixth arg to _apply() */
sqlite3_changeset_iter *p /* Handle describing change */
),
int(*xConflict)(
void *pCtx, /* Copy of sixth arg to _apply() */
int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
sqlite3_changeset_iter *p /* Handle describing change and conflict */
),
void *pCtx, /* First argument passed to xConflict */
void **ppRebase, int *pnRebase, /* OUT: Rebase data */
int flags /* SESSION_CHANGESETAPPLY_* flags */
);
/*
** CAPI3REF: Flags for sqlite3changeset_apply_v2
@@ -1746,6 +1772,23 @@ int sqlite3changeset_apply_v2_strm(
void **ppRebase, int *pnRebase,
int flags
);
int sqlite3changeset_apply_v3_strm(
sqlite3 *db, /* Apply change to "main" db of this handle */
int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
void *pIn, /* First arg for xInput */
int(*xFilter)(
void *pCtx, /* Copy of sixth arg to _apply() */
sqlite3_changeset_iter *p
),
int(*xConflict)(
void *pCtx, /* Copy of sixth arg to _apply() */
int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
sqlite3_changeset_iter *p /* Handle describing change and conflict */
),
void *pCtx, /* First argument passed to xConflict */
void **ppRebase, int *pnRebase,
int flags
);
int sqlite3changeset_concat_strm(
int (*xInputA)(void *pIn, void *pData, int *pnData),
void *pInA,

View File

@@ -525,6 +525,65 @@ static int test_obj_eq_string(Tcl_Obj *p, const char *z){
return (nObj==n && (n==0 || 0==memcmp(zObj, z, n)));
}
static Tcl_Obj *testIterData(sqlite3_changeset_iter *pIter){
Tcl_Obj *pVar = 0;
int nCol; /* Number of columns in table */
int nCol2; /* Number of columns in table */
int op; /* SQLITE_INSERT, UPDATE or DELETE */
const char *zTab; /* Name of table change applies to */
Tcl_Obj *pOld; /* Vector of old.* values */
Tcl_Obj *pNew; /* Vector of new.* values */
int bIndirect;
char *zPK;
unsigned char *abPK;
int i;
sqlite3changeset_op(pIter, &zTab, &nCol, &op, &bIndirect);
pVar = Tcl_NewObj();
Tcl_ListObjAppendElement(0, pVar, Tcl_NewStringObj(
op==SQLITE_INSERT ? "INSERT" :
op==SQLITE_UPDATE ? "UPDATE" :
"DELETE", -1
));
Tcl_ListObjAppendElement(0, pVar, Tcl_NewStringObj(zTab, -1));
Tcl_ListObjAppendElement(0, pVar, Tcl_NewBooleanObj(bIndirect));
zPK = ckalloc(nCol+1);
memset(zPK, 0, nCol+1);
sqlite3changeset_pk(pIter, &abPK, &nCol2);
assert( nCol==nCol2 );
for(i=0; i<nCol; i++){
zPK[i] = (abPK[i] ? 'X' : '.');
}
Tcl_ListObjAppendElement(0, pVar, Tcl_NewStringObj(zPK, -1));
ckfree(zPK);
pOld = Tcl_NewObj();
if( op!=SQLITE_INSERT ){
for(i=0; i<nCol; i++){
sqlite3_value *pVal;
sqlite3changeset_old(pIter, i, &pVal);
test_append_value(pOld, pVal);
}
}
pNew = Tcl_NewObj();
if( op!=SQLITE_DELETE ){
for(i=0; i<nCol; i++){
sqlite3_value *pVal;
sqlite3changeset_new(pIter, i, &pVal);
test_append_value(pNew, pVal);
}
}
Tcl_ListObjAppendElement(0, pVar, pOld);
Tcl_ListObjAppendElement(0, pVar, pNew);
return pVar;
}
static int test_filter_handler(
void *pCtx, /* Pointer to TestConflictHandler structure */
const char *zTab /* Table name */
@@ -544,6 +603,29 @@ static int test_filter_handler(
Tcl_BackgroundError(interp);
}
Tcl_DecrRefCount(pEval);
return res;
}
static int test_filter_v3_handler(
void *pCtx, /* Pointer to TestConflictHandler structure */
sqlite3_changeset_iter *pIter
){
TestConflictHandler *p = (TestConflictHandler *)pCtx;
int res = 1;
Tcl_Obj *pEval = 0;
Tcl_Interp *interp = p->interp;
pEval = Tcl_DuplicateObj(p->pFilterScript);
Tcl_IncrRefCount(pEval);
Tcl_ListObjAppendElement(0, pEval, testIterData(pIter));
if( TCL_OK!=Tcl_EvalObjEx(interp, pEval, TCL_EVAL_GLOBAL)
|| TCL_OK!=Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &res)
){
Tcl_BackgroundError(interp);
}
Tcl_DecrRefCount(pEval);
return res;
}
@@ -781,7 +863,7 @@ static int testStreamInput(
static int SQLITE_TCLAPI testSqlite3changesetApply(
int bV2,
int iVersion,
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -798,11 +880,13 @@ static int SQLITE_TCLAPI testSqlite3changesetApply(
int nRebase = 0;
int flags = 0; /* Flags for apply_v2() */
assert( iVersion==1 || iVersion==2 || iVersion==3 );
memset(&sStr, 0, sizeof(sStr));
sStr.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
/* Check for the -nosavepoint, -invert or -ignorenoop switches */
if( bV2 ){
if( iVersion==2 || iVersion==3 ){
while( objc>1 ){
const char *z1 = Tcl_GetString(objv[1]);
int n = (int)strlen(z1);
@@ -827,7 +911,7 @@ static int SQLITE_TCLAPI testSqlite3changesetApply(
if( objc!=4 && objc!=5 ){
const char *zMsg;
if( bV2 ){
if( iVersion==2 || iVersion==3 ){
zMsg = "?-nosavepoint? ?-inverse? ?-ignorenoop? "
"DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?";
}else{
@@ -847,30 +931,49 @@ static int SQLITE_TCLAPI testSqlite3changesetApply(
ctx.interp = interp;
if( sStr.nStream==0 ){
if( bV2==0 ){
rc = sqlite3changeset_apply(db, (int)nChangeset, pChangeset,
(objc==5)?test_filter_handler:0, test_conflict_handler, (void *)&ctx
);
}else{
rc = sqlite3changeset_apply_v2(db, (int)nChangeset, pChangeset,
(objc==5)?test_filter_handler:0, test_conflict_handler, (void *)&ctx,
&pRebase, &nRebase, flags
);
switch( iVersion ){
case 1:
rc = sqlite3changeset_apply(db, (int)nChangeset, pChangeset,
(objc==5)?test_filter_handler:0, test_conflict_handler, (void*)&ctx
);
break;
case 2:
rc = sqlite3changeset_apply_v2(db, (int)nChangeset, pChangeset,
(objc==5)?test_filter_handler:0, test_conflict_handler, (void*)&ctx,
&pRebase, &nRebase, flags
);
break;
case 3:
rc = sqlite3changeset_apply_v3(db, (int)nChangeset, pChangeset,
(objc==5)?test_filter_v3_handler:0, test_conflict_handler,
(void*)&ctx, &pRebase, &nRebase, flags
);
break;
}
}else{
sStr.aData = (unsigned char*)pChangeset;
sStr.nData = (int)nChangeset;
if( bV2==0 ){
rc = sqlite3changeset_apply_strm(db, testStreamInput, (void*)&sStr,
(objc==5) ? test_filter_handler : 0,
test_conflict_handler, (void *)&ctx
);
}else{
rc = sqlite3changeset_apply_v2_strm(db, testStreamInput, (void*)&sStr,
(objc==5) ? test_filter_handler : 0,
test_conflict_handler, (void *)&ctx,
&pRebase, &nRebase, flags
);
switch( iVersion ){
case 1:
rc = sqlite3changeset_apply_strm(db, testStreamInput, (void*)&sStr,
(objc==5) ? test_filter_handler : 0,
test_conflict_handler, (void *)&ctx
);
break;
case 2:
rc = sqlite3changeset_apply_v2_strm(db, testStreamInput, (void*)&sStr,
(objc==5) ? test_filter_handler : 0,
test_conflict_handler, (void *)&ctx,
&pRebase, &nRebase, flags
);
break;
case 3:
rc = sqlite3changeset_apply_v3_strm(db, testStreamInput, (void*)&sStr,
(objc==5) ? test_filter_v3_handler : 0,
test_conflict_handler, (void *)&ctx,
&pRebase, &nRebase, flags
);
break;
}
}
@@ -878,7 +981,7 @@ static int SQLITE_TCLAPI testSqlite3changesetApply(
return test_session_error(interp, rc, 0);
}else{
Tcl_ResetResult(interp);
if( bV2 && pRebase ){
if( (iVersion==2 || iVersion==3) && pRebase ){
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pRebase, nRebase));
}
}
@@ -895,7 +998,7 @@ static int SQLITE_TCLAPI test_sqlite3changeset_apply(
int objc,
Tcl_Obj *CONST objv[]
){
return testSqlite3changesetApply(0, clientData, interp, objc, objv);
return testSqlite3changesetApply(1, clientData, interp, objc, objv);
}
/*
** sqlite3changeset_apply_v2 DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?
@@ -906,7 +1009,18 @@ static int SQLITE_TCLAPI test_sqlite3changeset_apply_v2(
int objc,
Tcl_Obj *CONST objv[]
){
return testSqlite3changesetApply(1, clientData, interp, objc, objv);
return testSqlite3changesetApply(2, clientData, interp, objc, objv);
}
/*
** sqlite3changeset_apply_v3 DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?
*/
static int SQLITE_TCLAPI test_sqlite3changeset_apply_v3(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
return testSqlite3changesetApply(3, clientData, interp, objc, objv);
}
/*
@@ -1039,64 +1153,6 @@ static int SQLITE_TCLAPI test_sqlite3changeset_concat(
return rc;
}
static Tcl_Obj *testIterData(sqlite3_changeset_iter *pIter){
Tcl_Obj *pVar = 0;
int nCol; /* Number of columns in table */
int nCol2; /* Number of columns in table */
int op; /* SQLITE_INSERT, UPDATE or DELETE */
const char *zTab; /* Name of table change applies to */
Tcl_Obj *pOld; /* Vector of old.* values */
Tcl_Obj *pNew; /* Vector of new.* values */
int bIndirect;
char *zPK;
unsigned char *abPK;
int i;
sqlite3changeset_op(pIter, &zTab, &nCol, &op, &bIndirect);
pVar = Tcl_NewObj();
Tcl_ListObjAppendElement(0, pVar, Tcl_NewStringObj(
op==SQLITE_INSERT ? "INSERT" :
op==SQLITE_UPDATE ? "UPDATE" :
"DELETE", -1
));
Tcl_ListObjAppendElement(0, pVar, Tcl_NewStringObj(zTab, -1));
Tcl_ListObjAppendElement(0, pVar, Tcl_NewBooleanObj(bIndirect));
zPK = ckalloc(nCol+1);
memset(zPK, 0, nCol+1);
sqlite3changeset_pk(pIter, &abPK, &nCol2);
assert( nCol==nCol2 );
for(i=0; i<nCol; i++){
zPK[i] = (abPK[i] ? 'X' : '.');
}
Tcl_ListObjAppendElement(0, pVar, Tcl_NewStringObj(zPK, -1));
ckfree(zPK);
pOld = Tcl_NewObj();
if( op!=SQLITE_INSERT ){
for(i=0; i<nCol; i++){
sqlite3_value *pVal;
sqlite3changeset_old(pIter, i, &pVal);
test_append_value(pOld, pVal);
}
}
pNew = Tcl_NewObj();
if( op!=SQLITE_DELETE ){
for(i=0; i<nCol; i++){
sqlite3_value *pVal;
sqlite3changeset_new(pIter, i, &pVal);
test_append_value(pNew, pVal);
}
}
Tcl_ListObjAppendElement(0, pVar, pOld);
Tcl_ListObjAppendElement(0, pVar, pNew);
return pVar;
}
/*
** sqlite3session_foreach VARNAME CHANGESET SCRIPT
*/
@@ -1877,6 +1933,7 @@ int TestSession_Init(Tcl_Interp *interp){
{ "sqlite3changeset_concat", test_sqlite3changeset_concat },
{ "sqlite3changeset_apply", test_sqlite3changeset_apply },
{ "sqlite3changeset_apply_v2", test_sqlite3changeset_apply_v2 },
{ "sqlite3changeset_apply_v3", test_sqlite3changeset_apply_v3 },
{ "sqlite3changeset_apply_replace_all",
test_sqlite3changeset_apply_replace_all },
{ "sql_exec_changeset", test_sql_exec_changeset },

View File

@@ -39,10 +39,11 @@
########################################################################
default: all
#default: quick
MAKEFILE := $(lastword $(MAKEFILE_LIST))
CLEAN_FILES :=
DISTCLEAN_FILES := config.make
MAKING_CLEAN := $(if $(filter %clean,$(MAKECMDGOALS)),1,0)
MAKEFILE = $(lastword $(MAKEFILE_LIST))
MAKEFILE.fiddle = fiddle.make
CLEAN_FILES =
DISTCLEAN_FILES = config.make
MAKING_CLEAN = $(if $(filter %clean,$(MAKECMDGOALS)),1,0)
.PHONY: clean distclean
clean:
-rm -f $(CLEAN_FILES)
@@ -53,17 +54,17 @@ distclean: clean
########################################################################
# Special-case builds for which we require certain pre-conditions
# which, if not met, may cause warnings or fatal errors in the build.
# This also affects the default optimization level flags. Note that
# the fiddle targets are in this list because they are used for
# generating sqlite.org/fiddle.
OPTIMIZED_TARGETS := dist snapshot fiddle fiddle.debug
# This also affects the default optimization level flags. The fiddle
# targets are in this list because they are used for generating
# sqlite.org/fiddle.
OPTIMIZED_TARGETS = dist snapshot fiddle fiddle.debug
ifeq (1,$(MAKING_CLEAN))
bin.wasm-strip := echo "not stripping"
bin.wasm-opt := irrelevant
bin.emcc := irrelevant
bin.bash := irrelevant
emcc.version := unknown
bin.wasm-strip = echo "not stripping"
bin.wasm-opt = irrelevant
bin.emcc = irrelevant
bin.bash = irrelevant
emcc.version = unknown
else
# Include config.make and perform some bootstrapping...
ifeq (,$(wildcard ./config.make))
@@ -76,7 +77,7 @@ else
ifeq (,$(bin.emcc))
$(error Configure script did not find emcc)
endif
emcc.version := $(shell $(bin.emcc) --version | sed -n 1p | sed -e 's/^.* \([3-9][^ ]*\) .*$$/\1/;')
emcc.version = $(shell $(bin.emcc) --version | sed -n 1p | sed -e 's/^.* \([3-9][^ ]*\) .*$$/\1/;')
$(info using emcc version [$(emcc.version)])
ifeq (,$(bin.wasm-strip))
####################################################################
@@ -98,7 +99,7 @@ else
ifneq (,$(filter $(OPTIMIZED_TARGETS),$(MAKECMDGOALS)))
$(error Cannot make release-quality binary because wasm-strip is not available.)
endif
bin.wasm-strip := echo "not wasm-stripping"
bin.wasm-strip = echo "not wasm-stripping"
endif
ifeq (,$(filter $(OPTIMIZED_TARGETS),$(MAKECMDGOALS)))
$(info ==============================================================)
@@ -108,7 +109,7 @@ else
endif
endif
# ^^^ end of are-we-MAKING_CLEAN
maybe-wasm-strip := $(bin.wasm-strip)
maybe-wasm-strip = $(bin.wasm-strip)
########################################################################
# JS_BUILD_NAMES exists for documentation purposes only. It enumerates
@@ -118,7 +119,7 @@ maybe-wasm-strip := $(bin.wasm-strip)
#
# - sqlite3-wasmfs = WASMFS-capable library build
#
JS_BUILD_NAMES := sqlite3 sqlite3-wasmfs
JS_BUILD_NAMES = sqlite3 sqlite3-wasmfs
########################################################################
# JS_BUILD_MODES exists for documentation purposes only. It enumerates
@@ -140,31 +141,31 @@ JS_BUILD_NAMES := sqlite3 sqlite3-wasmfs
# that persistent storage (OPFS) is not available in these builds.
# These builds are UNTESTED and UNSUPPORTED!
#
JS_BUILD_MODES := vanilla esm bunder-friendly node
JS_BUILD_MODES = vanilla esm bunder-friendly node
########################################################################
# dir.top = the top dir of the canonical build tree, where
# sqlite3.[ch] live.
dir.top := ../..
dir.top = ../..
# Maintenance reminder: some Emscripten flags require absolute paths
# but we want relative paths for most stuff simply to reduce
# noise. The $(abspath...) GNU make function can transform relative
# paths to absolute.
dir.wasm := $(patsubst %/,%,$(dir $(MAKEFILE)))
dir.api := api
dir.jacc := jaccwabyt
dir.common := common
dir.fiddle := fiddle
dir.fiddle-debug := fiddle-debug
dir.tool := $(dir.top)/tool
dir.wasm = $(patsubst %/,%,$(dir $(MAKEFILE)))
dir.api = api
dir.jacc = jaccwabyt
dir.common = common
dir.fiddle = fiddle
dir.fiddle-debug = fiddle-debug
dir.tool = $(dir.top)/tool
# dir.dout = output dir for deliverables
dir.dout := $(dir.wasm)/jswasm
dir.dout = $(dir.wasm)/jswasm
# dir.tmp = output dir for intermediary build files, as opposed to
# end-user deliverables.
dir.tmp := $(dir.wasm)/bld
dir.wasmfs := $(dir.dout)
dir.tmp = $(dir.wasm)/bld
dir.wasmfs = $(dir.dout)
MKDIR.bld := $(dir.tmp)
MKDIR.bld = $(dir.tmp)
$(MKDIR.bld):
@mkdir -p $@ $(dir.dout)
@@ -188,17 +189,17 @@ CLEAN_FILES += *~ $(dir.jacc)/*~ $(dir.api)/*~ $(dir.common)/*~ $(dir.fiddle)/*~
# $(sqlite3.canonical.c) must point to the sqlite3.c in
# the sqlite3 canonical source tree, as that source file
# is required for certain utility and test code.
sqlite3.canonical.c := $(dir.top)/sqlite3.c
sqlite3.canonical.c = $(dir.top)/sqlite3.c
sqlite3.c ?= $(firstword $(wildcard $(dir.top)/sqlite3-see.c) $(sqlite3.canonical.c))
sqlite3.h := $(dir.top)/sqlite3.h
sqlite3.h = $(dir.top)/sqlite3.h
ifeq (1,$(MAKING_CLEAN))
SQLITE_C_IS_SEE := 0
SQLITE_C_IS_SEE = 0
else
ifeq (,$(shell grep sqlite3_activate_see $(sqlite3.c)))
SQLITE_C_IS_SEE := 0
SQLITE_C_IS_SEE = 0
else
SQLITE_C_IS_SEE := 1
SQLITE_C_IS_SEE = 1
$(info This is an SEE build)
endif
endif
@@ -216,19 +217,19 @@ $(sqlite3.c): $(sqlite3.h)
# barebones=1 disables all "extraneous" stuff from sqlite3-wasm.c, the
# goal being to create a WASM file with only the core APIs.
ifeq (1,$(barebones))
wasm-bare-bones := 1
wasm-bare-bones = 1
$(info ==============================================================)
$(info == This is a bare-bones build. It trades away features for)
$(info == a smaller .wasm file.)
$(info ==============================================================)
else
wasm-bare-bones := 0
wasm-bare-bones = 0
endif
# undefine barebones # relatively new gmake feature, not ubiquitous
# Common options for building sqlite3-wasm.c and speedtest1.c.
# Explicit ENABLEs...
SQLITE_OPT.common := \
SQLITE_OPT.common = \
-DSQLITE_THREADSAFE=0 \
-DSQLITE_TEMP_STORE=2 \
-DSQLITE_ENABLE_MATH_FUNCTIONS \
@@ -249,7 +250,7 @@ SQLITE_OPT.common := \
SQLITE_OPT.common += -DSQLITE_WASM_ENABLE_C_TESTS
# Extra flags for full-featured builds...
SQLITE_OPT.full-featured := \
SQLITE_OPT.full-featured = \
-DSQLITE_ENABLE_BYTECODE_VTAB \
-DSQLITE_ENABLE_DBPAGE_VTAB \
-DSQLITE_ENABLE_DBSTAT_VTAB \
@@ -265,12 +266,12 @@ SQLITE_OPT.full-featured := \
ifeq (0,$(wasm-bare-bones))
# The so-called canonical build is full-featured:
SQLITE_OPT := \
SQLITE_OPT = \
$(SQLITE_OPT.common) \
$(SQLITE_OPT.full-featured)
else
# The so-called bare-bones build is exactly that:
SQLITE_OPT := \
SQLITE_OPT = \
$(SQLITE_OPT.common) \
-DSQLITE_WASM_BARE_BONES
# SQLITE_WASM_BARE_BONES tells sqlite3-wasm.c to explicitly omit
@@ -345,10 +346,10 @@ endif
# See example_extra_init.c for an example implementation.
########################################################################
sqlite3_wasm_extra_init.c ?= $(wildcard sqlite3_wasm_extra_init.c)
cflags.wasm_extra_init :=
cflags.wasm_extra_init =
ifneq (,$(sqlite3_wasm_extra_init.c))
$(info Enabling SQLITE_EXTRA_INIT via $(sqlite3_wasm_extra_init.c).)
cflags.wasm_extra_init := -DSQLITE_WASM_EXTRA_INIT
cflags.wasm_extra_init = -DSQLITE_WASM_EXTRA_INIT
endif
#########################################################################
@@ -362,7 +363,7 @@ endif
# end result is that the generated JS files may have static version
# info from $(bin.version-info) which differ from their runtime-emitted
# version info (e.g. from sqlite3_libversion()).
bin.version-info := $(dir.top)/version-info
bin.version-info = $(dir.top)/version-info
.NOTPARALLEL: $(bin.version-info)
$(bin.version-info): $(dir.tool)/version-info.c $(sqlite3.h) $(dir.top)/Makefile
$(MAKE) -C $(dir.top) version-info
@@ -373,7 +374,7 @@ $(bin.version-info): $(dir.tool)/version-info.c $(sqlite3.h) $(dir.top)/Makefile
# don't need for all builds. That app's -k flag is of particular
# importance here, as it allows us to retain the opening comment
# block(s), which contain the license header and version info.
bin.stripccomments := $(dir.tool)/stripccomments
bin.stripccomments = $(dir.tool)/stripccomments
$(bin.stripccomments): $(bin.stripccomments).c $(MAKEFILE)
$(CC) -o $@ $<
DISTCLEAN_FILES += $(bin.stripccomments)
@@ -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
$(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 \
@@ -429,13 +430,13 @@ 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
########################################################################
# cflags.common = C compiler flags for all builds
cflags.common := -I. -I$(dir $(sqlite3.c))
cflags.common = -I. -I$(dir $(sqlite3.c))
# emcc.WASM_BIGINT = 1 for BigInt (C int64) support, else 0. The API
# disables certain features if BigInt is not enabled and such builds
# _are not tested_ on any regular basis.
@@ -456,9 +457,24 @@ else
emcc_opt ?= -Oz
endif
# Our JS code installs bindings of each sqlite3_...() WASM export. The
# generated Emscripten JS file does the same using its own framework,
# but we don't use those results and can speed up lib init, and reduce
# memory cost a bit, by stripping them out. Emscripten-side changes
# can "break" this, causing this to be a no-op, but the worst that can
# happen in that case is that it doesn't actually strip anything,
# leading to slightly larger JS files.
#
# This snippet is intended to be used in makefile targets which
# generate an Emscripten module and where $@ is the module's .js/.mjs
# file.
SQLITE.strip-createExportWrapper = \
sed -i -e '/^.*= \(_sqlite3\|_fiddle\)[^=]* = createExportWrapper/d' $@ || exit; \
echo '(Probably) stripped out extraneous createExportWrapper() parts.'
# When passing emcc_opt from the CLI, += and re-assignment have no
# effect, so emcc_opt+=-g3 doesn't work. So...
emcc_opt_full := $(emcc_opt) -g3
emcc_opt_full = $(emcc_opt) -g3
# ^^^ ALWAYS use -g3. See below for why.
#
# ^^^ -flto improves runtime speed at -O0 considerably but doubles
@@ -489,31 +505,28 @@ emcc_opt_full := $(emcc_opt) -g3
########################################################################
# EXPORTED_FUNCTIONS.* = files for use with Emscripten's
# -sEXPORTED_FUNCTION flag.
EXPORTED_FUNCTIONS.api.core := $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-core
EXPORTED_FUNCTIONS.api.in := $(EXPORTED_FUNCTIONS.api.core)
EXPORTED_FUNCTIONS.api.core = $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-core
EXPORTED_FUNCTIONS.api.in = $(EXPORTED_FUNCTIONS.api.core)
ifeq (1,$(SQLITE_C_IS_SEE))
EXPORTED_FUNCTIONS.api.in += $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-see
endif
ifeq (0,$(wasm-bare-bones))
EXPORTED_FUNCTIONS.api.in += $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-extras
endif
EXPORTED_FUNCTIONS.api := $(dir.tmp)/EXPORTED_FUNCTIONS.api
EXPORTED_FUNCTIONS.api = $(dir.tmp)/EXPORTED_FUNCTIONS.api
$(EXPORTED_FUNCTIONS.api): $(MKDIR.bld) $(EXPORTED_FUNCTIONS.api.in) $(sqlite3.c) $(MAKEFILE)
cat $(EXPORTED_FUNCTIONS.api.in) > $@
########################################################################
# sqlite3-license-version.js = generated JS file with the license
# header and version info.
sqlite3-license-version.js := $(dir.tmp)/sqlite3-license-version.js
# sqlite3-license-version-header.js = JS file containing only the
# license header.
sqlite3-license-version-header.js := $(dir.api)/sqlite3-license-version-header.js
sqlite3-license-version.js = $(dir.tmp)/sqlite3-license-version.js
# sqlite3-api-build-version.js = generated JS file which populates the
# sqlite3.version object using $(bin.version-info).
sqlite3-api-build-version.js := $(dir.tmp)/sqlite3-api-build-version.js
sqlite3-api-build-version.js = $(dir.tmp)/sqlite3-api-build-version.js
# sqlite3-api.jses = the list of JS files which make up
# $(sqlite3-api.js.in), in the order they need to be assembled.
sqlite3-api.jses := $(sqlite3-license-version.js)
sqlite3-api.jses = $(sqlite3-license-version.js)
# sqlite3-api-prologue.js: initial bootstrapping bits:
sqlite3-api.jses += $(dir.api)/sqlite3-api-prologue.js
# whwhasm.js and jaccwabyt.js: Low-level utils, mostly replacing
@@ -547,13 +560,13 @@ sqlite3-api.jses += $(dir.api)/sqlite3-api-cleanup.js
# SOAP.js is an external API file which is part of our distribution
# but not part of the sqlite3-api.js amalgamation. It's a component of
# the first OPFS VFS and necessarily an external file.
SOAP.js := $(dir.api)/sqlite3-opfs-async-proxy.js
SOAP.js.bld := $(dir.dout)/$(notdir $(SOAP.js))
SOAP.js = $(dir.api)/sqlite3-opfs-async-proxy.js
SOAP.js.bld = $(dir.dout)/$(notdir $(SOAP.js))
#
# $(sqlite3-api.ext.jses) = API-related files which are standalone files,
# not part of the amalgamation.
#
sqlite3-api.ext.jses := $(SOAP.js.bld)
sqlite3-api.ext.jses = $(SOAP.js.bld)
$(SOAP.js.bld): $(SOAP.js)
cp $< $@
@@ -573,17 +586,12 @@ $(SOAP.js.bld): $(SOAP.js)
# Sidebar: some of the imports are used soley by the Emscripten glue,
# which the sqlite3 JS code does not rely on.
#
# We build $(sqlite3-api*.*) "because we can" and because it might be
# a useful point of experimentation for some clients, but the
# above-described caveat may well make them unusable for real-life
# clients.
#
# sqlite3-api.js.in = the generated sqlite3-api.js before it gets
# sqlite3-api.js.in = the amalgamated sqlite3-api.js before it gets
# preprocessed. It contains all of $(sqlite3-api.jses) but none of the
# Emscripten-specific headers and footers.
sqlite3-api.js.in := $(dir.tmp)/sqlite3-api.c-pp.js
sqlite3-api.js.in = $(dir.tmp)/sqlite3-api.c-pp.js
$(sqlite3-api.js.in): $(MKDIR.bld) $(sqlite3-api.jses) $(MAKEFILE)
@echo "Making $@..."
@echo "Making $@ ..."
@for i in $(sqlite3-api.jses); do \
echo "/* BEGIN FILE: $$i */"; \
cat $$i; \
@@ -592,7 +600,7 @@ $(sqlite3-api.js.in): $(MKDIR.bld) $(sqlite3-api.jses) $(MAKEFILE)
########################################################################
# emcc flags for .c/.o/.wasm/.js.
emcc.flags :=
emcc.flags =
ifeq (1,$(emcc.verbose))
emcc.flags += -v
# -v is _very_ loud but also informative about what it's doing
@@ -601,25 +609,25 @@ endif
########################################################################
# emcc flags for .c/.o.
emcc.cflags :=
emcc.cflags =
emcc.cflags += -std=c99 -fPIC
# -------------^^^^^^^^ we need c99 for $(sqlite3-wasm.c), primarily
# for variadic macros and snprintf() to implement
# sqlite3_wasm_enum_json().
# sqlite3__wasm_enum_json().
emcc.cflags += -I. -I$(dir.top)
########################################################################
# emcc flags specific to building .js/.wasm files...
emcc.jsflags := -fPIC
emcc.jsflags = -fPIC
emcc.jsflags += --no-entry
emcc.jsflags += -sWASM_BIGINT=$(emcc.WASM_BIGINT)
emcc.jsflags += -sMODULARIZE
emcc.jsflags += -sDYNAMIC_EXECUTION=0
emcc.jsflags += -sNO_POLYFILL
emcc.jsflags += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.api)
emcc.exportedRuntimeMethods := \
-sEXPORTED_RUNTIME_METHODS=wasmMemory,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAP64,HEAPU64
emcc.exportedRuntimeMethods = \
-sEXPORTED_RUNTIME_METHODS=wasmMemory
# wasmMemory ==> required by our code for use with -sIMPORTED_MEMORY
# Emscripten 4.0.7 (2025-04-15) stops exporting HEAP* by default
# 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
@@ -641,10 +649,10 @@ emcc.jsflags += -sSTRICT_JS=0
# tools should be installing, e.g. __syscall_geteuid32
# -sENVIRONMENT values for the various build modes:
emcc.environment.vanilla := web,worker
emcc.environment.bundler-friendly := $(emcc.environment.vanilla)
emcc.environment.esm := $(emcc.environment.vanilla)
emcc.environment.node := node
emcc.environment.vanilla = web,worker
emcc.environment.bundler-friendly = $(emcc.environment.vanilla)
emcc.environment.esm = $(emcc.environment.vanilla)
emcc.environment.node = node
# Note that adding ",node" to the list for the other builds causes
# Emscripten to generate code which confuses node: it cannot reliably
# determine whether the build is for a browser or for node.
@@ -666,12 +674,12 @@ emcc.environment.node := node
# supported in all configurations (#21071)."
# https://github.com/emscripten-core/emscripten/blob/main/ChangeLog.md
emcc.jsflags += -sALLOW_MEMORY_GROWTH
emcc.INITIAL_MEMORY.128 := 134217728
emcc.INITIAL_MEMORY.96 := 100663296
emcc.INITIAL_MEMORY.64 := 67108864
emcc.INITIAL_MEMORY.32 := 33554432
emcc.INITIAL_MEMORY.16 := 16777216
emcc.INITIAL_MEMORY.8 := 8388608
emcc.INITIAL_MEMORY.128 = 134217728
emcc.INITIAL_MEMORY.96 = 100663296
emcc.INITIAL_MEMORY.64 = 67108864
emcc.INITIAL_MEMORY.32 = 33554432
emcc.INITIAL_MEMORY.16 = 16777216
emcc.INITIAL_MEMORY.8 = 8388608
emcc.INITIAL_MEMORY ?= 16
ifeq (,$(emcc.INITIAL_MEMORY.$(emcc.INITIAL_MEMORY)))
$(error emcc.INITIAL_MEMORY must be one of: 8, 16, 32, 64, 96, 128 (megabytes))
@@ -704,7 +712,7 @@ emcc.jsflags += -sSTACK_SIZE=512KB
# symbols: we cannot "delete" the Emscripten-defined
# $(sqlite3.js.init-func) from vanilla builds (as opposed to ESM
# builds) because it's declared with "var".
sqlite3.js.init-func := sqlite3InitModule
sqlite3.js.init-func = sqlite3InitModule
emcc.jsflags += -sEXPORT_NAME=$(sqlite3.js.init-func)
emcc.jsflags += -sGLOBAL_BASE=4096 # HYPOTHETICALLY keep func table indexes from overlapping w/ heap addr.
#emcc.jsflags += -sSTRICT # fails due to missing __syscall_...()
@@ -772,17 +780,17 @@ $(sqlite3-api-build-version.js): $(MKDIR.bld) $(bin.version-info) $(MAKEFILE)
#
# Maintenance reminder: there are awk binaries out there which do not
# support -e SCRIPT.
$(sqlite3-license-version.js): $(MKDIR.bld) $(sqlite3.h) $(sqlite3-license-version-header.js) \
$(MAKEFILE)
$(sqlite3-license-version.js): $(MKDIR.bld) $(sqlite3.h) \
$(dir.api)/sqlite3-license-version-header.js $(MAKEFILE)
@echo "Making $@..."; { \
cat $(sqlite3-license-version-header.js); \
cat $(dir.api)/sqlite3-license-version-header.js; \
echo '/*'; \
echo '** This code was built from sqlite3 version...'; \
echo "**"; \
awk '/define SQLITE_VERSION/{$$1=""; print "**" $$0}' $(sqlite3.h); \
awk '/define SQLITE_SOURCE_ID/{$$1=""; print "**" $$0}' $(sqlite3.h); \
echo "**"; \
echo "** Using the Emscripten SDK version $(emcc.version)."; \
echo "** with the help of Emscripten SDK version $(emcc.version)."; \
echo '*/'; \
} > $@
@@ -794,9 +802,9 @@ $(sqlite3-license-version.js): $(MKDIR.bld) $(sqlite3.h) $(sqlite3-license-versi
# --post-js injects code which runs after the WASM module is loaded
# and includes the entirety of the library plus some
# Emscripten-specific post-bootstrapping code.
pre-js.js.in := $(dir.api)/pre-js.c-pp.js
post-js.js.in := $(dir.tmp)/post-js.c-pp.js
post-jses.js := \
pre-js.js.in = $(dir.api)/pre-js.c-pp.js
post-js.js.in = $(dir.tmp)/post-js.c-pp.js
post-jses.js = \
$(dir.api)/post-js-header.js \
$(sqlite3-api.js.in) \
$(dir.api)/post-js-footer.js
@@ -812,10 +820,10 @@ $(post-js.js.in): $(MKDIR.bld) $(post-jses.js) $(MAKEFILE)
# Undocumented Emscripten feature: if the target file extension is
# "mjs", it defaults to ES6 module builds:
# https://github.com/emscripten-core/emscripten/issues/14383
sqlite3.wasm := $(dir.dout)/sqlite3.wasm
sqlite3-wasm.c := $(dir.api)/sqlite3-wasm.c
sqlite3-wasm.cfiles := $(sqlite3-wasm.c) $(sqlite3_wasm_extra_init.c)
sqlite3-wasmfs.cfiles := $(sqlite3-wasm.cfiles)
sqlite3.wasm = $(dir.dout)/sqlite3.wasm
sqlite3-wasm.c = $(dir.api)/sqlite3-wasm.c
sqlite3-wasm.cfiles = $(sqlite3-wasm.c) $(sqlite3_wasm_extra_init.c)
sqlite3-wasmfs.cfiles = $(sqlite3-wasm.cfiles)
# sqlite3-wasm.o vs sqlite3-wasm.c: building against the latter
# (predictably) results in a slightly faster binary. We're close
# enough to the target speed requirements that the 500ms makes a
@@ -860,17 +868,9 @@ if [ x1 = x$(1) ]; then \
fi
endef
sqlite3-api.js := $(dir.dout)/sqlite3-api.js
sqlite3.js := $(dir.dout)/sqlite3.js
sqlite3-api.mjs := $(dir.dout)/sqlite3-api.mjs
sqlite3.mjs := $(dir.dout)/sqlite3.mjs
sqlite3-api-bundler-friendly.mjs := $(dir.dout)/sqlite3-api-bundler-friendly.mjs
sqlite3-bundler-friendly.mjs := $(dir.dout)/sqlite3-bundler-friendly.mjs
sqlite3-api-node.mjs := $(dir.dout)/sqlite3-api-node.mjs
sqlite3-node.mjs := $(dir.dout)/sqlite3-node.mjs
sqlite3-api-wasmfs.mjs := $(dir.tmp)/sqlite3-api-wasmfs.mjs
sqlite3-wasmfs.mjs := $(dir.wasmfs)/sqlite3-wasmfs.mjs
EXPORTED_FUNCTIONS.fiddle := $(dir.tmp)/EXPORTED_FUNCTIONS.fiddle
sqlite3.js = $(dir.dout)/sqlite3.js
sqlite3.mjs = $(dir.dout)/sqlite3.mjs
EXPORTED_FUNCTIONS.fiddle = $(dir.tmp)/EXPORTED_FUNCTIONS.fiddle
# The various -D... values used by *.c-pp.js include:
#
@@ -904,24 +904,10 @@ EXPORTED_FUNCTIONS.fiddle := $(dir.tmp)/EXPORTED_FUNCTIONS.fiddle
# build time).
$(sqlite3.wasm): $(sqlite3.js)
$(sqlite3.mjs): $(sqlite3.js)
$(sqlite3-bundler-friendly.mjs): $(sqlite3.mjs)
$(sqlite3-node.mjs): $(sqlite3.mjs)
$(dir.dout)/sqlite3-bundler-friendly.mjs: $(sqlite3.mjs)
$(dir.dout)/sqlite3-node.mjs: $(sqlite3.mjs)
#CLEAN_FILES += $(sqlite3.wasm)
########################################################################
# We need separate copies of certain supplementary JS files for the
# bundler-friendly build. Concretely, any supplemental JS files which
# themselves use importScripts() or Workers or URL() constructors
# which refer to other in-tree (m)JS files require a bundler-friendly
# copy.
sqlite3-worker1.js.in := $(dir.api)/sqlite3-worker1.c-pp.js
sqlite3-worker1-promiser.js.in := $(dir.api)/sqlite3-worker1-promiser.c-pp.js
sqlite3-worker1.js := $(dir.dout)/sqlite3-worker1.js
sqlite3-worker1-promiser.js := $(dir.dout)/sqlite3-worker1-promiser.js
sqlite3-worker1-promiser.mjs := $(dir.dout)/sqlite3-worker1-promiser.mjs
sqlite3-worker1-bundler-friendly.mjs := $(dir.dout)/sqlite3-worker1-bundler-friendly.mjs
sqlite3-worker1-promiser-bundler-friendly.js := $(dir.dout)/sqlite3-worker1-promiser-bundler-friendly.js
ifneq (1,$(MAKING_CLEAN))
# This block MUST come between the above definitions of
# sqlite3-...js/mjs and the $(eval) calls below this block which use
@@ -934,7 +920,10 @@ ifneq (1,$(MAKING_CLEAN))
# the $ references in those languages made it just as illegible as the
# native makefile code. Somewhat surprisingly, moving that code generation
# to C makes it slightly less illegible than the previous 3 options.
bin.mkwb := ./mkwasmbuilds
#
# Maintenance note: the various $(c-pp.D.XYZ) vars are defined in this
# step.
bin.mkwb = ./mkwasmbuilds
$(bin.mkwb): $(bin.mkwb).c $(MAKEFILE)
$(CC) -o $@ $<
DISTCLEAN_FILES += $(bin.mkwb)
@@ -946,45 +935,60 @@ DISTCLEAN_FILES += $(bin.mkwb)
endif
DISTCLEAN_FILES += .wasmbuilds.make
$(eval $(call SQLITE.CALL.C-PP.FILTER,$(sqlite3-worker1.js.in),$(sqlite3-worker1.js)))
$(eval $(call SQLITE.CALL.C-PP.FILTER,$(sqlite3-worker1.js.in),$(sqlite3-worker1-bundler-friendly.mjs),\
########################################################################
# We need separate copies of certain supplementary JS files for the
# bundler-friendly build. Concretely, any supplemental JS files which
# themselves use importScripts() or Workers or URL() constructors
# which refer to other in-tree (m)JS files require a bundler-friendly
# copy. Bundler-friendly builds replace certain references to string
# vars/expressions with string literals, as bundler tools are static
# code analyzers and cannot cope with the former.
#
# Most of what follows is the generation of those copies.
$(eval $(call SQLITE.CALL.C-PP.FILTER,$(dir.api)/sqlite3-worker1.c-pp.js,\
$(dir.dout)/sqlite3-worker1.js))
$(eval $(call SQLITE.CALL.C-PP.FILTER,$(dir.api)/sqlite3-worker1.c-pp.js,\
$(dir.dout)/sqlite3-worker1-bundler-friendly.mjs,\
$(c-pp.D.sqlite3-bundler-friendly)))
$(eval $(call SQLITE.CALL.C-PP.FILTER,$(sqlite3-worker1-promiser.js.in),$(sqlite3-worker1-promiser.js)))
$(eval $(call SQLITE.CALL.C-PP.FILTER,$(sqlite3-worker1-promiser.js.in),\
$(sqlite3-worker1-promiser-bundler-friendly.js),\
$(eval $(call SQLITE.CALL.C-PP.FILTER,$(dir.api)/sqlite3-worker1-promiser.c-pp.js,\
$(dir.dout)/sqlite3-worker1-promiser.js))
$(eval $(call SQLITE.CALL.C-PP.FILTER,$(dir.api)/sqlite3-worker1-promiser.c-pp.js,\
$(dir.dout)/sqlite3-worker1-promiser-bundler-friendly.js,\
$(c-pp.D.sqlite3-bundler-friendly)))
$(eval $(call SQLITE.CALL.C-PP.FILTER,$(sqlite3-worker1-promiser.js.in),$(sqlite3-worker1-promiser.mjs),\
$(eval $(call SQLITE.CALL.C-PP.FILTER,$(dir.api)/sqlite3-worker1-promiser.c-pp.js,\
$(dir.dout)/sqlite3-worker1-promiser.mjs,\
-Dtarget=es6-module -Dtarget=es6-bundler-friendly))
$(sqlite3-bundler-friendly.mjs): $(sqlite3-worker1-bundler-friendly.mjs) \
$(sqlite3-worker1-promiser-bundler-friendly.js)
$(eval $(call SQLITE.CALL.C-PP.FILTER,demo-worker1-promiser.c-pp.js,demo-worker1-promiser.js))
$(eval $(call SQLITE.CALL.C-PP.FILTER,demo-worker1-promiser.c-pp.js,demo-worker1-promiser.mjs,\
-Dtarget=es6-module))
$(eval $(call SQLITE.CALL.C-PP.FILTER,demo-worker1-promiser.c-pp.html,demo-worker1-promiser.html))
$(eval $(call SQLITE.CALL.C-PP.FILTER,demo-worker1-promiser.c-pp.html,demo-worker1-promiser-esm.html,\
-Dtarget=es6-module))
all: $(sqlite3-worker1.js) \
$(sqlite3-worker1-promiser.js) $(sqlite3-worker1-promiser.mjs)
demo-worker1-promiser.html: $(sqlite3-worker1-promiser.js) demo-worker1-promiser.js
$(dir.dout)/sqlite3-bundler-friendly.mjs: \
$(dir.dout)/sqlite3-worker1-bundler-friendly.mjs \
$(dir.dout)/sqlite3-worker1-promiser-bundler-friendly.js
demo-worker1-promiser.html: $(dir.dout)/sqlite3-worker1-promiser.js demo-worker1-promiser.js
demo-worker1-promiser-esm.html: $(sqlite3-worker1-promiser.mjs) demo-worker1-promiser.mjs
all: demo-worker1-promiser.html demo-worker1-promiser-esm.html
sqlite3-api.ext.jses += \
$(sqlite3-worker1-promiser.mjs) \
$(sqlite3-worker1-bundler-friendly.mjs) \
$(sqlite3-worker1.js)
$(dir.dout)/sqlite3-worker1-promiser.mjs \
$(dir.dout)/sqlite3-worker1-promiser.js \
$(dir.dout)/sqlite3-worker1-bundler-friendly.mjs \
$(dir.dout)/sqlite3-worker1.js
all quick: $(sqlite3-api.ext.jses)
q: quick
########################################################################
# batch-runner.js is part of one of the test apps which reads in SQL
# dumps generated by $(speedtest1) and executes them.
dir.sql := sql
speedtest1 := ../../speedtest1
speedtest1.c := ../../test/speedtest1.c
speedtest1.sql := $(dir.sql)/speedtest1.sql
speedtest1.cliflags := --size 10 --big-transactions
dir.sql = sql
speedtest1 = ../../speedtest1
speedtest1.c = ../../test/speedtest1.c
speedtest1.sql = $(dir.sql)/speedtest1.sql
speedtest1.cliflags = --size 10 --big-transactions
$(speedtest1):
$(MAKE) -C ../.. speedtest1
$(speedtest1.sql): $(speedtest1) $(MAKEFILE)
@@ -1005,8 +1009,8 @@ batch: batch-runner.list
#
# emcc.speedtest1.common = emcc flags used by multiple builds of speedtest1
# emcc.speedtest1 = emcc flags used by main build of speedtest1
emcc.speedtest1.common := $(emcc_opt_full)
emcc.speedtest1 := -I. -I$(dir $(sqlite3.canonical.c))
emcc.speedtest1.common = $(emcc_opt_full)
emcc.speedtest1 = -I. -I$(dir $(sqlite3.canonical.c))
emcc.speedtest1 += -sENVIRONMENT=web
emcc.speedtest1 += -sALLOW_MEMORY_GROWTH
emcc.speedtest1 += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.$(emcc.INITIAL_MEMORY))
@@ -1019,7 +1023,7 @@ emcc.speedtest1.common += -Wno-limited-postlink-optimizations
emcc.speedtest1.common += -Wno-unused-main
# ^^^^ -Wno-unused-main is for emcc 3.1.52+. speedtest1 has a wasm_main() which is
# exported and called by the JS code.
EXPORTED_FUNCTIONS.speedtest1 := $(abspath $(dir.tmp)/EXPORTED_FUNCTIONS.speedtest1)
EXPORTED_FUNCTIONS.speedtest1 = $(abspath $(dir.tmp)/EXPORTED_FUNCTIONS.speedtest1)
emcc.speedtest1.common += -sSTACK_SIZE=512KB
emcc.speedtest1.common += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.speedtest1)
emcc.speedtest1.common += $(emcc.exportedRuntimeMethods)
@@ -1028,8 +1032,8 @@ emcc.speedtest1.common += -sDYNAMIC_EXECUTION=0
emcc.speedtest1.common += --minify 0
emcc.speedtest1.common += -sEXPORT_NAME=$(sqlite3.js.init-func)
emcc.speedtest1.common += -sWASM_BIGINT=$(emcc.WASM_BIGINT)
speedtest1.exit-runtime0 := -sEXIT_RUNTIME=0
speedtest1.exit-runtime1 := -sEXIT_RUNTIME=1
speedtest1.exit-runtime0 = -sEXIT_RUNTIME=0
speedtest1.exit-runtime1 = -sEXIT_RUNTIME=1
# Re -sEXIT_RUNTIME=1 vs 0: if it's 1 and speedtest1 crashes, we get
# this error from emscripten:
#
@@ -1050,10 +1054,9 @@ speedtest1.exit-runtime1 := -sEXIT_RUNTIME=1
$(EXPORTED_FUNCTIONS.speedtest1): $(MKDIR.bld) $(EXPORTED_FUNCTIONS.api.core)
@echo "Making $@ ..."
@{ echo _wasm_main; cat $(EXPORTED_FUNCTIONS.api.core); } > $@
speedtest1.js := $(dir.dout)/speedtest1.js
speedtest1.wasm := $(dir.dout)/speedtest1.wasm
emcc.flags.speedtest1-vanilla := $(cflags.common) -DSQLITE_SPEEDTEST1_WASM
speedtest1.cfiles := $(speedtest1.c) $(sqlite3-wasm.c)
speedtest1.js = $(dir.dout)/speedtest1.js
emcc.flags.speedtest1-vanilla = $(cflags.common) -DSQLITE_SPEEDTEST1_WASM
speedtest1.cfiles = $(speedtest1.c) $(sqlite3-wasm.c)
$(speedtest1.js): $(MAKEFILE) $(speedtest1.cfiles) \
$(pre-post-speedtest1-vanilla.deps) \
$(EXPORTED_FUNCTIONS.speedtest1)
@@ -1067,14 +1070,13 @@ $(speedtest1.js): $(MAKEFILE) $(speedtest1.cfiles) \
-USQLITE_C -DSQLITE_C=$(sqlite3.canonical.c) \
$(speedtest1.exit-runtime0) \
-o $@ $(speedtest1.cfiles) -lm
$(maybe-wasm-strip) $(speedtest1.wasm)
sed -i -e '/^var _sqlite3.*createExportWrapper/d' $@
chmod -x $(speedtest1.wasm)
ls -la $@ $(speedtest1.wasm)
@chmod -x $(basename $@).wasm
@$(maybe-wasm-strip) $(basename $@).wasm
@$(SQLITE.strip-createExportWrapper)
@ls -la $@ $(speedtest1.wasm)
speedtest1: $(speedtest1.js)
all: speedtest1
#CLEAN_FILES += $(speedtest1.js) $(speedtest1.wasm)
# end speedtest1.js
########################################################################
@@ -1099,7 +1101,7 @@ $(eval $(call SQLITE.CALL.C-PP.FILTER,tester1.c-pp.js,tester1.mjs,$(c-pp.D.sqlit
$(eval $(call SQLITE.CALL.C-PP.FILTER,tester1.c-pp.html,tester1.html))
$(eval $(call SQLITE.CALL.C-PP.FILTER,tester1.c-pp.html,tester1-esm.html,$(c-pp.D.sqlite3-esm)))
tester1: tester1.js tester1.mjs tester1.html tester1-esm.html
# Note that we do not include $(sqlite3-bundler-friendly.mjs) in this
# Note that we do not include $(dir.dout)/sqlite3-bundler-friendly.mjs in this
# because bundlers are client-specific.
all quick: tester1
quick: $(sqlite3.js)
@@ -1111,7 +1113,7 @@ quick: $(sqlite3.js)
# painful.
.PHONY: o0 o1 o2 o3 os oz
emcc-opt-extra :=
emcc-opt-extra =
#ifeq (1,$(wasm-bare-bones))
#emcc-opt-extra += -flto
# ^^^^ -flto can have a considerably performance boost at -O0 but
@@ -1139,7 +1141,7 @@ oz: clean
# Sub-makes...
# sqlite.org/fiddle application...
include fiddle.make
include $(MAKEFILE.fiddle)
# Only add wasmfs if wasmfs.enable=1 or we're running (dist)clean
ifneq (,$(filter wasmfs,$(MAKECMDGOALS)))
@@ -1157,16 +1159,17 @@ ifeq (1,$(wasmfs.enable))
# little benefit.
#
########################################################################
# Some platforms do not support the WASMFS build. Raspberry Pi OS is one
# of them. As such platforms are discovered, add their (uname -m) name
# to PLATFORMS_WITH_NO_WASMFS to exclude the wasmfs build parts.
PLATFORMS_WITH_NO_WASMFS := aarch64 # add any others here
THIS_ARCH := $(shell /usr/bin/uname -m)
# Some platforms do not support the WASMFS build. Raspberry Pi OS is
# one of them (or was when that comment was initially written). As
# such platforms are discovered, add their (uname -m) name to
# PLATFORMS_WITH_NO_WASMFS to exclude the wasmfs build parts.
PLATFORMS_WITH_NO_WASMFS = aarch64 # add any others here
THIS_ARCH = $(shell /usr/bin/uname -m)
ifneq (,$(filter $(THIS_ARCH),$(PLATFORMS_WITH_NO_WASMFS)))
$(info This platform does not support the WASMFS build.)
HAVE_WASMFS := 0
HAVE_WASMFS = 0
else
HAVE_WASMFS := 1
HAVE_WASMFS = 1
include wasmfs.make
endif
endif
@@ -1204,7 +1207,7 @@ update-docs:
echo "Pass wasm.docs.home=/path/to/wasm/docs/checkout or edit this makefile to suit."; \
exit 127
else
wasm.docs.jswasm := $(wasm.docs.home)/jswasm
wasm.docs.jswasm = $(wasm.docs.home)/jswasm
update-docs: $(bin.stripccomments) $(sqlite3.js) $(sqlite3.wasm)
@echo "Copying files to the /wasm docs. Be sure to use an -Oz build for this!"
cp $(sqlite3.wasm) $(wasm.docs.jswasm)/.

View File

@@ -13,7 +13,7 @@
This file contains the so-called OO #1 API wrapper for the sqlite3
WASM build. It requires that sqlite3-api-glue.js has already run
and it installs its deliverable as globalThis.sqlite3.oo1.
and it installs its deliverable as sqlite3.oo1.
*/
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const toss3 = (...args)=>{throw new sqlite3.SQLite3Error(...args)};
@@ -37,6 +37,21 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
it.
*/
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.
@@ -234,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;
}
};
@@ -403,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:
@@ -429,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
@@ -457,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,
@@ -467,7 +496,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
boolean: 4,
blob: 5
};
BindTypes['undefined'] == BindTypes.null;
if(wasm.bigIntEnabled){
BindTypes.bigint = BindTypes.number;
}
@@ -486,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. */
@@ -698,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.
@@ -721,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()}
@@ -737,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*/}
@@ -1450,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. */
@@ -1474,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;
}
@@ -1641,12 +1733,19 @@ 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);
__execLock.delete(this);
__stmtMayGet.delete(this);
@@ -2134,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,

View File

@@ -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),

View File

@@ -1,15 +1,16 @@
# Gets filtered by the configure script
# config.make.in gets filtered by the top-most configure script to
# create config.make.
bin.bash = @BIN_BASH@
bin.emcc = @EMCC_WRAPPER@
bin.wasm-strip = @BIN_WASM_STRIP@
bin.wasm-opt = @BIN_WASM_OPT@
SHELL := $(bin.bash)
SHELL = $(bin.bash)
# The following overrides can be uncommented to test various
# validation and if/else branches the makefile code:
#
#bin.bash :=
#bin.emcc :=
#bin.wasm-strip :=
#bin.wasm-opt :=
#bin.bash =
#bin.emcc =
#bin.wasm-strip =
#bin.wasm-opt =

View File

@@ -11,7 +11,7 @@
# distinctly different zip file and top directory name to distinguish
# them from release builds.
#######################################################################
MAKEFILE.dist := $(lastword $(MAKEFILE_LIST))
MAKEFILE.dist = $(lastword $(MAKEFILE_LIST))
########################################################################
# Chicken/egg situation: we need $(bin.version-info) to get the
@@ -20,16 +20,16 @@ MAKEFILE.dist := $(lastword $(MAKEFILE_LIST))
# have to use a temporary name for the archive until we can get
# that binary built.
ifeq (1,$(SQLITE_C_IS_SEE))
dist-name-extra := -see
dist-name-extra = -see
else
dist-name-extra :=
dist-name-extra =
endif
ifeq (,$(filter snapshot,$(MAKECMDGOALS)))
dist-name-prefix := sqlite-wasm$(dist-name-extra)
dist-name-prefix = sqlite-wasm$(dist-name-extra)
else
dist-name-prefix := sqlite-wasm$(dist-name-extra)-snapshot-$(shell /usr/bin/date +%Y%m%d)
dist-name-prefix = sqlite-wasm$(dist-name-extra)-snapshot-$(shell /usr/bin/date +%Y%m%d)
endif
dist-name := $(dist-name-prefix)-TEMP
dist-name = $(dist-name-prefix)-TEMP
########################################################################
# dist.build must be the name of a target which triggers the build of
@@ -45,10 +45,10 @@ dist-name := $(dist-name-prefix)-TEMP
# reason not to.
dist.build ?= oz
dist-dir.top := $(dist-name)
dist-dir.jswasm := $(dist-dir.top)/$(notdir $(dir.dout))
dist-dir.common := $(dist-dir.top)/common
dist.top.extras := \
dist-dir.top = $(dist-name)
dist-dir.jswasm = $(dist-dir.top)/$(notdir $(dir.dout))
dist-dir.common = $(dist-dir.top)/common
dist.top.extras = \
demo-123.html demo-123-worker.html demo-123.js \
tester1.html tester1-worker.html tester1-esm.html \
tester1.js tester1.mjs \
@@ -56,9 +56,9 @@ dist.top.extras := \
demo-worker1.html demo-worker1.js \
demo-worker1-promiser.html demo-worker1-promiser.js \
demo-worker1-promiser-esm.html demo-worker1-promiser.mjs
dist.jswasm.extras := $(sqlite3.wasm) \
dist.jswasm.extras = $(sqlite3.wasm) \
$(sqlite3-api.ext.jses)
dist.common.extras := \
dist.common.extras = \
$(wildcard $(dir.common)/*.css) \
$(dir.common)/SqliteTestUtil.js
@@ -77,12 +77,12 @@ $(bin.stripccomments) $(2) < $(1) > $(dist-dir.jswasm)/$(notdir $(1)) || exit;
endef
# STRIP_K1.js = list of JS files which need to be passed through
# $(bin.stripcomments) with a single -k flag.
STRIP_K1.js := $(sqlite3-worker1.js) $(sqlite3-worker1-promiser.js) \
STRIP_K1.js = $(sqlite3-worker1.js) $(sqlite3-worker1-promiser.js) \
$(sqlite3-worker1-bundler-friendly.js) \
$(sqlite3-api.ext.jses)
# STRIP_K2.js = list of JS files which need to be passed through
# $(bin.stripcomments) with two -k flags.
STRIP_K2.js := $(sqlite3.js) $(sqlite3.mjs) \
STRIP_K2.js = $(sqlite3.js) $(sqlite3.mjs) \
$(sqlite3-bundler-friendly.mjs) $(sqlite3-node.mjs)
########################################################################
# dist: create the end-user deliverable archive.
@@ -104,8 +104,8 @@ STRIP_K2.js := $(sqlite3.js) $(sqlite3.mjs) \
# to know that it's in a regex or string literal. Because of that,
# comment-stripping is currently disabled, which means the builds will
# be significantly larger than before.
#apply_comment_stripper := false
apply_comment_stripper := true
#apply_comment_stripper = false
apply_comment_stripper = true
# ^^^ shell command true or false
dist: \
$(bin.stripccomments) $(bin.version-info) \

View File

@@ -3,13 +3,12 @@
#
# Intended to include'd by ./GNUmakefile.
#######################################################################
MAKEFILE.fiddle := $(lastword $(MAKEFILE_LIST))
########################################################################
# shell.c and its build flags...
ifneq (1,$(MAKING_CLEAN))
make-np-0 := make -C $(dir.top) -n -p
make-np-1 := sed -e 's/(TOP)/(dir.top)/g'
make-np-0 = make -C $(dir.top) -n -p
make-np-1 = sed -e 's/(TOP)/(dir.top)/g'
# Extract SHELL_OPT and SHELL_DEP from the top-most makefile and import
# them as vars here...
$(eval $(shell $(make-np-0) | grep -e '^SHELL_OPT ' | $(make-np-1)))
@@ -27,7 +26,7 @@ endif
# /shell.c
########################################################################
EXPORTED_FUNCTIONS.fiddle := $(dir.tmp)/EXPORTED_FUNCTIONS.fiddle
EXPORTED_FUNCTIONS.fiddle = $(dir.tmp)/EXPORTED_FUNCTIONS.fiddle
fiddle.emcc-flags = \
$(emcc.cflags) $(emcc_opt_full) \
--minify 0 \
@@ -40,9 +39,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) \
@@ -53,12 +51,12 @@ fiddle.emcc-flags = \
# Flags specifically for debug builds of fiddle. Performance suffers
# greatly in debug builds.
fiddle.emcc-flags.debug := $(fiddle.emcc-flags) \
fiddle.emcc-flags.debug = $(fiddle.emcc-flags) \
-DSQLITE_DEBUG \
-DSQLITE_ENABLE_SELECTTRACE \
-DSQLITE_ENABLE_WHERETRACE
fiddle.EXPORTED_FUNCTIONS.in := \
fiddle.EXPORTED_FUNCTIONS.in = \
EXPORTED_FUNCTIONS.fiddle.in \
$(dir.api)/EXPORTED_FUNCTIONS.sqlite3-core \
$(dir.api)/EXPORTED_FUNCTIONS.sqlite3-extras
@@ -67,10 +65,7 @@ $(EXPORTED_FUNCTIONS.fiddle): $(MKDIR.bld) $(fiddle.EXPORTED_FUNCTIONS.in) \
$(MAKEFILE.fiddle)
sort -u $(fiddle.EXPORTED_FUNCTIONS.in) > $@
fiddle.cses := $(dir.top)/shell.c $(sqlite3-wasm.c)
fiddle: $(fiddle-module.js) $(fiddle-module.js.debug)
fiddle.debug: $(fiddle-module.js.debug)
fiddle.cses = $(dir.top)/shell.c $(sqlite3-wasm.c)
clean: clean-fiddle
clean-fiddle:
@@ -84,10 +79,9 @@ clean-fiddle:
all: fiddle
########################################################################
# fiddle_remote is the remote destination for the fiddle app. It
# must be a [user@]HOST:/path for rsync.
# Note that the target "should probably" contain a symlink of
# index.html -> fiddle.html.
# fiddle_remote is the remote destination for the fiddle app. It must
# be a [user@]HOST:/path for rsync. The target "should probably"
# contain a symlink of index.html -> fiddle.html.
fiddle_remote ?=
ifeq (,$(fiddle_remote))
ifneq (,$(wildcard /home/stephan))
@@ -154,11 +148,6 @@ push-fiddle: fiddle
# because certain execution environments disallow those constructs.
# This flag is not strictly necessary, however.
#
# -sWASM_BIGINT is UNTESTED but "should" allow the int64-using C APIs
# to work with JS/wasm, insofar as the JS environment supports the
# BigInt type. That support requires an extremely recent browser:
# Safari didn't get that support until late 2020.
#
# --no-entry: for compiling library code with no main(). If this is
# not supplied and the code has a main(), it is called as part of the
# module init process. Note that main() is #if'd out of shell.c
@@ -180,14 +169,15 @@ push-fiddle: fiddle
# minification makes little difference in terms of overall
# distributable size.
#
# --minify 0: disables minification of the generated JS code,
# regardless of optimization level. Minification of the JS has
# minimal overall effect in the larger scheme of things and results
# in JS files which can neither be edited nor viewed as text files in
# Fossil (which flags them as binary because of their extreme line
# lengths). Interestingly, whether or not the comments in the
# generated JS file get stripped is unaffected by this setting and
# depends entirely on the optimization level. Higher optimization
# --minify 0: supposedly disables minification of the generated JS
# code, regardless of optimization level, but that's not quite true:
# search the main makefile for wasm-strip for details. Minification
# of the JS has minimal overall effect in the larger scheme of things
# and results in JS files which can neither be edited nor viewed as
# text files in Fossil (which flags them as binary because of their
# extreme line lengths). Interestingly, whether or not the comments
# in the generated JS file get stripped is unaffected by this setting
# and depends entirely on the optimization level. Higher optimization
# levels reduce the size of the JS considerably even without
# minification.
#

View File

@@ -11,18 +11,17 @@
*************************************************************************
**
** This app's single purpose is to emit parts of the Makefile code for
** building sqlite3's WASM build. The main motivation is to generate
** code which "can" be created via GNU Make's eval command but is
** sqlite3's canonical WASM build. The main motivation is to generate
** code which "could" be created via GNU Make's eval command but is
** highly illegible when constructed that way. Attempts to write this
** app in Bash and TCL have suffered from the problem that both
** require escaping $ symbols, making the resulting script code as
** illegible as the eval spaghetti we want to get away from. Writing
** it in C is, somewhat surprisingly, _slightly_ less illegible than
** writing it in bash, tcl, or native Make code.
** app in Bash and TCL have suffered from the problem that those
** languages require escaping $ symbols, making the resulting script
** code as illegible as the eval spaghetti we want to get away
** from. Maintaining it in C is, somewhat surprisingly, _slightly_
** less illegible than writing it in bash, tcl, or native Make code.
**
** The emitted makefile code is not standalone - it depends on
** variables and $(call)able functions from the main makefile.
**
*/
#undef NDEBUG
@@ -33,38 +32,145 @@
#define pf printf
#define ps puts
/* Very common printf() args combo. */
#define zNM zName, zMode
/*
** Valid names for the zName arguments.
** Valid build names. Each build is a combination of one of these and
** one of JS_BUILD_MODES, but only certain combinations are legal.
** This macro and JS_BUILD_MODES exist solely for documentation
** purposes: they are not expanded into code anywhere.
*/
#define JS_BUILD_NAMES sqlite3 sqlite3-wasmfs
/*
** Valid names for the zMode arguments of the "sqlite3" build. For the
** "sqlite3-wasmfs" build, only "esm" (ES6 Module) is legal.
** Valid build modes. For the "sqlite3-wasmfs" build, only "esm" (ES6
** Module) is legal.
*/
#define JS_BUILD_MODES vanilla esm bundler-friendly node
/* Separator to help eyeballs find the different sections */
/* Separator to help eyeballs find the different output sections */
static const char * zBanner =
"\n########################################################################\n";
/*
** Flags for use with BuildDef::flags and the 3rd argument to
** mk_pre_post().
**
** Maintenance reminder: do not combine flags within this enum,
** e.g. LIBMODE_BUNDLER_FRIENDLY=0x02|LIBMODE_ESM, as that will lead
** to breakage in some of the flag checks.
*/
enum LibModeFlags {
/* Indicates an ESM module build. */
LIBMODE_ESM = 0x01,
/* Indicates a "bundler-friendly" build mode. */
LIBMODE_BUNDLER_FRIENDLY = 0x02,
/* Indicates that this build is unsupported. Such builds are not
** added to the 'all' target. The unsupported builds exist primarily
** for experimentation's sake. */
LIBMODE_UNSUPPORTED = 0x04,
/* Indicates a node.js-for-node.js build (untested and
** unsupported). */
LIBMODE_NODEJS = 0x08,
/* Indicates a wasmfs build (untested and unsupported). */
LIBMODE_WASMFS = 0x10
};
/*
** Info needed for building one combination of JS_BUILD_NAMES and
** JS_BUILD_MODE, noting that only a subset of those combinations are
** legal/sensical.
*/
struct BuildDef {
const char *zName; /* Name from JS_BUILD_NAMES */
const char *zMode; /* Name from JS_BUILD_MODES */
int flags; /* Flags from LibModeFlags */
const char *zJsOut; /* Name of generated sqlite3.js/.mjs */
/* TODO: dynamically determine zJsOut based on zName, zMode, and
flags. */
const char *zCmppD; /* Extra -D... flags for c-pp */
const char *zEmcc; /* Extra flags for emcc */
};
typedef struct BuildDef BuildDef;
/*
** The set of WASM builds for the library (as opposed to the apps
** (fiddle, speedtest1)). This array must end with an empty sentinel
** entry. Their order is mostly insignificant, but some makefile vars
** used by some builds are set up by prior builds. Because of that,
** the (sqlite3, vanilla), (sqlite3, esm), and (sqlite3,
** bundler-friendly) builds should be defined first (in that order).
*/
const BuildDef aBuildDefs[] = {
{/* Core build */
"sqlite3", "vanilla", 0, "$(sqlite3.js)", 0, 0},
{/* Core ESM */
"sqlite3", "esm", LIBMODE_ESM, "$(sqlite3.mjs)",
"-Dtarget=es6-module", 0},
{/* Core bundler-friendly build. Untested and "not really"
** supported, but required by the downstream npm subproject.
** Testing these would require special-purpose node-based tools and
** custom test apps. Or we can pass them off as-is to the npm
** subproject and they spot failures pretty quickly ;). */
"sqlite3", "bundler-friendly",
LIBMODE_BUNDLER_FRIENDLY | LIBMODE_ESM,
"$(dir.dout)/sqlite3-bundler-friendly.mjs",
"$(c-pp.D.sqlite3-esm) -Dtarget=es6-bundler-friendly", 0},
{/* node.js mode. Untested and unsupported. */
"sqlite3", "node", LIBMODE_UNSUPPORTED | LIBMODE_NODEJS,
"$(dir.dout)/sqlite3-node.mjs",
"$(c-pp.D.sqlite3-bundler-friendly) -Dtarget=node", 0},
{/* Wasmfs build. Fully unsupported and largely untested. */
"sqlite3-wasmfs", "esm" ,
LIBMODE_UNSUPPORTED | LIBMODE_WASMFS | LIBMODE_ESM,
"$(dir.wasmfs)/sqlite3-wasmfs.mjs",
"$(c-pp.D.sqlite3-bundler-friendly) -Dwasmfs",
"-sEXPORT_ES6 -sUSE_ES6_IMPORT_META"},
{/*End-of-list sentinel*/0,0,0,0,0,0}
};
/*
** Emits common vars needed by the rest of the emitted code (but not
** needed by makefile code outside of these generated pieces).
*/
static void mk_prologue(void){
/* A 0-terminated list of makefile vars which we expect to have been
** set up by this point in the build process. */
char const * aRequiredVars[] = {
"dir.top",
"dir.api", "dir.dout", "dir.tmp",
"sqlite3-license-version.js",
"MAKEFILE", "MAKEFILE_LIST",
/* Fiddle... */
"dir.fiddle", "dir.fiddle-debug",
"MAKEFILE.fiddle",
"EXPORTED_FUNCTIONS.fiddle",
/*"just-testing",*/
0
};
char const * zVar;
int i;
pf("%s# Build setup sanity checks...\n", zBanner);
for( i = 0; (zVar = aRequiredVars[i]); ++i ){
pf("ifeq (,$(%s))\n", zVar);
pf(" $(error build process error: expecting make var $$(%s) to "
"have been set up by now)\n", zVar);
ps("endif");
}
pf("%s", zBanner);
ps("# extern-post-js* and extern-pre-js* are files for use with");
ps("# Emscripten's --extern-pre-js and --extern-post-js flags.");
ps("extern-pre-js.js := $(dir.api)/extern-pre-js.js");
ps("extern-post-js.js.in := $(dir.api)/extern-post-js.c-pp.js");
ps("extern-pre-js.js = $(dir.api)/extern-pre-js.js");
ps("extern-post-js.js.in = $(dir.api)/extern-post-js.c-pp.js");
ps("# Emscripten flags for --[extern-][pre|post]-js=... for the");
ps("# various builds.");
ps("pre-post-common.flags := --extern-pre-js=$(sqlite3-license-version.js)");
ps("# pre-post-jses.deps.* = a list of dependencies for the");
ps("# --[extern-][pre/post]-js files.");
ps("pre-post-jses.deps.common := $(extern-pre-js.js) $(sqlite3-license-version.js)");
ps("pre-post-common.flags = --extern-pre-js=$(sqlite3-license-version.js)");
ps("# pre-post-jses.deps.* = a list of dependencies for the\n"
"# --[extern-][pre/post]-js files.");
ps("pre-post-jses.deps.common = $(extern-pre-js.js) $(sqlite3-license-version.js)");
{
/* SQLITE.CALL.WASM-OPT = shell code to run $(1) (source wasm file
@@ -127,7 +233,7 @@ static void mk_prologue(void){
"\t\techo -n 'After wasm-opt: '; \\\n"
"\t\tls -l $(1); \\\n"
"\telse \\\n"
"\t\techo 'WARNING: ignoring wasm-opt failure'; \\\n"
"\t\techo 'WARNING: ignoring wasm-opt failure for $(1)'; \\\n"
"\tfi\n",
zOptFlags
);
@@ -136,28 +242,6 @@ static void mk_prologue(void){
}
}
/*
** Flags for use with the 3rd argument to mk_pre_post() and
** mk_lib_mode().
**
** Maintenance reminder: do not combine flags within this enum,
** e.g. LIBMODE_BUNDLER_FRIENDLY=0x02|LIBMODE_ESM, as that will lead
** to breakage in some of the flag checks.
*/
enum LibModeFlags {
/* Indicates an ESM module build. */
LIBMODE_ESM = 0x01,
/* Indicates a "bundler-friendly" build mode. */
LIBMODE_BUNDLER_FRIENDLY = 0x02,
/* Indicates to _not_ add this build to the 'all' target. */
LIBMODE_DONT_ADD_TO_ALL = 0x04,
/* Indicates a node.js-for-node.js build (untested and
** unsupported). */
LIBMODE_NODEJS = 0x08,
/* Indicates a wasmfs build (untested and unsupported). */
LIBMODE_WASMFS = 0x10
};
/*
** Emits makefile code for setting up values for the --pre-js=FILE,
** --post-js=FILE, and --extern-post-js=FILE emcc flags, as well as
@@ -165,24 +249,26 @@ enum LibModeFlags {
*/
static void mk_pre_post(const char *zName /* build name */,
const char *zMode /* build mode */,
int flags /* LIBMODE_... mask */,
const char *zCmppD /* optional -D flags for c-pp for the
** --pre/--post-js files. */){
/* Very common printf() args combo. */
#define zNM zName, zMode
pf("%s# Begin --pre/--post flags for %s-%s\n", zBanner, zNM);
pf("c-pp.D.%s-%s := %s\n", zNM, zCmppD ? zCmppD : "");
pf("c-pp.D.%s-%s = %s\n", zNM, zCmppD ? zCmppD : "");
pf("pre-post-%s-%s.flags ?=\n", zNM);
/* --pre-js=... */
pf("pre-js.js.%s-%s := $(dir.tmp)/pre-js.%s-%s.js\n",
pf("pre-js.js.%s-%s = $(dir.tmp)/pre-js.%s-%s.js\n",
zNM, zNM);
pf("$(pre-js.js.%s-%s): $(MAKEFILE_LIST)\n", zNM);
pf("$(pre-js.js.%s-%s): $(MAKEFILE_LIST) $(sqlite3-license-version.js)\n", zNM);
#if 1
pf("$(eval $(call SQLITE.CALL.C-PP.FILTER,$(pre-js.js.in),$(pre-js.js.%s-%s),"
"$(c-pp.D.%s-%s)))\n", zNM, zNM);
#else
/* This part is needed if/when we re-enable the custom
** Module.instantiateModule() impl in api/pre-js.c-pp.js. */
pf("pre-js.js.%s-%s.intermediary := $(dir.tmp)/pre-js.%s-%s.intermediary.js\n",
pf("pre-js.js.%s-%s.intermediary = $(dir.tmp)/pre-js.%s-%s.intermediary.js\n",
zNM, zNM);
pf("$(eval $(call SQLITE.CALL.C-PP.FILTER,$(pre-js.js.in),$(pre-js.js.%s-%s.intermediary),"
"$(c-pp.D.%s-%s) -Dcustom-Module.instantiateModule))\n", zNM, zNM);
@@ -200,17 +286,17 @@ static void mk_pre_post(const char *zName /* build name */,
#endif
/* --post-js=... */
pf("post-js.js.%s-%s := $(dir.tmp)/post-js.%s-%s.js\n", zNM, zNM);
pf("post-js.js.%s-%s = $(dir.tmp)/post-js.%s-%s.js\n", zNM, zNM);
pf("$(eval $(call SQLITE.CALL.C-PP.FILTER,$(post-js.js.in),"
"$(post-js.js.%s-%s),$(c-pp.D.%s-%s)))\n", zNM, zNM);
/* --extern-post-js=... */
pf("extern-post-js.js.%s-%s := $(dir.tmp)/extern-post-js.%s-%s.js\n", zNM, zNM);
pf("extern-post-js.js.%s-%s = $(dir.tmp)/extern-post-js.%s-%s.js\n", zNM, zNM);
pf("$(eval $(call SQLITE.CALL.C-PP.FILTER,$(extern-post-js.js.in),$(extern-post-js.js.%s-%s),"
"$(c-pp.D.%s-%s)))\n", zNM, zNM);
/* Combined flags for use with emcc... */
pf("pre-post-common.flags.%s-%s := "
pf("pre-post-common.flags.%s-%s = "
"$(pre-post-common.flags) "
"--post-js=$(post-js.js.%s-%s) "
"--extern-post-js=$(extern-post-js.js.%s-%s)\n", zNM, zNM, zNM);
@@ -219,30 +305,29 @@ static void mk_pre_post(const char *zName /* build name */,
"--pre-js=$(pre-js.js.%s-%s)\n", zNM, zNM, zNM);
/* Set up deps... */
pf("pre-post-jses.%s-%s.deps := $(pre-post-jses.deps.common) "
pf("pre-post-jses.%s-%s.deps = $(pre-post-jses.deps.common) "
"$(post-js.js.%s-%s) $(extern-post-js.js.%s-%s)\n",
zNM, zNM, zNM);
pf("pre-post-%s-%s.deps := $(pre-post-jses.%s-%s.deps) $(dir.tmp)/pre-js.%s-%s.js\n",
pf("pre-post-%s-%s.deps = $(pre-post-jses.%s-%s.deps) $(dir.tmp)/pre-js.%s-%s.js\n",
zNM, zNM, zNM);
pf("# End --pre/--post flags for %s-%s%s", zNM, zBanner);
#undef zNM
}
/*
** Emits rules for the fiddle builds.
**
*/
static void mk_fiddle(){
static void mk_fiddle(void){
int i = 0;
mk_pre_post("fiddle-module","vanilla", 0, 0);
mk_pre_post("fiddle-module","vanilla", 0);
for( ; i < 2; ++i ){
/* 0==normal, 1==debug */
const char *zTail = i ? ".debug" : "";
const char *zDir = i ? "$(dir.fiddle-debug)" : "$(dir.fiddle)";
pf("%s# Begin fiddle%s\n", zBanner, zTail);
pf("fiddle-module.js%s := %s/fiddle-module.js\n", zTail, zDir);
pf("fiddle-module.wasm%s := "
"$(subst .js,.wasm,$(fiddle-module.js%s))\n", zTail, zTail);
pf("fiddle-module.js%s = %s/fiddle-module.js\n", zTail, zDir);
pf("$(fiddle-module.js%s):%s $(MAKEFILE_LIST) $(MAKEFILE.fiddle) "
"$(EXPORTED_FUNCTIONS.fiddle) "
"$(fiddle.cses) $(pre-post-fiddle-module-vanilla.deps) "
@@ -254,7 +339,9 @@ static void mk_fiddle(){
pf("\t$(bin.emcc) -o $@ $(fiddle.emcc-flags%s) "
"$(pre-post-fiddle-module-vanilla.flags) $(fiddle.cses)\n",
zTail);
pf("\t$(maybe-wasm-strip) $(fiddle-module.wasm%s)\n", zTail);
ps("\t@chmod -x $(basename $@).wasm");
ps("\t@$(maybe-wasm-strip) $(basename $@).wasm");
ps("\t@$(SQLITE.strip-createExportWrapper)");
pf("\t@cp -p $(SOAP.js) $(dir $@)\n");
if( 1==i ){/*fiddle.debug*/
pf("\tcp -p $(dir.fiddle)/index.html "
@@ -263,13 +350,13 @@ static void mk_fiddle(){
"$(dir $@)\n");
}
pf("\t@for i in %s/*.*js %s/*.html %s/*.wasm; do \\\n"
"\t\ttest -f $${i} || continue; \\\n"
"\t\ttest -f $${i} || continue; \\\n"
"\t\tgzip < $${i} > $${i}.gz; \\\n"
"\tdone\n", zDir, zDir, zDir);
if( 0==i ){
ps("fiddle: $(fiddle-module.js)");
}else{
ps("fiddle-debug: $(fiddle-module-debug.js)");
ps("fiddle-debug: $(fiddle-module.js.debug)");
}
pf("# End fiddle%s%s", zTail, zBanner);
}
@@ -280,138 +367,110 @@ static void mk_fiddle(){
** by the combination of zName and zMode, each of which must be values
** from JS_BUILD_NAMES resp. JS_BUILD_MODES.
*/
static void mk_lib_mode(const char *zName /* build name */,
const char *zMode /* build mode */,
int flags /* LIBMODE_... mask */,
const char *zApiJsOut /* name of generated sqlite3-api.js/.mjs */,
const char *zJsOut /* name of generated sqlite3.js/.mjs */,
const char *zCmppD /* extra -D flags for c-pp */,
const char *zEmcc /* extra flags for emcc */){
static void mk_lib_mode(const BuildDef * pB){
const char * zWasmOut = "$(basename $@).wasm"
/* The various targets named X.js or X.mjs (zJsOut) also generate
** X.wasm, and we need that part of the name to perform some
** post-processing after Emscripten generates X.wasm. */;
assert( zName );
assert( zMode );
assert( zApiJsOut );
assert( zJsOut );
if( !zCmppD ) zCmppD = "";
if( !zEmcc ) zEmcc = "";
assert( pB->zName );
assert( pB->zMode );
assert( pB->zJsOut );
/* Very common printf() args combo. */
#define zNM pB->zName, pB->zMode
pf("%s# Begin build [%s-%s]\n", zBanner, zNM);
pf("# zApiJsOut=%s\n# zJsOut=%s\n# zCmppD=%s\n", zApiJsOut, zJsOut, zCmppD);
pf("$(info Setting up build [%s-%s]: %s)\n", zNM, zJsOut);
mk_pre_post(zNM, flags, zCmppD);
pf("%s# Begin build [%s-%s]. flags=0x%02x\n", zBanner, zNM, pB->flags);
pf("# zJsOut=%s\n# zCmppD=%s\n", pB->zJsOut,
pB->zCmppD ? pB->zCmppD : "<none>");
pf("$(info Setting up build [%s-%s]: %s)\n", zNM, pB->zJsOut);
mk_pre_post(zNM, pB->zCmppD);
pf("\nemcc.flags.%s.%s ?=\n", zNM);
if( zEmcc[0] ){
pf("emcc.flags.%s.%s += %s\n", zNM, zEmcc);
if( pB->zEmcc && pB->zEmcc[0] ){
pf("emcc.flags.%s.%s += %s\n", zNM, pB->zEmcc);
}
pf("$(eval $(call SQLITE.CALL.C-PP.FILTER, $(sqlite3-api.js.in), %s, %s))\n",
zApiJsOut, zCmppD);
/* target zJsOut */
pf("%s: %s $(MAKEFILE_LIST) $(sqlite3-wasm.cfiles) $(EXPORTED_FUNCTIONS.api) "
/* target pB->zJsOut */
pf("%s: $(MAKEFILE_LIST) $(sqlite3-wasm.cfiles) $(EXPORTED_FUNCTIONS.api) "
"$(pre-post-%s-%s.deps) "
"$(sqlite3-api.ext.jses)"
/* ^^^ maintenance reminder: we set these as deps so that they
get copied into place early. That allows the developer to
reload the base-most test pages while the later-stage builds
are still compiling, which is especially helpful when running
builds with long build times (like -Oz). */
** get copied into place early. That allows the developer to
** reload the base-most test pages while the later-stage builds
** are still compiling, which is especially helpful when running
** builds with long build times (like -Oz). */
"\n",
zJsOut, zApiJsOut, zNM);
pB->zJsOut, zNM);
pf("\t@echo \"Building $@ ...\"\n");
if( LIBMODE_UNSUPPORTED & pB->flags ){
ps("\t@echo 'ACHTUNG: $@ is an unsupported build. "
"Use at your own risk.'");
}
pf("\t$(bin.emcc) -o $@ $(emcc_opt_full) $(emcc.flags) \\\n");
pf("\t\t$(emcc.jsflags) -sENVIRONMENT=$(emcc.environment.%s) \\\n", zMode);
pf("\t\t$(emcc.jsflags) -sENVIRONMENT=$(emcc.environment.%s) \\\n",
pB->zMode);
pf("\t\t$(pre-post-%s-%s.flags) \\\n", zNM);
pf("\t\t$(emcc.flags.%s) $(emcc.flags.%s.%s) \\\n", zName, zNM);
pf("\t\t$(emcc.flags.%s) $(emcc.flags.%s.%s) \\\n", pB->zName, zNM);
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) || (LIBMODE_NODEJS & flags) ){
"\t\t$(cflags.wasm_extra_init) $(sqlite3-wasm.cfiles)\n", pB->zName, zNM);
if( (LIBMODE_ESM & pB->flags) || (LIBMODE_NODEJS & pB->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
** program. */
pf("\t@$(call SQLITE.CALL.xJS.ESM-EXPORT-DEFAULT,1,%d)\n",
(LIBMODE_WASMFS & flags) ? 1 : 0);
(LIBMODE_WASMFS & pB->flags) ? 1 : 0);
}
pf("\t@chmod -x %s; \\\n"
"\t\t$(maybe-wasm-strip) %s;\n",
zWasmOut, zWasmOut);
pf("\t@chmod -x %s\n", zWasmOut);
pf("\t@$(maybe-wasm-strip) %s\n", zWasmOut);
pf("\t@$(call SQLITE.CALL.WASM-OPT,%s)\n", zWasmOut);
pf("\t@sed -i -e '/^var _sqlite3.*createExportWrapper/d' %s || exit; \\\n"
/* ^^^^^^ reminder: Mac/BSD sed has no -i flag */
"\t\techo 'Stripped out createExportWrapper() parts.'\n",
zJsOut) /* Our JS code installs bindings of each WASM export. The
generated Emscripten JS file does the same using its
own framework, but we don't use those results and can
speed up lib init, and reduce memory cost
considerably, by stripping them out. */;
ps("\t@$(SQLITE.strip-createExportWrapper)");
/*
** The above $(bin.emcc) call will write zJsOut and will create a
** like-named .wasm file (zWasmOut). That .wasm file name gets
** hard-coded into zJsOut so we need to, for some cases, patch
** zJsOut to use the name sqlite3.wasm instead. Note that the
** The above $(bin.emcc) call will write pB->zJsOut, a.k.a. $@, and
** will create a like-named .wasm file (zWasmOut). That .wasm file
** name gets hard-coded into $@ so we need to, for some cases, patch
** zJsOut to use the name sqlite3.wasm instead. Note that the
** resulting .wasm file is identical for all builds for which zEmcc
** is empty.
*/
if( (LIBMODE_BUNDLER_FRIENDLY & flags)
|| (LIBMODE_NODEJS & flags) ){
pf("\t@echo 'Patching $@ for %s.wasm...'; \\\n", zName);
if( (LIBMODE_BUNDLER_FRIENDLY & pB->flags) ){
pf("\t@echo 'Patching $@ for %s.wasm...'; \\\n", pB->zName);
pf("\t\trm -f %s; \\\n", zWasmOut);
pf("\t\tsed -i -e 's/%s-%s.wasm/%s.wasm/g' $@ || exit;\n",
/* ^^^^^^ reminder: Mac/BSD sed has no -i flag */
zNM, zName);
/* ^^^^^^ reminder: Mac/BSD sed has no -i flag but this
** build process explicitly requires a Linux system. */
zNM, pB->zName);
pf("\t@ls -la $@\n");
if( LIBMODE_BUNDLER_FRIENDLY & flags ){
if( LIBMODE_BUNDLER_FRIENDLY & pB->flags ){
/* Avoid a 3rd occurrence of the bug fixed by 65798c09a00662a3,
** which was (in two cases) caused by makefile refactoring and
** not recognized until after a release was made with the broken
** sqlite3-bundler-friendly.mjs: */
** sqlite3-bundler-friendly.mjs (which is used by the npm
** subproject but is otherwise untested/unsupported): */
pf("\t@if grep -e '^ *importScripts(' $@; "
"then echo 'ERROR: bug fixed in 65798c09a00662a3 has re-appeared'; "
"exit 1; fi;\n");
}
}else{
pf("\t@ls -la %s $@\n", zWasmOut);
}
if( 0==(LIBMODE_DONT_ADD_TO_ALL & flags) ){
pf("all: %s\n", zJsOut);
if( 0==(LIBMODE_UNSUPPORTED & pB->flags) ){
pf("all: %s\n", pB->zJsOut);
}
pf("# End build [%s-%s]%s", zNM, zBanner);
#undef zNM
}
int main(void){
int rc = 0;
const BuildDef *pB = &aBuildDefs[0];
pf("# What follows was GENERATED by %s. Edit at your own risk.\n", __FILE__);
mk_prologue();
mk_lib_mode("sqlite3", "vanilla", 0,
"$(sqlite3-api.js)", "$(sqlite3.js)", 0, 0);
mk_lib_mode("sqlite3", "esm", LIBMODE_ESM,
"$(sqlite3-api.mjs)", "$(sqlite3.mjs)",
"-Dtarget=es6-module", 0);
mk_lib_mode("sqlite3", "bundler-friendly",
LIBMODE_BUNDLER_FRIENDLY | LIBMODE_ESM,
"$(sqlite3-api-bundler-friendly.mjs)",
"$(sqlite3-bundler-friendly.mjs)",
"$(c-pp.D.sqlite3-esm) -Dtarget=es6-bundler-friendly", 0);
mk_lib_mode("sqlite3" , "node",
LIBMODE_NODEJS | LIBMODE_DONT_ADD_TO_ALL,
"$(sqlite3-api-node.mjs)", "$(sqlite3-node.mjs)",
"$(c-pp.D.sqlite3-bundler-friendly) -Dtarget=node", 0);
mk_lib_mode("sqlite3-wasmfs", "esm" ,
LIBMODE_WASMFS | LIBMODE_ESM | LIBMODE_DONT_ADD_TO_ALL,
/* The sqlite3-wasmfs build is optional and needs to be invoked
** conditionally using info we don't have here. */
"$(sqlite3-api-wasmfs.mjs)", "$(sqlite3-wasmfs.mjs)",
"$(c-pp.D.sqlite3-bundler-friendly) -Dwasmfs",
"-sEXPORT_ES6 -sUSE_ES6_IMPORT_META");
for( ; pB->zName; ++pB ){
mk_lib_mode( pB );
}
mk_fiddle();
mk_pre_post("speedtest1","vanilla", 0, 0);
mk_pre_post("speedtest1-wasmfs","esm", 0,
mk_pre_post("speedtest1","vanilla", 0);
mk_pre_post("speedtest1-wasmfs","esm",
"$(c-pp.D.sqlite3-bundler-friendly) -Dwasmfs");
return rc;
}

View File

@@ -23,11 +23,10 @@
</figure>
<div class="emscripten" id="module-status">Downloading...</div>
<div class="emscripten">
<progress value="0" max="100" id="module-progress" hidden='1'></progress>
<progress value="0" max="100" id="module-progress" hidden='1'></progress>
</div><!-- /emscripten bits -->
<div class='warning'>This page starts running the main exe when it loads, which will
block the UI until it finishes! Adding UI controls to manually configure and start it
are TODO.</div>
block the UI until it finishes!</div>
</div>
<div class='warning'>Achtung: running it with the dev tools open may
<em>drastically</em> slow it down. For faster results, keep the dev
@@ -118,7 +117,7 @@
argv.push("--vfs", vfs);
log2('',"Using VFS:",vfs);
if('kvvfs' === vfs){
forceSize = 2 /* 5 uses approx. 4.96mb */;
forceSize = 2 /* >2 is too big as of mid-2025 */;
dbFile = 'session';
log2('warning',"kvvfs VFS: forcing --size",forceSize,
"and filename '"+dbFile+"'.");

View File

@@ -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);
@@ -1268,6 +1366,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
/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))
@@ -1490,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);
@@ -3329,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") )

View File

@@ -5,31 +5,28 @@
# sqlite3.wasm. It is intended to be "include"d from the main
# GNUMakefile.
########################################################################
MAKEFILE.wasmfs := $(lastword $(MAKEFILE_LIST))
MAKEFILE.wasmfs = $(lastword $(MAKEFILE_LIST))
# ensure that the following message starts on line 10 or higher for proper
# $(warning) alignment!
ifneq (1,$(MAKING_CLEAN))
$(warning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)
$(warning !! The WASMFS build is not well-supported. WASMFS is a proverbial)
$(warning !! moving target, sometimes changing in incompatible ways between)
$(warning !! Emscripten versions. This build is provided for adventurous folks)
$(warning !! and is not a supported deliverable of the SQLite project.)
$(warning !! The WASMFS build is unsupported. Use at your own risk.
$(warning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)
endif
sqlite3-wasmfs.js := $(dir.wasmfs)/sqlite3-wasmfs.js
sqlite3-wasmfs.wasm := $(dir.wasmfs)/sqlite3-wasmfs.wasm
sqlite3-wasmfs.js = $(dir.wasmfs)/sqlite3-wasmfs.js
sqlite3-wasmfs.wasm = $(dir.wasmfs)/sqlite3-wasmfs.wasm
########################################################################
# emcc flags for .c/.o.
cflags.sqlite3-wasmfs :=
cflags.sqlite3-wasmfs =
cflags.sqlite3-wasmfs += -std=c99 -fPIC
cflags.sqlite3-wasmfs += -pthread
cflags.sqlite3-wasmfs += -DSQLITE_ENABLE_WASMFS
########################################################################
# emcc flags specific to building the final .js/.wasm file...
emcc.flags.sqlite3-wasmfs :=
emcc.flags.sqlite3-wasmfs =
emcc.flags.sqlite3-wasmfs += \
-sEXPORTED_RUNTIME_METHODS=wasmMemory
# wasmMemory ==> for -sIMPORTED_MEMORY
@@ -43,7 +40,7 @@ emcc.flags.sqlite3-wasmfs += -Wno-limited-postlink-optimizations
emcc.flags.sqlite3-wasmfs += -sMEMORY64=0
emcc.flags.sqlite3-wasmfs += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.128)
# ^^^^ 64MB is not enough for WASMFS/OPFS test runs using batch-runner.js
sqlite3-wasmfs.fsflags := -pthread -sWASMFS \
sqlite3-wasmfs.fsflags = -pthread -sWASMFS \
-sPTHREAD_POOL_SIZE=1 \
-sERROR_ON_UNDEFINED_SYMBOLS=0 -sLLD_REPORT_UNDEFINED
# ^^^^^ why undefined symbols are necessary for the wasmfs build is anyone's guess.
@@ -53,10 +50,9 @@ emcc.flags.sqlite3-wasmfs += -sALLOW_MEMORY_GROWTH=0
# USE_PTHREADS + ALLOW_MEMORY_GROWTH may run non-wasm code slowly,
# see https://github.com/WebAssembly/design/issues/1271 [-Wpthreads-mem-growth]
# And, indeed, it runs slowly if memory is permitted to grow.
#emcc.flags.sqlite3-wasmfs.vanilla :=
#emcc.flags.sqlite3-wasmfs.esm := -sEXPORT_ES6 -sUSE_ES6_IMPORT_META
all: $(sqlite3-wasmfs.mjs)
$(sqlite3-wasmfs.js) $(sqlite3-wasmfs.mjs): $(MAKEFILE.wasmfs)
#emcc.flags.sqlite3-wasmfs.vanilla =
#emcc.flags.sqlite3-wasmfs.esm = -sEXPORT_ES6 -sUSE_ES6_IMPORT_META
$(sqlite3-wasmfs.js) $(dir.wasmfs)/sqlite3-wasmfs.mjs: $(MAKEFILE.wasmfs)
########################################################################
# Build quirk: we cannot build BOTH .js and .mjs with our current
# build infrastructure because the supplemental *.worker.js files get
@@ -68,31 +64,31 @@ $(sqlite3-wasmfs.js) $(sqlite3-wasmfs.mjs): $(MAKEFILE.wasmfs)
# names is that it means that the corresponding .wasm file is also
# built/saved multiple times. It is likely that anyone wanting to use
# WASMFS will want an ES6 module, so that's what we build here.
wasmfs.build.ext := mjs
$(sqlite3-wasmfs.js) $(sqlite3-wasmfs.mjs): $(SOAP.js.bld)
wasmfs.build.ext = mjs
$(sqlite3-wasmfs.js) $(dir.wasmfs)/sqlite3-wasmfs.mjs: $(SOAP.js.bld)
ifeq (js,$(wasmfs.build.ext))
$(sqlite3-wasmfs.wasm): $(sqlite3-wasmfs.js)
wasmfs: $(sqlite3-wasmfs.js)
else
$(sqlite3-wasmfs.wasm): $(sqlite3-wasmfs.mjs)
wasmfs: $(sqlite3-wasmfs.mjs)
$(sqlite3-wasmfs.wasm): $(dir.wasmfs)/sqlite3-wasmfs.mjs
wasmfs: $(dir.wasmfs)/sqlite3-wasmfs.mjs
endif
all: wasmfs
########################################################################
# speedtest1 for wasmfs.
speedtest1-wasmfs.mjs := $(dir.wasmfs)/speedtest1-wasmfs.mjs
speedtest1-wasmfs.wasm := $(subst .mjs,.wasm,$(speedtest1-wasmfs.mjs))
emcc.flags.speedtest1-wasmfs := $(sqlite3-wasmfs.fsflags)
speedtest1-wasmfs.mjs = $(dir.wasmfs)/speedtest1-wasmfs.mjs
speedtest1-wasmfs.wasm = $(subst .mjs,.wasm,$(speedtest1-wasmfs.mjs))
emcc.flags.speedtest1-wasmfs = $(sqlite3-wasmfs.fsflags)
emcc.flags.speedtest1-wasmfs += $(SQLITE_OPT)
emcc.flags.speedtest1-wasmfs += -sALLOW_MEMORY_GROWTH=0
emcc.flags.speedtest1-wasmfs += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.128)
#$(eval $(call call-make-pre-js,speedtest1-wasmfs,ems))
#$(info speedtest DEPS=pre-post-sqlite3-wasmfs-esm.deps=$(pre-post-sqlite3-wasmfs-esm.deps))
$(speedtest1-wasmfs.mjs): $(speedtest1.cfiles) $(sqlite3-wasmfs.js) \
$(MAKEFILE) $(MAKEFILE.wasmfs) \
$(pre-post-sqlite3-wasmfs-esm.deps) \
$(MAKEFILE) $(MAKEFILE.wasmfs) $(pre-post-sqlite3-wasmfs-esm.deps) \
$(EXPORTED_FUNCTIONS.speedtest1)
@echo "Building $@ ..."
$(emcc.bin) \
$(bin.emcc) \
$(pre-post-sqlite3-wasmfs-esm.flags) \
$(cflags.common) \
$(cflags.sqlite3-wasmfs) \