Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Merge trunk into wasi-patches branch. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | wasi-patches |
Files: | files | file ages | folders |
SHA3-256: |
52f40ab12e437c59af2b91c7ac105ab7 |
User & Date: | stephan 2022-12-24 15:31:56.293 |
Context
2022-12-24
| ||
15:34 | Incorporate wasi-sdk RANLIB configure script patch from the VMware OCTO team. (check-in: 478fe96ee7 user: stephan tags: wasi-patches) | |
15:31 | Merge trunk into wasi-patches branch. (check-in: 52f40ab12e user: stephan tags: wasi-patches) | |
15:28 | Replace JS-side use of SQLITE_TRANSIENT with the new SQLITE_WASM_DEALLOC, reducing the amount allocation/copying required by sqlite3_bind_blob/text() and sqlite3_result_blob/text(). Remove the 'experimental' log message from the virtual table tests. (check-in: ffe2999a91 user: stephan tags: trunk) | |
2022-12-10
| ||
12:06 | Rerun autoconf using version 2.69 to minimize configure script differences with trunk. (check-in: b633428394 user: drh tags: wasi-patches) | |
Changes
Changes to Makefile.in.
︙ | ︙ | |||
433 434 435 436 437 438 439 | $(TOP)/src/test_wsd.c \ $(TOP)/ext/fts3/fts3_term.c \ $(TOP)/ext/fts3/fts3_test.c \ $(TOP)/ext/session/test_session.c \ $(TOP)/ext/recover/sqlite3recover.c \ $(TOP)/ext/recover/dbdata.c \ $(TOP)/ext/recover/test_recover.c \ | | | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | $(TOP)/src/test_wsd.c \ $(TOP)/ext/fts3/fts3_term.c \ $(TOP)/ext/fts3/fts3_test.c \ $(TOP)/ext/session/test_session.c \ $(TOP)/ext/recover/sqlite3recover.c \ $(TOP)/ext/recover/dbdata.c \ $(TOP)/ext/recover/test_recover.c \ $(TOP)/ext/rbu/test_rbu.c # Statically linked extensions # TESTSRC += \ $(TOP)/ext/expert/sqlite3expert.c \ $(TOP)/ext/expert/test_expert.c \ $(TOP)/ext/misc/amatch.c \ |
︙ | ︙ | |||
1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 | # Source files that go into making shell.c SHELL_SRC = \ $(TOP)/src/shell.c.in \ $(TOP)/ext/misc/appendvfs.c \ $(TOP)/ext/misc/completion.c \ $(TOP)/ext/misc/decimal.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/series.c \ $(TOP)/ext/misc/shathree.c \ $(TOP)/ext/misc/sqlar.c \ $(TOP)/ext/misc/uint.c \ | > > > | 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 | # Source files that go into making shell.c SHELL_SRC = \ $(TOP)/src/shell.c.in \ $(TOP)/ext/misc/appendvfs.c \ $(TOP)/ext/misc/completion.c \ $(TOP)/ext/misc/decimal.c \ $(TOP)/ext/misc/basexx.c \ $(TOP)/ext/misc/base64.c \ $(TOP)/ext/misc/base85.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/series.c \ $(TOP)/ext/misc/shathree.c \ $(TOP)/ext/misc/sqlar.c \ $(TOP)/ext/misc/uint.c \ |
︙ | ︙ |
Changes to Makefile.msc.
︙ | ︙ | |||
2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 | .\mkkeywordhash.exe > keywordhash.h # Source files that go into making shell.c SHELL_SRC = \ $(TOP)\src\shell.c.in \ $(TOP)\ext\misc\appendvfs.c \ $(TOP)\ext\misc\completion.c \ $(TOP)\ext\misc\decimal.c \ $(TOP)\ext\misc\fileio.c \ $(TOP)\ext\misc\ieee754.c \ $(TOP)\ext\misc\regexp.c \ $(TOP)\ext\misc\series.c \ $(TOP)\ext\misc\shathree.c \ $(TOP)\ext\misc\uint.c \ | > > | 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 | .\mkkeywordhash.exe > keywordhash.h # Source files that go into making shell.c SHELL_SRC = \ $(TOP)\src\shell.c.in \ $(TOP)\ext\misc\appendvfs.c \ $(TOP)\ext\misc\completion.c \ $(TOP)\ext\misc\base64.c \ $(TOP)\ext\misc\base85.c \ $(TOP)\ext\misc\decimal.c \ $(TOP)\ext\misc\fileio.c \ $(TOP)\ext\misc\ieee754.c \ $(TOP)\ext\misc\regexp.c \ $(TOP)\ext\misc\series.c \ $(TOP)\ext\misc\shathree.c \ $(TOP)\ext\misc\uint.c \ |
︙ | ︙ |
Changes to ext/fts5/fts5_index.c.
︙ | ︙ | |||
5069 5070 5071 5072 5073 5074 5075 | Fts5Buffer out = {0, 0, 0}; Fts5Buffer tmp = {0, 0, 0}; i64 iLastRowid = 0; /* Initialize a doclist-iterator for each input buffer. Arrange them in ** a linked-list starting at pHead in ascending order of rowid. Avoid ** linking any iterators already at EOF into the linked list at all. */ | | | 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 | Fts5Buffer out = {0, 0, 0}; Fts5Buffer tmp = {0, 0, 0}; i64 iLastRowid = 0; /* Initialize a doclist-iterator for each input buffer. Arrange them in ** a linked-list starting at pHead in ascending order of rowid. Avoid ** linking any iterators already at EOF into the linked list at all. */ assert( nBuf+1<=(int)(sizeof(aMerger)/sizeof(aMerger[0])) ); memset(aMerger, 0, sizeof(PrefixMerger)*(nBuf+1)); pHead = &aMerger[nBuf]; fts5DoclistIterInit(p1, &pHead->iter); for(i=0; i<nBuf; i++){ fts5DoclistIterInit(&aBuf[i], &aMerger[i].iter); fts5PrefixMergerInsertByRowid(&pHead, &aMerger[i]); nOut += aBuf[i].n; |
︙ | ︙ |
Changes to ext/fts5/fts5_main.c.
︙ | ︙ | |||
256 257 258 259 260 261 262 | case FTS5_BEGIN: assert( p->ts.eState==0 ); p->ts.eState = 1; p->ts.iSavepoint = -1; break; case FTS5_SYNC: | | | | | | 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 | case FTS5_BEGIN: assert( p->ts.eState==0 ); p->ts.eState = 1; p->ts.iSavepoint = -1; break; case FTS5_SYNC: assert( p->ts.eState==1 || p->ts.eState==2 ); p->ts.eState = 2; break; case FTS5_COMMIT: assert( p->ts.eState==2 ); p->ts.eState = 0; break; case FTS5_ROLLBACK: assert( p->ts.eState==1 || p->ts.eState==2 || p->ts.eState==0 ); p->ts.eState = 0; break; case FTS5_SAVEPOINT: assert( p->ts.eState>=1 ); assert( iSavepoint>=0 ); assert( iSavepoint>=p->ts.iSavepoint ); p->ts.iSavepoint = iSavepoint; break; case FTS5_RELEASE: assert( p->ts.eState>=1 ); assert( iSavepoint>=0 ); assert( iSavepoint<=p->ts.iSavepoint ); p->ts.iSavepoint = iSavepoint-1; break; case FTS5_ROLLBACKTO: assert( p->ts.eState>=1 ); assert( iSavepoint>=-1 ); /* The following assert() can fail if another vtab strikes an error ** within an xSavepoint() call then SQLite calls xRollbackTo() - without ** having called xSavepoint() on this vtab. */ /* assert( iSavepoint<=p->ts.iSavepoint ); */ p->ts.iSavepoint = iSavepoint; break; |
︙ | ︙ |
Changes to ext/fts5/test/fts5misc.test.
︙ | ︙ | |||
347 348 349 350 351 352 353 354 355 356 | do_test 13.2 { sqlite3_finalize $::STMT } {SQLITE_OK} do_test 13.3 { sqlite3_errmsg db } {not an error} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 | do_test 13.2 { sqlite3_finalize $::STMT } {SQLITE_OK} do_test 13.3 { sqlite3_errmsg db } {not an error} #------------------------------------------------------------------------- reset_db db close sqlite3 db test.db -uri 1 do_execsql_test 14.0 { PRAGMA locking_mode=EXCLUSIVE; BEGIN; ATTACH 'file:/one?vfs=memdb' AS aux1; ATTACH 'file:/one?vfs=memdb' AS aux2; CREATE VIRTUAL TABLE t1 USING fts5(x); } {exclusive} do_catchsql_test 14.1 { ANALYZE; } {1 {database is locked}} do_catchsql_test 14.2 { COMMIT; } {1 {database is locked}} do_catchsql_test 14.3 { COMMIT; } {1 {database is locked}} do_catchsql_test 14.4 { ROLLBACK; } {0 {}} #------------------------------------------------------------------------- reset_db sqlite3 db2 test.db do_execsql_test 15.0 { CREATE TABLE t1(a, b); BEGIN; SELECT * FROM t1; } do_execsql_test -db db2 15.1 { BEGIN; CREATE VIRTUAL TABLE x1 USING fts5(y); } do_test 15.2 { list [catch { db2 eval COMMIT } msg] $msg } {1 {database is locked}} do_execsql_test -db db2 15.3 { SAVEPOINT one; } {} do_execsql_test 15.4 END do_test 15.4 { list [catch { db2 eval COMMIT } msg] $msg } {0 {}} finish_test |
Changes to ext/misc/base64.c.
︙ | ︙ | |||
49 50 51 52 53 54 55 | ** OSX: gcc -O2 -dynamiclib -fPIC -I$SQDIR -o base64.dylib base64.c ** Win32: gcc -O2 -shared -I%SQDIR% -o base64.dll base64.c ** Win32: cl /Os -I%SQDIR% base64.c -link -dll -out:base64.dll */ #include <assert.h> | < < | | | | | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | ** OSX: gcc -O2 -dynamiclib -fPIC -I$SQDIR -o base64.dylib base64.c ** Win32: gcc -O2 -shared -I%SQDIR% -o base64.dll base64.c ** Win32: cl /Os -I%SQDIR% base64.c -link -dll -out:base64.dll */ #include <assert.h> #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1; #define PC 0x80 /* pad character */ #define WS 0x81 /* whitespace */ #define ND 0x82 /* Not above or digit-value */ #define PAD_CHAR '=' #ifndef U8_TYPEDEF typedef unsigned char u8; #define U8_TYPEDEF #endif static const u8 b64DigitValues[128] = { /* HT LF VT FF CR */ ND,ND,ND,ND, ND,ND,ND,ND, ND,WS,WS,WS, WS,WS,ND,ND, /* US */ ND,ND,ND,ND, ND,ND,ND,ND, ND,ND,ND,ND, ND,ND,ND,ND, /*sp + / */ WS,ND,ND,ND, ND,ND,ND,ND, ND,ND,ND,62, ND,ND,ND,63, /* 0 1 5 9 = */ |
︙ | ︙ | |||
88 89 90 91 92 93 94 | 41,42,43,44, 45,46,47,48, 49,50,51,ND, ND,ND,ND,ND }; static const char b64Numerals[64+1] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; #define BX_DV_PROTO(c) \ | | | | | | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | 41,42,43,44, 45,46,47,48, 49,50,51,ND, ND,ND,ND,ND }; static const char b64Numerals[64+1] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; #define BX_DV_PROTO(c) \ ((((u8)(c))<0x80)? (u8)(b64DigitValues[(u8)(c)]) : 0x80) #define IS_BX_DIGIT(bdp) (((u8)(bdp))<0x80) #define IS_BX_WS(bdp) ((bdp)==WS) #define IS_BX_PAD(bdp) ((bdp)==PC) #define BX_NUMERAL(dv) (b64Numerals[(u8)(dv)]) /* Width of base64 lines. Should be an integer multiple of 4. */ #define B64_DARK_MAX 72 /* Encode a byte buffer into base64 text with linefeeds appended to limit ** encoded group lengths to B64_DARK_MAX or to terminate the last group. */ static char* toBase64( u8 *pIn, int nbIn, char *pOut ){ int nCol = 0; while( nbIn >= 3 ){ /* Do the bit-shuffle, exploiting unsigned input to avoid masking. */ pOut[0] = BX_NUMERAL(pIn[0]>>2); pOut[1] = BX_NUMERAL(((pIn[0]<<4)|(pIn[1]>>4))&0x3f); pOut[2] = BX_NUMERAL(((pIn[1]&0xf)<<2)|(pIn[2]>>6)); pOut[3] = BX_NUMERAL(pIn[2]&0x3f); |
︙ | ︙ | |||
124 125 126 127 128 129 130 | int nbe; unsigned long qv = *pIn++; for( nbe=1; nbe<3; ++nbe ){ qv <<= 8; if( nbe<nbIn ) qv |= *pIn++; } for( nbe=3; nbe>=0; --nbe ){ | | | | | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | int nbe; unsigned long qv = *pIn++; for( nbe=1; nbe<3; ++nbe ){ qv <<= 8; if( nbe<nbIn ) qv |= *pIn++; } for( nbe=3; nbe>=0; --nbe ){ char ce = (nbe<nco)? BX_NUMERAL((u8)(qv & 0x3f)) : PAD_CHAR; qv >>= 6; pOut[nbe] = ce; } pOut += 4; *pOut++ = '\n'; } *pOut = 0; return pOut; } /* Skip over text which is not base64 numeral(s). */ static char * skipNonB64( char *s ){ char c; while( (c = *s) && !IS_BX_DIGIT(BX_DV_PROTO(c)) ) ++s; return s; } /* Decode base64 text into a byte buffer. */ static u8* fromBase64( char *pIn, int ncIn, u8 *pOut ){ if( ncIn>0 && pIn[ncIn-1]=='\n' ) --ncIn; while( ncIn>0 && *pIn!=PAD_CHAR ){ static signed char nboi[] = { 0, 0, 1, 2, 3 }; char *pUse = skipNonB64(pIn); unsigned long qv = 0L; int nti, nbo, nac; ncIn -= (pUse - pIn); pIn = pUse; nti = (ncIn>4)? 4 : ncIn; ncIn -= nti; nbo = nboi[nti]; if( nbo==0 ) break; for( nac=0; nac<4; ++nac ){ char c = (nac<nti)? *pIn++ : b64Numerals[0]; u8 bdp = BX_DV_PROTO(c); switch( bdp ){ case ND: /* Treat dark non-digits as pad, but they terminate decode too. */ ncIn = 0; /* fall thru */ case WS: /* Treat whitespace as pad and terminate this group.*/ |
︙ | ︙ | |||
196 197 198 199 200 201 202 | /* This function does the work for the SQLite base64(x) UDF. */ static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){ int nb, nc, nv = sqlite3_value_bytes(av[0]); int nvMax = sqlite3_limit(sqlite3_context_db_handle(context), SQLITE_LIMIT_LENGTH, -1); char *cBuf; | | | | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | /* This function does the work for the SQLite base64(x) UDF. */ static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){ int nb, nc, nv = sqlite3_value_bytes(av[0]); int nvMax = sqlite3_limit(sqlite3_context_db_handle(context), SQLITE_LIMIT_LENGTH, -1); char *cBuf; u8 *bBuf; assert(na==1); switch( sqlite3_value_type(av[0]) ){ case SQLITE_BLOB: nb = nv; nc = 4*(nv+2/3); /* quads needed */ nc += (nc+(B64_DARK_MAX-1))/B64_DARK_MAX + 1; /* LFs and a 0-terminator */ if( nvMax < nc ){ sqlite3_result_error(context, "blob expanded to base64 too big", -1); return; } cBuf = sqlite3_malloc(nc); if( !cBuf ) goto memFail; bBuf = (u8*)sqlite3_value_blob(av[0]); nc = (int)(toBase64(bBuf, nb, cBuf) - cBuf); sqlite3_result_text(context, cBuf, nc, sqlite3_free); break; case SQLITE_TEXT: nc = nv; nb = 3*((nv+3)/4); /* may overestimate due to LF and padding */ if( nvMax < nb ){ |
︙ | ︙ |
Changes to ext/misc/base85.c.
︙ | ︙ | |||
81 82 83 84 85 86 87 | #include <assert.h> #ifndef OMIT_BASE85_CHECKER # include <ctype.h> #endif #ifndef BASE85_STANDALONE | < < | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | #include <assert.h> #ifndef OMIT_BASE85_CHECKER # include <ctype.h> #endif #ifndef BASE85_STANDALONE # include "sqlite3ext.h" SQLITE_EXTENSION_INIT1; #else # ifdef _WIN32 # include <io.h> |
︙ | ︙ | |||
109 110 111 112 113 114 115 | ; static void sayHelp(){ printf("%s", zHelp); } #endif | | | | | | | | | | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | ; static void sayHelp(){ printf("%s", zHelp); } #endif #ifndef U8_TYPEDEF typedef unsigned char u8; #define U8_TYPEDEF #endif /* Classify c according to interval within USASCII set w.r.t. base85 * Values of 1 and 3 are base85 numerals. Values of 0, 2, or 4 are not. */ #define B85_CLASS( c ) (((c)>='#')+((c)>'&')+((c)>='*')+((c)>'z')) /* Provide digitValue to b85Numeral offset as a function of above class. */ static u8 b85_cOffset[] = { 0, '#', 0, '*'-4, 0 }; #define B85_DNOS( c ) b85_cOffset[B85_CLASS(c)] /* Say whether c is a base85 numeral. */ #define IS_B85( c ) (B85_CLASS(c) & 1) #if 0 /* Not used, */ static u8 base85DigitValue( char c ){ u8 dv = (u8)(c - '#'); if( dv>87 ) return 0xff; return (dv > 3)? dv-3 : dv; } #endif /* Width of base64 lines. Should be an integer multiple of 5. */ #define B85_DARK_MAX 80 static char * skipNonB85( char *s ){ char c; while( (c = *s) && !IS_B85(c) ) ++s; return s; } /* Convert small integer, known to be in 0..84 inclusive, to base85 numeral. * Do not use the macro form with argument expression having a side-effect.*/ #if 0 static char base85Numeral( u8 b ){ return (b < 4)? (char)(b + '#') : (char)(b - 4 + '*'); } #else # define base85Numeral( dn )\ ((char)(((dn) < 4)? (char)((dn) + '#') : (char)((dn) - 4 + '*'))) #endif static char *putcs(char *pc, char *s){ char c; while( (c = *s++)!=0 ) *pc++ = c; return pc; } /* Encode a byte buffer into base85 text. If pSep!=0, it's a C string ** to be appended to encoded groups to limit their length to B85_DARK_MAX ** or to terminate the last group (to aid concatenation.) */ static char* toBase85( u8 *pIn, int nbIn, char *pOut, char *pSep ){ int nCol = 0; while( nbIn >= 4 ){ int nco = 5; unsigned long qbv = (pIn[0]<<24)|(pIn[1]<<16)|(pIn[2]<<8)|pIn[3]; while( nco > 0 ){ unsigned nqv = (unsigned)(qbv/85UL); unsigned char dv = qbv - 85UL*nqv; |
︙ | ︙ | |||
193 194 195 196 197 198 199 | unsigned long qv = *pIn++; int nbe = 1; while( nbe++ < nbIn ){ qv = (qv<<8) | *pIn++; } nCol += nco; while( nco > 0 ){ | | | | | 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | unsigned long qv = *pIn++; int nbe = 1; while( nbe++ < nbIn ){ qv = (qv<<8) | *pIn++; } nCol += nco; while( nco > 0 ){ u8 dv = (u8)(qv % 85); qv /= 85; pOut[--nco] = base85Numeral(dv); } pOut += (nbIn+1); } if( pSep && nCol>0 ) pOut = putcs(pOut, pSep); *pOut = 0; return pOut; } /* Decode base85 text into a byte buffer. */ static u8* fromBase85( char *pIn, int ncIn, u8 *pOut ){ if( ncIn>0 && pIn[ncIn-1]=='\n' ) --ncIn; while( ncIn>0 ){ static signed char nboi[] = { 0, 0, 1, 2, 3, 4 }; char *pUse = skipNonB85(pIn); unsigned long qv = 0L; int nti, nbo; ncIn -= (pUse - pIn); pIn = pUse; nti = (ncIn>5)? 5 : ncIn; nbo = nboi[nti]; if( nbo==0 ) break; while( nti>0 ){ char c = *pIn++; u8 cdo = B85_DNOS(c); --ncIn; if( cdo==0 ) break; qv = 85 * qv + (c - cdo); --nti; } nbo -= nti; /* Adjust for early (non-digit) end of group. */ switch( nbo ){ |
︙ | ︙ | |||
283 284 285 286 287 288 289 | /* This function does the work for the SQLite base85(x) UDF. */ static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){ int nb, nc, nv = sqlite3_value_bytes(av[0]); int nvMax = sqlite3_limit(sqlite3_context_db_handle(context), SQLITE_LIMIT_LENGTH, -1); char *cBuf; | | | | 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | /* This function does the work for the SQLite base85(x) UDF. */ static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){ int nb, nc, nv = sqlite3_value_bytes(av[0]); int nvMax = sqlite3_limit(sqlite3_context_db_handle(context), SQLITE_LIMIT_LENGTH, -1); char *cBuf; u8 *bBuf; assert(na==1); switch( sqlite3_value_type(av[0]) ){ case SQLITE_BLOB: nb = nv; /* ulongs tail newlines tailenc+nul*/ nc = 5*(nv/4) + nv%4 + nv/64+1 + 2; if( nvMax < nc ){ sqlite3_result_error(context, "blob expanded to base85 too big", -1); return; } cBuf = sqlite3_malloc(nc); if( !cBuf ) goto memFail; bBuf = (u8*)sqlite3_value_blob(av[0]); nc = (int)(toBase85(bBuf, nb, cBuf, "\n") - cBuf); sqlite3_result_text(context, cBuf, nc, sqlite3_free); break; case SQLITE_TEXT: nc = nv; nb = 4*(nv/5) + nv%5; /* may overestimate */ if( nvMax < nb ){ |
︙ | ︙ | |||
366 367 368 369 370 371 372 | # define BASE85_EXPOSE(db, pzErr) /* Not needed, ..._init() does this. */ #else /* standalone program */ int main(int na, char *av[]){ int cin; int rc = 0; | | | 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 | # define BASE85_EXPOSE(db, pzErr) /* Not needed, ..._init() does this. */ #else /* standalone program */ int main(int na, char *av[]){ int cin; int rc = 0; u8 bBuf[4*(B85_DARK_MAX/5)]; char cBuf[5*(sizeof(bBuf)/4)+2]; size_t nio; # ifndef OMIT_BASE85_CHECKER int b85Clean = 1; # endif char rw; FILE *fb = 0, *foc = 0; |
︙ | ︙ |
Changes to ext/misc/basexx.c.
︙ | ︙ | |||
44 45 46 47 48 49 50 51 52 53 54 55 56 57 | SQLITE_EXTENSION_INIT2(pApi); } #undef SQLITE_EXTENSION_INIT1 #define SQLITE_EXTENSION_INIT1 /* */ #undef SQLITE_EXTENSION_INIT2 #define SQLITE_EXTENSION_INIT2(v) (void)v /* These next 2 undef's are only needed because the entry point names * collide when formulated per the rules stated for loadable extension * entry point names that will be deduced from the file basenames. */ #undef sqlite3_base_init #define sqlite3_base_init sqlite3_base64_init | > > > | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | SQLITE_EXTENSION_INIT2(pApi); } #undef SQLITE_EXTENSION_INIT1 #define SQLITE_EXTENSION_INIT1 /* */ #undef SQLITE_EXTENSION_INIT2 #define SQLITE_EXTENSION_INIT2(v) (void)v typedef unsigned char u8; #define U8_TYPEDEF /* These next 2 undef's are only needed because the entry point names * collide when formulated per the rules stated for loadable extension * entry point names that will be deduced from the file basenames. */ #undef sqlite3_base_init #define sqlite3_base_init sqlite3_base64_init |
︙ | ︙ |
Changes to ext/misc/decimal.c.
︙ | ︙ | |||
612 613 614 615 616 617 618 | { "decimal_mul", 2, decimalMulFunc }, }; unsigned int i; (void)pzErrMsg; /* Unused parameter */ SQLITE_EXTENSION_INIT2(pApi); | | | 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 | { "decimal_mul", 2, decimalMulFunc }, }; unsigned int i; (void)pzErrMsg; /* Unused parameter */ SQLITE_EXTENSION_INIT2(pApi); for(i=0; i<(int)(sizeof(aFunc)/sizeof(aFunc[0])) && rc==SQLITE_OK; i++){ rc = sqlite3_create_function(db, aFunc[i].zFuncName, aFunc[i].nArg, SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, 0, aFunc[i].xFunc, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_create_window_function(db, "decimal_sum", 1, SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, 0, |
︙ | ︙ |
Changes to ext/misc/regexp.c.
︙ | ︙ | |||
799 800 801 802 803 804 805 806 807 808 809 810 811 812 | const char *zPattern; const char *zErr; ReCompiled *pRe; sqlite3_str *pStr; int i; int n; char *z; zPattern = (const char*)sqlite3_value_text(argv[0]); if( zPattern==0 ) return; zErr = re_compile(&pRe, zPattern, sqlite3_user_data(context)!=0); if( zErr ){ re_free(pRe); sqlite3_result_error(context, zErr, -1); | > | 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 | const char *zPattern; const char *zErr; ReCompiled *pRe; sqlite3_str *pStr; int i; int n; char *z; (void)argc; zPattern = (const char*)sqlite3_value_text(argv[0]); if( zPattern==0 ) return; zErr = re_compile(&pRe, zPattern, sqlite3_user_data(context)!=0); if( zErr ){ re_free(pRe); sqlite3_result_error(context, zErr, -1); |
︙ | ︙ |
Changes to ext/misc/stmt.c.
︙ | ︙ | |||
93 94 95 96 97 98 99 100 101 102 103 104 105 106 | #define STMT_COLUMN_NAIDX 6 /* SQLITE_STMTSTATUS_AUTOINDEX */ #define STMT_COLUMN_NSTEP 7 /* SQLITE_STMTSTATUS_VM_STEP */ #define STMT_COLUMN_REPREP 8 /* SQLITE_STMTSTATUS_REPREPARE */ #define STMT_COLUMN_RUN 9 /* SQLITE_STMTSTATUS_RUN */ #define STMT_COLUMN_MEM 10 /* SQLITE_STMTSTATUS_MEMUSED */ rc = sqlite3_declare_vtab(db, "CREATE TABLE x(sql,ncol,ro,busy,nscan,nsort,naidx,nstep," "reprep,run,mem)"); if( rc==SQLITE_OK ){ pNew = sqlite3_malloc64( sizeof(*pNew) ); *ppVtab = (sqlite3_vtab*)pNew; if( pNew==0 ) return SQLITE_NOMEM; | > > > > | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | #define STMT_COLUMN_NAIDX 6 /* SQLITE_STMTSTATUS_AUTOINDEX */ #define STMT_COLUMN_NSTEP 7 /* SQLITE_STMTSTATUS_VM_STEP */ #define STMT_COLUMN_REPREP 8 /* SQLITE_STMTSTATUS_REPREPARE */ #define STMT_COLUMN_RUN 9 /* SQLITE_STMTSTATUS_RUN */ #define STMT_COLUMN_MEM 10 /* SQLITE_STMTSTATUS_MEMUSED */ (void)pAux; (void)argc; (void)argv; (void)pzErr; rc = sqlite3_declare_vtab(db, "CREATE TABLE x(sql,ncol,ro,busy,nscan,nsort,naidx,nstep," "reprep,run,mem)"); if( rc==SQLITE_OK ){ pNew = sqlite3_malloc64( sizeof(*pNew) ); *ppVtab = (sqlite3_vtab*)pNew; if( pNew==0 ) return SQLITE_NOMEM; |
︙ | ︙ | |||
212 213 214 215 216 217 218 219 220 221 222 223 224 225 | int argc, sqlite3_value **argv ){ stmt_cursor *pCur = (stmt_cursor *)pVtabCursor; sqlite3_stmt *p = 0; sqlite3_int64 iRowid = 1; StmtRow **ppRow = 0; stmtCsrReset(pCur); ppRow = &pCur->pRow; for(p=sqlite3_next_stmt(pCur->db, 0); p; p=sqlite3_next_stmt(pCur->db, p)){ const char *zSql = sqlite3_sql(p); sqlite3_int64 nSql = zSql ? strlen(zSql)+1 : 0; StmtRow *pNew = (StmtRow*)sqlite3_malloc64(sizeof(StmtRow) + nSql); | > > > > | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | int argc, sqlite3_value **argv ){ stmt_cursor *pCur = (stmt_cursor *)pVtabCursor; sqlite3_stmt *p = 0; sqlite3_int64 iRowid = 1; StmtRow **ppRow = 0; (void)idxNum; (void)idxStr; (void)argc; (void)argv; stmtCsrReset(pCur); ppRow = &pCur->pRow; for(p=sqlite3_next_stmt(pCur->db, 0); p; p=sqlite3_next_stmt(pCur->db, p)){ const char *zSql = sqlite3_sql(p); sqlite3_int64 nSql = zSql ? strlen(zSql)+1 : 0; StmtRow *pNew = (StmtRow*)sqlite3_malloc64(sizeof(StmtRow) + nSql); |
︙ | ︙ | |||
267 268 269 270 271 272 273 274 275 276 277 278 279 280 | ** a query plan for each invocation and compute an estimated cost for that ** plan. */ static int stmtBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ pIdxInfo->estimatedCost = (double)500; pIdxInfo->estimatedRows = 500; return SQLITE_OK; } /* ** This following structure defines all the methods for the | > | 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | ** a query plan for each invocation and compute an estimated cost for that ** plan. */ static int stmtBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ (void)tab; pIdxInfo->estimatedCost = (double)500; pIdxInfo->estimatedRows = 500; return SQLITE_OK; } /* ** This following structure defines all the methods for the |
︙ | ︙ |
Changes to ext/misc/zipfile.c.
︙ | ︙ | |||
348 349 350 351 352 353 354 355 356 357 358 359 360 361 | char **pzErr ){ int nByte = sizeof(ZipfileTab) + ZIPFILE_BUFFER_SIZE; int nFile = 0; const char *zFile = 0; ZipfileTab *pNew = 0; int rc; /* If the table name is not "zipfile", require that the argument be ** specified. This stops zipfile tables from being created as: ** ** CREATE VIRTUAL TABLE zzz USING zipfile(); ** ** It does not prevent: | > | 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 | char **pzErr ){ int nByte = sizeof(ZipfileTab) + ZIPFILE_BUFFER_SIZE; int nFile = 0; const char *zFile = 0; ZipfileTab *pNew = 0; int rc; (void)pAux; /* If the table name is not "zipfile", require that the argument be ** specified. This stops zipfile tables from being created as: ** ** CREATE VIRTUAL TABLE zzz USING zipfile(); ** ** It does not prevent: |
︙ | ︙ | |||
804 805 806 807 808 809 810 811 812 813 814 815 816 817 | FILE *pFile, /* If aBlob==0, read from this file */ i64 iOff, /* Offset of CDS record */ ZipfileEntry **ppEntry /* OUT: Pointer to new object */ ){ u8 *aRead; char **pzErr = &pTab->base.zErrMsg; int rc = SQLITE_OK; if( aBlob==0 ){ aRead = pTab->aBuffer; rc = zipfileReadData(pFile, aRead, ZIPFILE_CDS_FIXED_SZ, iOff, pzErr); }else{ aRead = (u8*)&aBlob[iOff]; } | > | 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 | FILE *pFile, /* If aBlob==0, read from this file */ i64 iOff, /* Offset of CDS record */ ZipfileEntry **ppEntry /* OUT: Pointer to new object */ ){ u8 *aRead; char **pzErr = &pTab->base.zErrMsg; int rc = SQLITE_OK; (void)nBlob; if( aBlob==0 ){ aRead = pTab->aBuffer; rc = zipfileReadData(pFile, aRead, ZIPFILE_CDS_FIXED_SZ, iOff, pzErr); }else{ aRead = (u8*)&aBlob[iOff]; } |
︙ | ︙ | |||
1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 | int argc, sqlite3_value **argv ){ ZipfileTab *pTab = (ZipfileTab*)cur->pVtab; ZipfileCsr *pCsr = (ZipfileCsr*)cur; const char *zFile = 0; /* Zip file to scan */ int rc = SQLITE_OK; /* Return Code */ int bInMemory = 0; /* True for an in-memory zipfile */ zipfileResetCursor(pCsr); if( pTab->zFile ){ zFile = pTab->zFile; }else if( idxNum==0 ){ zipfileCursorErr(pCsr, "zipfile() function requires an argument"); | > > > | 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 | int argc, sqlite3_value **argv ){ ZipfileTab *pTab = (ZipfileTab*)cur->pVtab; ZipfileCsr *pCsr = (ZipfileCsr*)cur; const char *zFile = 0; /* Zip file to scan */ int rc = SQLITE_OK; /* Return Code */ int bInMemory = 0; /* True for an in-memory zipfile */ (void)idxStr; (void)argc; zipfileResetCursor(pCsr); if( pTab->zFile ){ zFile = pTab->zFile; }else if( idxNum==0 ){ zipfileCursorErr(pCsr, "zipfile() function requires an argument"); |
︙ | ︙ | |||
1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 | static int zipfileBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ int i; int idx = -1; int unusable = 0; for(i=0; i<pIdxInfo->nConstraint; i++){ const struct sqlite3_index_constraint *pCons = &pIdxInfo->aConstraint[i]; if( pCons->iColumn!=ZIPFILE_F_COLUMN_IDX ) continue; if( pCons->usable==0 ){ unusable = 1; }else if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){ | > | 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 | static int zipfileBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ int i; int idx = -1; int unusable = 0; (void)tab; for(i=0; i<pIdxInfo->nConstraint; i++){ const struct sqlite3_index_constraint *pCons = &pIdxInfo->aConstraint[i]; if( pCons->iColumn!=ZIPFILE_F_COLUMN_IDX ) continue; if( pCons->usable==0 ){ unusable = 1; }else if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){ |
︙ | ︙ | |||
1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 | u8 *pFree = 0; /* Free this */ char *zFree = 0; /* Also free this */ ZipfileEntry *pOld = 0; ZipfileEntry *pOld2 = 0; int bUpdate = 0; /* True for an update that modifies "name" */ int bIsDir = 0; u32 iCrc32 = 0; if( pTab->pWriteFd==0 ){ rc = zipfileBegin(pVtab); if( rc!=SQLITE_OK ) return rc; } /* If this is a DELETE or UPDATE, find the archive entry to delete. */ | > > | 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 | u8 *pFree = 0; /* Free this */ char *zFree = 0; /* Also free this */ ZipfileEntry *pOld = 0; ZipfileEntry *pOld2 = 0; int bUpdate = 0; /* True for an update that modifies "name" */ int bIsDir = 0; u32 iCrc32 = 0; (void)pRowid; if( pTab->pWriteFd==0 ){ rc = zipfileBegin(pVtab); if( rc!=SQLITE_OK ) return rc; } /* If this is a DELETE or UPDATE, find the archive entry to delete. */ |
︙ | ︙ | |||
1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 | static int zipfileFindFunction( sqlite3_vtab *pVtab, /* Virtual table handle */ int nArg, /* Number of SQL function arguments */ const char *zName, /* Name of SQL function */ void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */ void **ppArg /* OUT: User data for *pxFunc */ ){ if( sqlite3_stricmp("zipfile_cds", zName)==0 ){ *pxFunc = zipfileFunctionCds; *ppArg = (void*)pVtab; return 1; } return 0; } | > | 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 | static int zipfileFindFunction( sqlite3_vtab *pVtab, /* Virtual table handle */ int nArg, /* Number of SQL function arguments */ const char *zName, /* Name of SQL function */ void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */ void **ppArg /* OUT: User data for *pxFunc */ ){ (void)nArg; if( sqlite3_stricmp("zipfile_cds", zName)==0 ){ *pxFunc = zipfileFunctionCds; *ppArg = (void*)pVtab; return 1; } return 0; } |
︙ | ︙ |
Changes to ext/rbu/rbuB.test.
︙ | ︙ | |||
44 45 46 47 48 49 50 | proc xLog {err msg} { lappend ::errlog $err } do_test 1.2 { run_rbu test.db rbu.db } {SQLITE_DONE} do_test 1.3 { set ::errlog | | | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | proc xLog {err msg} { lappend ::errlog $err } do_test 1.2 { run_rbu test.db rbu.db } {SQLITE_DONE} do_test 1.3 { set ::errlog } {SQLITE_NOTICE_RECOVER_WAL SQLITE_NOTICE_RBU} do_execsql_test 1.4 { SELECT * FROM t1 } {1 2 3 4 5 6 7 8 9} db close sqlite3_shutdown |
︙ | ︙ |
Changes to ext/rbu/sqlite3rbu.c.
︙ | ︙ | |||
3027 3028 3029 3030 3031 3032 3033 | ** array. ** ** * Calls to xShmLock(UNLOCK) to release the exclusive shm WRITER, ** READ0 and CHECKPOINT locks taken as part of the checkpoint are ** no-ops. These locks will not be released until the connection ** is closed. ** | | | | | 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 | ** array. ** ** * Calls to xShmLock(UNLOCK) to release the exclusive shm WRITER, ** READ0 and CHECKPOINT locks taken as part of the checkpoint are ** no-ops. These locks will not be released until the connection ** is closed. ** ** * Attempting to xSync() the database file causes an SQLITE_NOTICE ** error. ** ** As a result, unless an error (i.e. OOM or SQLITE_BUSY) occurs, the ** checkpoint below fails with SQLITE_NOTICE, and leaves the aFrame[] ** array populated with a set of (frame -> page) mappings. Because the ** WRITER, CHECKPOINT and READ0 locks are still held, it is safe to copy ** data from the wal file into the database file according to the ** contents of aFrame[]. */ if( p->rc==SQLITE_OK ){ int rc2; p->eStage = RBU_STAGE_CAPTURE; rc2 = sqlite3_exec(p->dbMain, "PRAGMA main.wal_checkpoint=restart", 0, 0,0); if( rc2!=SQLITE_NOTICE ) p->rc = rc2; } if( p->rc==SQLITE_OK && p->nFrame>0 ){ p->eStage = RBU_STAGE_CKPT; p->nStep = (pState ? pState->nRow : 0); p->aBuf = rbuMalloc(p, p->pgsz); p->iWalCksum = rbuShmChecksum(p); |
︙ | ︙ | |||
3087 3088 3089 3090 3091 3092 3093 | */ static int rbuCaptureWalRead(sqlite3rbu *pRbu, i64 iOff, int iAmt){ const u32 mReq = (1<<WAL_LOCK_WRITE)|(1<<WAL_LOCK_CKPT)|(1<<WAL_LOCK_READ0); u32 iFrame; if( pRbu->mLock!=mReq ){ pRbu->rc = SQLITE_BUSY; | | | 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 | */ static int rbuCaptureWalRead(sqlite3rbu *pRbu, i64 iOff, int iAmt){ const u32 mReq = (1<<WAL_LOCK_WRITE)|(1<<WAL_LOCK_CKPT)|(1<<WAL_LOCK_READ0); u32 iFrame; if( pRbu->mLock!=mReq ){ pRbu->rc = SQLITE_BUSY; return SQLITE_NOTICE_RBU; } pRbu->pgsz = iAmt; if( pRbu->nFrame==pRbu->nFrameAlloc ){ int nNew = (pRbu->nFrameAlloc ? pRbu->nFrameAlloc : 64) * 2; RbuFrame *aNew; aNew = (RbuFrame*)sqlite3_realloc64(pRbu->aFrame, nNew * sizeof(RbuFrame)); |
︙ | ︙ | |||
4474 4475 4476 4477 4478 4479 4480 | ** all xWrite() calls on the target database file perform no IO. ** Instead the frame and page numbers that would be read and written ** are recorded. Additionally, successful attempts to obtain exclusive ** xShmLock() WRITER, CHECKPOINTER and READ0 locks on the target ** database file are recorded. xShmLock() calls to unlock the same ** locks are no-ops (so that once obtained, these locks are never ** relinquished). Finally, calls to xSync() on the target database | | | 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 | ** all xWrite() calls on the target database file perform no IO. ** Instead the frame and page numbers that would be read and written ** are recorded. Additionally, successful attempts to obtain exclusive ** xShmLock() WRITER, CHECKPOINTER and READ0 locks on the target ** database file are recorded. xShmLock() calls to unlock the same ** locks are no-ops (so that once obtained, these locks are never ** relinquished). Finally, calls to xSync() on the target database ** file fail with SQLITE_NOTICE errors. */ static void rbuUnlockShm(rbu_file *p){ assert( p->openFlags & SQLITE_OPEN_MAIN_DB ); if( p->pRbu ){ int (*xShmLock)(sqlite3_file*,int,int,int) = p->pReal->pMethods->xShmLock; int i; |
︙ | ︙ | |||
4753 4754 4755 4756 4757 4758 4759 | /* ** Sync an rbuVfs-file. */ static int rbuVfsSync(sqlite3_file *pFile, int flags){ rbu_file *p = (rbu_file *)pFile; if( p->pRbu && p->pRbu->eStage==RBU_STAGE_CAPTURE ){ if( p->openFlags & SQLITE_OPEN_MAIN_DB ){ | | | 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 | /* ** Sync an rbuVfs-file. */ static int rbuVfsSync(sqlite3_file *pFile, int flags){ rbu_file *p = (rbu_file *)pFile; if( p->pRbu && p->pRbu->eStage==RBU_STAGE_CAPTURE ){ if( p->openFlags & SQLITE_OPEN_MAIN_DB ){ return SQLITE_NOTICE_RBU; } return SQLITE_OK; } return p->pReal->pMethods->xSync(p->pReal, flags); } /* |
︙ | ︙ |
Changes to ext/recover/dbdata.c.
︙ | ︙ | |||
160 161 162 163 164 165 166 167 168 169 170 171 172 173 | int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ DbdataTable *pTab = 0; int rc = sqlite3_declare_vtab(db, pAux ? DBPTR_SCHEMA : DBDATA_SCHEMA); if( rc==SQLITE_OK ){ pTab = (DbdataTable*)sqlite3_malloc64(sizeof(DbdataTable)); if( pTab==0 ){ rc = SQLITE_NOMEM; }else{ memset(pTab, 0, sizeof(DbdataTable)); pTab->db = db; | > > > | 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ DbdataTable *pTab = 0; int rc = sqlite3_declare_vtab(db, pAux ? DBPTR_SCHEMA : DBDATA_SCHEMA); (void)argc; (void)argv; (void)pzErr; if( rc==SQLITE_OK ){ pTab = (DbdataTable*)sqlite3_malloc64(sizeof(DbdataTable)); if( pTab==0 ){ rc = SQLITE_NOMEM; }else{ memset(pTab, 0, sizeof(DbdataTable)); pTab->db = db; |
︙ | ︙ | |||
764 765 766 767 768 769 770 771 772 773 774 775 776 777 | int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ DbdataCursor *pCsr = (DbdataCursor*)pCursor; DbdataTable *pTab = (DbdataTable*)pCursor->pVtab; int rc = SQLITE_OK; const char *zSchema = "main"; dbdataResetCursor(pCsr); assert( pCsr->iPgno==1 ); if( idxNum & 0x01 ){ zSchema = (const char*)sqlite3_value_text(argv[0]); if( zSchema==0 ) zSchema = ""; } | > > | 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 | int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ DbdataCursor *pCsr = (DbdataCursor*)pCursor; DbdataTable *pTab = (DbdataTable*)pCursor->pVtab; int rc = SQLITE_OK; const char *zSchema = "main"; (void)idxStr; (void)argc; dbdataResetCursor(pCsr); assert( pCsr->iPgno==1 ); if( idxNum & 0x01 ){ zSchema = (const char*)sqlite3_value_text(argv[0]); if( zSchema==0 ) zSchema = ""; } |
︙ | ︙ | |||
932 933 934 935 936 937 938 939 940 941 942 | #endif int sqlite3_dbdata_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ SQLITE_EXTENSION_INIT2(pApi); return sqlite3DbdataRegister(db); } #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ | > | 937 938 939 940 941 942 943 944 945 946 947 948 | #endif int sqlite3_dbdata_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; return sqlite3DbdataRegister(db); } #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ |
Changes to ext/recover/sqlite3recover.c.
︙ | ︙ | |||
757 758 759 760 761 762 763 764 765 766 767 768 769 770 | */ static void recoverEscapeCrnl( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zText = (const char*)sqlite3_value_text(argv[0]); if( zText && zText[0]=='\'' ){ int nText = sqlite3_value_bytes(argv[0]); int i; char zBuf1[20]; char zBuf2[20]; const char *zNL = 0; const char *zCR = 0; | > | 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 | */ static void recoverEscapeCrnl( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zText = (const char*)sqlite3_value_text(argv[0]); (void)argc; if( zText && zText[0]=='\'' ){ int nText = sqlite3_value_bytes(argv[0]); int i; char zBuf1[20]; char zBuf2[20]; const char *zNL = 0; const char *zCR = 0; |
︙ | ︙ | |||
909 910 911 912 913 914 915 | sqlite3 *db2 = 0; int rc = sqlite3_open("", &db2); if( rc!=SQLITE_OK ){ recoverDbError(p, db2); return; } | | | 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 | sqlite3 *db2 = 0; int rc = sqlite3_open("", &db2); if( rc!=SQLITE_OK ){ recoverDbError(p, db2); return; } for(ii=0; ii<(int)(sizeof(aPragma)/sizeof(aPragma[0])); ii++){ const char *zPrag = aPragma[ii]; sqlite3_stmt *p1 = 0; p1 = recoverPreparePrintf(p, p->dbIn, "PRAGMA %Q.%s", p->zDb, zPrag); if( p->errCode==SQLITE_OK && sqlite3_step(p1)==SQLITE_ROW ){ const char *zArg = (const char*)sqlite3_column_text(p1, 0); char *z2 = recoverMPrintf(p, "PRAGMA %s = %Q", zPrag, zArg); recoverSqlCallback(p, z2); |
︙ | ︙ | |||
987 988 989 990 991 992 993 | ** module depends on the input handle supporting the sqlite_dbpage ** virtual table only. */ if( p->errCode==SQLITE_OK ){ p->errCode = sqlite3_dbdata_init(db, 0, 0); } /* Register the custom user-functions with the output handle. */ | > | > | 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 | ** module depends on the input handle supporting the sqlite_dbpage ** virtual table only. */ if( p->errCode==SQLITE_OK ){ p->errCode = sqlite3_dbdata_init(db, 0, 0); } /* Register the custom user-functions with the output handle. */ for(ii=0; p->errCode==SQLITE_OK && ii<(int)(sizeof(aFunc)/sizeof(aFunc[0])); ii++){ p->errCode = sqlite3_create_function(db, aFunc[ii].zName, aFunc[ii].nArg, SQLITE_UTF8, (void*)p, aFunc[ii].xFunc, 0, 0 ); } p->dbOut = db; return p->errCode; |
︙ | ︙ | |||
2384 2385 2386 2387 2388 2389 2390 | aHdr[19] = a[19]; recoverPutU32(&aHdr[28], dbsz); recoverPutU32(&aHdr[56], enc); recoverPutU16(&aHdr[105], pgsz-nReserve); if( pgsz==65536 ) pgsz = 1; recoverPutU16(&aHdr[16], pgsz); aHdr[20] = nReserve; | | | 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 | aHdr[19] = a[19]; recoverPutU32(&aHdr[28], dbsz); recoverPutU32(&aHdr[56], enc); recoverPutU16(&aHdr[105], pgsz-nReserve); if( pgsz==65536 ) pgsz = 1; recoverPutU16(&aHdr[16], pgsz); aHdr[20] = nReserve; for(ii=0; ii<(int)(sizeof(aPreserve)/sizeof(aPreserve[0])); ii++){ memcpy(&aHdr[aPreserve[ii]], &a[aPreserve[ii]], 4); } memcpy(aBuf, aHdr, sizeof(aHdr)); memset(&((u8*)aBuf)[sizeof(aHdr)], 0, nByte-sizeof(aHdr)); memcpy(p->pPage1Cache, aBuf, nByte); }else{ |
︙ | ︙ | |||
2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 | static int recoverVfsFetch( sqlite3_file *pFd, sqlite3_int64 iOff, int iAmt, void **pp ){ *pp = 0; return SQLITE_OK; } static int recoverVfsUnfetch(sqlite3_file *pFd, sqlite3_int64 iOff, void *p){ return SQLITE_OK; } /* ** Install the VFS wrapper around the file-descriptor open on the input ** database for recover handle p. Mutex RECOVER_MUTEX_ID must be held ** when this function is called. | > > > > > > | 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 | static int recoverVfsFetch( sqlite3_file *pFd, sqlite3_int64 iOff, int iAmt, void **pp ){ (void)pFd; (void)iOff; (void)iAmt; *pp = 0; return SQLITE_OK; } static int recoverVfsUnfetch(sqlite3_file *pFd, sqlite3_int64 iOff, void *p){ (void)pFd; (void)iOff; (void)p; return SQLITE_OK; } /* ** Install the VFS wrapper around the file-descriptor open on the input ** database for recover handle p. Mutex RECOVER_MUTEX_ID must be held ** when this function is called. |
︙ | ︙ |
Changes to ext/rtree/geopoly.c.
︙ | ︙ | |||
300 301 302 303 304 305 306 | sqlite3_value *pVal, /* The value to decode */ int *pRc /* Write error here */ ){ GeoPoly *p = 0; int nByte; testcase( pCtx==0 ); if( sqlite3_value_type(pVal)==SQLITE_BLOB | | | 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 | sqlite3_value *pVal, /* The value to decode */ int *pRc /* Write error here */ ){ GeoPoly *p = 0; int nByte; testcase( pCtx==0 ); if( sqlite3_value_type(pVal)==SQLITE_BLOB && (nByte = sqlite3_value_bytes(pVal))>=(int)(4+6*sizeof(GeoCoord)) ){ const unsigned char *a = sqlite3_value_blob(pVal); int nVertex; if( a==0 ){ if( pCtx ) sqlite3_result_error_nomem(pCtx); return 0; } |
︙ | ︙ | |||
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 | */ static void geopolyBlobFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); if( p ){ sqlite3_result_blob(context, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); sqlite3_free(p); } } /* ** SQL function: geopoly_json(X) ** ** Interpret X as a polygon and render it as a JSON array ** of coordinates. Or, if X is not a valid polygon, return NULL. */ static void geopolyJsonFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); if( p ){ sqlite3 *db = sqlite3_context_db_handle(context); sqlite3_str *x = sqlite3_str_new(db); int i; sqlite3_str_append(x, "[", 1); for(i=0; i<p->nVertex; i++){ sqlite3_str_appendf(x, "[%!g,%!g],", GeoX(p,i), GeoY(p,i)); | > > | 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 | */ static void geopolyBlobFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); (void)argc; if( p ){ sqlite3_result_blob(context, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); sqlite3_free(p); } } /* ** SQL function: geopoly_json(X) ** ** Interpret X as a polygon and render it as a JSON array ** of coordinates. Or, if X is not a valid polygon, return NULL. */ static void geopolyJsonFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); (void)argc; if( p ){ sqlite3 *db = sqlite3_context_db_handle(context); sqlite3_str *x = sqlite3_str_new(db); int i; sqlite3_str_append(x, "[", 1); for(i=0; i<p->nVertex; i++){ sqlite3_str_appendf(x, "[%!g,%!g],", GeoX(p,i), GeoY(p,i)); |
︙ | ︙ | |||
458 459 460 461 462 463 464 465 466 467 468 469 470 471 | double B = sqlite3_value_double(argv[2]); double C = sqlite3_value_double(argv[3]); double D = sqlite3_value_double(argv[4]); double E = sqlite3_value_double(argv[5]); double F = sqlite3_value_double(argv[6]); GeoCoord x1, y1, x0, y0; int ii; if( p ){ for(ii=0; ii<p->nVertex; ii++){ x0 = GeoX(p,ii); y0 = GeoY(p,ii); x1 = (GeoCoord)(A*x0 + B*y0 + E); y1 = (GeoCoord)(C*x0 + D*y0 + F); GeoX(p,ii) = x1; | > | 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 | double B = sqlite3_value_double(argv[2]); double C = sqlite3_value_double(argv[3]); double D = sqlite3_value_double(argv[4]); double E = sqlite3_value_double(argv[5]); double F = sqlite3_value_double(argv[6]); GeoCoord x1, y1, x0, y0; int ii; (void)argc; if( p ){ for(ii=0; ii<p->nVertex; ii++){ x0 = GeoX(p,ii); y0 = GeoY(p,ii); x1 = (GeoCoord)(A*x0 + B*y0 + E); y1 = (GeoCoord)(C*x0 + D*y0 + F); GeoX(p,ii) = x1; |
︙ | ︙ | |||
508 509 510 511 512 513 514 515 516 517 518 519 520 521 | */ static void geopolyAreaFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); if( p ){ sqlite3_result_double(context, geopolyArea(p)); sqlite3_free(p); } } /* | > | 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 | */ static void geopolyAreaFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); (void)argc; if( p ){ sqlite3_result_double(context, geopolyArea(p)); sqlite3_free(p); } } /* |
︙ | ︙ | |||
533 534 535 536 537 538 539 540 541 542 543 544 545 546 | */ static void geopolyCcwFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); if( p ){ if( geopolyArea(p)<0.0 ){ int ii, jj; for(ii=1, jj=p->nVertex-1; ii<jj; ii++, jj--){ GeoCoord t = GeoX(p,ii); GeoX(p,ii) = GeoX(p,jj); GeoX(p,jj) = t; | > | 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 | */ static void geopolyCcwFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); (void)argc; if( p ){ if( geopolyArea(p)<0.0 ){ int ii, jj; for(ii=1, jj=p->nVertex-1; ii<jj; ii++, jj--){ GeoCoord t = GeoX(p,ii); GeoX(p,ii) = GeoX(p,jj); GeoX(p,jj) = t; |
︙ | ︙ | |||
587 588 589 590 591 592 593 594 595 596 597 598 599 600 | ){ double x = sqlite3_value_double(argv[0]); double y = sqlite3_value_double(argv[1]); double r = sqlite3_value_double(argv[2]); int n = sqlite3_value_int(argv[3]); int i; GeoPoly *p; if( n<3 || r<=0.0 ) return; if( n>1000 ) n = 1000; p = sqlite3_malloc64( sizeof(*p) + (n-1)*2*sizeof(GeoCoord) ); if( p==0 ){ sqlite3_result_error_nomem(context); return; | > | 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 | ){ double x = sqlite3_value_double(argv[0]); double y = sqlite3_value_double(argv[1]); double r = sqlite3_value_double(argv[2]); int n = sqlite3_value_int(argv[3]); int i; GeoPoly *p; (void)argc; if( n<3 || r<=0.0 ) return; if( n>1000 ) n = 1000; p = sqlite3_malloc64( sizeof(*p) + (n-1)*2*sizeof(GeoCoord) ); if( p==0 ){ sqlite3_result_error_nomem(context); return; |
︙ | ︙ | |||
696 697 698 699 700 701 702 703 704 705 706 707 708 709 | */ static void geopolyBBoxFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyBBox(context, argv[0], 0, 0); if( p ){ sqlite3_result_blob(context, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); sqlite3_free(p); } } | > | 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 | */ static void geopolyBBoxFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyBBox(context, argv[0], 0, 0); (void)argc; if( p ){ sqlite3_result_blob(context, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); sqlite3_free(p); } } |
︙ | ︙ | |||
723 724 725 726 727 728 729 730 731 732 733 734 735 736 | static void geopolyBBoxStep( sqlite3_context *context, int argc, sqlite3_value **argv ){ RtreeCoord a[4]; int rc = SQLITE_OK; (void)geopolyBBox(context, argv[0], a, &rc); if( rc==SQLITE_OK ){ GeoBBox *pBBox; pBBox = (GeoBBox*)sqlite3_aggregate_context(context, sizeof(*pBBox)); if( pBBox==0 ) return; if( pBBox->isInit==0 ){ pBBox->isInit = 1; | > | 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 | static void geopolyBBoxStep( sqlite3_context *context, int argc, sqlite3_value **argv ){ RtreeCoord a[4]; int rc = SQLITE_OK; (void)argc; (void)geopolyBBox(context, argv[0], a, &rc); if( rc==SQLITE_OK ){ GeoBBox *pBBox; pBBox = (GeoBBox*)sqlite3_aggregate_context(context, sizeof(*pBBox)); if( pBBox==0 ) return; if( pBBox->isInit==0 ){ pBBox->isInit = 1; |
︙ | ︙ | |||
811 812 813 814 815 816 817 818 819 820 821 822 823 824 | ){ GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); double x0 = sqlite3_value_double(argv[1]); double y0 = sqlite3_value_double(argv[2]); int v = 0; int cnt = 0; int ii; if( p1==0 ) return; for(ii=0; ii<p1->nVertex-1; ii++){ v = pointBeneathLine(x0,y0,GeoX(p1,ii), GeoY(p1,ii), GeoX(p1,ii+1),GeoY(p1,ii+1)); if( v==2 ) break; cnt += v; } | > > | 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 | ){ GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); double x0 = sqlite3_value_double(argv[1]); double y0 = sqlite3_value_double(argv[2]); int v = 0; int cnt = 0; int ii; (void)argc; if( p1==0 ) return; for(ii=0; ii<p1->nVertex-1; ii++){ v = pointBeneathLine(x0,y0,GeoX(p1,ii), GeoY(p1,ii), GeoX(p1,ii+1),GeoY(p1,ii+1)); if( v==2 ) break; cnt += v; } |
︙ | ︙ | |||
850 851 852 853 854 855 856 857 858 859 860 861 862 863 | static void geopolyWithinFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0); if( p1 && p2 ){ int x = geopolyOverlap(p1, p2); if( x<0 ){ sqlite3_result_error_nomem(context); }else{ sqlite3_result_int(context, x==2 ? 1 : x==4 ? 2 : 0); } | > | 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 | static void geopolyWithinFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0); (void)argc; if( p1 && p2 ){ int x = geopolyOverlap(p1, p2); if( x<0 ){ sqlite3_result_error_nomem(context); }else{ sqlite3_result_int(context, x==2 ? 1 : x==4 ? 2 : 0); } |
︙ | ︙ | |||
1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 | static void geopolyOverlapFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0); if( p1 && p2 ){ int x = geopolyOverlap(p1, p2); if( x<0 ){ sqlite3_result_error_nomem(context); }else{ sqlite3_result_int(context, x); } } sqlite3_free(p1); sqlite3_free(p2); } /* ** Enable or disable debugging output */ static void geopolyDebugFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ #ifdef GEOPOLY_ENABLE_DEBUG geo_debug = sqlite3_value_int(argv[0]); #endif } /* ** This function is the implementation of both the xConnect and xCreate ** methods of the geopoly virtual table. ** | > > > > > | 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 | static void geopolyOverlapFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0); (void)argc; if( p1 && p2 ){ int x = geopolyOverlap(p1, p2); if( x<0 ){ sqlite3_result_error_nomem(context); }else{ sqlite3_result_int(context, x); } } sqlite3_free(p1); sqlite3_free(p2); } /* ** Enable or disable debugging output */ static void geopolyDebugFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ (void)context; (void)argc; #ifdef GEOPOLY_ENABLE_DEBUG geo_debug = sqlite3_value_int(argv[0]); #else (void)argv; #endif } /* ** This function is the implementation of both the xConnect and xCreate ** methods of the geopoly virtual table. ** |
︙ | ︙ | |||
1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 | int rc = SQLITE_OK; Rtree *pRtree; sqlite3_int64 nDb; /* Length of string argv[1] */ sqlite3_int64 nName; /* Length of string argv[2] */ sqlite3_str *pSql; char *zSql; int ii; sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); /* Allocate the sqlite3_vtab structure */ nDb = strlen(argv[1]); nName = strlen(argv[2]); pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2); | > | 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 | int rc = SQLITE_OK; Rtree *pRtree; sqlite3_int64 nDb; /* Length of string argv[1] */ sqlite3_int64 nName; /* Length of string argv[2] */ sqlite3_str *pSql; char *zSql; int ii; (void)pAux; sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); /* Allocate the sqlite3_vtab structure */ nDb = strlen(argv[1]); nName = strlen(argv[2]); pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2); |
︙ | ︙ | |||
1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 | int argc, sqlite3_value **argv /* Parameters to the query plan */ ){ Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; RtreeNode *pRoot = 0; int rc = SQLITE_OK; int iCell = 0; rtreeReference(pRtree); /* Reset the cursor to the same state as rtreeOpen() leaves it in. */ resetCursor(pCsr); pCsr->iStrategy = idxNum; | > | 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 | int argc, sqlite3_value **argv /* Parameters to the query plan */ ){ Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; RtreeNode *pRoot = 0; int rc = SQLITE_OK; int iCell = 0; (void)idxStr; rtreeReference(pRtree); /* Reset the cursor to the same state as rtreeOpen() leaves it in. */ resetCursor(pCsr); pCsr->iStrategy = idxNum; |
︙ | ︙ | |||
1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 | ** ------------------------------------------------ */ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int ii; int iRowidTerm = -1; int iFuncTerm = -1; int idxNum = 0; for(ii=0; ii<pIdxInfo->nConstraint; ii++){ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii]; if( !p->usable ) continue; if( p->iColumn<0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ iRowidTerm = ii; break; | > | 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 | ** ------------------------------------------------ */ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int ii; int iRowidTerm = -1; int iFuncTerm = -1; int idxNum = 0; (void)tab; for(ii=0; ii<pIdxInfo->nConstraint; ii++){ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii]; if( !p->usable ) continue; if( p->iColumn<0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ iRowidTerm = ii; break; |
︙ | ︙ | |||
1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 | static int geopolyFindFunction( sqlite3_vtab *pVtab, int nArg, const char *zName, void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void **ppArg ){ if( sqlite3_stricmp(zName, "geopoly_overlap")==0 ){ *pxFunc = geopolyOverlapFunc; *ppArg = 0; return SQLITE_INDEX_CONSTRAINT_FUNCTION; } if( sqlite3_stricmp(zName, "geopoly_within")==0 ){ *pxFunc = geopolyWithinFunc; | > > | 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 | static int geopolyFindFunction( sqlite3_vtab *pVtab, int nArg, const char *zName, void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void **ppArg ){ (void)pVtab; (void)nArg; if( sqlite3_stricmp(zName, "geopoly_overlap")==0 ){ *pxFunc = geopolyOverlapFunc; *ppArg = 0; return SQLITE_INDEX_CONSTRAINT_FUNCTION; } if( sqlite3_stricmp(zName, "geopoly_within")==0 ){ *pxFunc = geopolyWithinFunc; |
︙ | ︙ | |||
1786 1787 1788 1789 1790 1791 1792 | static const struct { void (*xStep)(sqlite3_context*,int,sqlite3_value**); void (*xFinal)(sqlite3_context*); const char *zName; } aAgg[] = { { geopolyBBoxStep, geopolyBBoxFinal, "geopoly_group_bbox" }, }; | | | 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 | static const struct { void (*xStep)(sqlite3_context*,int,sqlite3_value**); void (*xFinal)(sqlite3_context*); const char *zName; } aAgg[] = { { geopolyBBoxStep, geopolyBBoxFinal, "geopoly_group_bbox" }, }; unsigned int i; for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){ int enc; if( aFunc[i].bPure ){ enc = SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS; }else{ enc = SQLITE_UTF8|SQLITE_DIRECTONLY; } |
︙ | ︙ |
Changes to ext/rtree/rtree.c.
︙ | ︙ | |||
497 498 499 500 501 502 503 | ** Functions to deserialize a 16 bit integer, 32 bit real number and ** 64 bit integer. The deserialized value is returned. */ static int readInt16(u8 *p){ return (p[0]<<8) + p[1]; } static void readCoord(u8 *p, RtreeCoord *pCoord){ | | | 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 | ** Functions to deserialize a 16 bit integer, 32 bit real number and ** 64 bit integer. The deserialized value is returned. */ static int readInt16(u8 *p){ return (p[0]<<8) + p[1]; } static void readCoord(u8 *p, RtreeCoord *pCoord){ assert( (((sqlite3_uint64)p)&3)==0 ); /* p is always 4-byte aligned */ #if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 pCoord->u = _byteswap_ulong(*(u32*)p); #elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 pCoord->u = __builtin_bswap32(*(u32*)p); #elif SQLITE_BYTEORDER==4321 pCoord->u = *(u32*)p; #else |
︙ | ︙ | |||
551 552 553 554 555 556 557 | */ static void writeInt16(u8 *p, int i){ p[0] = (i>> 8)&0xFF; p[1] = (i>> 0)&0xFF; } static int writeCoord(u8 *p, RtreeCoord *pCoord){ u32 i; | | | 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 | */ static void writeInt16(u8 *p, int i){ p[0] = (i>> 8)&0xFF; p[1] = (i>> 0)&0xFF; } static int writeCoord(u8 *p, RtreeCoord *pCoord){ u32 i; assert( (((sqlite3_uint64)p)&3)==0 ); /* p is always 4-byte aligned */ assert( sizeof(RtreeCoord)==4 ); assert( sizeof(u32)==4 ); #if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 i = __builtin_bswap32(pCoord->u); memcpy(p, &i, 4); #elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 i = _byteswap_ulong(pCoord->u); |
︙ | ︙ | |||
1279 1280 1281 1282 1283 1284 1285 | ** in a coordinate pair. But make pCellData point to the lower bound. */ pCellData += 8 + 4*(p->iCoord&0xfe); assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE || p->op==RTREE_FALSE ); | | | 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 | ** in a coordinate pair. But make pCellData point to the lower bound. */ pCellData += 8 + 4*(p->iCoord&0xfe); assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE || p->op==RTREE_FALSE ); assert( (((sqlite3_uint64)pCellData)&3)==0 ); /* 4-byte aligned */ switch( p->op ){ case RTREE_TRUE: return; /* Always satisfied */ case RTREE_FALSE: break; /* Never satisfied */ case RTREE_EQ: RTREE_DECODE_COORD(eInt, pCellData, val); /* val now holds the lower bound of the coordinate pair */ if( p->u.rValue>=val ){ |
︙ | ︙ | |||
1332 1333 1334 1335 1336 1337 1338 | ){ RtreeDValue xN; /* Coordinate value converted to a double */ assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE || p->op==RTREE_FALSE ); pCellData += 8 + p->iCoord*4; | | | 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 | ){ RtreeDValue xN; /* Coordinate value converted to a double */ assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE || p->op==RTREE_FALSE ); pCellData += 8 + p->iCoord*4; assert( (((sqlite3_uint64)pCellData)&3)==0 ); /* 4-byte aligned */ RTREE_DECODE_COORD(eInt, pCellData, xN); switch( p->op ){ case RTREE_TRUE: return; /* Always satisfied */ case RTREE_FALSE: break; /* Never satisfied */ case RTREE_LE: if( xN <= p->u.rValue ) return; break; case RTREE_LT: if( xN < p->u.rValue ) return; break; case RTREE_GE: if( xN >= p->u.rValue ) return; break; |
︙ | ︙ |
Changes to ext/session/sessionat.test.
︙ | ︙ | |||
239 240 241 242 243 244 245 246 247 248 249 250 251 252 | } proc xConfict {args} { return "OMIT" } do_test $tn.6.3 { sqlite3changeset_apply db $cinv xConflict execsql { SELECT * FROM t7 } } {1 1 ccc 2 2 ccc 3 3 ccc} }] } catch { db close } catch { db2 close } sqlite3_shutdown test_sqlite3_log | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 | } proc xConfict {args} { return "OMIT" } do_test $tn.6.3 { sqlite3changeset_apply db $cinv xConflict execsql { SELECT * FROM t7 } } {1 1 ccc 2 2 ccc 3 3 ccc} #----------------------------------------------------------------------- reset_test do_execsql_test $tn.7.0 { CREATE TABLE t8(a PRIMARY KEY, b, c); } do_execsql_test -db db2 $tn.7.1 { CREATE TABLE t8(a PRIMARY KEY, b, c, d DEFAULT 'D', e DEFAULT 'E'); } do_then_apply_sql { INSERT INTO t8 VALUES(1, 2, 3); INSERT INTO t8 VALUES(4, 5, 6); } do_execsql_test $tn.7.2.1 { SELECT * FROM t8 } {1 2 3 4 5 6} do_execsql_test -db db2 $tn.7.2.2 { SELECT * FROM t8 } {1 2 3 D E 4 5 6 D E} do_then_apply_sql { UPDATE t8 SET c=45 WHERE a=4; } do_execsql_test $tn.7.3.1 { SELECT * FROM t8 } {1 2 3 4 5 45} do_execsql_test -db db2 $tn.7.3.2 { SELECT * FROM t8 } {1 2 3 D E 4 5 45 D E} #----------------------------------------------------------------------- reset_test do_execsql_test $tn.8.0 { CREATE TABLE t9(a PRIMARY KEY, b, c, d, e, f, g, h); } do_execsql_test -db db2 $tn.8.1 { CREATE TABLE t9(a PRIMARY KEY, b, c, d, e, f, g, h, i, j, k, l); } do_then_apply_sql { INSERT INTO t9 VALUES(1, 2, 3, 4, 5, 6, 7, 8); } do_then_apply_sql { UPDATE t9 SET h=450 WHERE a=1 } do_execsql_test -db db2 $tn.8.2 { SELECT * FROM t9 } {1 2 3 4 5 6 7 450 {} {} {} {}} do_then_apply_sql { UPDATE t9 SET h=NULL } do_execsql_test -db db2 $tn.8.2 { SELECT * FROM t9 } {1 2 3 4 5 6 7 {} {} {} {} {}} }] } catch { db close } catch { db2 close } sqlite3_shutdown test_sqlite3_log |
︙ | ︙ |
Changes to ext/session/sqlite3session.c.
︙ | ︙ | |||
1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 | sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */ sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */ ){ sqlite3_session *pSession; int nDb = sqlite3Strlen30(zDb); assert( sqlite3_mutex_held(db->mutex) ); for(pSession=(sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){ SessionTable *pTab; /* If this session is attached to a different database ("main", "temp" ** etc.), or if it is not currently enabled, there is nothing to do. Skip ** to the next session object attached to this database. */ | > > | 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 | sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */ sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */ ){ sqlite3_session *pSession; int nDb = sqlite3Strlen30(zDb); assert( sqlite3_mutex_held(db->mutex) ); (void)iKey1; (void)iKey2; for(pSession=(sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){ SessionTable *pTab; /* If this session is attached to a different database ("main", "temp" ** etc.), or if it is not currently enabled, there is nothing to do. Skip ** to the next session object attached to this database. */ |
︙ | ︙ | |||
1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 | return SQLITE_OK; } static int sessionDiffCount(void *pCtx){ SessionDiffCtx *p = (SessionDiffCtx*)pCtx; return p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt); } static int sessionDiffDepth(void *pCtx){ return 0; } /* ** Install the diff hooks on the session object passed as the only ** argument. */ | > | 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 | return SQLITE_OK; } static int sessionDiffCount(void *pCtx){ SessionDiffCtx *p = (SessionDiffCtx*)pCtx; return p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt); } static int sessionDiffDepth(void *pCtx){ (void)pCtx; return 0; } /* ** Install the diff hooks on the session object passed as the only ** argument. */ |
︙ | ︙ | |||
1644 1645 1646 1647 1648 1649 1650 | zRet = sqlite3_mprintf("0"); } return zRet; } static char *sessionSelectFindNew( | < | 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 | zRet = sqlite3_mprintf("0"); } return zRet; } static char *sessionSelectFindNew( const char *zDb1, /* Pick rows in this db only */ const char *zDb2, /* But not in this one */ const char *zTbl, /* Table name */ const char *zExpr ){ char *zRet = sqlite3_mprintf( "SELECT * FROM \"%w\".\"%w\" WHERE NOT EXISTS (" |
︙ | ︙ | |||
1668 1669 1670 1671 1672 1673 1674 | sqlite3_session *pSession, SessionTable *pTab, const char *zDb1, const char *zDb2, char *zExpr ){ int rc = SQLITE_OK; | | | 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 | sqlite3_session *pSession, SessionTable *pTab, const char *zDb1, const char *zDb2, char *zExpr ){ int rc = SQLITE_OK; char *zStmt = sessionSelectFindNew(zDb1, zDb2, pTab->zName,zExpr); if( zStmt==0 ){ rc = SQLITE_NOMEM; }else{ sqlite3_stmt *pStmt; rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0); if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 | p->apValue[i+p->nCol] = 0; } } }else if( p->bInvert ){ if( p->op==SQLITE_INSERT ) p->op = SQLITE_DELETE; else if( p->op==SQLITE_DELETE ) p->op = SQLITE_INSERT; } } return SQLITE_ROW; } /* ** Advance the changeset iterator to the next change. | > > > > > > > > > > > > > > > > | 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 | p->apValue[i+p->nCol] = 0; } } }else if( p->bInvert ){ if( p->op==SQLITE_INSERT ) p->op = SQLITE_DELETE; else if( p->op==SQLITE_DELETE ) p->op = SQLITE_INSERT; } /* If this is an UPDATE that is part of a changeset, then check that ** there are no fields in the old.* record that are not (a) PK fields, ** or (b) also present in the new.* record. ** ** Such records are technically corrupt, but the rebaser was at one ** point generating them. Under most circumstances this is benign, but ** can cause spurious SQLITE_RANGE errors when applying the changeset. */ if( p->bPatchset==0 && p->op==SQLITE_UPDATE){ for(i=0; i<p->nCol; i++){ if( p->abPK[i]==0 && p->apValue[i+p->nCol]==0 ){ sqlite3ValueFree(p->apValue[i]); p->apValue[i] = 0; } } } } return SQLITE_ROW; } /* ** Advance the changeset iterator to the next change. |
︙ | ︙ | |||
4169 4170 4171 4172 4173 4174 4175 | ** not require a reset(). ** ** If the iterator currently points to an INSERT record, bind values from the ** new.* record to the SELECT statement. Or, if it points to a DELETE or ** UPDATE, bind values from the old.* record. */ static int sessionSeekToRow( | < | 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 | ** not require a reset(). ** ** If the iterator currently points to an INSERT record, bind values from the ** new.* record to the SELECT statement. Or, if it points to a DELETE or ** UPDATE, bind values from the old.* record. */ static int sessionSeekToRow( sqlite3_changeset_iter *pIter, /* Changeset iterator */ u8 *abPK, /* Primary key flags array */ sqlite3_stmt *pSelect /* SELECT statement from sessionSelectRow() */ ){ int rc; /* Return code */ int nCol; /* Number of columns in table */ int op; /* Changset operation (SQLITE_UPDATE etc.) */ |
︙ | ︙ | |||
4299 4300 4301 4302 4303 4304 4305 | assert( eType==SQLITE_CHANGESET_CONFLICT || eType==SQLITE_CHANGESET_DATA ); assert( SQLITE_CHANGESET_CONFLICT+1==SQLITE_CHANGESET_CONSTRAINT ); assert( SQLITE_CHANGESET_DATA+1==SQLITE_CHANGESET_NOTFOUND ); /* Bind the new.* PRIMARY KEY values to the SELECT statement. */ if( pbReplace ){ | | | 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 | assert( eType==SQLITE_CHANGESET_CONFLICT || eType==SQLITE_CHANGESET_DATA ); assert( SQLITE_CHANGESET_CONFLICT+1==SQLITE_CHANGESET_CONSTRAINT ); assert( SQLITE_CHANGESET_DATA+1==SQLITE_CHANGESET_NOTFOUND ); /* Bind the new.* PRIMARY KEY values to the SELECT statement. */ if( pbReplace ){ rc = sessionSeekToRow(pIter, p->abPK, p->pSelect); }else{ rc = SQLITE_OK; } if( rc==SQLITE_ROW ){ /* There exists another row with the new.* primary key. */ pIter->pConflict = p->pSelect; |
︙ | ︙ | |||
4473 4474 4475 4476 4477 4478 4479 | }else{ assert( op==SQLITE_INSERT ); if( p->bStat1 ){ /* Check if there is a conflicting row. For sqlite_stat1, this needs ** to be done using a SELECT, as there is no PRIMARY KEY in the ** database schema to throw an exception if a duplicate is inserted. */ | | | 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 | }else{ assert( op==SQLITE_INSERT ); if( p->bStat1 ){ /* Check if there is a conflicting row. For sqlite_stat1, this needs ** to be done using a SELECT, as there is no PRIMARY KEY in the ** database schema to throw an exception if a duplicate is inserted. */ rc = sessionSeekToRow(pIter, p->abPK, p->pSelect); if( rc==SQLITE_ROW ){ rc = SQLITE_CONSTRAINT; sqlite3_reset(p->pSelect); } } if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
5519 5520 5521 5522 5523 5524 5525 | for(i=0; i<pIter->nCol; i++){ int n1 = sessionSerialLen(a1); int n2 = sessionSerialLen(a2); if( pIter->abPK[i] || a2[0]==0 ){ if( !pIter->abPK[i] && a1[0] ) bData = 1; memcpy(pOut, a1, n1); pOut += n1; | | | 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 | for(i=0; i<pIter->nCol; i++){ int n1 = sessionSerialLen(a1); int n2 = sessionSerialLen(a2); if( pIter->abPK[i] || a2[0]==0 ){ if( !pIter->abPK[i] && a1[0] ) bData = 1; memcpy(pOut, a1, n1); pOut += n1; }else if( a2[0]!=0xFF && a1[0] ){ bData = 1; memcpy(pOut, a2, n2); pOut += n2; }else{ *pOut++ = '\0'; } a1 += n1; |
︙ | ︙ |
Changes to ext/session/test_session.c.
︙ | ︙ | |||
94 95 96 97 98 99 100 101 102 103 104 105 106 107 | /* Delete the session object */ sqlite3session_delete(pSession); return rc; } /************************************************************************/ /* ** Tclcmd: sql_exec_changeset DB SQL */ static int SQLITE_TCLAPI test_sql_exec_changeset( void * clientData, Tcl_Interp *interp, int objc, | > > > > > > > > > > > > > | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | /* Delete the session object */ sqlite3session_delete(pSession); return rc; } /************************************************************************/ #ifdef SQLITE_DEBUG static int sqlite3_test_changeset(int, void *, char **); static void assert_changeset_is_ok(int n, void *p){ int rc = 0; char *z = 0; rc = sqlite3_test_changeset(n, p, &z); assert( z==0 ); } #else # define assert_changeset_is_ok(n,p) #endif /* ** Tclcmd: sql_exec_changeset DB SQL */ static int SQLITE_TCLAPI test_sql_exec_changeset( void * clientData, Tcl_Interp *interp, int objc, |
︙ | ︙ | |||
123 124 125 126 127 128 129 130 131 132 133 134 135 136 | rc = sql_exec_changeset(db, zSql, &nChangeset, &pChangeset); if( rc!=SQLITE_OK ){ Tcl_ResetResult(interp); Tcl_AppendResult(interp, "error in sql_exec_changeset()", 0); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pChangeset, nChangeset)); sqlite3_free(pChangeset); return TCL_OK; } | > | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | rc = sql_exec_changeset(db, zSql, &nChangeset, &pChangeset); if( rc!=SQLITE_OK ){ Tcl_ResetResult(interp); Tcl_AppendResult(interp, "error in sql_exec_changeset()", 0); return TCL_ERROR; } assert_changeset_is_ok(nChangeset, pChangeset); Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pChangeset, nChangeset)); sqlite3_free(pChangeset); return TCL_OK; } |
︙ | ︙ | |||
291 292 293 294 295 296 297 298 299 300 301 302 303 304 | if( iSub==7 ){ rc = sqlite3session_patchset(pSession, &o.n, &o.p); }else{ rc = sqlite3session_changeset(pSession, &o.n, &o.p); } } if( rc==SQLITE_OK ){ Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(o.p, o.n)); } sqlite3_free(o.p); if( rc!=SQLITE_OK ){ return test_session_error(interp, rc, 0); } break; | > | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | if( iSub==7 ){ rc = sqlite3session_patchset(pSession, &o.n, &o.p); }else{ rc = sqlite3session_changeset(pSession, &o.n, &o.p); } } if( rc==SQLITE_OK ){ assert_changeset_is_ok(o.n, o.p); Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(o.p, o.n)); } sqlite3_free(o.p); if( rc!=SQLITE_OK ){ return test_session_error(interp, rc, 0); } break; |
︙ | ︙ | |||
949 950 951 952 953 954 955 956 957 958 959 960 961 962 | ); }else{ rc = sqlite3changeset_invert(sIn.nData, sIn.aData, &sOut.n, &sOut.p); } if( rc!=SQLITE_OK ){ rc = test_session_error(interp, rc, 0); }else{ Tcl_SetObjResult(interp,Tcl_NewByteArrayObj((unsigned char*)sOut.p,sOut.n)); } sqlite3_free(sOut.p); return rc; } /* | > | 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 | ); }else{ rc = sqlite3changeset_invert(sIn.nData, sIn.aData, &sOut.n, &sOut.p); } if( rc!=SQLITE_OK ){ rc = test_session_error(interp, rc, 0); }else{ assert_changeset_is_ok(sOut.n, sOut.p); Tcl_SetObjResult(interp,Tcl_NewByteArrayObj((unsigned char*)sOut.p,sOut.n)); } sqlite3_free(sOut.p); return rc; } /* |
︙ | ︙ | |||
997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 | sLeft.nData, sLeft.aData, sRight.nData, sRight.aData, &sOut.n, &sOut.p ); } if( rc!=SQLITE_OK ){ rc = test_session_error(interp, rc, 0); }else{ Tcl_SetObjResult(interp,Tcl_NewByteArrayObj((unsigned char*)sOut.p,sOut.n)); } sqlite3_free(sOut.p); return rc; } /* | > | 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 | sLeft.nData, sLeft.aData, sRight.nData, sRight.aData, &sOut.n, &sOut.p ); } if( rc!=SQLITE_OK ){ rc = test_session_error(interp, rc, 0); }else{ assert_changeset_is_ok(sOut.n, sOut.p); Tcl_SetObjResult(interp,Tcl_NewByteArrayObj((unsigned char*)sOut.p,sOut.n)); } sqlite3_free(sOut.p); return rc; } /* |
︙ | ︙ | |||
1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 | testStreamOutput, (void*)&sOut ); }else{ rc = sqlite3rebaser_rebase(p, sStr.nData, sStr.aData, &sOut.n, &sOut.p); } if( rc==SQLITE_OK ){ Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(sOut.p, sOut.n)); } sqlite3_free(sOut.p); break; } } | > | 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 | testStreamOutput, (void*)&sOut ); }else{ rc = sqlite3rebaser_rebase(p, sStr.nData, sStr.aData, &sOut.n, &sOut.p); } if( rc==SQLITE_OK ){ assert_changeset_is_ok(sOut.n, sOut.p); Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(sOut.p, sOut.n)); } sqlite3_free(sOut.p); break; } } |
︙ | ︙ | |||
1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 | Tcl_CreateObjCommand(interp, Tcl_GetString(objv[1]), test_rebaser_cmd, (ClientData)pNew, test_rebaser_del ); Tcl_SetObjResult(interp, objv[1]); return TCL_OK; } /* ** tclcmd: sqlite3rebaser_configure OP VALUE */ static int SQLITE_TCLAPI test_sqlite3session_config( void * clientData, Tcl_Interp *interp, | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 | Tcl_CreateObjCommand(interp, Tcl_GetString(objv[1]), test_rebaser_cmd, (ClientData)pNew, test_rebaser_del ); Tcl_SetObjResult(interp, objv[1]); return TCL_OK; } /* ** Run some sanity checks on the changeset in nChangeset byte buffer ** pChangeset. If any fail, return a non-zero value and, optionally, ** set output variable (*pzErr) to point to a buffer containing an ** English language error message describing the problem. In this ** case it is the responsibility of the caller to free the buffer ** using sqlite3_free(). ** ** Or, if the changeset appears to be well-formed, this function ** returns SQLITE_OK and sets (*pzErr) to NULL. */ static int sqlite3_test_changeset( int nChangeset, void *pChangeset, char **pzErr ){ sqlite3_changeset_iter *pIter = 0; char *zErr = 0; int rc = SQLITE_OK; int bPatch = (nChangeset>0 && ((char*)pChangeset)[0]=='P'); rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset); if( rc==SQLITE_OK ){ int rc2; while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter) ){ unsigned char *aPk = 0; int nCol = 0; int op = 0; const char *zTab = 0; sqlite3changeset_pk(pIter, &aPk, &nCol); sqlite3changeset_op(pIter, &zTab, &nCol, &op, 0); if( op==SQLITE_UPDATE ){ int iCol; for(iCol=0; iCol<nCol; iCol++){ sqlite3_value *pNew = 0; sqlite3_value *pOld = 0; sqlite3changeset_new(pIter, iCol, &pNew); sqlite3changeset_old(pIter, iCol, &pOld); if( aPk[iCol] ){ if( pOld==0 ) rc = SQLITE_ERROR; }else if( bPatch ){ if( pOld ) rc = SQLITE_ERROR; }else{ if( (pOld==0)!=(pNew==0) ) rc = SQLITE_ERROR; } if( rc!=SQLITE_OK ){ zErr = sqlite3_mprintf( "unexpected SQLITE_UPDATE (bPatch=%d pk=%d pOld=%d pNew=%d)", bPatch, (int)aPk[iCol], pOld!=0, pNew!=0 ); break; } } } } rc2 = sqlite3changeset_finalize(pIter); if( rc==SQLITE_OK ){ rc = rc2; } } *pzErr = zErr; return rc; } /* ** test_changeset CHANGESET */ static int SQLITE_TCLAPI test_changeset( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ void *pChangeset = 0; /* Buffer containing changeset */ int nChangeset = 0; /* Size of buffer aChangeset in bytes */ int rc = SQLITE_OK; char *z = 0; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "CHANGESET"); return TCL_ERROR; } pChangeset = (void *)Tcl_GetByteArrayFromObj(objv[1], &nChangeset); Tcl_ResetResult(interp); rc = sqlite3_test_changeset(nChangeset, pChangeset, &z); if( rc!=SQLITE_OK ){ char *zErr = sqlite3_mprintf("(%d) - \"%s\"", rc, z); Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1)); sqlite3_free(zErr); } sqlite3_free(z); return rc ? TCL_ERROR : TCL_OK; } /* ** tclcmd: sqlite3rebaser_configure OP VALUE */ static int SQLITE_TCLAPI test_sqlite3session_config( void * clientData, Tcl_Interp *interp, |
︙ | ︙ | |||
1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 | { "sqlite3changeset_apply", test_sqlite3changeset_apply }, { "sqlite3changeset_apply_v2", test_sqlite3changeset_apply_v2 }, { "sqlite3changeset_apply_replace_all", test_sqlite3changeset_apply_replace_all }, { "sql_exec_changeset", test_sql_exec_changeset }, { "sqlite3rebaser_create", test_sqlite3rebaser_create }, { "sqlite3session_config", test_sqlite3session_config }, }; int i; for(i=0; i<sizeof(aCmd)/sizeof(struct Cmd); i++){ struct Cmd *p = &aCmd[i]; Tcl_CreateObjCommand(interp, p->zCmd, p->xProc, 0, 0); } return TCL_OK; } #endif /* SQLITE_TEST && SQLITE_SESSION && SQLITE_PREUPDATE_HOOK */ | > | 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 | { "sqlite3changeset_apply", test_sqlite3changeset_apply }, { "sqlite3changeset_apply_v2", test_sqlite3changeset_apply_v2 }, { "sqlite3changeset_apply_replace_all", test_sqlite3changeset_apply_replace_all }, { "sql_exec_changeset", test_sql_exec_changeset }, { "sqlite3rebaser_create", test_sqlite3rebaser_create }, { "sqlite3session_config", test_sqlite3session_config }, { "test_changeset", test_changeset }, }; int i; for(i=0; i<sizeof(aCmd)/sizeof(struct Cmd); i++){ struct Cmd *p = &aCmd[i]; Tcl_CreateObjCommand(interp, p->zCmd, p->xProc, 0, 0); } return TCL_OK; } #endif /* SQLITE_TEST && SQLITE_SESSION && SQLITE_PREUPDATE_HOOK */ |
Changes to ext/wasm/GNUmakefile.
︙ | ︙ | |||
10 11 12 13 14 15 16 17 18 19 | # Primary targets: # # default, all = build in dev mode # # o0, o1, o2, o3, os, oz = full clean/rebuild with the -Ox level indicated # by the target name. Rebuild is necessary for all components to get # the desired optimization level. # # dist = create end user deliverables. Add dist.build=oX to build # with a specific optimization level, where oX is one of the | > > > > > | > > > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | # Primary targets: # # default, all = build in dev mode # # o0, o1, o2, o3, os, oz = full clean/rebuild with the -Ox level indicated # by the target name. Rebuild is necessary for all components to get # the desired optimization level. # # quick, q = do just a minimal build (sqlite3.js/wasm, tester1) for # faster development-mode turnaround. # # qo2, qoz = a combination of quick+o2/oz. # # dist = create end user deliverables. Add dist.build=oX to build # with a specific optimization level, where oX is one of the # above-listed o? or qo? target names. # # snapshot = like dist, but uses a zip file name which clearly # marks it as a prerelease/snapshot build. # # clean = clean up # # Required tools beyond those needed for the canonical builds: # # - Emscripten SDK: https://emscripten.org/docs/getting_started/downloads.html # - The bash shell |
︙ | ︙ | |||
201 202 203 204 205 206 207 | # seems likely to. # # c-pp.c was written specifically for the sqlite project's JavaScript # builds but is maintained as a standalone project: # https://fossil.wanderinghorse.net/r/c-pp bin.c-pp := ./c-pp $(bin.c-pp): c-pp.c $(sqlite3.c) $(MAKEFILE) | | > > > | 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | # seems likely to. # # c-pp.c was written specifically for the sqlite project's JavaScript # builds but is maintained as a standalone project: # https://fossil.wanderinghorse.net/r/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 \ -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_WAL -DSQLITE_THREADSAFE=0 \ -DSQLITE_TEMP_STORE=3 define C-PP.FILTER # Create $2 from $1 using $(bin.c-pp) # $1 = Input file: c-pp -f $(1).js # $2 = Output file: c-pp -o $(2).js # $3 = optional c-pp -D... flags $(2): $(1) $$(MAKEFILE) $$(bin.c-pp) $$(bin.c-pp) -f $(1) -o $$@ $(3) |
︙ | ︙ | |||
303 304 305 306 307 308 309 | define COPY_XAPI sqlite3-api.ext.jses += $$(dir.dout)/$$(notdir $(1)) $$(dir.dout)/$$(notdir $(1)): $(1) $$(MAKEFILE) cp $$< $$@ endef $(foreach X,$(SOAP.js) $(sqlite3-worker1.js) $(sqlite3-worker1-promiser.js),\ $(eval $(call COPY_XAPI,$(X)))) | | > | 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | define COPY_XAPI sqlite3-api.ext.jses += $$(dir.dout)/$$(notdir $(1)) $$(dir.dout)/$$(notdir $(1)): $(1) $$(MAKEFILE) cp $$< $$@ endef $(foreach X,$(SOAP.js) $(sqlite3-worker1.js) $(sqlite3-worker1-promiser.js),\ $(eval $(call COPY_XAPI,$(X)))) all quick: $(sqlite3-api.ext.jses) q: quick # sqlite3-api.js.in = the generated 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): $(sqlite3-api.jses) $(MAKEFILE) @echo "Making $@..." |
︙ | ︙ | |||
448 449 450 451 452 453 454 | emcc.jsflags += -sWASM_BIGINT=$(emcc.WASM_BIGINT) emcc.jsflags += -sMODULARIZE emcc.jsflags += -sSTRICT_JS emcc.jsflags += -sDYNAMIC_EXECUTION=0 emcc.jsflags += -sNO_POLYFILL emcc.jsflags += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.api) emcc.exportedRuntimeMethods := \ | | < < < | 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 | emcc.jsflags += -sWASM_BIGINT=$(emcc.WASM_BIGINT) emcc.jsflags += -sMODULARIZE emcc.jsflags += -sSTRICT_JS emcc.jsflags += -sDYNAMIC_EXECUTION=0 emcc.jsflags += -sNO_POLYFILL emcc.jsflags += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.api) emcc.exportedRuntimeMethods := \ -sEXPORTED_RUNTIME_METHODS=wasmMemory # wasmMemory ==> required by our code for use with -sIMPORTED_MEMORY emcc.jsflags += $(emcc.exportedRuntimeMethods) emcc.jsflags += -sUSE_CLOSURE_COMPILER=0 emcc.jsflags += -sIMPORTED_MEMORY emcc.environment := -sENVIRONMENT=web,worker ######################################################################## # -sINITIAL_MEMORY: How much memory we need to start with is governed |
︙ | ︙ | |||
484 485 486 487 488 489 490 | $(error emcc.INITIAL_MEMORY must be one of: 8, 16, 32, 64, 96, 128 (megabytes)) endif emcc.jsflags += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.$(emcc.INITIAL_MEMORY)) # /INITIAL_MEMORY ######################################################################## emcc.jsflags += $(emcc.environment) | | | 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 | $(error emcc.INITIAL_MEMORY must be one of: 8, 16, 32, 64, 96, 128 (megabytes)) endif emcc.jsflags += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.$(emcc.INITIAL_MEMORY)) # /INITIAL_MEMORY ######################################################################## emcc.jsflags += $(emcc.environment) emcc.jsflags += -sSTACK_SIZE=512KB # ^^^ ACHTUNG: emsdk 3.1.27 reduced the default stack size from 5MB to # a mere 64KB, which leads to silent memory corruption via the kvvfs # VFS, which requires twice that for its xRead() and xWrite() methods. ######################################################################## # $(sqlite3.js.init-func) is the name Emscripten assigns our exported # module init/load function. This symbol name is hard-coded in # $(extern-post-js.js) as well as in numerous docs. |
︙ | ︙ | |||
589 590 591 592 593 594 595 596 597 598 599 600 601 | # overwritten version of that function and cannot "export default" # twice. Because of this, we have to sed $(sqlite3.mjs) to remove the # _first_ instance (only) of /^export default/. # # Upstream RFE: # https://github.com/emscripten-core/emscripten/issues/18237 ######################################################################## define SQLITE3.xJS.RECIPE @echo "Building $@ ..." $(emcc.bin) -o $@ $(emcc_opt_full) $(emcc.flags) \ $(emcc.jsflags) \ $(pre-post-sqlite3.flags.$(1)) $(emcc.flags.sqlite3.$(1)) \ $(cflags.common) $(SQLITE_OPT) $(sqlite3-wasm.c) | > > > > > > > > > > > > > | < < < < < < < | | > | 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 | # overwritten version of that function and cannot "export default" # twice. Because of this, we have to sed $(sqlite3.mjs) to remove the # _first_ instance (only) of /^export default/. # # Upstream RFE: # https://github.com/emscripten-core/emscripten/issues/18237 ######################################################################## # SQLITE3.xJS.EXPORT-DEFAULT is part of SQLITE3[-WASMFS].xJS.RECIPE, # factored into a separate piece to avoid code duplication. $1 is # the build mode: one of (vanilla, esm). define SQLITE3.xJS.ESM-EXPORT-DEFAULT if [ esm = $(1) ]; then \ echo "Fragile workaround for an Emscripten annoyance. See SQLITE3.xJS.RECIPE."; \ sed -i -e '0,/^export default/{/^export default/d;}' $@ || exit $$?; \ if ! grep -q '^export default' $@; then \ echo "Cannot find export default." 1>&2; \ exit 1; \ fi; \ fi endef define SQLITE3.xJS.RECIPE @echo "Building $@ ..." $(emcc.bin) -o $@ $(emcc_opt_full) $(emcc.flags) \ $(emcc.jsflags) \ $(pre-post-sqlite3.flags.$(1)) $(emcc.flags.sqlite3.$(1)) \ $(cflags.common) $(SQLITE_OPT) $(sqlite3-wasm.c) @$(call SQLITE3.xJS.ESM-EXPORT-DEFAULT,$(1)) chmod -x $(sqlite3.wasm) $(maybe-wasm-strip) $(sqlite3.wasm) @ls -la $@ $(sqlite3.wasm) endef emcc.flags.sqlite3.vanilla := emcc.flags.sqlite3.esm := -sEXPORT_ES6 -sUSE_ES6_IMPORT_META $(sqlite3.js): $(call SQLITE3.xJS.RECIPE,vanilla) $(sqlite3.mjs): $(call SQLITE3.xJS.RECIPE,esm) ######################################################################## # We have to ensure that we do not build both $(sqlite3.js) and # $(sqlite3.mjs) in parallel because both result in the creation of # $(sqlite3.wasm). We have no(?) way to build just the .mjs file # without also building the .wasm file. i.e. we're building # $(sqlite3.wasm) twice, but that's apparently unavoidable (and # harmless, just a waste of build time). $(sqlite3.wasm): $(sqlite3.js) $(sqlite3.mjs): $(sqlite3.js) CLEAN_FILES += $(sqlite3.js) $(sqlite3.mjs) $(sqlite3.wasm) all: $(sqlite3.js) $(sqlite3.mjs) quick: $(sqlite3.js) quick: $(sqlite3.mjs) # for the sake of the snapshot build # End main $(sqlite3.js) build ######################################################################## ######################################################################## # 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 |
︙ | ︙ | |||
654 655 656 657 658 659 660 | # pieces each time is an unnecessary time sink. batch: batch-runner.list all: batch # end batch-runner.js ######################################################################## # Wasmified speedtest1 is our primary benchmarking tool. # | | | | | | | | | | | | | | | | | | | | | | | | 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 | # pieces each time is an unnecessary time sink. batch: batch-runner.list all: batch # end batch-runner.js ######################################################################## # Wasmified speedtest1 is our primary benchmarking tool. # # 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 := emcc.speedtest1 += -sENVIRONMENT=web emcc.speedtest1 += -sALLOW_MEMORY_GROWTH emcc.speedtest1 += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.$(emcc.INITIAL_MEMORY)) emcc.speedtest1.common += -sINVOKE_RUN=0 emcc.speedtest1.common += --no-entry #emcc.speedtest1.common += -flto emcc.speedtest1.common += -sABORTING_MALLOC emcc.speedtest1.common += -sSTRICT_JS emcc.speedtest1.common += -sMODULARIZE emcc.speedtest1.common += -Wno-limited-postlink-optimizations 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) emcc.speedtest1.common += -sALLOW_TABLE_GROWTH 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 # Re -sEXIT_RUNTIME=1 vs 0: if it's 1 and speedtest1 crashes, we get # this error from emscripten: # # > native function `free` called after runtime exit (use # NO_EXIT_RUNTIME to keep it alive after main() exits)) |
︙ | ︙ | |||
701 702 703 704 705 706 707 | # which runs speedtest1 multiple times. $(EXPORTED_FUNCTIONS.speedtest1): $(EXPORTED_FUNCTIONS.api) @echo "Making $@ ..." @{ echo _wasm_main; cat $(EXPORTED_FUNCTIONS.api); } > $@ speedtest1.js := $(dir.dout)/speedtest1.js speedtest1.wasm := $(dir.dout)/speedtest1.wasm | | | | | 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 | # which runs speedtest1 multiple times. $(EXPORTED_FUNCTIONS.speedtest1): $(EXPORTED_FUNCTIONS.api) @echo "Making $@ ..." @{ echo _wasm_main; cat $(EXPORTED_FUNCTIONS.api); } > $@ speedtest1.js := $(dir.dout)/speedtest1.js speedtest1.wasm := $(dir.dout)/speedtest1.wasm cflags.speedtest1 := $(cflags.common) -DSQLITE_SPEEDTEST1_WASM speedtest1.cses := $(speedtest1.c) $(sqlite3-wasm.c) $(eval $(call call-make-pre-js,speedtest1,vanilla)) $(speedtest1.js): $(MAKEFILE) $(speedtest1.cses) \ $(pre-post-speedtest1.deps.vanilla) \ $(EXPORTED_FUNCTIONS.speedtest1) @echo "Building $@ ..." $(emcc.bin) \ $(emcc.speedtest1) $(emcc.speedtest1.common) \ $(cflags.speedtest1) $(pre-post-speedtest1.flags.vanilla) \ $(SQLITE_OPT) \ $(speedtest1.exit-runtime0) \ -o $@ $(speedtest1.cses) -lm $(maybe-wasm-strip) $(speedtest1.wasm) ls -la $@ $(speedtest1.wasm) speedtest1: $(speedtest1.js) |
︙ | ︙ | |||
744 745 746 747 748 749 750 | # # To create those, we filter tester1.c-pp.js with $(bin.c-pp)... $(eval $(call C-PP.FILTER,tester1.c-pp.js,tester1.js)) $(eval $(call C-PP.FILTER,tester1.c-pp.js,tester1.mjs,$(c-pp.D.esm))) $(eval $(call C-PP.FILTER,tester1.c-pp.html,tester1.html)) $(eval $(call C-PP.FILTER,tester1.c-pp.html,tester1-esm.html,$(c-pp.D.esm))) tester1: tester1.js tester1.mjs tester1.html tester1-esm.html | | | > | > > | > > | 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 | # # To create those, we filter tester1.c-pp.js with $(bin.c-pp)... $(eval $(call C-PP.FILTER,tester1.c-pp.js,tester1.js)) $(eval $(call C-PP.FILTER,tester1.c-pp.js,tester1.mjs,$(c-pp.D.esm))) $(eval $(call C-PP.FILTER,tester1.c-pp.html,tester1.html)) $(eval $(call C-PP.FILTER,tester1.c-pp.html,tester1-esm.html,$(c-pp.D.esm))) tester1: tester1.js tester1.mjs tester1.html tester1-esm.html all quick: tester1 ######################################################################## # Convenience rules to rebuild with various -Ox levels. Much # experimentation shows -O2 to be the clear winner in terms of speed. # Note that build times with anything higher than -O0 are somewhat # painful. .PHONY: o0 o1 o2 o3 os oz o-xtra := #o-xtra ?= -flto # ^^^^ -flto can have a considerably performance boost at -O0 but # doubles the build time and seems to have negligible, if any, effect # on higher optimization levels. o0: clean $(MAKE) -e "emcc_opt=-O0" o1: clean $(MAKE) -e "emcc_opt=-O1 $(o-xtra)" o2: clean $(MAKE) -j2 -e "emcc_opt=-O2 $(o-xtra)" qo2: clean $(MAKE) -j2 -e "emcc_opt=-O2 $(o-xtra)" quick o3: clean $(MAKE) -e "emcc_opt=-O3 $(o-xtra)" os: clean @echo "WARNING: -Os can result in a build with mysteriously missing pieces!" $(MAKE) -e "emcc_opt=-Os $(o-xtra)" oz: clean $(MAKE) -j2 -e "emcc_opt=-Oz $(o-xtra)" qoz: clean $(MAKE) -j2 -e "emcc_opt=-Oz $(o-xtra)" quick ######################################################################## # Sub-makes... # sqlite.org/fiddle application... include fiddle.make |
︙ | ︙ |
Changes to ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api.
︙ | ︙ | |||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | _sqlite3_column_count _sqlite3_column_double _sqlite3_column_int _sqlite3_column_int64 _sqlite3_column_name _sqlite3_column_text _sqlite3_column_type _sqlite3_compileoption_get _sqlite3_compileoption_used _sqlite3_complete _sqlite3_create_collation _sqlite3_create_collation_v2 _sqlite3_create_function _sqlite3_create_function_v2 _sqlite3_create_module _sqlite3_create_module_v2 _sqlite3_create_window_function _sqlite3_data_count _sqlite3_db_filename _sqlite3_db_handle _sqlite3_db_name _sqlite3_db_status _sqlite3_declare_vtab _sqlite3_deserialize _sqlite3_drop_modules _sqlite3_errmsg _sqlite3_error_offset _sqlite3_errstr _sqlite3_exec _sqlite3_expanded_sql _sqlite3_extended_errcode _sqlite3_extended_result_codes _sqlite3_file_control _sqlite3_finalize _sqlite3_free _sqlite3_get_auxdata _sqlite3_initialize _sqlite3_libversion _sqlite3_libversion_number _sqlite3_malloc _sqlite3_malloc64 _sqlite3_msize _sqlite3_open _sqlite3_open_v2 _sqlite3_overload_function _sqlite3_prepare_v2 _sqlite3_prepare_v3 _sqlite3_randomness _sqlite3_realloc _sqlite3_realloc64 _sqlite3_reset _sqlite3_result_blob _sqlite3_result_double _sqlite3_result_error _sqlite3_result_error_code _sqlite3_result_error_nomem _sqlite3_result_error_toobig _sqlite3_result_int _sqlite3_result_int64 _sqlite3_result_null _sqlite3_result_pointer _sqlite3_result_subtype _sqlite3_result_text _sqlite3_result_zeroblob _sqlite3_result_zeroblob64 _sqlite3_serialize _sqlite3_set_auxdata _sqlite3_shutdown _sqlite3_sourceid _sqlite3_sql _sqlite3_status _sqlite3_status64 _sqlite3_step _sqlite3_stmt_status _sqlite3_strglob _sqlite3_stricmp _sqlite3_strlike _sqlite3_strnicmp _sqlite3_table_column_metadata _sqlite3_total_changes _sqlite3_total_changes64 _sqlite3_trace_v2 _sqlite3_uri_boolean _sqlite3_uri_int64 _sqlite3_uri_key _sqlite3_uri_parameter _sqlite3_user_data _sqlite3_value_blob _sqlite3_value_bytes | > > > > > > > > > > > > > | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | _sqlite3_column_count _sqlite3_column_double _sqlite3_column_int _sqlite3_column_int64 _sqlite3_column_name _sqlite3_column_text _sqlite3_column_type _sqlite3_column_value _sqlite3_compileoption_get _sqlite3_compileoption_used _sqlite3_complete _sqlite3_create_collation _sqlite3_create_collation_v2 _sqlite3_create_function _sqlite3_create_function_v2 _sqlite3_create_module _sqlite3_create_module_v2 _sqlite3_create_window_function _sqlite3_data_count _sqlite3_db_filename _sqlite3_db_handle _sqlite3_db_name _sqlite3_db_status _sqlite3_declare_vtab _sqlite3_deserialize _sqlite3_drop_modules _sqlite3_errcode _sqlite3_errmsg _sqlite3_error_offset _sqlite3_errstr _sqlite3_exec _sqlite3_expanded_sql _sqlite3_extended_errcode _sqlite3_extended_result_codes _sqlite3_file_control _sqlite3_finalize _sqlite3_free _sqlite3_get_auxdata _sqlite3_initialize _sqlite3_keyword_count _sqlite3_keyword_name _sqlite3_keyword_check _sqlite3_last_insert_rowid _sqlite3_libversion _sqlite3_libversion_number _sqlite3_limit _sqlite3_malloc _sqlite3_malloc64 _sqlite3_msize _sqlite3_open _sqlite3_open_v2 _sqlite3_overload_function _sqlite3_prepare_v2 _sqlite3_prepare_v3 _sqlite3_progress_handler _sqlite3_randomness _sqlite3_realloc _sqlite3_realloc64 _sqlite3_reset _sqlite3_result_blob _sqlite3_result_double _sqlite3_result_error _sqlite3_result_error_code _sqlite3_result_error_nomem _sqlite3_result_error_toobig _sqlite3_result_int _sqlite3_result_int64 _sqlite3_result_null _sqlite3_result_pointer _sqlite3_result_subtype _sqlite3_result_text _sqlite3_result_zeroblob _sqlite3_result_zeroblob64 _sqlite3_serialize _sqlite3_set_authorizer _sqlite3_set_auxdata _sqlite3_set_last_insert_rowid _sqlite3_shutdown _sqlite3_sourceid _sqlite3_sql _sqlite3_status _sqlite3_status64 _sqlite3_step _sqlite3_stmt_isexplain _sqlite3_stmt_readonly _sqlite3_stmt_status _sqlite3_strglob _sqlite3_stricmp _sqlite3_strlike _sqlite3_strnicmp _sqlite3_table_column_metadata _sqlite3_total_changes _sqlite3_total_changes64 _sqlite3_trace_v2 _sqlite3_txn_state _sqlite3_uri_boolean _sqlite3_uri_int64 _sqlite3_uri_key _sqlite3_uri_parameter _sqlite3_user_data _sqlite3_value_blob _sqlite3_value_bytes |
︙ | ︙ |
Changes to ext/wasm/api/README.md.
︙ | ︙ | |||
75 76 77 78 79 80 81 | `sqlite3-api-worker1.js`. - **`sqlite3-worker1-promiser.js`**\ Is likewise not part of the amalgamated sources and provides a Promise-based interface into the Worker #1 API. This is a far user-friendlier way to interface with databases running in a Worker thread. - **`sqlite3-v-helper.js`**\ | | | | | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | `sqlite3-api-worker1.js`. - **`sqlite3-worker1-promiser.js`**\ Is likewise not part of the amalgamated sources and provides a Promise-based interface into the Worker #1 API. This is a far user-friendlier way to interface with databases running in a Worker thread. - **`sqlite3-v-helper.js`**\ Installs `sqlite3.vfs` and `sqlite3.vtab`, namespaces which contain helpers for use by downstream code which creates `sqlite3_vfs` and `sqlite3_module` implementations. - **`sqlite3-vfs-opfs.c-pp.js`**\ is an sqlite3 VFS implementation which supports Google Chrome's Origin-Private FileSystem (OPFS) as a storage layer to provide persistent storage for database files in a browser. It requires... - **`sqlite3-opfs-async-proxy.js`**\ is the asynchronous backend part of the OPFS proxy. It speaks directly to the (async) OPFS API and channels those results back |
︙ | ︙ |
Changes to ext/wasm/api/sqlite3-api-glue.js.
︙ | ︙ | |||
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 'use strict'; const toss = (...args)=>{throw new Error(args.join(' '))}; const toss3 = sqlite3.SQLite3Error.toss; const capi = sqlite3.capi, wasm = sqlite3.wasm, util = sqlite3.util; self.WhWasmUtilInstaller(wasm); delete self.WhWasmUtilInstaller; /** Install JS<->C struct bindings for the non-opaque struct types we need... */ sqlite3.StructBinder = self.Jaccwabyt({ heap: 0 ? wasm.memory : wasm.heap8u, alloc: wasm.alloc, dealloc: wasm.dealloc, bigIntEnabled: wasm.bigIntEnabled, memberPrefix: /* Never change this: this prefix is baked into any amount of code and client-facing docs. */ '$' }); delete self.Jaccwabyt; {/* Convert Arrays and certain TypedArrays to strings for 'string:flexible'-type arguments */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | 'use strict'; const toss = (...args)=>{throw new Error(args.join(' '))}; const toss3 = sqlite3.SQLite3Error.toss; const capi = sqlite3.capi, wasm = sqlite3.wasm, util = sqlite3.util; self.WhWasmUtilInstaller(wasm); delete self.WhWasmUtilInstaller; { /** Find a mapping for SQLITE_WASM_DEALLOC, which the API guarantees is a WASM pointer to the same underlying function as wasm.dealloc() (noting that wasm.dealloc() is permitted to be a JS wrapper around the WASM function). There is unfortunately no O(1) algorithm for finding this pointer: we have to walk the WASM indirect function table to find it. However, experience indicates that that particular function is always very close to the front of the table (it's been entry #3 in all relevant tests). */ const dealloc = wasm.exports[sqlite3.config.deallocExportName]; const nFunc = wasm.functionTable().length; let i; for(i = 0; i < nFunc; ++i){ const e = wasm.functionEntry(i); if(dealloc === e){ capi.SQLITE_WASM_DEALLOC = i; break; } } if(dealloc !== wasm.functionEntry(capi.SQLITE_WASM_DEALLOC)){ toss("Internal error: cannot find function pointer for SQLITE_WASM_DEALLOC."); } } /** Signatures for the WASM-exported C-side functions. Each entry is an array with 2+ elements: [ "c-side name", "result type" (wasm.xWrap() syntax), [arg types in xWrap() syntax] // ^^^ this needn't strictly be an array: it can be subsequent // elements instead: [x,y,z] is equivalent to x,y,z ] Note that support for the API-specific data types in the result/argument type strings gets plugged in at a later phase in the API initialization process. */ wasm.bindingSignatures = [ // Please keep these sorted by function name! ["sqlite3_aggregate_context","void*", "sqlite3_context*", "int"], /* sqlite3_bind_blob() and sqlite3_bind_text() have hand-written bindings to permit more flexible inputs. */ ["sqlite3_bind_double","int", "sqlite3_stmt*", "int", "f64"], ["sqlite3_bind_int","int", "sqlite3_stmt*", "int", "int"], ["sqlite3_bind_null",undefined, "sqlite3_stmt*", "int"], ["sqlite3_bind_parameter_count", "int", "sqlite3_stmt*"], ["sqlite3_bind_parameter_index","int", "sqlite3_stmt*", "string"], ["sqlite3_bind_pointer", "int", "sqlite3_stmt*", "int", "*", "string:static", "*"], ["sqlite3_busy_handler","int", [ "sqlite3*", new wasm.xWrap.FuncPtrAdapter({ signature: 'i(pi)', contextKey: (argIndex,argv)=>'sqlite3@'+argv[0] }), "*" ]], ["sqlite3_busy_timeout","int", "sqlite3*", "int"], ["sqlite3_close_v2", "int", "sqlite3*"], ["sqlite3_changes", "int", "sqlite3*"], ["sqlite3_clear_bindings","int", "sqlite3_stmt*"], ["sqlite3_collation_needed", "int", "sqlite3*", "*", "*"/*=>v(ppis)*/], ["sqlite3_column_blob","*", "sqlite3_stmt*", "int"], ["sqlite3_column_bytes","int", "sqlite3_stmt*", "int"], ["sqlite3_column_count", "int", "sqlite3_stmt*"], ["sqlite3_column_double","f64", "sqlite3_stmt*", "int"], ["sqlite3_column_int","int", "sqlite3_stmt*", "int"], ["sqlite3_column_name","string", "sqlite3_stmt*", "int"], ["sqlite3_column_text","string", "sqlite3_stmt*", "int"], ["sqlite3_column_type","int", "sqlite3_stmt*", "int"], ["sqlite3_column_value","sqlite3_value*", "sqlite3_stmt*", "int"], ["sqlite3_compileoption_get", "string", "int"], ["sqlite3_compileoption_used", "int", "string"], ["sqlite3_complete", "int", "string:flexible"], /* sqlite3_create_function(), sqlite3_create_function_v2(), and sqlite3_create_window_function() use hand-written bindings to simplify handling of their function-type arguments. */ /* sqlite3_create_collation() and sqlite3_create_collation_v2() use hand-written bindings to simplify passing of the callback function. ["sqlite3_create_collation", "int", "sqlite3*", "string", "int",//SQLITE_UTF8 is the only legal value "*", "*"], ["sqlite3_create_collation_v2", "int", "sqlite3*", "string", "int",//SQLITE_UTF8 is the only legal value "*", "*", "*"], */ ["sqlite3_data_count", "int", "sqlite3_stmt*"], ["sqlite3_db_filename", "string", "sqlite3*", "string"], ["sqlite3_db_handle", "sqlite3*", "sqlite3_stmt*"], ["sqlite3_db_name", "string", "sqlite3*", "int"], ["sqlite3_db_status", "int", "sqlite3*", "int", "*", "*", "int"], ["sqlite3_errcode", "int", "sqlite3*"], ["sqlite3_errmsg", "string", "sqlite3*"], ["sqlite3_error_offset", "int", "sqlite3*"], ["sqlite3_errstr", "string", "int"], /*["sqlite3_exec", "int", "sqlite3*", "string", "*", "*", "**" Handled seperately to perform translation of the callback into a WASM-usable one. ],*/ ["sqlite3_expanded_sql", "string", "sqlite3_stmt*"], ["sqlite3_extended_errcode", "int", "sqlite3*"], ["sqlite3_extended_result_codes", "int", "sqlite3*", "int"], ["sqlite3_file_control", "int", "sqlite3*", "string", "int", "*"], ["sqlite3_finalize", "int", "sqlite3_stmt*"], ["sqlite3_free", undefined,"*"], ["sqlite3_get_auxdata", "*", "sqlite3_context*", "int"], ["sqlite3_initialize", undefined], /*["sqlite3_interrupt", undefined, "sqlite3*" ^^^ we cannot actually currently support this because JS is single-threaded and we don't have a portable way to access a DB from 2 SharedWorkers concurrently. ],*/ ["sqlite3_keyword_count", "int"], ["sqlite3_keyword_name", "int", ["int", "**", "*"]], ["sqlite3_keyword_check", "int", ["string", "int"]], ["sqlite3_libversion", "string"], ["sqlite3_libversion_number", "int"], ["sqlite3_limit", "int", ["sqlite3*", "int", "int"]], ["sqlite3_malloc", "*","int"], ["sqlite3_open", "int", "string", "*"], ["sqlite3_open_v2", "int", "string", "*", "int", "string"], /* sqlite3_prepare_v2() and sqlite3_prepare_v3() are handled separately due to us requiring two different sets of semantics for those, depending on how their SQL argument is provided. */ /* sqlite3_randomness() uses a hand-written wrapper to extend the range of supported argument types. */ [ "sqlite3_progress_handler", undefined, [ "sqlite3*", "int", new wasm.xWrap.FuncPtrAdapter({ name: 'xProgressHandler', signature: 'i(p)', bindScope: 'context', contextKey: (argIndex,argv)=>'sqlite3@'+argv[0] }), "*" ] ], ["sqlite3_realloc", "*","*","int"], ["sqlite3_reset", "int", "sqlite3_stmt*"], ["sqlite3_result_blob", undefined, "sqlite3_context*", "*", "int", "*"], ["sqlite3_result_double", undefined, "sqlite3_context*", "f64"], ["sqlite3_result_error", undefined, "sqlite3_context*", "string", "int"], ["sqlite3_result_error_code", undefined, "sqlite3_context*", "int"], ["sqlite3_result_error_nomem", undefined, "sqlite3_context*"], ["sqlite3_result_error_toobig", undefined, "sqlite3_context*"], ["sqlite3_result_int", undefined, "sqlite3_context*", "int"], ["sqlite3_result_null", undefined, "sqlite3_context*"], ["sqlite3_result_pointer", undefined, "sqlite3_context*", "*", "string:static", "*"], ["sqlite3_result_subtype", undefined, "sqlite3_value*", "int"], ["sqlite3_result_text", undefined, "sqlite3_context*", "string", "int", "*"], ["sqlite3_result_zeroblob", undefined, "sqlite3_context*", "int"], ["sqlite3_set_auxdata", undefined, "sqlite3_context*", "int", "*", "*"/* => v(*) */], ["sqlite3_shutdown", undefined], ["sqlite3_sourceid", "string"], ["sqlite3_sql", "string", "sqlite3_stmt*"], ["sqlite3_status", "int", "int", "*", "*", "int"], ["sqlite3_step", "int", "sqlite3_stmt*"], ["sqlite3_stmt_isexplain", "int", ["sqlite3_stmt*"]], ["sqlite3_stmt_readonly", "int", ["sqlite3_stmt*"]], ["sqlite3_stmt_status", "int", "sqlite3_stmt*", "int", "int"], ["sqlite3_strglob", "int", "string","string"], ["sqlite3_stricmp", "int", "string", "string"], ["sqlite3_strlike", "int", "string", "string","int"], ["sqlite3_strnicmp", "int", "string", "string", "int"], ["sqlite3_table_column_metadata", "int", "sqlite3*", "string", "string", "string", "**", "**", "*", "*", "*"], ["sqlite3_total_changes", "int", "sqlite3*"], ["sqlite3_trace_v2", "int", "sqlite3*", "int", new wasm.xWrap.FuncPtrAdapter({ name: 'sqlite3_trace_v2::callback', signature: 'i(ippp)', contextKey: (argIndex, argv)=>'sqlite3@'+argv[0] }), "*"], ["sqlite3_txn_state", "int", ["sqlite3*","string"]], /* Note that sqlite3_uri_...() have very specific requirements for their first C-string arguments, so we cannot perform any value conversion on those. */ ["sqlite3_uri_boolean", "int", "sqlite3_filename", "string", "int"], ["sqlite3_uri_key", "string", "sqlite3_filename", "int"], ["sqlite3_uri_parameter", "string", "sqlite3_filename", "string"], ["sqlite3_user_data","void*", "sqlite3_context*"], ["sqlite3_value_blob", "*", "sqlite3_value*"], ["sqlite3_value_bytes","int", "sqlite3_value*"], ["sqlite3_value_double","f64", "sqlite3_value*"], ["sqlite3_value_dup", "sqlite3_value*", "sqlite3_value*"], ["sqlite3_value_free", undefined, "sqlite3_value*"], ["sqlite3_value_frombind", "int", "sqlite3_value*"], ["sqlite3_value_int","int", "sqlite3_value*"], ["sqlite3_value_nochange", "int", "sqlite3_value*"], ["sqlite3_value_numeric_type", "int", "sqlite3_value*"], ["sqlite3_value_pointer", "*", "sqlite3_value*", "string:static"], ["sqlite3_value_subtype", "int", "sqlite3_value*"], ["sqlite3_value_text", "string", "sqlite3_value*"], ["sqlite3_value_type", "int", "sqlite3_value*"], ["sqlite3_vfs_find", "*", "string"], ["sqlite3_vfs_register", "int", "sqlite3_vfs*", "int"], ["sqlite3_vfs_unregister", "int", "sqlite3_vfs*"] ]/*wasm.bindingSignatures*/; if(false && wasm.compileOptionUsed('SQLITE_ENABLE_NORMALIZE')){ /* ^^^ "the problem" is that this is an option feature and the build-time function-export list does not currently take optional features into account. */ wasm.bindingSignatures.push(["sqlite3_normalized_sql", "string", "sqlite3_stmt*"]); } /** Functions which require BigInt (int64) support are separated from the others because we need to conditionally bind them or apply dummy impls, depending on the capabilities of the environment. Note that not all of these functions directly require int64 but are only for use with APIs which require int64. For example, the vtab-related functions. */ wasm.bindingSignatures.int64 = [ ["sqlite3_bind_int64","int", ["sqlite3_stmt*", "int", "i64"]], ["sqlite3_changes64","i64", ["sqlite3*"]], ["sqlite3_column_int64","i64", ["sqlite3_stmt*", "int"]], ["sqlite3_create_module", "int", ["sqlite3*","string","sqlite3_module*","*"]], ["sqlite3_create_module_v2", "int", ["sqlite3*","string","sqlite3_module*","*","*"]], ["sqlite3_declare_vtab", "int", ["sqlite3*", "string:flexible"]], ["sqlite3_deserialize", "int", "sqlite3*", "string", "*", "i64", "i64", "int"] /* Careful! Short version: de/serialize() are problematic because they might use a different allocator than the user for managing the deserialized block. de/serialize() are ONLY safe to use with sqlite3_malloc(), sqlite3_free(), and its 64-bit variants. */, ["sqlite3_drop_modules", "int", ["sqlite3*", "**"]], ["sqlite3_last_insert_rowid", "i64", ["sqlite3*"]], ["sqlite3_malloc64", "*","i64"], ["sqlite3_msize", "i64", "*"], ["sqlite3_overload_function", "int", ["sqlite3*","string","int"]], ["sqlite3_realloc64", "*","*", "i64"], ["sqlite3_result_int64", undefined, "*", "i64"], ["sqlite3_result_zeroblob64", "int", "*", "i64"], ["sqlite3_serialize","*", "sqlite3*", "string", "*", "int"], /* sqlite3_set_authorizer() requires a hand-written binding for string conversions, so is defined elsewhere. */ ["sqlite3_set_last_insert_rowid", undefined, ["sqlite3*", "i64"]], ["sqlite3_status64", "int", "int", "*", "*", "int"], ["sqlite3_total_changes64", "i64", ["sqlite3*"]], ["sqlite3_uri_int64", "i64", ["sqlite3_filename", "string", "i64"]], ["sqlite3_value_int64","i64", "sqlite3_value*"], ["sqlite3_vtab_collation","string","sqlite3_index_info*","int"], ["sqlite3_vtab_distinct","int", "sqlite3_index_info*"], ["sqlite3_vtab_in","int", "sqlite3_index_info*", "int", "int"], ["sqlite3_vtab_in_first", "int", "sqlite3_value*", "**"], ["sqlite3_vtab_in_next", "int", "sqlite3_value*", "**"], /*["sqlite3_vtab_config" is variadic and requires a hand-written proxy.] */ ["sqlite3_vtab_nochange","int", "sqlite3_context*"], ["sqlite3_vtab_on_conflict","int", "sqlite3*"], ["sqlite3_vtab_rhs_value","int", "sqlite3_index_info*", "int", "**"] ]; /** Functions which are intended solely for API-internal use by the WASM components, not client code. These get installed into sqlite3.wasm. Some of them get exposed to clients via variants named sqlite3_js_...(). */ wasm.bindingSignatures.wasm = [ ["sqlite3_wasm_db_reset", "int", "sqlite3*"], ["sqlite3_wasm_db_vfs", "sqlite3_vfs*", "sqlite3*","string"], ["sqlite3_wasm_vfs_create_file", "int", "sqlite3_vfs*","string","*", "int"], ["sqlite3_wasm_vfs_unlink", "int", "sqlite3_vfs*","string"] ]; /** Install JS<->C struct bindings for the non-opaque struct types we need... */ sqlite3.StructBinder = self.Jaccwabyt({ heap: 0 ? wasm.memory : wasm.heap8u, alloc: wasm.alloc, dealloc: wasm.dealloc, bigIntEnabled: wasm.bigIntEnabled, memberPrefix: /* Never change this: this prefix is baked into any amount of code and client-facing docs. */ '$' }); delete self.Jaccwabyt; {/* Convert Arrays and certain TypedArrays to strings for 'string:flexible'-type arguments */ const __xString = wasm.xWrap.argAdapter('string'); wasm.xWrap.argAdapter( 'string:flexible', (v)=>__xString(util.flexibleString(v)) ); /** The 'string:static' argument adapter treats its argument as either... - WASM pointer: assumed to be a long-lived C-string which gets |
︙ | ︙ | |||
67 68 69 70 71 72 73 | */ wasm.xWrap.argAdapter( 'string:static', function(v){ if(wasm.isPtr(v)) return v; v = ''+v; let rc = this[v]; | | | | | 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 | */ wasm.xWrap.argAdapter( 'string:static', function(v){ if(wasm.isPtr(v)) return v; v = ''+v; let rc = this[v]; return rc || (this[v] = wasm.allocCString(v)); }.bind(Object.create(null)) ); }/* special-case string-type argument conversions */ if(1){// wasm.xWrap() bindings... /** Add some descriptive xWrap() aliases for '*' intended to (A) initially improve readability/correctness of capi.signatures and (B) provide automatic conversion from higher-level representations, e.g. capi.sqlite3_vfs to `sqlite3_vfs*` via capi.sqlite3_vfs.pointer. */ |
︙ | ︙ | |||
112 113 114 115 116 117 118 | */ ('sqlite3_vfs*', (v)=>{ if('string'===typeof v){ /* A NULL sqlite3_vfs pointer will be treated as the default VFS in many contexts. We specifically do not want that behavior here. */ return capi.sqlite3_vfs_find(v) | | > > > | | | | | | | | | > > | | | | | 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 | */ ('sqlite3_vfs*', (v)=>{ if('string'===typeof v){ /* A NULL sqlite3_vfs pointer will be treated as the default VFS in many contexts. We specifically do not want that behavior here. */ return capi.sqlite3_vfs_find(v) || sqlite3.SQLite3Error.toss( capi.SQLITE_NOTFOUND, "Unknown sqlite3_vfs name:", v ); } return aPtr((v instanceof (capi.sqlite3_vfs || nilType)) ? v.pointer : v); }); const __xRcPtr = wasm.xWrap.resultAdapter('*'); wasm.xWrap.resultAdapter('sqlite3*', __xRcPtr) ('sqlite3_context*', __xRcPtr) ('sqlite3_stmt*', __xRcPtr) ('sqlite3_value*', __xRcPtr) ('sqlite3_vfs*', __xRcPtr) ('void*', __xRcPtr); /** Populate api object with sqlite3_...() by binding the "raw" wasm exports into type-converting proxies using wasm.xWrap(). */ for(const e of wasm.bindingSignatures){ capi[e[0]] = wasm.xWrap.apply(null, e); } for(const e of wasm.bindingSignatures.wasm){ wasm[e[0]] = wasm.xWrap.apply(null, e); } /* For C API functions which cannot work properly unless wasm.bigIntEnabled is true, install a bogus impl which throws if called when bigIntEnabled is false. The alternative would be to elide these functions altogether, which seems likely to cause more confusion. */ const fI64Disabled = function(fname){ return ()=>toss(fname+"() is unavailable due to lack", "of BigInt support in this build."); }; for(const e of wasm.bindingSignatures.int64){ capi[e[0]] = wasm.bigIntEnabled ? wasm.xWrap.apply(null, e) : fI64Disabled(e[0]); } /* There's no need to expose bindingSignatures to clients, implicitly making it part of the public interface. */ delete wasm.bindingSignatures; if(wasm.exports.sqlite3_wasm_db_error){ const __db_err = wasm.xWrap( 'sqlite3_wasm_db_error', 'int', 'sqlite3*', 'int', 'string' ); /** Sets the given db's error state. Accepts: - (sqlite3*, int code, string msg) - (sqlite3*, Error e [,string msg = ''+e]) If passed a WasmAllocError, the message is ignored and the result code is SQLITE_NOMEM. If passed any other Error type, the result code defaults to SQLITE_ERROR unless the Error object has a resultCode property, in which case that is used (e.g. SQLite3Error has that). If passed a non-WasmAllocError exception, the message string defaults to theError.message. Returns the resulting code. Pass (pDb,0,0) to clear the error state. */ util.sqlite3_wasm_db_error = function(pDb, resultCode, message){ if(resultCode instanceof sqlite3.WasmAllocError){ resultCode = capi.SQLITE_NOMEM; message = 0 /*avoid allocating message string*/; }else if(resultCode instanceof Error){ message = message || ''+resultCode; resultCode = (resultCode.resultCode || capi.SQLITE_ERROR); } return __db_err(pDb, resultCode, message); }; }else{ util.sqlite3_wasm_db_error = function(pDb,errCode,msg){ console.warn("sqlite3_wasm_db_error() is not exported.",arguments); |
︙ | ︙ | |||
203 204 205 206 207 208 209 | */ const __dbArgcMismatch = (pDb,f,n)=>{ return sqlite3.util.sqlite3_wasm_db_error(pDb, capi.SQLITE_MISUSE, f+"() requires "+n+" argument"+ (1===n?"":'s')+"."); }; | > > > > > > > > > | | > > > | > | > > > > > > | > > > > > > > > > > > | > | > > > > > | < > > | < | | | < < < < < < | < < < | < | > > > > | | 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 | */ const __dbArgcMismatch = (pDb,f,n)=>{ return sqlite3.util.sqlite3_wasm_db_error(pDb, capi.SQLITE_MISUSE, f+"() requires "+n+" argument"+ (1===n?"":'s')+"."); }; /** Code duplication reducer for functions which take an encoding argument and require SQLITE_UTF8. Sets the db error code to SQLITE_FORMAT and returns that code. */ const __errEncoding = (pDb)=>{ return util.sqlite3_wasm_db_error( pDb, capi.SQLITE_FORMAT, "SQLITE_UTF8 is the only supported encoding." ); }; if(1){/* Bindings for sqlite3_create_collation[_v2]() */ const __collationContextKey = (argIndex,argv)=>{ return 'argv['+argIndex+']:sqlite3@'+argv[0]+ ':'+wasm.cstrToJs(argv[1]).toLowerCase() }; const __ccv2 = wasm.xWrap( 'sqlite3_create_collation_v2', 'int', 'sqlite3*','string','int','*', new wasm.xWrap.FuncPtrAdapter({ /* int(*xCompare)(void*,int,const void*,int,const void*) */ name: 'sqlite3_create_collation_v2::xCompare', signature: 'i(pipip)', bindScope: 'context', contextKey: __collationContextKey }), new wasm.xWrap.FuncPtrAdapter({ /* void(*xDestroy(void*) */ name: 'sqlite3_create_collation_v2::xDestroy', signature: 'v(p)', bindScope: 'context', contextKey: __collationContextKey }) ); /** Works exactly like C's sqlite3_create_collation_v2() except that: 1) It returns capi.SQLITE_FORMAT if the 3rd argument contains any encoding-related value other than capi.SQLITE_UTF8. No other encodings are supported. As a special case, if the bottom 4 bits of that argument are 0, SQLITE_UTF8 is assumed. 2) It accepts JS functions for its function-pointer arguments, for which it will install WASM-bound proxies. The bindings are "permanent," in that they will stay in the WASM environment until it shuts down unless the client calls this again with the same collation name and a value of 0 or null for the the function pointer(s). For consistency with the C API, it requires the same number of arguments. It returns capi.SQLITE_MISUSE if passed any other argument count. Returns 0 on success, non-0 on error, in which case the error state of pDb (of type `sqlite3*` or argument-convertible to it) may contain more information. */ capi.sqlite3_create_collation_v2 = function(pDb,zName,eTextRep,pArg,xCompare,xDestroy){ if(6!==arguments.length) return __dbArgcMismatch(pDb, 'sqlite3_create_collation_v2', 6); else if( 0 === (eTextRep & 0xf) ){ eTextRep |= capi.SQLITE_UTF8; }else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){ return __errEncoding(pDb); } let rc, pfCompare, pfDestroy; try{ rc = __ccv2(pDb, zName, eTextRep, pArg, xCompare, xDestroy); }catch(e){ rc = util.sqlite3_wasm_db_error(pDb, e); } return rc; }; capi.sqlite3_create_collation = (pDb,zName,eTextRep,pArg,xCompare)=>{ return (5===arguments.length) ? capi.sqlite3_create_collation_v2(pDb,zName,eTextRep,pArg,xCompare,0) : __dbArgcMismatch(pDb, 'sqlite3_create_collation', 5); }; }/*sqlite3_create_collation() and friends*/ if(1){/* Special-case handling of sqlite3_exec() */ const __exec = wasm.xWrap("sqlite3_exec", "int", ["sqlite3*", "string:flexible", new wasm.xWrap.FuncPtrAdapter({ signature: 'i(pipp)', bindScope: 'transient' }), "*", "**"]); /* Documented in the api object's initializer. */ capi.sqlite3_exec = function f(pDb, sql, callback, pVoid, pErrMsg){ if(f.length!==arguments.length){ return __dbArgcMismatch(pDb,"sqlite3_exec",f.length); }else if(!(callback instanceof Function)){ return __exec(pDb, sql, callback, pVoid, pErrMsg); } /* Wrap the callback in a WASM-bound function and convert the callback's `(char**)` arguments to arrays of strings... */ const cbwrap = function(pVoid, nCols, pColVals, pColNames){ let rc = capi.SQLITE_ERROR; try { |
︙ | ︙ | |||
290 291 292 293 294 295 296 | /* If we set the db error state here, the higher-level exec() call replaces it with its own, so we have no way of reporting the exception message except the console. We must not propagate exceptions through the C API. */ } return rc; }; | | < | | < < > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > | > | | | | | | > | | < | | > > > > > | | 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 | /* If we set the db error state here, the higher-level exec() call replaces it with its own, so we have no way of reporting the exception message except the console. We must not propagate exceptions through the C API. */ } return rc; }; let rc; try{ rc = __exec(pDb, sql, cbwrap, pVoid, pErrMsg); }catch(e){ rc = util.sqlite3_wasm_db_error(pDb, capi.SQLITE_ERROR, "Error running exec(): "+e); } return rc; }; }/*sqlite3_exec() proxy*/; if(1){/* Special-case handling of sqlite3_create_function_v2() and sqlite3_create_window_function() */ /* Maintenance reminder: FuncPtrAdapter is not expressive enough to be able to perform these mappings. */ const sqlite3CreateFunction = wasm.xWrap( "sqlite3_create_function_v2", "int", ["sqlite3*", "string"/*funcName*/, "int"/*nArg*/, "int"/*eTextRep*/, "*"/*pApp*/, "*"/*xStep*/,"*"/*xFinal*/, "*"/*xValue*/, "*"/*xDestroy*/] ); const sqlite3CreateWindowFunction = wasm.xWrap( "sqlite3_create_window_function", "int", ["sqlite3*", "string"/*funcName*/, "int"/*nArg*/, "int"/*eTextRep*/, "*"/*pApp*/, "*"/*xStep*/,"*"/*xFinal*/, "*"/*xValue*/, "*"/*xInverse*/, "*"/*xDestroy*/] ); const __xFunc = function(callback){ return function(pCtx, argc, pArgv){ try{ capi.sqlite3_result_js( pCtx, callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv)) ); }catch(e){ //console.error('xFunc() caught:',e); capi.sqlite3_result_error_js(pCtx, e); } }; }; const __xInverseAndStep = function(callback){ return function(pCtx, argc, pArgv){ try{ callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv)) } catch(e){ capi.sqlite3_result_error_js(pCtx, e) } }; }; const __xFinalAndValue = function(callback){ return function(pCtx){ try{ capi.sqlite3_result_js(pCtx, callback(pCtx)) } catch(e){ capi.sqlite3_result_error_js(pCtx, e) } }; }; const __xDestroy = function(callback){ return function(pVoid){ try{ callback(pVoid) } catch(e){ console.error("UDF xDestroy method threw:",e) } }; }; const __xMap = Object.assign(Object.create(null), { xFunc: {sig:'v(pip)', f:__xFunc}, xStep: {sig:'v(pip)', f:__xInverseAndStep}, xInverse: {sig:'v(pip)', f:__xInverseAndStep}, xFinal: {sig:'v(p)', f:__xFinalAndValue}, xValue: {sig:'v(p)', f:__xFinalAndValue}, xDestroy: {sig:'v(p)', f:__xDestroy} }); /* Internal helper for sqlite3_create_function() and friends. */ const __xWrapFuncs = function(theKeys, theFuncs, tgtUninst){ const rc = [] for(const k of theKeys){ let fArg = theFuncs[k]; if('function'===typeof fArg){ const w = __xMap[k] || toss3("Internal error in __xWrapFuncs: invalid key:",k); fArg = wasm.installFunction(w.sig, w.f(fArg)); tgtUninst.push(fArg); } rc.push(fArg); } return rc; }; /* Documented in the api object's initializer. */ capi.sqlite3_create_function_v2 = function f( pDb, funcName, nArg, eTextRep, pApp, xFunc, //void (*xFunc)(sqlite3_context*,int,sqlite3_value**) xStep, //void (*xStep)(sqlite3_context*,int,sqlite3_value**) xFinal, //void (*xFinal)(sqlite3_context*) xDestroy //void (*xDestroy)(void*) ){ if( f.length!==arguments.length ){ return __dbArgcMismatch(pDb,"sqlite3_create_function_v2",f.length); }else if( 0 === (eTextRep & 0xf) ){ eTextRep |= capi.SQLITE_UTF8; }else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){ return __errEncoding(pDb); } /* Wrap the callbacks in a WASM-bound functions... */ const uninstall = [/*funcs to uninstall on error*/]; let rc; try{ const funcArgs = __xWrapFuncs(['xFunc','xStep','xFinal','xDestroy'], {xFunc, xStep, xFinal, xDestroy}, uninstall); rc = sqlite3CreateFunction(pDb, funcName, nArg, eTextRep, pApp, ...funcArgs); }catch(e){ console.error("sqlite3_create_function_v2() setup threw:",e); for(let v of uninstall){ wasm.uninstallFunction(v); |
︙ | ︙ | |||
499 500 501 502 503 504 505 | pDb, funcName, nArg, eTextRep, pApp, xStep, //void (*xStep)(sqlite3_context*,int,sqlite3_value**) xFinal, //void (*xFinal)(sqlite3_context*) xValue, //void (*xFinal)(sqlite3_context*) xInverse,//void (*xStep)(sqlite3_context*,int,sqlite3_value**) xDestroy //void (*xDestroy)(void*) ){ | | > > > > > | < < < < < < < < < < < < < < | | < | < < < < < < < | < < | < < < < < | < < < | < < > | > | 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 | pDb, funcName, nArg, eTextRep, pApp, xStep, //void (*xStep)(sqlite3_context*,int,sqlite3_value**) xFinal, //void (*xFinal)(sqlite3_context*) xValue, //void (*xFinal)(sqlite3_context*) xInverse,//void (*xStep)(sqlite3_context*,int,sqlite3_value**) xDestroy //void (*xDestroy)(void*) ){ if( f.length!==arguments.length ){ return __dbArgcMismatch(pDb,"sqlite3_create_window_function",f.length); }else if( 0 === (eTextRep & 0xf) ){ eTextRep |= capi.SQLITE_UTF8; }else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){ return __errEncoding(pDb); } /* Wrap the callbacks in a WASM-bound functions... */ const uninstall = [/*funcs to uninstall on error*/]; let rc; try{ const funcArgs = __xWrapFuncs(['xStep','xFinal','xValue','xInverse','xDestroy'], {xStep, xFinal, xValue, xInverse, xDestroy}, uninstall); rc = sqlite3CreateWindowFunction(pDb, funcName, nArg, eTextRep, pApp, ...funcArgs); }catch(e){ console.error("sqlite3_create_window_function() setup threw:",e); for(let v of uninstall){ wasm.uninstallFunction(v); } rc = util.sqlite3_wasm_db_error(pDb, capi.SQLITE_ERROR, "Creation of UDF threw: "+e.message); } return rc; }; /** A _deprecated_ alias for capi.sqlite3_result_js() which predates the addition of that function in the public API. */ capi.sqlite3_create_function_v2.udfSetResult = capi.sqlite3_create_function.udfSetResult = capi.sqlite3_create_window_function.udfSetResult = capi.sqlite3_result_js; /** A _deprecated_ alias for capi.sqlite3_values_to_js() which predates the addition of that function in the public API. */ capi.sqlite3_create_function_v2.udfConvertArgs = capi.sqlite3_create_function.udfConvertArgs = capi.sqlite3_create_window_function.udfConvertArgs = capi.sqlite3_values_to_js; /** A _deprecated_ alias for capi.sqlite3_result_error_js() which predates the addition of that function in the public API. */ capi.sqlite3_create_function_v2.udfSetError = capi.sqlite3_create_function.udfSetError = capi.sqlite3_create_window_function.udfSetError = capi.sqlite3_result_error_js; }/*sqlite3_create_function_v2() and sqlite3_create_window_function() proxies*/; if(1){/* Special-case handling of sqlite3_prepare_v2() and sqlite3_prepare_v3() */ /** Helper for string:flexible conversions which require a byte-length counterpart argument. Passed a value and its ostensible length, this function returns [V,N], where V is either v or a transformed copy of v and N is either n, -1, or the byte length of v (if it's a byte array). */ |
︙ | ︙ | |||
604 605 606 607 608 609 610 | } return [v, n]; }; /** Scope-local holder of the two impls of sqlite3_prepare_v2/v3(). */ | | | | | | | | | | | | | | | | | | | | | | | | | | | > | 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 | } return [v, n]; }; /** Scope-local holder of the two impls of sqlite3_prepare_v2/v3(). */ const __prepare = { /** This binding expects a JS string as its 2nd argument and null as its final argument. In order to compile multiple statements from a single string, the "full" impl (see below) must be used. */ basic: wasm.xWrap('sqlite3_prepare_v3', "int", ["sqlite3*", "string", "int"/*ignored for this impl!*/, "int", "**", "**"/*MUST be 0 or null or undefined!*/]), /** Impl which requires that the 2nd argument be a pointer to the SQL string, instead of being converted to a string. This variant is necessary for cases where we require a non-NULL value for the final argument (exec()'ing multiple statements from one input string). For simpler cases, where only the first statement in the SQL string is required, the wrapper named sqlite3_prepare_v2() is sufficient and easier to use because it doesn't require dealing with pointers. */ full: wasm.xWrap('sqlite3_prepare_v3', "int", ["sqlite3*", "*", "int", "int", "**", "**"]) }; /* Documented in the capi object's initializer. */ capi.sqlite3_prepare_v3 = function f(pDb, sql, sqlLen, prepFlags, ppStmt, pzTail){ if(f.length!==arguments.length){ return __dbArgcMismatch(pDb,"sqlite3_prepare_v3",f.length); } const [xSql, xSqlLen] = __flexiString(sql, sqlLen); |
︙ | ︙ | |||
654 655 656 657 658 659 660 | /* Documented in the capi object's initializer. */ capi.sqlite3_prepare_v2 = function f(pDb, sql, sqlLen, ppStmt, pzTail){ return (f.length===arguments.length) ? capi.sqlite3_prepare_v3(pDb, sql, sqlLen, 0, ppStmt, pzTail) : __dbArgcMismatch(pDb,"sqlite3_prepare_v2",f.length); }; | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 | /* Documented in the capi object's initializer. */ capi.sqlite3_prepare_v2 = function f(pDb, sql, sqlLen, ppStmt, pzTail){ return (f.length===arguments.length) ? capi.sqlite3_prepare_v3(pDb, sql, sqlLen, 0, ppStmt, pzTail) : __dbArgcMismatch(pDb,"sqlite3_prepare_v2",f.length); }; }/*sqlite3_prepare_v2/v3()*/ {/*sqlite3_bind_text/blob()*/ const __bindText = wasm.xWrap("sqlite3_bind_text", "int", [ "sqlite3_stmt*", "int", "string", "int", "*" ]); const __bindBlob = wasm.xWrap("sqlite3_bind_blob", "int", [ "sqlite3_stmt*", "int", "*", "int", "*" ]); /** Documented in the capi object's initializer. */ capi.sqlite3_bind_text = function f(pStmt, iCol, text, nText, xDestroy){ if(f.length!==arguments.length){ return __dbArgcMismatch(capi.sqlite3_db_handle(pStmt), "sqlite3_bind_text", f.length); }else if(wasm.isPtr(text) || null===text){ return __bindText(pStmt, iCol, text, nText, xDestroy); }else if(text instanceof ArrayBuffer){ text = new Uint8Array(text); }else if(Array.isArray(pMem)){ text = pMem.join(''); } let p, n; try{ if(util.isSQLableTypedArray(text)){ p = wasm.allocFromTypedArray(text); n = text.byteLength; }else if('string'===typeof text){ [p, n] = wasm.allocCString(text); }else{ return util.sqlite3_wasm_db_error( capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE, "Invalid 3rd argument type for sqlite3_bind_text()." ); } return __bindText(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC); }catch(e){ wasm.dealloc(p); return util.sqlite3_wasm_db_error( capi.sqlite3_db_handle(pStmt), e ); } }/*sqlite3_bind_text()*/; /** Documented in the capi object's initializer. */ capi.sqlite3_bind_blob = function f(pStmt, iCol, pMem, nMem, xDestroy){ if(f.length!==arguments.length){ return __dbArgcMismatch(capi.sqlite3_db_handle(pStmt), "sqlite3_bind_blob", f.length); }else if(wasm.isPtr(pMem) || null===pMem){ return __bindBlob(pStmt, iCol, pMem, nMem, xDestroy); }else if(pMem instanceof ArrayBuffer){ pMem = new Uint8Array(pMem); }else if(Array.isArray(pMem)){ pMem = pMem.join(''); } let p, n; try{ if(util.isBindableTypedArray(pMem)){ p = wasm.allocFromTypedArray(pMem); n = nMem>=0 ? nMem : pMem.byteLength; }else if('string'===typeof pMem){ [p, n] = wasm.allocCString(pMem); }else{ return util.sqlite3_wasm_db_error( capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE, "Invalid 3rd argument type for sqlite3_bind_blob()." ); } return __bindBlob(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC); }catch(e){ wasm.dealloc(p); return util.sqlite3_wasm_db_error( capi.sqlite3_db_handle(pStmt), e ); } }/*sqlite3_bind_blob()*/; }/*sqlite3_bind_text/blob()*/ {/* sqlite3_set_authorizer() */ const __ssa = wasm.xWrap("sqlite3_set_authorizer", 'int', [ "sqlite3*", new wasm.xWrap.FuncPtrAdapter({ name: "sqlite3_set_authorizer::xAuth", signature: "i(pi"+"ssss)", contextKey: (argIndex, argv)=>argv[0/*(sqlite3*)*/] }), "*" ]); capi.sqlite3_set_authorizer = function(pDb, xAuth, pUserData){ if(3!==arguments.length) return __dbArgcMismatch(pDb, 'sqlite3_set_authorizer', 3); if(xAuth instanceof Function){ const xProxy = xAuth; /* Create a proxy which will receive the C-strings from WASM and convert them to JS strings for the client-supplied function. */ xAuth = function(pV, iCode, s0, s1, s2, s3){ try{ s0 = s0 && wasm.cstrToJs(s0); s1 = s1 && wasm.cstrToJs(s1); s2 = s2 && wasm.cstrToJs(s2); s3 = s3 && wasm.cstrToJs(s3); return xProxy(pV, iCode, s0, s1, s2, s3) || 0; }catch(e){ return util.sqlite3_wasm_db_error(pDb, e); } }; } return __ssa(pDb, xAuth, pUserData); }; }/* sqlite3_set_authorizer() */ {/* sqlite3_config() */ /** Wraps a small subset of the C API's sqlite3_config() options. Unsupported options trigger the return of capi.SQLITE_NOTFOUND. Passing fewer than 2 arguments triggers return of capi.SQLITE_MISUSE. */ capi.sqlite3_config = function(op, ...args){ if(arguments.length<2) return capi.SQLITE_MISUSE; switch(op){ case capi.SQLITE_CONFIG_COVERING_INDEX_SCAN: // 20 /* int */ case capi.SQLITE_CONFIG_MEMSTATUS:// 9 /* boolean */ case capi.SQLITE_CONFIG_SMALL_MALLOC: // 27 /* boolean */ case capi.SQLITE_CONFIG_SORTERREF_SIZE: // 28 /* int nByte */ case capi.SQLITE_CONFIG_STMTJRNL_SPILL: // 26 /* int nByte */ case capi.SQLITE_CONFIG_URI:// 17 /* int */ return wasm.exports.sqlite3_wasm_config_i(op, args[0]); case capi.SQLITE_CONFIG_LOOKASIDE: // 13 /* int int */ return wasm.exports.sqlite3_wasm_config_ii(op, args[0], args[1]); case capi.SQLITE_CONFIG_MEMDB_MAXSIZE: // 29 /* sqlite3_int64 */ return wasm.exports.sqlite3_wasm_config_j(op, args[0]); case capi.SQLITE_CONFIG_GETMALLOC: // 5 /* sqlite3_mem_methods* */ case capi.SQLITE_CONFIG_GETMUTEX: // 11 /* sqlite3_mutex_methods* */ case capi.SQLITE_CONFIG_GETPCACHE2: // 19 /* sqlite3_pcache_methods2* */ case capi.SQLITE_CONFIG_GETPCACHE: // 15 /* no-op */ case capi.SQLITE_CONFIG_HEAP: // 8 /* void*, int nByte, int min */ case capi.SQLITE_CONFIG_LOG: // 16 /* xFunc, void* */ case capi.SQLITE_CONFIG_MALLOC:// 4 /* sqlite3_mem_methods* */ case capi.SQLITE_CONFIG_MMAP_SIZE: // 22 /* sqlite3_int64, sqlite3_int64 */ case capi.SQLITE_CONFIG_MULTITHREAD: // 2 /* nil */ case capi.SQLITE_CONFIG_MUTEX: // 10 /* sqlite3_mutex_methods* */ case capi.SQLITE_CONFIG_PAGECACHE: // 7 /* void*, int sz, int N */ case capi.SQLITE_CONFIG_PCACHE2: // 18 /* sqlite3_pcache_methods2* */ case capi.SQLITE_CONFIG_PCACHE: // 14 /* no-op */ case capi.SQLITE_CONFIG_PCACHE_HDRSZ: // 24 /* int *psz */ case capi.SQLITE_CONFIG_PMASZ: // 25 /* unsigned int szPma */ case capi.SQLITE_CONFIG_SERIALIZED: // 3 /* nil */ case capi.SQLITE_CONFIG_SINGLETHREAD: // 1 /* nil */: case capi.SQLITE_CONFIG_SQLLOG: // 21 /* xSqllog, void* */ case capi.SQLITE_CONFIG_WIN32_HEAPSIZE: // 23 /* int nByte */ default: return capi.SQLITE_NOTFOUND; } }; }/* sqlite3_config() */ {/* Import C-level constants and structs... */ const cJson = wasm.xCall('sqlite3_wasm_enum_json'); if(!cJson){ toss("Maintenance required: increase sqlite3_wasm_enum_json()'s", "static buffer size!"); } wasm.ctype = JSON.parse(wasm.cstrToJs(cJson)); //console.debug('wasm.ctype length =',wasm.cstrlen(cJson)); const defineGroups = ['access', 'authorizer', 'blobFinalizers', 'config', 'dataTypes', 'dbConfig', 'dbStatus', 'encodings', 'fcntl', 'flock', 'ioCap', 'limits', 'openFlags', 'prepareFlags', 'resultCodes', 'serialize', 'sqlite3Status', 'stmtStatus', 'syncFlags', 'trace', 'txnState', 'udfFlags', 'version' ]; if(wasm.bigIntEnabled){ defineGroups.push('vtab'); } for(const t of defineGroups){ for(const e of Object.entries(wasm.ctype[t])){ // ^^^ [k,v] there triggers a buggy code transformation via |
︙ | ︙ | |||
723 724 725 726 727 728 729 | ** passed them to StructBinder. */ for(const k of ['sqlite3_index_constraint', 'sqlite3_index_orderby', 'sqlite3_index_constraint_usage']){ capi.sqlite3_index_info[k] = capi[k]; delete capi[k]; } | | | | > | 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 | ** passed them to StructBinder. */ for(const k of ['sqlite3_index_constraint', 'sqlite3_index_orderby', 'sqlite3_index_constraint_usage']){ capi.sqlite3_index_info[k] = capi[k]; delete capi[k]; } capi.sqlite3_vtab_config = wasm.xWrap( 'sqlite3_wasm_vtab_config','int',[ 'sqlite3*', 'int', 'int'] ); }/* end vtab-related setup */ }/*end C constant and struct imports*/ const pKvvfs = capi.sqlite3_vfs_find("kvvfs"); if( pKvvfs ){/* kvvfs-specific glue */ if(util.isUIThread()){ const kvvfsMethods = new capi.sqlite3_kvvfs_methods( |
︙ | ︙ |
Changes to ext/wasm/api/sqlite3-api-oo1.js.
︙ | ︙ | |||
154 155 156 157 158 159 160 161 162 163 164 165 166 167 | 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); if(flagsStr.indexOf('t')>=0){ capi.sqlite3_trace_v2(pDb, capi.SQLITE_TRACE_STMT, __dbTraceToConsole, 0); } }catch( e ){ if( pDb ) capi.sqlite3_close_v2(pDb); throw e; | > | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | 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, 0); } }catch( e ){ if( pDb ) capi.sqlite3_close_v2(pDb); throw e; |
︙ | ︙ | |||
332 333 334 335 336 337 338 | - `columnCount`: the number of result columns in the query, or 0 for queries which cannot return results. - `parameterCount`: the number of bindable paramters in the query. */ const Stmt = function(){ if(BindTypes!==arguments[2]){ | | | 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | - `columnCount`: the number of result columns in the query, or 0 for queries which cannot return results. - `parameterCount`: the number of bindable paramters in the query. */ const Stmt = function(){ 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.columnCount = capi.sqlite3_column_count(this.pointer); this.parameterCount = capi.sqlite3_bind_parameter_count(this.pointer); }; |
︙ | ︙ | |||
434 435 436 437 438 439 440 | } out.cbArg = (stmt)=>stmt; break; default: if(util.isInt32(opt.rowMode)){ out.cbArg = (stmt)=>stmt.get(opt.rowMode); break; | | > > | > > > | < | | | < < > | > | | < | 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 | } out.cbArg = (stmt)=>stmt; break; default: if(util.isInt32(opt.rowMode)){ out.cbArg = (stmt)=>stmt.get(opt.rowMode); break; }else if('string'===typeof opt.rowMode && opt.rowMode.length>1 && '$'===opt.rowMode[0]){ /* "$X": fetch column named "X" (case-sensitive!). Prior to 2022-12-14 ":X" and "@X" were also permitted, but having so many options is unnecessary and likely to cause confusion. */ const $colName = opt.rowMode.substr(1); out.cbArg = (stmt)=>{ const rc = stmt.get(Object.create(null))[$colName]; return (undefined===rc) ? toss3(capi.SQLITE_NOTFOUND, "exec(): unknown result column:",$colName) : rc; }; break; } toss3("Invalid rowMode:",opt.rowMode); } } return out; }; |
︙ | ︙ | |||
601 602 603 604 605 606 607 | affirmDbOpen(this).pointer, dbName ); if(pVfs){ const v = new capi.sqlite3_vfs(pVfs); try{ rc = wasm.cstrToJs(v.$zName) } finally { v.dispose() } } | | | 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 | affirmDbOpen(this).pointer, dbName ); if(pVfs){ const v = new capi.sqlite3_vfs(pVfs); try{ rc = wasm.cstrToJs(v.$zName) } finally { v.dispose() } } return rc; }, /** Compiles the given SQL and returns a prepared Stmt. This is the only way to create new Stmt objects. Throws on error. The given SQL must be a string, a Uint8Array holding SQL, a WASM pointer to memory holding the NUL-terminated SQL string, |
︙ | ︙ | |||
690 691 692 693 694 695 696 | - `columnNames`: if this is an array, the column names of the result set are stored in this array before the callback (if any) is triggered (regardless of whether the query produces any result rows). If no statement has result columns, this value is unchanged. Achtung: an SQL result may have multiple columns with identical names. | | | | > > > > | > > | 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 | - `columnNames`: if this is an array, the column names of the result set are stored in this array before the callback (if any) is triggered (regardless of whether the query produces any result rows). If no statement has result columns, this value is unchanged. Achtung: an SQL result may have multiple columns with identical names. - `callback` = a function which gets called for each row of the result set, but only if that statement has any result _rows_. The callback's "this" is the options object, noting that this function synthesizes one if the caller does not pass one to exec(). The second argument passed to the callback is always the current Stmt object, as it's needed if the caller wants to fetch the column names or some such (noting that they could also be fetched via `this.columnNames`, if the client provides the `columnNames` option). If the callback returns a literal `false` (as opposed to any other falsy value, e.g. an implicit `undefined` return), any ongoing statement-`step()` iteration stops without an error. The return value of the callback is otherwise ignored. ACHTUNG: The callback MUST NOT modify the Stmt object. Calling any of the Stmt.get() variants, Stmt.getColumnName(), or similar, is legal, but calling step() or finalize() is not. Member methods which are illegal in this context will trigger an exception, but clients must also refrain from using any lower-level (C-style) APIs which might modify the statement. The first argument passed to the callback defaults to an array of values from the current result row but may be changed with ... - `rowMode` = specifies the type of he callback's first argument. It may be any of... |
︙ | ︙ | |||
735 736 737 738 739 740 741 | `resultRows` is an array because appending the statement to the array would be downright unhelpful. B) An integer, indicating a zero-based column in the result row. Only that one single value will be passed on. C) A string with a minimum length of 2 and leading character of | | | | | | | | | < < | | 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 | `resultRows` is an array because appending the statement to the array would be downright unhelpful. B) An integer, indicating a zero-based column in the result row. Only that one single value will be passed on. C) A string with a minimum length of 2 and leading character of '$' will fetch the row as an object, extract that one field, and pass that field's value to the callback. Note that these keys are case-sensitive so must match the case used in the SQL. e.g. `"select a A from t"` with a `rowMode` of `'$A'` would work but `'$a'` would not. A reference to a column not in the result set will trigger an exception on the first row (as the check is not performed until rows are fetched). Note also that `$` is a legal identifier character in JS so need not be quoted. Any other `rowMode` value triggers an exception. - `resultRows`: if this is an array, it functions similarly to the `callback` option: each row of the result set (if any), with the exception that the `rowMode` 'stmt' is not legal. It is legal to use both `resultRows` and `callback`, but |
︙ | ︙ | |||
794 795 796 797 798 799 800 | } const opt = arg.opt; const callback = opt.callback; const resultRows = Array.isArray(opt.resultRows) ? opt.resultRows : undefined; let stmt; let bind = opt.bind; | | > > > | > | < > | 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 | } const opt = arg.opt; const callback = opt.callback; const resultRows = Array.isArray(opt.resultRows) ? opt.resultRows : undefined; let stmt; let bind = opt.bind; let evalFirstResult = !!( arg.cbArg || opt.columnNames || resultRows ) /* true to step through the first result-returning statement */; const stack = wasm.scopedAllocPush(); const saveSql = Array.isArray(opt.saveSql) ? opt.saveSql : undefined; try{ const isTA = util.isSQLableTypedArray(arg.sql) /* Optimization: if the SQL is a TypedArray we can save some string conversion costs. */; /* Allocate the two output pointers (ppStmt, pzTail) and heap space for the SQL (pSql). When prepare_v2() returns, pzTail will point to somewhere in pSql. */ let sqlByteLen = isTA ? arg.sql.byteLength : wasm.jstrlen(arg.sql); const ppStmt = wasm.scopedAlloc( /* output (sqlite3_stmt**) arg and pzTail */ (2 * wasm.ptrSizeof) + (sqlByteLen + 1/* SQL + NUL */) ); const pzTail = ppStmt + wasm.ptrSizeof /* final arg to sqlite3_prepare_v2() */; let pSql = pzTail + wasm.ptrSizeof; const pSqlEnd = pSql + sqlByteLen; if(isTA) wasm.heap8().set(arg.sql, pSql); else wasm.jstrcpy(arg.sql, wasm.heap8(), pSql, sqlByteLen, false); wasm.poke(pSql + sqlByteLen, 0/*NUL terminator*/); while(pSql && wasm.peek(pSql, 'i8') |
︙ | ︙ | |||
829 830 831 832 833 834 835 | DB.checkRc(this, capi.sqlite3_prepare_v3( this.pointer, pSql, sqlByteLen, 0, ppStmt, pzTail )); const pStmt = wasm.peekPtr(ppStmt); pSql = wasm.peekPtr(pzTail); sqlByteLen = pSqlEnd - pSql; if(!pStmt) continue; | < | < | > | | | | > > > > | | | < | | > | > > | 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 | DB.checkRc(this, capi.sqlite3_prepare_v3( this.pointer, pSql, sqlByteLen, 0, ppStmt, pzTail )); const pStmt = wasm.peekPtr(ppStmt); pSql = wasm.peekPtr(pzTail); sqlByteLen = pSqlEnd - pSql; if(!pStmt) continue; if(saveSql) saveSql.push(capi.sqlite3_sql(pStmt).trim()); stmt = new Stmt(this, pStmt, BindTypes); if(bind && stmt.parameterCount){ stmt.bind(bind); bind = null; } if(evalFirstResult && stmt.columnCount){ /* Only forward SELECT results for the FIRST query in the SQL which potentially has them. */ evalFirstResult = false; if(Array.isArray(opt.columnNames)){ stmt.getColumnNames(opt.columnNames); } if(arg.cbArg || resultRows){ for(; stmt.step(); stmt._isLocked = false){ stmt._isLocked = true; const row = arg.cbArg(stmt); if(resultRows) resultRows.push(row); if(callback && false === callback.call(opt, row, stmt)){ break; } } stmt._isLocked = false; } }else{ stmt.step(); } stmt.finalize(); stmt = null; } }/*catch(e){ console.warn("DB.exec() is propagating exception",opt,e); throw e; }*/finally{ if(stmt){ delete stmt._isLocked; stmt.finalize(); } wasm.scopedAllocPop(stack); } return arg.returnVal(); }/*exec()*/, /** Creates a new UDF (User-Defined Function) which is accessible via SQL code. This function may be called in any of the following forms: - (name, function) - (name, function, optionsObject) - (name, optionsObject) - (optionsObject) In the final two cases, the function must be defined as the `callback` property of the options object (optionally called `xFunc` to align with the C API documentation). In the final case, the function's name must be the 'name' property. The first two call forms can only be used for creating scalar functions. Creating an aggregate or window function requires the options-object form (see below for details). UDFs can be removed as documented for sqlite3_create_function_v2() and sqlite3_create_window_function(), but doing so will "leak" the JS-created WASM binding of those functions (meaning that their entries in the WASM indirect function table still exist). Eliminating that potential leak is a pending TODO. On success, returns this object. Throws on error. When called from SQL arguments to the UDF, and its result, will be converted between JS and SQL with as much fidelity as is feasible, triggering an exception if a type conversion cannot be determined. The docs for sqlite3_create_function_v2() |
︙ | ︙ | |||
1209 1210 1211 1212 1213 1214 1215 | case BindTypes.string: return t; case BindTypes.bigint: if(wasm.bigIntEnabled) return t; /* else fall through */ default: //console.log("isSupportedBindType",t,v); | > | | 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 | case BindTypes.string: return t; case BindTypes.bigint: if(wasm.bigIntEnabled) return t; /* else fall through */ default: //console.log("isSupportedBindType",t,v); return (util.isBindableTypedArray(v) || (v instanceof ArrayBuffer)) ? BindTypes.blob : undefined; } }; /** If isSupportedBindType(v) returns a truthy value, this function returns that value, else it throws. */ |
︙ | ︙ | |||
1263 1264 1265 1266 1267 1268 1269 | /** Binds a single bound parameter value on the given stmt at the given index (numeric or named) using the given bindType (see the BindTypes enum) and value. Throws on error. Returns stmt on success. */ const bindOne = function f(stmt,ndx,bindType,val){ | | < < < < | < < | | < < < < < < < < < < < < < < | 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 | /** Binds a single bound parameter value on the given stmt at the given index (numeric or named) using the given bindType (see the BindTypes enum) and value. Throws on error. Returns stmt on success. */ const bindOne = function f(stmt,ndx,bindType,val){ affirmUnlocked(affirmStmtOpen(stmt), 'bind()'); if(!f._){ f._tooBigInt = (v)=>toss3( "BigInt value is too big to store without precision loss:", v ); /* Reminder: when not in BigInt mode, it's impossible for JS to represent a number out of the range we can bind, so we have no range checking. */ f._ = { string: function(stmt, ndx, val, asBlob){ const [pStr, n] = wasm.allocCString(val, true); const f = asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text; return f(stmt.pointer, ndx, pStr, n, capi.SQLITE_WASM_DEALLOC); } }; }/* static init */ affirmSupportedBindType(val); ndx = affirmParamIndex(stmt,ndx); let rc = 0; switch((null===val || undefined===val) ? BindTypes.null : bindType){ |
︙ | ︙ | |||
1340 1341 1342 1343 1344 1345 1346 1347 1348 | } case BindTypes.boolean: rc = capi.sqlite3_bind_int(stmt.pointer, ndx, val ? 1 : 0); break; case BindTypes.blob: { if('string'===typeof val){ rc = f._.string(stmt, ndx, val, true); }else if(!util.isBindableTypedArray(val)){ toss3("Binding a value as a blob requires", | > > > | < < < < < < < < < < | < | < > | | < < < < > | 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 | } case BindTypes.boolean: rc = capi.sqlite3_bind_int(stmt.pointer, ndx, val ? 1 : 0); break; case BindTypes.blob: { if('string'===typeof val){ rc = f._.string(stmt, ndx, val, true); break; }else if(val instanceof ArrayBuffer){ val = new Uint8Array(val); }else if(!util.isBindableTypedArray(val)){ toss3("Binding a value as a blob requires", "that it be a string, Uint8Array, Int8Array, or ArrayBuffer."); } const pBlob = wasm.alloc(val.byteLength || 1); wasm.heap8().set(val.byteLength ? val : [0], pBlob) rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength, capi.SQLITE_WASM_DEALLOC); break; } default: console.warn("Unsupported bind() argument type:",val); toss3("Unsupported bind() argument type: "+(typeof val)); } if(rc) DB.checkRc(stmt.db.pointer, rc); stmt._mayGet = false; return stmt; }; Stmt.prototype = { /** "Finalizes" this statement. This is a no-op if the statement has already been finalizes. Returns |
︙ | ︙ | |||
1457 1458 1459 1460 1461 1462 1463 | BigInt as an int32 or a double if it can do so without loss of precision. If the BigInt is _too BigInt_ then it will throw. - Strings are bound as strings (use bindAsBlob() to force blob binding). | | | | 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 | BigInt as an int32 or a double if it can do so without loss of precision. If the BigInt is _too BigInt_ then it will throw. - Strings are bound as strings (use bindAsBlob() to force blob binding). - Uint8Array, Int8Array, and ArrayBuffer instances are bound as blobs. (TODO? binding the other TypedArray types.) If passed an array, each element of the array is bound at the parameter index equal to the array index plus 1 (because arrays are 0-based but binding is 1-based). If passed an object, each object key is treated as a bindable parameter name. The object keys _must_ match any |
︙ | ︙ | |||
1513 1514 1515 1516 1517 1518 1519 1520 | else if(Array.isArray(arg)){ /* bind each entry by index */ if(1!==arguments.length){ toss3("When binding an array, an index argument is not permitted."); } arg.forEach((v,i)=>bindOne(this, i+1, affirmSupportedBindType(v), v)); return this; } | > > | | 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 | else if(Array.isArray(arg)){ /* bind each entry by index */ if(1!==arguments.length){ toss3("When binding an array, an index argument is not permitted."); } arg.forEach((v,i)=>bindOne(this, i+1, affirmSupportedBindType(v), v)); return this; }else if(arg instanceof ArrayBuffer){ arg = new Uint8Array(arg); } if('object'===typeof arg/*null was checked above*/ && !util.isBindableTypedArray(arg)){ /* Treat each property of arg as a named bound parameter. */ if(1!==arguments.length){ toss3("When binding an object, an index argument is not permitted."); } Object.keys(arg) .forEach(k=>bindOne(this, k, |
︙ | ︙ | |||
1536 1537 1538 1539 1540 1541 1542 | }, /** Special case of bind() which binds the given value using the BLOB binding mechanism instead of the default selected one for the value. The ndx may be a numbered or named bind index. The value must be of type string, null/undefined (both get treated as null), or a TypedArray of a type supported by the bind() | | | < < | 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 | }, /** Special case of bind() which binds the given value using the BLOB binding mechanism instead of the default selected one for the value. The ndx may be a numbered or named bind index. The value must be of type string, null/undefined (both get treated as null), or a TypedArray of a type supported by the bind() API. This API cannot bind numbers as blobs. If passed a single argument, a bind index of 1 is assumed and the first argument is the value. */ bindAsBlob: function(ndx,arg){ affirmStmtOpen(this); if(1===arguments.length){ arg = ndx; ndx = 1; } const t = affirmSupportedBindType(arg); if(BindTypes.string !== t && BindTypes.blob !== t && BindTypes.null !== t){ toss3("Invalid value type for bindAsBlob()"); } return bindOne(this, ndx, BindTypes.blob, arg); }, /** Steps the statement one time. If the result indicates that a row of data is available, a truthy value is returned. If no row of data is available, a falsy value is returned. Throws on error. */ |
︙ | ︙ |
Changes to ext/wasm/api/sqlite3-api-prologue.js.
︙ | ︙ | |||
75 76 77 78 79 80 81 | the `free(3)`-compatible routine for the WASM environment. Defaults to `"sqlite3_free"`. - `reallocExportName`: the name of the function, in `exports`, of the `realloc(3)`-compatible routine for the WASM environment. Defaults to `"sqlite3_realloc"`. | | < < < | < | | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | the `free(3)`-compatible routine for the WASM environment. Defaults to `"sqlite3_free"`. - `reallocExportName`: the name of the function, in `exports`, of the `realloc(3)`-compatible routine for the WASM environment. Defaults to `"sqlite3_realloc"`. - `wasmfsOpfsDir`[^1]: As of 2022-12-17, this feature does not currently work due to incompatible Emscripten-side changes made in the WASMFS+OPFS combination. This option is currently ignored. [^1] = This property may optionally be a function, in which case this function re-assigns it to the value returned from that function, enabling delayed evaluation. */ 'use strict'; |
︙ | ︙ | |||
134 135 136 137 138 139 140 141 142 143 144 145 146 147 | // the result of calling that function... 'exports', 'memory', 'wasmfsOpfsDir' ].forEach((k)=>{ if('function' === typeof config[k]){ config[k] = config[k](); } }); /** The main sqlite3 binding API gets installed into this object, mimicking the C API as closely as we can. The numerous members names with prefixes 'sqlite3_' and 'SQLITE_' behave, insofar as possible, identically to the C-native counterparts, as documented at: | > > > > | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | // the result of calling that function... 'exports', 'memory', 'wasmfsOpfsDir' ].forEach((k)=>{ if('function' === typeof config[k]){ config[k] = config[k](); } }); config.wasmOpfsDir = /* 2022-12-17: WASMFS+OPFS can no longer be activated from the main thread (aborts via a failed assert() if it's attempted), which eliminates any(?) benefit to supporting it. */ false; /** The main sqlite3 binding API gets installed into this object, mimicking the C API as closely as we can. The numerous members names with prefixes 'sqlite3_' and 'SQLITE_' behave, insofar as possible, identically to the C-native counterparts, as documented at: |
︙ | ︙ | |||
317 318 319 320 321 322 323 | const typedArrayPart = (aTypedArray, begin, end)=>{ return isSharedTypedArray(aTypedArray) ? aTypedArray.slice(begin, end) : aTypedArray.subarray(begin, end); }; /** | | | | | > > | < > > | | > | 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 | const typedArrayPart = (aTypedArray, begin, end)=>{ return isSharedTypedArray(aTypedArray) ? aTypedArray.slice(begin, end) : aTypedArray.subarray(begin, end); }; /** Returns v if v appears to be one of our bind()-able TypedArray types: Uint8Array or Int8Array or ArrayBuffer. Support for TypedArrays with element sizes >1 is a potential TODO just waiting on a use case to justify them. Until then, their `buffer` property can be used to pass them as an ArrayBuffer. If it's not a bindable array type, a falsy value is returned. */ const isBindableTypedArray = (v)=>{ return v && (v instanceof Uint8Array || v instanceof Int8Array || v instanceof ArrayBuffer); }; /** Returns true if v appears to be one of the TypedArray types which is legal for holding SQL code (as opposed to binary blobs). Currently this is the same as isBindableTypedArray() but it seems likely that we'll eventually want to add Uint32Array and friends to the isBindableTypedArray() list but not to the isSQLableTypedArray() list. */ const isSQLableTypedArray = (v)=>{ return v && (v instanceof Uint8Array || v instanceof Int8Array || v instanceof ArrayBuffer); }; /** Returns true if isBindableTypedArray(v) does, else throws with a message that v is not a supported TypedArray value. */ const affirmBindableTypedArray = (v)=>{ return isBindableTypedArray(v) || toss3("Value is not of a supported TypedArray type."); |
︙ | ︙ | |||
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 | ``` */ WasmAllocError.toss = (...args)=>{ throw new WasmAllocError(...args); }; Object.assign(capi, { /** sqlite3_create_function_v2() differs from its native counterpart only in the following ways: 1) The fourth argument (`eTextRep`) argument must not specify any encoding other than sqlite3.SQLITE_UTF8. The JS API does not currently support any other encoding and likely never will. This function does not replace that argument on its own | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > | 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 | ``` */ WasmAllocError.toss = (...args)=>{ throw new WasmAllocError(...args); }; Object.assign(capi, { /** sqlite3_bind_blob() works exactly like its C counterpart unless its 3rd argument is one of: - JS string: the 3rd argument is converted to a C string, the 4th argument is ignored, and the C-string's length is used in its place. - Array: converted to a string as defined for "flexible strings" and then it's treated as a JS string. - Int8Array or Uint8Array: wasm.allocFromTypedArray() is used to conver the memory to the WASM heap. If the 4th argument is 0 or greater, it is used as-is, otherwise the array's byteLength value is used. This is an exception to the C API's undefined behavior for a negative 4th argument, but results are undefined if the given 4th argument value is greater than the byteLength of the input array. - If it's an ArrayBuffer, it gets wrapped in a Uint8Array and treated as that type. In all of those cases, the final argument (destructor) is ignored and capi.SQLITE_WASM_DEALLOC is assumed. A 3rd argument of `null` is treated as if it were a WASM pointer of 0. If the 3rd argument is neither a WASM pointer nor one of the above-described types, capi.SQLITE_MISUSE is returned. The first argument may be either an `sqlite3_stmt*` WASM pointer or an sqlite3.oo1.Stmt instance. For consistency with the C API, it requires the same number of arguments. It returns capi.SQLITE_MISUSE if passed any other argument count. */ sqlite3_bind_blob: undefined/*installed later*/, /** sqlite3_bind_text() works exactly like its C counterpart unless its 3rd argument is one of: - JS string: the 3rd argument is converted to a C string, the 4th argument is ignored, and the C-string's length is used in its place. - Array: converted to a string as defined for "flexible strings". The 4th argument is ignored and a value of -1 is assumed. - Int8Array or Uint8Array: is assumed to contain UTF-8 text, is converted to a string. The 4th argument is ignored, replaced by the array's byteLength value. - If it's an ArrayBuffer, it gets wrapped in a Uint8Array and treated as that type. In each of those cases, the final argument (text destructor) is ignored and capi.SQLITE_WASM_DEALLOC is assumed. A 3rd argument of `null` is treated as if it were a WASM pointer of 0. If the 3rd argument is neither a WASM pointer nor one of the above-described types, capi.SQLITE_MISUSE is returned. The first argument may be either an `sqlite3_stmt*` WASM pointer or an sqlite3.oo1.Stmt instance. For consistency with the C API, it requires the same number of arguments. It returns capi.SQLITE_MISUSE if passed any other argument count. If client code needs to bind partial strings, it needs to either parcel the string up before passing it in here or it must pass in a WASM pointer for the 3rd argument and a valid 4th-argument value, taking care not to pass a value which truncates a multi-byte UTF-8 character. When passing WASM-format strings, it is important that the final argument be valid or unexpected content can result can result, or even a crash if the application reads past the WASM heap bounds. */ sqlite3_bind_text: undefined/*installed later*/, /** sqlite3_create_function_v2() differs from its native counterpart only in the following ways: 1) The fourth argument (`eTextRep`) argument must not specify any encoding other than sqlite3.SQLITE_UTF8. The JS API does not currently support any other encoding and likely never will. This function does not replace that argument on its own because it may contain other flags. As a special case, if the bottom 4 bits of that argument are 0, SQLITE_UTF8 is assumed. 2) Any of the four final arguments may be either WASM pointers (assumed to be function pointers) or JS Functions. In the latter case, each gets bound to WASM using sqlite3.capi.wasm.installFunction() and that wrapper is passed on to the native implementation. For consistency with the C API, it requires the same number of arguments. It returns capi.SQLITE_MISUSE if passed any other argument count. The semantics of JS functions are: xFunc: is passed `(pCtx, ...values)`. Its return value becomes the new SQL function's result. xStep: is passed `(pCtx, ...values)`. Its return value is |
︙ | ︙ | |||
515 516 517 518 519 520 521 | C reference: https://www.sqlite.org/c3ref/create_function.html Maintenance reminder: the ability to add new WASM-accessible functions to the runtime requires that the WASM build is compiled with emcc's `-sALLOW_TABLE_GROWTH` flag. */ | | | | | | | | 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 | C reference: https://www.sqlite.org/c3ref/create_function.html Maintenance reminder: the ability to add new WASM-accessible functions to the runtime requires that the WASM build is compiled with emcc's `-sALLOW_TABLE_GROWTH` flag. */ sqlite3_create_function_v2: ( pDb, funcName, nArg, eTextRep, pApp, xFunc, xStep, xFinal, xDestroy )=>{/*installed later*/}, /** Equivalent to passing the same arguments to sqlite3_create_function_v2(), with 0 as the final argument. */ sqlite3_create_function: ( pDb, funcName, nArg, eTextRep, pApp, xFunc, xStep, xFinal )=>{/*installed later*/}, /** The sqlite3_create_window_function() JS wrapper differs from its native implementation in the exact same way that sqlite3_create_function_v2() does. The additional function, xInverse(), is treated identically to xStep() by the wrapping layer. */ sqlite3_create_window_function: ( pDb, funcName, nArg, eTextRep, pApp, xStep, xFinal, xValue, xInverse, xDestroy )=>{/*installed later*/}, /** The sqlite3_prepare_v3() binding handles two different uses with differing JS/WASM semantics: 1) sqlite3_prepare_v3(pDb, sqlString, -1, prepFlags, ppStmt , null) 2) sqlite3_prepare_v3(pDb, sqlPointer, sqlByteLen, prepFlags, ppStmt, sqlPointerToPointer) |
︙ | ︙ | |||
659 660 661 662 663 664 665 | isUIThread: ()=>(self.window===self && !!self.document), // is this true for ESM?: 'undefined'===typeof WorkerGlobalScope isSharedTypedArray, toss: function(...args){throw new Error(args.join(' '))}, toss3, typedArrayPart }; | | | 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 | isUIThread: ()=>(self.window===self && !!self.document), // is this true for ESM?: 'undefined'===typeof WorkerGlobalScope isSharedTypedArray, toss: function(...args){throw new Error(args.join(' '))}, toss3, typedArrayPart }; Object.assign(wasm, { /** Emscripten APIs have a deep-seated assumption that all pointers are 32 bits. We'll remain optimistic that that won't always be the case and will use this constant in places where we might otherwise use a hard-coded 4. */ |
︙ | ︙ | |||
874 875 876 877 878 879 880 | return optName; } return ( 'string'===typeof optName ) ? !!capi.sqlite3_compileoption_used(optName) : false; }/*compileOptionUsed()*/; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 970 971 972 973 974 975 976 977 978 979 980 981 982 983 | return optName; } return ( 'string'===typeof optName ) ? !!capi.sqlite3_compileoption_used(optName) : false; }/*compileOptionUsed()*/; /** sqlite3.wasm.pstack (pseudo-stack) holds a special-case stack-style allocator intended only for use with _small_ data of not more than (in total) a few kb in size, managed as if it were stack-based. It has only a single intended usage: |
︙ | ︙ | |||
1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 | } wasm.exports.sqlite3_randomness(...args); }; /** State for sqlite3_wasmfs_opfs_dir(). */ let __wasmfsOpfsDir = undefined; /** If the wasm environment has a WASMFS/OPFS-backed persistent storage directory, its path is returned by this function. If it does not then it returns "" (noting that "" is a falsy value). The first time this is called, this function inspects the current environment to determine whether persistence support is available and, if it is, enables it (if needed). This function currently only recognizes the WASMFS/OPFS storage combination and its path refers to storage rooted in the Emscripten-managed virtual filesystem. */ capi.sqlite3_wasmfs_opfs_dir = function(){ if(undefined !== __wasmfsOpfsDir) return __wasmfsOpfsDir; // If we have no OPFS, there is no persistent dir const pdir = config.wasmfsOpfsDir; if(!pdir || !self.FileSystemHandle || !self.FileSystemDirectoryHandle || !self.FileSystemFileHandle){ return __wasmfsOpfsDir = ""; } try{ | > > > > > > > > > | 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 | } wasm.exports.sqlite3_randomness(...args); }; /** State for sqlite3_wasmfs_opfs_dir(). */ let __wasmfsOpfsDir = undefined; /** 2022-12-17: incompatible WASMFS changes have made WASMFS+OPFS unavailable from the main thread, which eliminates the most significant benefit of supporting WASMFS. This function is now a no-op which always returns a falsy value. Before that change, this function behaved as documented below (and how it will again if we can find a compelling reason to support it). If the wasm environment has a WASMFS/OPFS-backed persistent storage directory, its path is returned by this function. If it does not then it returns "" (noting that "" is a falsy value). The first time this is called, this function inspects the current environment to determine whether persistence support is available and, if it is, enables it (if needed). This function currently only recognizes the WASMFS/OPFS storage combination and its path refers to storage rooted in the Emscripten-managed virtual filesystem. */ capi.sqlite3_wasmfs_opfs_dir = function(){ if(undefined !== __wasmfsOpfsDir) return __wasmfsOpfsDir; // If we have no OPFS, there is no persistent dir const pdir = config.wasmfsOpfsDir; console.error("sqlite3_wasmfs_opfs_dir() can no longer work due "+ "to incompatible WASMFS changes. It will be removed."); if(!pdir || !self.FileSystemHandle || !self.FileSystemDirectoryHandle || !self.FileSystemFileHandle){ return __wasmfsOpfsDir = ""; } try{ |
︙ | ︙ | |||
1668 1669 1670 1671 1672 1673 1674 | /** Given a (sqlite3_value*), this function attempts to convert it to an equivalent JS value with as much fidelity as feasible and return it. By default it throws if it cannot determine any sensible conversion. If passed a falsy second argument, it instead returns | | | > > | 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 | /** Given a (sqlite3_value*), this function attempts to convert it to an equivalent JS value with as much fidelity as feasible and return it. By default it throws if it cannot determine any sensible conversion. If passed a falsy second argument, it instead returns `undefined` if no suitable conversion is found. Note that there is no conversion from SQL to JS which results in the `undefined` value, so `undefined` has an unambiguous meaning here. It will always throw a WasmAllocError if allocating memory for a conversion fails. Caveats: - It does not support sqlite3_value_to_pointer() conversions because those require a type name string which this function does not have and cannot sensibly be given at the level of the API where this is used (e.g. automatically converting UDF |
︙ | ︙ | |||
1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 | toss3(capi.SQLITE_MISMATCH, "Unhandled sqlite3_value_type():",valType); } arg = undefined; } return arg; }; /* The remainder of the API will be set up in later steps. */ const sqlite3 = { WasmAllocError: WasmAllocError, SQLite3Error: SQLite3Error, capi, util, wasm, config, /** Holds the version info of the sqlite3 source tree from which the generated sqlite3-api.js gets built. Note that its version may well differ from that reported by sqlite3_libversion(), but that should be considered a source file mismatch, as the JS and WASM files are intended to be built and distributed together. This object is initially a placeholder which gets replaced by a build-generated object. */ version: Object.create(null), /** Performs any optional asynchronous library-level initialization which might be required. This function returns a Promise which resolves to the sqlite3 namespace object. Any error in the async init will be fatal to the init as a whole, but init routines are themselves welcome to install dummy catch() handlers which are not fatal if their failure should be | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 | toss3(capi.SQLITE_MISMATCH, "Unhandled sqlite3_value_type():",valType); } arg = undefined; } return arg; }; /** Requires a C-style array of `sqlite3_value*` objects and the number of entries in that array. Returns a JS array containing the results of passing each C array entry to sqlite3_value_to_js(). The 3rd argument to this function is passed on as the 2nd argument to that one. */ capi.sqlite3_values_to_js = function(argc,pArgv,throwIfCannotConvert=true){ let i; const tgt = []; for(i = 0; i < argc; ++i){ /** Curiously: despite ostensibly requiring 8-byte alignment, the pArgv array is parcelled into chunks of 4 bytes (1 pointer each). The values those point to have 8-byte alignment but the individual argv entries do not. */ tgt.push(capi.sqlite3_value_to_js( wasm.peekPtr(pArgv + (wasm.ptrSizeof * i)) )); } return tgt; }; /** Calls either sqlite3_result_error_nomem(), if e is-a WasmAllocError, or sqlite3_result_error(). In the latter case, the second arugment is coerced to a string to create the error message. The first argument is a (sqlite3_context*). Returns void. Does not throw. */ capi.sqlite3_result_error_js = function(pCtx,e){ if(e instanceof WasmAllocError){ capi.sqlite3_result_error_nomem(pCtx); }else{ /* Maintenance reminder: ''+e, rather than e.message, will prefix e.message with e.name, so it includes the exception's type name in the result. */; capi.sqlite3_result_error(pCtx, ''+e, -1); } }; /** This function passes its 2nd argument to one of the sqlite3_result_xyz() routines, depending on the type of that argument: - If (val instanceof Error), this function passes it to sqlite3_result_error_js(). - `null`: `sqlite3_result_null()` - `boolean`: `sqlite3_result_int()` with a value of 0 or 1. - `number`: `sqlite3_result_int()`, `sqlite3_result_int64()`, or `sqlite3_result_double()`, depending on the range of the number and whether or not int64 support is enabled. - `bigint`: similar to `number` but will trigger an error if the value is too big to store in an int64. - `string`: `sqlite3_result_text()` - Uint8Array or Int8Array or ArrayBuffer: `sqlite3_result_blob()` - `undefined`: is a no-op provided to simplify certain use cases. Anything else triggers `sqlite3_result_error()` with a description of the problem. The first argument to this function is a `(sqlite3_context*)`. Returns void. Does not throw. */ capi.sqlite3_result_js = function(pCtx,val){ if(val instanceof Error){ capi.sqlite3_result_error_js(pCtx, val); return; } try{ switch(typeof val) { case 'undefined': /* This is a no-op. This routine originated in the create_function() family of APIs and in that context, passing in undefined indicated that the caller was responsible for calling sqlite3_result_xxx() (if needed). */ break; case 'boolean': capi.sqlite3_result_int(pCtx, val ? 1 : 0); break; case 'bigint': if(util.bigIntFits32(val)){ capi.sqlite3_result_int(pCtx, Number(val)); }else if(util.bigIntFitsDouble(val)){ capi.sqlite3_result_double(pCtx, Number(val)); }else if(wasm.bigIntEnabled){ if(util.bigIntFits64(val)) capi.sqlite3_result_int64(pCtx, val); else toss3("BigInt value",val.toString(),"is too BigInt for int64."); }else{ toss3("BigInt value",val.toString(),"is too BigInt."); } break; case 'number': { let f; if(util.isInt32(val)){ f = capi.sqlite3_result_int; }else if(wasm.bigIntEnabled && Number.isInteger(val) && util.bigIntFits64(BigInt(val))){ f = capi.sqlite3_result_int64; }else{ f = capi.sqlite3_result_double; } f(pCtx, val); break; } case 'string': { const [p, n] = wasm.allocCString(val,true); capi.sqlite3_result_text(pCtx, p, n, capi.SQLITE_WASM_DEALLOC); break; } case 'object': if(null===val/*yes, typeof null === 'object'*/) { capi.sqlite3_result_null(pCtx); break; }else if(util.isBindableTypedArray(val)){ const pBlob = wasm.allocFromTypedArray(val); capi.sqlite3_result_blob( pCtx, pBlob, val.byteLength, capi.SQLITE_WASM_DEALLOC ); break; } // else fall through default: toss3("Don't not how to handle this UDF result value:",(typeof val), val); } }catch(e){ capi.sqlite3_result_error_js(pCtx, e); } }; /** Returns the result sqlite3_column_value(pStmt,iCol) passed to sqlite3_value_to_js(). The 3rd argument of this function is ignored by this function except to pass it on as the second argument of sqlite3_value_to_js(). If the sqlite3_column_value() returns NULL (e.g. because the column index is out of range), this function returns `undefined`, regardless of the 3rd argument. 3rd argument is falsy and conversion fails, `undefined` will be returned. Note that sqlite3_column_value() returns an "unprotected" value object, but in a single-threaded environment (like this one) there is no distinction between protected and unprotected values. */ capi.sqlite3_column_js = function(pStmt, iCol, throwIfCannotConvert=true){ const v = capi.sqlite3_column_value(pStmt, iCol); return (0===v) ? undefined : capi.sqlite3_value_to_js(v, throwIfCannotConvert); }; /* The remainder of the API will be set up in later steps. */ const sqlite3 = { WasmAllocError: WasmAllocError, SQLite3Error: SQLite3Error, capi, util, wasm, config, /** Holds the version info of the sqlite3 source tree from which the generated sqlite3-api.js gets built. Note that its version may well differ from that reported by sqlite3_libversion(), but that should be considered a source file mismatch, as the JS and WASM files are intended to be built and distributed together. This object is initially a placeholder which gets replaced by a build-generated object. */ version: Object.create(null), /** The library reserves the 'client' property for client-side use and promises to never define a property with this name nor to ever rely on specific contents of it. It makes no such guarantees for other properties. */ client: undefined, /** Performs any optional asynchronous library-level initialization which might be required. This function returns a Promise which resolves to the sqlite3 namespace object. Any error in the async init will be fatal to the init as a whole, but init routines are themselves welcome to install dummy catch() handlers which are not fatal if their failure should be |
︙ | ︙ | |||
1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 | }); const postInit = ()=>{ if(!sqlite3.__isUnderTest){ /* Delete references to internal-only APIs which are used by some initializers. Retain them when running in test mode so that we can add tests for them. */ delete sqlite3.util; delete sqlite3.StructBinder; } return sqlite3; }; if(1){ /* Run all initializers in sequence. The advantage is that it allows us to have post-init cleanup defined outside of this | > > > > | 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 | }); const postInit = ()=>{ if(!sqlite3.__isUnderTest){ /* Delete references to internal-only APIs which are used by some initializers. Retain them when running in test mode so that we can add tests for them. */ delete sqlite3.util; /* It's conceivable that we might want to expose StructBinder to client-side code, but it's only useful if clients build their own sqlite3.wasm which contains their one C struct types. */ delete sqlite3.StructBinder; } return sqlite3; }; if(1){ /* Run all initializers in sequence. The advantage is that it allows us to have post-init cleanup defined outside of this |
︙ | ︙ |
Changes to ext/wasm/api/sqlite3-v-helper.js.
︙ | ︙ | |||
315 316 317 318 319 320 321 | } } if(!count) toss("Misuse: installVfs() options object requires at least", "one of:", propList); return this; }; | < < < < < < < < < < | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 | } } if(!count) toss("Misuse: installVfs() options object requires at least", "one of:", propList); return this; }; /** Internal factory function for xVtab and xCursor impls. */ const __xWrapFactory = function(methodName,StructType){ return function(ptr,removeMapping=false){ if(0===arguments.length) ptr = new StructType; if(ptr instanceof StructType){ |
︙ | ︙ | |||
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 | sqlite3_vtab: to be called from sqlite3_module methods which take a (sqlite3_vtab*) pointer _except_ for xDestroy()/xDisconnect(), in which case unget() or dispose(). sqlite3_vtab_cursor: to be called from any sqlite3_module methods which take a `sqlite3_vtab_cursor*` argument except xClose(), in which case use unget() or dispose(). */ get: (pCObj)=>__xWrap(pCObj), /** Identical to get() but also disconnects the mapping between the given pointer and the returned StructType object, such that future calls to this function or get() with the same pointer will return the undefined value. Its intended usage depends on StructType: sqlite3_vtab: to be called from sqlite3_module::xDisconnect() or xDestroy() implementations or in error handling of a failed xCreate() or xConnect(). sqlite3_vtab_cursor: to be called from xClose() or during cleanup in a failed xOpen(). */ unget: (pCObj)=>__xWrap(pCObj,true), /** Works like unget() plus it calls dispose() on the StructType object. */ dispose: (pCObj)=>{ | > > > > > > | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 | sqlite3_vtab: to be called from sqlite3_module methods which take a (sqlite3_vtab*) pointer _except_ for xDestroy()/xDisconnect(), in which case unget() or dispose(). sqlite3_vtab_cursor: to be called from any sqlite3_module methods which take a `sqlite3_vtab_cursor*` argument except xClose(), in which case use unget() or dispose(). Rule to remember: _never_ call dispose() on an instance returned by this function. */ get: (pCObj)=>__xWrap(pCObj), /** Identical to get() but also disconnects the mapping between the given pointer and the returned StructType object, such that future calls to this function or get() with the same pointer will return the undefined value. Its intended usage depends on StructType: sqlite3_vtab: to be called from sqlite3_module::xDisconnect() or xDestroy() implementations or in error handling of a failed xCreate() or xConnect(). sqlite3_vtab_cursor: to be called from xClose() or during cleanup in a failed xOpen(). Calling this method obligates the caller to call dispose() on the returned object when they're done with it. */ unget: (pCObj)=>__xWrap(pCObj,true), /** Works like unget() plus it calls dispose() on the StructType object. */ dispose: (pCObj)=>{ |
︙ | ︙ |
Changes to ext/wasm/api/sqlite3-wasm.c.
︙ | ︙ | |||
98 99 100 101 102 103 104 105 106 107 108 109 110 111 | #endif #ifndef SQLITE_ENABLE_FTS4 # define SQLITE_ENABLE_FTS4 1 #endif #ifndef SQLITE_ENABLE_OFFSET_SQL_FUNC # define SQLITE_ENABLE_OFFSET_SQL_FUNC 1 #endif #ifndef SQLITE_ENABLE_RTREE # define SQLITE_ENABLE_RTREE 1 #endif #ifndef SQLITE_ENABLE_STMTVTAB # define SQLITE_ENABLE_STMTVTAB 1 #endif #ifndef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION | > > > | 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | #endif #ifndef SQLITE_ENABLE_FTS4 # define SQLITE_ENABLE_FTS4 1 #endif #ifndef SQLITE_ENABLE_OFFSET_SQL_FUNC # define SQLITE_ENABLE_OFFSET_SQL_FUNC 1 #endif #ifndef SQLITE_ENABLE_MATH_FUNCTIONS # define SQLITE_ENABLE_MATH_FUNCTIONS 1 #endif #ifndef SQLITE_ENABLE_RTREE # define SQLITE_ENABLE_RTREE 1 #endif #ifndef SQLITE_ENABLE_STMTVTAB # define SQLITE_ENABLE_STMTVTAB 1 #endif #ifndef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION |
︙ | ︙ | |||
364 365 366 367 368 369 370 | ** ** If this function returns NULL then it means that the internal ** buffer is not large enough for the generated JSON and needs to be ** increased. In debug builds that will trigger an assert(). */ SQLITE_WASM_KEEP const char * sqlite3_wasm_enum_json(void){ | | | 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 | ** ** If this function returns NULL then it means that the internal ** buffer is not large enough for the generated JSON and needs to be ** increased. In debug builds that will trigger an assert(). */ SQLITE_WASM_KEEP const char * sqlite3_wasm_enum_json(void){ static char aBuffer[1024 * 20] = {0} /* where the JSON goes */; int n = 0, nChildren = 0, nStruct = 0 /* output counters for figuring out where commas go */; char * zPos = &aBuffer[1] /* skip first byte for now to help protect ** against a small race condition */; char const * const zEnd = &aBuffer[0] + sizeof(aBuffer) /* one-past-the-end */; if(aBuffer[0]) return aBuffer; /* Leave aBuffer[0] at 0 until the end to help guard against a tiny |
︙ | ︙ | |||
406 407 408 409 410 411 412 | /* The following groups are sorted alphabetic by group name. */ DefGroup(access){ DefInt(SQLITE_ACCESS_EXISTS); DefInt(SQLITE_ACCESS_READWRITE); DefInt(SQLITE_ACCESS_READ)/*docs say this is unused*/; } _DefGroup; | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 | /* The following groups are sorted alphabetic by group name. */ DefGroup(access){ DefInt(SQLITE_ACCESS_EXISTS); DefInt(SQLITE_ACCESS_READWRITE); DefInt(SQLITE_ACCESS_READ)/*docs say this is unused*/; } _DefGroup; DefGroup(authorizer){ DefInt(SQLITE_DENY); DefInt(SQLITE_IGNORE); DefInt(SQLITE_CREATE_INDEX); DefInt(SQLITE_CREATE_TABLE); DefInt(SQLITE_CREATE_TEMP_INDEX); DefInt(SQLITE_CREATE_TEMP_TABLE); DefInt(SQLITE_CREATE_TEMP_TRIGGER); DefInt(SQLITE_CREATE_TEMP_VIEW); DefInt(SQLITE_CREATE_TRIGGER); DefInt(SQLITE_CREATE_VIEW); DefInt(SQLITE_DELETE); DefInt(SQLITE_DROP_INDEX); DefInt(SQLITE_DROP_TABLE); DefInt(SQLITE_DROP_TEMP_INDEX); DefInt(SQLITE_DROP_TEMP_TABLE); DefInt(SQLITE_DROP_TEMP_TRIGGER); DefInt(SQLITE_DROP_TEMP_VIEW); DefInt(SQLITE_DROP_TRIGGER); DefInt(SQLITE_DROP_VIEW); DefInt(SQLITE_INSERT); DefInt(SQLITE_PRAGMA); DefInt(SQLITE_READ); DefInt(SQLITE_SELECT); DefInt(SQLITE_TRANSACTION); DefInt(SQLITE_UPDATE); DefInt(SQLITE_ATTACH); DefInt(SQLITE_DETACH); DefInt(SQLITE_ALTER_TABLE); DefInt(SQLITE_REINDEX); DefInt(SQLITE_ANALYZE); DefInt(SQLITE_CREATE_VTABLE); DefInt(SQLITE_DROP_VTABLE); DefInt(SQLITE_FUNCTION); DefInt(SQLITE_SAVEPOINT); //DefInt(SQLITE_COPY) /* No longer used */; DefInt(SQLITE_RECURSIVE); } _DefGroup; DefGroup(blobFinalizers) { /* SQLITE_STATIC/TRANSIENT need to be handled explicitly as ** integers to avoid casting-related warnings. */ out("\"SQLITE_STATIC\":0, \"SQLITE_TRANSIENT\":-1"); } _DefGroup; DefGroup(config){ DefInt(SQLITE_CONFIG_SINGLETHREAD); DefInt(SQLITE_CONFIG_MULTITHREAD); DefInt(SQLITE_CONFIG_SERIALIZED); DefInt(SQLITE_CONFIG_MALLOC); DefInt(SQLITE_CONFIG_GETMALLOC); DefInt(SQLITE_CONFIG_SCRATCH); DefInt(SQLITE_CONFIG_PAGECACHE); DefInt(SQLITE_CONFIG_HEAP); DefInt(SQLITE_CONFIG_MEMSTATUS); DefInt(SQLITE_CONFIG_MUTEX); DefInt(SQLITE_CONFIG_GETMUTEX); /* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ DefInt(SQLITE_CONFIG_LOOKASIDE); DefInt(SQLITE_CONFIG_PCACHE); DefInt(SQLITE_CONFIG_GETPCACHE); DefInt(SQLITE_CONFIG_LOG); DefInt(SQLITE_CONFIG_URI); DefInt(SQLITE_CONFIG_PCACHE2); DefInt(SQLITE_CONFIG_GETPCACHE2); DefInt(SQLITE_CONFIG_COVERING_INDEX_SCAN); DefInt(SQLITE_CONFIG_SQLLOG); DefInt(SQLITE_CONFIG_MMAP_SIZE); DefInt(SQLITE_CONFIG_WIN32_HEAPSIZE); DefInt(SQLITE_CONFIG_PCACHE_HDRSZ); DefInt(SQLITE_CONFIG_PMASZ); DefInt(SQLITE_CONFIG_STMTJRNL_SPILL); DefInt(SQLITE_CONFIG_SMALL_MALLOC); DefInt(SQLITE_CONFIG_SORTERREF_SIZE); DefInt(SQLITE_CONFIG_MEMDB_MAXSIZE); } _DefGroup; DefGroup(dataTypes) { DefInt(SQLITE_INTEGER); DefInt(SQLITE_FLOAT); DefInt(SQLITE_TEXT); DefInt(SQLITE_BLOB); DefInt(SQLITE_NULL); |
︙ | ︙ | |||
546 547 548 549 550 551 552 553 554 555 556 557 558 559 | DefInt(SQLITE_IOCAP_POWERSAFE_OVERWRITE); DefInt(SQLITE_IOCAP_IMMUTABLE); DefInt(SQLITE_IOCAP_BATCH_ATOMIC); } _DefGroup; DefGroup(limits) { DefInt(SQLITE_MAX_ALLOCATION_SIZE); } _DefGroup; DefGroup(openFlags) { /* Noting that not all of these will have any effect in ** WASM-space. */ DefInt(SQLITE_OPEN_READONLY); DefInt(SQLITE_OPEN_READWRITE); | > > > > > > > > > > > > > > > > > > > > > > > > | 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 | DefInt(SQLITE_IOCAP_POWERSAFE_OVERWRITE); DefInt(SQLITE_IOCAP_IMMUTABLE); DefInt(SQLITE_IOCAP_BATCH_ATOMIC); } _DefGroup; DefGroup(limits) { DefInt(SQLITE_MAX_ALLOCATION_SIZE); DefInt(SQLITE_LIMIT_LENGTH); DefInt(SQLITE_MAX_LENGTH); DefInt(SQLITE_LIMIT_SQL_LENGTH); DefInt(SQLITE_MAX_SQL_LENGTH); DefInt(SQLITE_LIMIT_COLUMN); DefInt(SQLITE_MAX_COLUMN); DefInt(SQLITE_LIMIT_EXPR_DEPTH); DefInt(SQLITE_MAX_EXPR_DEPTH); DefInt(SQLITE_LIMIT_COMPOUND_SELECT); DefInt(SQLITE_MAX_COMPOUND_SELECT); DefInt(SQLITE_LIMIT_VDBE_OP); DefInt(SQLITE_MAX_VDBE_OP); DefInt(SQLITE_LIMIT_FUNCTION_ARG); DefInt(SQLITE_MAX_FUNCTION_ARG); DefInt(SQLITE_LIMIT_ATTACHED); DefInt(SQLITE_MAX_ATTACHED); DefInt(SQLITE_LIMIT_LIKE_PATTERN_LENGTH); DefInt(SQLITE_MAX_LIKE_PATTERN_LENGTH); DefInt(SQLITE_LIMIT_VARIABLE_NUMBER); DefInt(SQLITE_MAX_VARIABLE_NUMBER); DefInt(SQLITE_LIMIT_TRIGGER_DEPTH); DefInt(SQLITE_MAX_TRIGGER_DEPTH); DefInt(SQLITE_LIMIT_WORKER_THREADS); DefInt(SQLITE_MAX_WORKER_THREADS); } _DefGroup; DefGroup(openFlags) { /* Noting that not all of these will have any effect in ** WASM-space. */ DefInt(SQLITE_OPEN_READONLY); DefInt(SQLITE_OPEN_READWRITE); |
︙ | ︙ | |||
735 736 737 738 739 740 741 742 743 744 745 746 747 748 | DefGroup(trace) { DefInt(SQLITE_TRACE_STMT); DefInt(SQLITE_TRACE_PROFILE); DefInt(SQLITE_TRACE_ROW); DefInt(SQLITE_TRACE_CLOSE); } _DefGroup; DefGroup(udfFlags) { DefInt(SQLITE_DETERMINISTIC); DefInt(SQLITE_DIRECTONLY); DefInt(SQLITE_INNOCUOUS); } _DefGroup; | > > > > > > | 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 | DefGroup(trace) { DefInt(SQLITE_TRACE_STMT); DefInt(SQLITE_TRACE_PROFILE); DefInt(SQLITE_TRACE_ROW); DefInt(SQLITE_TRACE_CLOSE); } _DefGroup; DefGroup(txnState){ DefInt(SQLITE_TXN_NONE); DefInt(SQLITE_TXN_READ); DefInt(SQLITE_TXN_WRITE); } _DefGroup; DefGroup(udfFlags) { DefInt(SQLITE_DETERMINISTIC); DefInt(SQLITE_DIRECTONLY); DefInt(SQLITE_INNOCUOUS); } _DefGroup; |
︙ | ︙ | |||
1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 | sqlite3_db_config(pDb, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0); } } return rc; } /* ** Uses the given database's VFS xRead to stream the db file's ** contents out to the given callback. The callback gets a single ** chunk of size n (its 2nd argument) on each call and must return 0 ** on success, non-0 on error. This function returns 0 on success, ** SQLITE_NOTFOUND if no db is open, or propagates any other non-0 ** code from the callback. Note that this is not thread-friendly: it ** expects that it will be the only thread reading the db file and | > > > | 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 | sqlite3_db_config(pDb, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0); } } return rc; } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** Uses the given database's VFS xRead to stream the db file's ** contents out to the given callback. The callback gets a single ** chunk of size n (its 2nd argument) on each call and must return 0 ** on success, non-0 on error. This function returns 0 on success, ** SQLITE_NOTFOUND if no db is open, or propagates any other non-0 ** code from the callback. Note that this is not thread-friendly: it ** expects that it will be the only thread reading the db file and |
︙ | ︙ | |||
1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 | } if( 0==rc ) rc = xCallback(buf, nBuf); } return rc; } /* ** A proxy for sqlite3_serialize() which serializes the schema zSchema ** of pDb, placing the serialized output in pOut and nOut. nOut may be ** NULL. If zSchema is NULL then "main" is assumed. If pDb or pOut are ** NULL then SQLITE_MISUSE is returned. If allocation of the ** serialized copy fails, SQLITE_NOMEM is returned. On success, 0 is ** returned and `*pOut` will contain a pointer to the memory unless ** mFlags includes SQLITE_SERIALIZE_NOCOPY and the database has no | > > > | 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 | } if( 0==rc ) rc = xCallback(buf, nBuf); } return rc; } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** A proxy for sqlite3_serialize() which serializes the schema zSchema ** of pDb, placing the serialized output in pOut and nOut. nOut may be ** NULL. If zSchema is NULL then "main" is assumed. If pDb or pOut are ** NULL then SQLITE_MISUSE is returned. If allocation of the ** serialized copy fails, SQLITE_NOMEM is returned. On success, 0 is ** returned and `*pOut` will contain a pointer to the memory unless ** mFlags includes SQLITE_SERIALIZE_NOCOPY and the database has no |
︙ | ︙ | |||
1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 | switch(op){ case SQLITE_DBCONFIG_MAINDBNAME: return sqlite3_db_config(pDb, op, zArg); default: return SQLITE_MISUSE; } } #if defined(__EMSCRIPTEN__) && defined(SQLITE_ENABLE_WASMFS) #include <emscripten/wasmfs.h> /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings, specifically | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 | switch(op){ case SQLITE_DBCONFIG_MAINDBNAME: return sqlite3_db_config(pDb, op, zArg); default: return SQLITE_MISUSE; } } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** Binding for combinations of sqlite3_config() arguments which take ** a single integer argument. */ SQLITE_WASM_KEEP int sqlite3_wasm_config_i(int op, int arg){ return sqlite3_config(op, arg); } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** Binding for combinations of sqlite3_config() arguments which take ** two int arguments. */ SQLITE_WASM_KEEP int sqlite3_wasm_config_ii(int op, int arg1, int arg2){ return sqlite3_config(op, arg1, arg2); } /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings. ** ** Binding for combinations of sqlite3_config() arguments which take ** a single i64 argument. */ SQLITE_WASM_KEEP int sqlite3_wasm_config_j(int op, sqlite3_int64 arg){ return sqlite3_config(op, arg); } #if defined(__EMSCRIPTEN__) && defined(SQLITE_ENABLE_WASMFS) #include <emscripten/wasmfs.h> /* ** This function is NOT part of the sqlite3 public API. It is strictly ** for use by the sqlite project's own JS/WASM bindings, specifically |
︙ | ︙ | |||
1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 | #if SQLITE_WASM_TESTS SQLITE_WASM_KEEP int sqlite3_wasm_test_intptr(int * p){ return *p = *p * 2; } SQLITE_WASM_KEEP int64_t sqlite3_wasm_test_int64_max(void){ return (int64_t)0x7fffffffffffffff; } SQLITE_WASM_KEEP | > > > > > | 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 | #if SQLITE_WASM_TESTS SQLITE_WASM_KEEP int sqlite3_wasm_test_intptr(int * p){ return *p = *p * 2; } SQLITE_WASM_KEEP void * sqlite3_wasm_test_voidptr(void * p){ return p; } SQLITE_WASM_KEEP int64_t sqlite3_wasm_test_int64_max(void){ return (int64_t)0x7fffffffffffffff; } SQLITE_WASM_KEEP |
︙ | ︙ | |||
1510 1511 1512 1513 1514 1515 1516 | } SQLITE_WASM_KEEP void sqlite3_wasm_test_stack_overflow(int recurse){ if(recurse) sqlite3_wasm_test_stack_overflow(recurse); } | | | 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 | } SQLITE_WASM_KEEP void sqlite3_wasm_test_stack_overflow(int recurse){ if(recurse) sqlite3_wasm_test_stack_overflow(recurse); } /* For testing the 'string:dealloc' whwasmutil.xWrap() conversion. */ SQLITE_WASM_KEEP char * sqlite3_wasm_test_str_hello(int fail){ char * s = fail ? 0 : (char *)sqlite3_malloc(6); if(s){ memcpy(s, "hello", 5); s[5] = 0; } return s; } #endif /* SQLITE_WASM_TESTS */ #undef SQLITE_WASM_KEEP |
Changes to ext/wasm/common/whwasmutil.js.
︙ | ︙ | |||
355 356 357 358 359 360 361 | - Use `__indirect_function_table` as the import name for the table, which is what LLVM does. */ }; /** Given a function pointer, returns the WASM function table entry | | > | 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 | - Use `__indirect_function_table` as the import name for the table, which is what LLVM does. */ }; /** Given a function pointer, returns the WASM function table entry if found, else returns a falsy value: undefined if fptr is out of range or null if it's in range but the table entry is empty. */ target.functionEntry = function(fptr){ const ft = target.functionTable(); return fptr < ft.length ? ft.get(fptr) : undefined; }; /** |
︙ | ︙ | |||
490 491 492 493 494 495 496 | 0x01, 0x01, 0x66, 0x00, 0x00 ); return (new WebAssembly.Instance( new WebAssembly.Module(new Uint8Array(wasmCode)), { e: { f: func } })).exports['f']; }/*jsFuncToWasm()*/; | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 | 0x01, 0x01, 0x66, 0x00, 0x00 ); return (new WebAssembly.Instance( new WebAssembly.Module(new Uint8Array(wasmCode)), { e: { f: func } })).exports['f']; }/*jsFuncToWasm()*/; /** Documented as target.installFunction() except for the 3rd argument: if truthy, the newly-created function pointer is stashed in the current scoped-alloc scope and will be cleaned up at the matching scopedAllocPop(), else it is not stashed there. */ const __installFunction = function f(func, sig, scoped){ if(scoped && !cache.scopedAlloc.length){ toss("No scopedAllocPush() scope is active."); } if('string'===typeof func){ const x = sig; sig = func; func = x; } if('string'!==typeof sig || !(func instanceof Function)){ toss("Invalid arguments: expecting (function,signature) "+ "or (signature,function)."); } const ft = target.functionTable(); const oldLen = ft.length; let ptr; while(cache.freeFuncIndexes.length){ ptr = cache.freeFuncIndexes.pop(); if(ft.get(ptr)){ /* Table was modified via a different API */ ptr = null; continue; }else{ break; } } if(!ptr){ ptr = oldLen; ft.grow(1); } try{ /*this will only work if func is a WASM-exported function*/ ft.set(ptr, func); if(scoped){ cache.scopedAlloc[cache.scopedAlloc.length-1].push(ptr); } return ptr; }catch(e){ if(!(e instanceof TypeError)){ if(ptr===oldLen) cache.freeFuncIndexes.push(oldLen); throw e; } } // It's not a WASM-exported function, so compile one... try { const fptr = target.jsFuncToWasm(func, sig); ft.set(ptr, fptr); if(scoped){ cache.scopedAlloc[cache.scopedAlloc.length-1].push(ptr); } }catch(e){ if(ptr===oldLen) cache.freeFuncIndexes.push(oldLen); throw e; } return ptr; }; /** Expects a JS function and signature, exactly as for this.jsFuncToWasm(). It uses that function to create a WASM-exported function, installs that function to the next available slot of this.functionTable(), and returns the function's index in that table (which acts as a pointer to that function). The returned pointer can be passed to |
︙ | ︙ | |||
522 523 524 525 526 527 528 | _primarily_ in that it does not share that function's undocumented behavior of reusing a function if it's passed to addFunction() more than once, which leads to uninstallFunction() breaking clients which do not take care to avoid that case: https://github.com/emscripten-core/emscripten/issues/17323 */ | | < < | < < < < > > | > | < < < < | < | < < < < < < < < < | | < < < < < < < < < > | < < < < < < > > > > > | 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 | _primarily_ in that it does not share that function's undocumented behavior of reusing a function if it's passed to addFunction() more than once, which leads to uninstallFunction() breaking clients which do not take care to avoid that case: https://github.com/emscripten-core/emscripten/issues/17323 */ target.installFunction = (func, sig)=>__installFunction(func, sig, false); /** EXPERIMENTAL! DO NOT USE IN CLIENT CODE! Works exactly like installFunction() but requires that a scopedAllocPush() is active and uninstalls the given function when that alloc scope is popped via scopedAllocPop(). This is used for implementing JS/WASM function bindings which should only persist for the life of a call into a single C-side function. */ target.scopedInstallFunction = (func, sig)=>__installFunction(func, sig, true); /** Requires a pointer value previously returned from this.installFunction(). Removes that function from the WASM function table, marks its table slot as free for re-use, and returns that function. It is illegal to call this before installFunction() has been called and results are undefined if ptr was not returned by that function. The returned function may be passed back to installFunction() to reinstall it. To simplify certain use cases, if passed a falsy non-0 value (noting that 0 is a valid function table index), this function has no side effects and returns undefined. */ target.uninstallFunction = function(ptr){ if(!ptr && 0!==ptr) return undefined; const fi = cache.freeFuncIndexes; const ft = target.functionTable(); fi.push(ptr); const rc = ft.get(ptr); ft.set(ptr, null); return rc; }; |
︙ | ︙ | |||
693 694 695 696 697 698 699 | */ target.poke = function(ptr, value, type='i8'){ if (type.endsWith('*')) type = ptrIR; const c = (cache.memory && cache.heapSize === cache.memory.buffer.byteLength) ? cache : heapWrappers(); for(const p of (Array.isArray(ptr) ? ptr : [ptr])){ switch (type) { | | | 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 | */ target.poke = function(ptr, value, type='i8'){ if (type.endsWith('*')) type = ptrIR; const c = (cache.memory && cache.heapSize === cache.memory.buffer.byteLength) ? cache : heapWrappers(); for(const p of (Array.isArray(ptr) ? ptr : [ptr])){ switch (type) { case 'i1': case 'i8': c.HEAP8[p>>0] = value; continue; case 'i16': c.HEAP16[p>>1] = value; continue; case 'i32': c.HEAP32[p>>2] = value; continue; case 'float': case 'f32': c.HEAP32F[p>>2] = value; continue; case 'double': case 'f64': c.HEAP64F[p>>3] = value; continue; case 'i64': if(c.HEAP64){ |
︙ | ︙ | |||
722 723 724 725 726 727 728 | it returns the value of that one pointer address. If passed multiple arguments, or a single array of arguments, it returns an array of their values. */ target.peekPtr = (...ptr)=>target.peek( (1===ptr.length ? ptr[0] : ptr), ptrIR ); /** | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 | it returns the value of that one pointer address. If passed multiple arguments, or a single array of arguments, it returns an array of their values. */ target.peekPtr = (...ptr)=>target.peek( (1===ptr.length ? ptr[0] : ptr), ptrIR ); /** A variant of poke() intended for setting pointer-to-pointer values. Its differences from poke() are that (1) it defaults to a value of 0 and (2) it always writes to the pointer-sized heap view. */ target.pokePtr = (ptr, value=0)=>target.poke(ptr, value, ptrIR); /** Convenience form of peek() intended for fetching i8 values. If passed a single non-array argument it returns the value of that one pointer address. If passed multiple arguments, or a single array of arguments, it returns an array of their values. */ target.peek8 = (...ptr)=>target.peek( (1===ptr.length ? ptr[0] : ptr), 'i8' ); /** Convience form of poke() intended for setting individual bytes. Its difference from poke() is that it always writes to the i8-sized heap view. */ target.poke8 = (ptr, value)=>target.poke(ptr, value, 'i8'); /** i16 variant of peek8(). */ target.peek16 = (...ptr)=>target.peek( (1===ptr.length ? ptr[0] : ptr), 'i16' ); /** i16 variant of poke8(). */ target.poke16 = (ptr, value)=>target.poke(ptr, value, 'i16'); /** i32 variant of peek8(). */ target.peek32 = (...ptr)=>target.peek( (1===ptr.length ? ptr[0] : ptr), 'i32' ); /** i32 variant of poke8(). */ target.poke32 = (ptr, value)=>target.poke(ptr, value, 'i32'); /** i64 variant of peek8(). Will throw if this build is not configured for BigInt support. */ target.peek64 = (...ptr)=>target.peek( (1===ptr.length ? ptr[0] : ptr), 'i64' ); /** i64 variant of poke8(). Will throw if this build is not configured for BigInt support. Note that this returns a BigInt-type value, not a Number-type value. */ target.poke64 = (ptr, value)=>target.poke(ptr, value, 'i64'); /** f32 variant of peek8(). */ target.peek32f = (...ptr)=>target.peek( (1===ptr.length ? ptr[0] : ptr), 'f32' ); /** f32 variant of poke8(). */ target.poke32f = (ptr, value)=>target.poke(ptr, value, 'f32'); /** f64 variant of peek8(). */ target.peek64f = (...ptr)=>target.peek( (1===ptr.length ? ptr[0] : ptr), 'f64' ); /** f64 variant of poke8(). */ target.poke64f = (ptr, value)=>target.poke(ptr, value, 'f64'); /** Deprecated alias for getMemValue() */ target.getMemValue = target.peek; /** Deprecated alias for peekPtr() */ target.getPtrValue = target.peekPtr; /** Deprecated alias for poke() */ target.setMemValue = target.poke; /** Deprecated alias for pokePtr() */ |
︙ | ︙ | |||
1079 1080 1081 1082 1083 1084 1085 | __affirmAlloc(target, 'scopedAllocPop'); const n = arguments.length ? cache.scopedAlloc.indexOf(state) : cache.scopedAlloc.length-1; if(n<0) toss("Invalid state object for scopedAllocPop()."); if(0===arguments.length) state = cache.scopedAlloc[n]; cache.scopedAlloc.splice(n,1); | | > > > > > > | 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 | __affirmAlloc(target, 'scopedAllocPop'); const n = arguments.length ? cache.scopedAlloc.indexOf(state) : cache.scopedAlloc.length-1; if(n<0) toss("Invalid state object for scopedAllocPop()."); if(0===arguments.length) state = cache.scopedAlloc[n]; cache.scopedAlloc.splice(n,1); for(let p; (p = state.pop()); ){ if(target.functionEntry(p)){ //console.warn("scopedAllocPop() uninstalling transient function",p); target.uninstallFunction(p); } else target.dealloc(p); } }; /** Allocates n bytes of memory using this.alloc() and records that fact in the state for the most recent call of scopedAllocPush(). Ownership of the memory is given to scopedAllocPop(), which will clean it up when it is called. The memory _must not_ be |
︙ | ︙ | |||
1270 1271 1272 1273 1274 1275 1276 | */ target.xGet = function(name){ return target.exports[name] || toss("Cannot find exported symbol:",name); }; const __argcMismatch = (f,n)=>toss(f+"() requires",n,"argument(s)."); | | | 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 | */ target.xGet = function(name){ return target.exports[name] || toss("Cannot find exported symbol:",name); }; const __argcMismatch = (f,n)=>toss(f+"() requires",n,"argument(s)."); /** Looks up a WASM-exported function named fname from target.exports. If found, it is called, passed all remaining arguments, and its return value is returned to xCall's caller. If not found, an exception is thrown. This function does no conversion of argument or return types, but see xWrap() and xCallWrapped() for variants which do. |
︙ | ︙ | |||
1299 1300 1301 1302 1303 1304 1305 | : f.apply(null, args); }; /** State for use with xWrap() */ cache.xWrap = Object.create(null); | | | | > | > | > | | | > > | | > > > > > | | > > > | > > | | | > < | | | | > > > > > | > | | | | > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | < | | | > > > > > > > | > > | | > | | > > > > > > | > > > > | > > > > > > > > > > > > > > > | > > > > > | > > | | | > > > > | > > > > > > > > | > > > > | | < < < < < | < | < < < < < | | | | > | | > > > > > > | | > > > | > > > > | | | | 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 | : f.apply(null, args); }; /** State for use with xWrap() */ cache.xWrap = Object.create(null); cache.xWrap.convert = Object.create(null); /** Map of type names to argument conversion functions. */ cache.xWrap.convert.arg = new Map; /** Map of type names to return result conversion functions. */ cache.xWrap.convert.result = new Map; const xArg = cache.xWrap.convert.arg, xResult = cache.xWrap.convert.result; if(target.bigIntEnabled){ xArg.set('i64', (i)=>BigInt(i)); } const __xArgPtr = 'i32' === ptrIR ? ((i)=>(i | 0)) : ((i)=>(BigInt(i) | BigInt(0))); xArg.set('i32', __xArgPtr ) .set('i16', (i)=>((i | 0) & 0xFFFF)) .set('i8', (i)=>((i | 0) & 0xFF)) .set('f32', (i)=>Number(i).valueOf()) .set('float', xArg.get('f32')) .set('f64', xArg.get('f32')) .set('double', xArg.get('f64')) .set('int', xArg.get('i32')) .set('null', (i)=>i) .set(null, xArg.get('null')) .set('**', __xArgPtr) .set('*', __xArgPtr); xResult.set('*', __xArgPtr) .set('pointer', __xArgPtr) .set('number', (v)=>Number(v)) .set('void', (v)=>undefined) .set('null', (v)=>v) .set(null, xResult.get('null')); { /* Copy certain xArg[...] handlers to xResult[...] and add pointer-style variants of them. */ const copyToResult = ['i8', 'i16', 'i32', 'int', 'f32', 'float', 'f64', 'double']; if(target.bigIntEnabled) copyToResult.push('i64'); const adaptPtr = xArg.get(ptrIR); for(const t of copyToResult){ xArg.set(t+'*', adaptPtr); xResult.set(t+'*', adaptPtr); xResult.set(t, (xArg.get(t) || toss("Missing arg converter:",t))); } } /** In order for args of type string to work in various contexts in the sqlite3 API, we need to pass them on as, variably, a C-string or a pointer value. Thus for ARGs of type 'string' and '*'/'pointer' we behave differently depending on whether the argument is a string or not: - If v is a string, scopeAlloc() a new C-string from it and return that temp string's pointer. - Else return the value from the arg adapter defined for ptrIR. TODO? Permit an Int8Array/Uint8Array and convert it to a string? Would that be too much magic concentrated in one place, ready to backfire? We handle that at the client level in sqlite3 with a custom argument converter. */ const __xArgString = function(v){ if('string'===typeof v) return target.scopedAllocCString(v); return v ? __xArgPtr(v) : null; }; xArg.set('string', __xArgString) .set('utf8', __xArgString) .set('pointer', __xArgString); //xArg.set('*', __xArgString); xResult.set('string', (i)=>target.cstrToJs(i)) .set('utf8', xResult.get('string')) .set('string:dealloc', (i)=>{ try { return i ? target.cstrToJs(i) : null } finally{ target.dealloc(i) } }) .set('utf8:dealloc', xResult.get('string:dealloc')) .set('json', (i)=>JSON.parse(target.cstrToJs(i))) .set('json:dealloc', (i)=>{ try{ return i ? JSON.parse(target.cstrToJs(i)) : null } finally{ target.dealloc(i) } }); /** Internal-use-only base class for FuncPtrAdapter and potentially additional stateful argument adapter classes. Note that its main interface (convertArg()) is strictly internal, not to be exposed to client code, as it may still need re-shaping. Only the constructors of concrete subclasses should be exposed to clients, and those in such a way that does not hinder internal redesign of the convertArg() interface. */ const AbstractArgAdapter = class { constructor(opt){ this.name = opt.name; } /** Gets called via xWrap() to "convert" v to whatever type this specific class supports. argIndex is the argv index of _this_ argument in the being-xWrap()'d call. argv is the current argument list undergoing xWrap() argument conversion. argv entries to the left of argIndex will have already undergone transformation and those to the right will not have (they will have the values the client-level code passed in, awaiting conversion). The RHS indexes must never be relied upon for anything because their types are indeterminate, whereas the LHS values will be WASM-compatible values by the time this is called. */ convertArg(v,argIndex,argv){ toss("AbstractArgAdapter must be subclassed."); } }; /** An attempt at adding function pointer conversion support to xWrap(). This type is recognized by xWrap() as a proxy for converting a JS function to a C-side function, either permanently, for the duration of a single call into the C layer, or semi-contextual, where it may keep track of a single binding for a given context and uninstall the binding if it's replaced. The constructor requires an options object with these properties: - name (optional): string describing the function binding. This is solely for debugging and error-reporting purposes. If not provided, an empty string is assumed. - signature: a function signature string compatible with jsFuncToWasm(). - bindScope (string): one of ('transient', 'context', 'singleton'). Bind scopes are: - 'transient': it will convert JS functions to WASM only for the duration of the xWrap()'d function call, using scopedInstallFunction(). Before that call returns, the WASM-side binding will be uninstalled. - 'singleton': holds one function-pointer binding for this instance. If it's called with a different function pointer, it uninstalls the previous one after converting the new value. This is only useful for use with "global" functions which do not rely on any state other than this function pointer. If the being-converted function pointer is intended to be mapped to some sort of state object (e.g. an `sqlite3*`) then "context" (see below) is the proper mode. - 'context': similar to singleton mode but for a given "context", where the context is a key provided by the user and possibly dependent on a small amount of call-time context. This mode is the default if bindScope is _not_ set but a property named contextKey (described below) is. - contextKey (function): is only used if bindScope is 'context' or if bindScope is not set and this function is, in which case 'context' is assumed. This function gets passed (argIndex,argv), where argIndex is the index of _this_ function pointer in its _wrapping_ function's arguments and argv is the _current_ still-being-xWrap()-processed args array. All arguments to the left of argIndex will have been processed by xWrap() by the time this is called. argv[argIndex] will be the value the user passed in to the xWrap()'d function for the argument this FuncPtrAdapter is mapped to. Arguments to the right of argv[argIndex] will not yet have been converted before this is called. The function must return a key which uniquely identifies this function mapping context for _this_ FuncPtrAdapter instance (other instances are not considered), taking into account that C functions often take some sort of state object as one or more of their arguments. As an example, if the xWrap()'d function takes `(int,T*,functionPtr,X*)` and this FuncPtrAdapter is the argv[2]nd arg, contextKey(2,argv) might return 'T@'+argv[1], or even just argv[1]. Note, however, that the (X*) argument will not yet have been processed by the time this is called and should not be used as part of that key because its pre-conversion data type might be unpredictable. Similarly, care must be taken with C-string-type arguments: those to the left in argv will, when this is called, be WASM pointers, whereas those to the right might (and likely do) have another data type. When using C-strings in keys, never use their pointers in the key because most C-strings in this constellation are transient. Yes, that ^^^ is a bit awkward, but it's what we have. The constructor only saves the above state for later, and does not actually bind any functions. Its convertArg() method is called via xWrap() to perform any bindings. Shortcomings: function pointers which include C-string arguments may still need a level of hand-written wrappers around them, depending on how they're used, in order to provide the client with JS strings. */ xArg.FuncPtrAdapter = class FuncPtrAdapter extends AbstractArgAdapter { constructor(opt) { super(opt); this.signature = opt.signature; if(!opt.bindScope && (opt.contextKey instanceof Function)){ opt.bindScope = 'context'; }else if(FuncPtrAdapter.bindScopes.indexOf(opt.bindScope)<0){ toss("Invalid options.bindScope ("+opt.bindMod+") for FuncPtrAdapter. "+ "Expecting one of: ("+FuncPtrAdapter.bindScopes.join(', ')+')'); } this.bindScope = opt.bindScope; if(opt.contextKey) this.contextKey = opt.contextKey /*else inherit one*/; this.isTransient = 'transient'===this.bindScope; this.isContext = 'context'===this.bindScope; if( ('singleton'===this.bindScope) ) this.singleton = []; else this.singleton = undefined; //console.warn("FuncPtrAdapter()",opt,this); } static bindScopes = [ 'transient', 'context', 'singleton' ]; /* Dummy impl. Overwritten per-instance as needed. */ contextKey(argIndex,argv){ return this; } /* Returns this objects mapping for the given context key, in the form of an an array, creating the mapping if needed. The key may be anything suitable for use in a Map. */ contextMap(key){ const cm = (this.__cmap || (this.__cmap = new Map)); let rc = cm.get(key); if(undefined===rc) cm.set(key, (rc = [])); return rc; } /** Gets called via xWrap() to "convert" v to a WASM-bound function pointer. If v is one of (a pointer, null, undefined) then (v||0) is returned and any earlier function installed by this mapping _might_, depending on how it's bound, be uninstalled. If v is not one of those types, it must be a Function, for which it creates (if needed) a WASM function binding and returns the WASM pointer to that binding. If this instance is not in 'transient' mode, it will remember the binding for at least the next call, to avoid recreating the function binding unnecessarily. If it's passed a pointer(ish) value for v, it does _not_ perform any function binding, so this object's bindMode is irrelevant for such cases. See the parent class's convertArg() docs for details on what exactly the 2nd and 3rd arguments are. */ convertArg(v,argIndex,argv){ //console.warn("FuncPtrAdapter.convertArg()",this.signature,this.transient,v); let pair = this.singleton; if(!pair && this.isContext){ pair = this.contextMap(this.contextKey(argIndex, argv)); } if(pair && pair[0]===v) return pair[1]; if(v instanceof Function){ const fp = __installFunction(v, this.signature, this.isTransient); if(pair){ /* Replace existing stashed mapping */ if(pair[1]){ try{target.uninstallFunction(pair[1])} catch(e){/*ignored*/} } pair[0] = v; pair[1] = fp; } return fp; }else if(target.isPtr(v) || null===v || undefined===v){ if(pair && pair[1] && pair[1]!==v){ /* uninstall stashed mapping and replace stashed mapping with v. */ //console.warn("FuncPtrAdapter is uninstalling function", this.contextKey(argIndex,argv),v); try{target.uninstallFunction(pair[1])} catch(e){/*ignored*/} pair[0] = pair[1] = (v || 0); } return v || 0; }else{ throw new TypeError("Invalid FuncPtrAdapter argument type. "+ "Expecting a function pointer or a "+ (this.name ? this.name+' ' : '')+ "function matching signature "+ this.signature+"."); } }/*convertArg()*/ }/*FuncPtrAdapter*/; const __xArgAdapterCheck = (t)=>xArg.get(t) || toss("Argument adapter not found:",t); const __xResultAdapterCheck = (t)=>xResult.get(t) || toss("Result adapter not found:",t); cache.xWrap.convertArg = (t,...args)=>__xArgAdapterCheck(t)(...args); cache.xWrap.convertArgNoCheck = (t,...args)=>xArg.get(t)(...args); cache.xWrap.convertResult = (t,v)=>(null===t ? v : (t ? __xResultAdapterCheck(t)(v) : undefined)); cache.xWrap.convertResultNoCheck = (t,v)=>(null===t ? v : (t ? xResult.get(t)(v) : undefined)); /** Creates a wrapper for another function which converts the arguments of the wrapper to argument types accepted by the wrapped function, then converts the wrapped function's result to another form for the wrapper. The first argument must be one of: - A JavaScript function. - The name of a WASM-exported function. In the latter case xGet() is used to fetch the exported function, which throws if it's not found. - A pointer into the indirect function table. e.g. a pointer returned from target.installFunction(). It returns either the passed-in function or a wrapper for that function which converts the JS-side argument types into WASM-side types and converts the result type. The second argument, `resultType`, describes the conversion for the wrapped functions result. A literal `null` or the string `'null'` both mean to return the original function's value as-is (mnemonic: there is "null" conversion going on). Literal `undefined` or the string `"void"` both mean to ignore the function's result and return `undefined`. Aside from those two special cases, the `resultType` value may be one of the values described below or any mapping installed by the client using xWrap.resultAdapter(). If passed 3 arguments and the final one is an array, that array must contain a list of type names (see below) for adapting the arguments from JS to WASM. If passed 2 arguments, more than 3, or the 3rd is not an array, all arguments after the 2nd (if any) are treated as type names. i.e.: ``` xWrap('funcname', 'i32', 'string', 'f64'); // is equivalent to: xWrap('funcname', 'i32', ['string', 'f64']); ``` This function enforces that the given list of arguments has the same arity as the being-wrapped function (as defined by its `length` property) and it will throw if that is not the case. Similarly, the created wrapper will throw if passed a differing argument count. Type names are symbolic names which map the arguments to an adapter function to convert, if needed, the value before passing it on to WASM or to convert a return result from WASM. The list of built-in names: - `i8`, `i16`, `i32` (args and results): all integer conversions which convert their argument to an integer and truncate it to the given bit length. - `N*` (args): a type name in the form `N*`, where N is a numeric type name, is treated the same as WASM pointer. - `*` and `pointer` (args): are assumed to be WASM pointer values and are returned coerced to an appropriately-sized pointer value (i32 or i64). Non-numeric values will coerce to 0 and out-of-range values will have undefined results (just as with any pointer misuse). - `*` and `pointer` (results): aliases for the current WASM pointer numeric type. - `**` (args): is simply a descriptive alias for the WASM pointer type. It's primarily intended to mark output-pointer arguments. - `i64` (args and results): passes the value to BigInt() to convert it to an int64. Only available if bigIntEnabled is true. - `f32` (`float`), `f64` (`double`) (args and results): pass their argument to Number(). i.e. the adapter does not currently distinguish between the two types of floating-point numbers. - `number` (results): converts the result to a JS Number using Number(theValue).valueOf(). Note that this is for result conversions only, as it's not possible to generically know which type of number to convert arguments to. Non-numeric conversions include: - `null` literal or `"null"` string (args and results): perform no translation and pass the arg on as-is. This is primarily useful for results but may have a use or two for arguments. - `string` or `utf8` (args): has two different semantics in order to accommodate various uses of certain C APIs (e.g. output-style strings)... - If the arg is a string, it creates a _temporary_ UTF-8-encoded C-string to pass to the exported function, cleaning it up before the wrapper returns. If a long-lived C-string pointer is required, that requires client-side code to create the string, then pass its pointer to the function. - Else the arg is assumed to be a pointer to a string the client has already allocated and it's passed on as a WASM pointer. - `string` or `utf8` (results): treats the result value as a const C-string, encoded as UTF-8, copies it to a JS string, and returns that JS string. - `string:dealloc` or `utf8:dealloc) (results): treats the result value as a non-const UTF-8 C-string, ownership of which has just been transfered to the caller. It copies the C-string to a JS string, frees the C-string, and returns the JS string. If such a result value is NULL, the JS result is `null`. Achtung: when using an API which returns results from a specific allocator, |
︙ | ︙ | |||
1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 | exception. Clients may map their own result and argument adapters using xWrap.resultAdapter() and xWrap.argAdapter(), noting that not all type conversions are valid for both arguments _and_ result types as they often have different memory ownership requirements. TODOs: - Figure out how/whether we can (semi-)transparently handle pointer-type _output_ arguments. Those currently require explicit handling by allocating pointers, assigning them before the call using poke(), and fetching them with peek() after the call. We may be able to automate some or all of that. - Figure out whether it makes sense to extend the arg adapter interface such that each arg adapter gets an array containing the results of the previous arguments in the current call. That might allow some interesting type-conversion feature. Use case: handling of the final argument to sqlite3_prepare_v2() depends on the type (pointer vs JS string) of its 2nd argument. Currently that distinction requires hand-writing a wrapper for that function. That case is unusual enough that abstracting it into this API (and taking on the associated costs) may well not make good sense. */ | > > > > > | > | > > > > > | | > > > | > | | > > > > > > > > > > > > > > > | | | | | | 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 | exception. Clients may map their own result and argument adapters using xWrap.resultAdapter() and xWrap.argAdapter(), noting that not all type conversions are valid for both arguments _and_ result types as they often have different memory ownership requirements. Design note: the ability to pass in a JS function as the first argument is of relatively limited use, primarily for testing argument and result converters. JS functions, by and large, will not want to deal with C-type arguments. TODOs: - Figure out how/whether we can (semi-)transparently handle pointer-type _output_ arguments. Those currently require explicit handling by allocating pointers, assigning them before the call using poke(), and fetching them with peek() after the call. We may be able to automate some or all of that. - Figure out whether it makes sense to extend the arg adapter interface such that each arg adapter gets an array containing the results of the previous arguments in the current call. That might allow some interesting type-conversion feature. Use case: handling of the final argument to sqlite3_prepare_v2() depends on the type (pointer vs JS string) of its 2nd argument. Currently that distinction requires hand-writing a wrapper for that function. That case is unusual enough that abstracting it into this API (and taking on the associated costs) may well not make good sense. */ target.xWrap = function(fArg, resultType, ...argTypes){ if(3===arguments.length && Array.isArray(arguments[2])){ argTypes = arguments[2]; } if(target.isPtr(fArg)){ fArg = target.functionEntry(fArg) || toss("Function pointer not found in WASM function table."); } const fIsFunc = (fArg instanceof Function); const xf = fIsFunc ? fArg : target.xGet(fArg); if(fIsFunc) fArg = xf.name || 'unnamed function'; if(argTypes.length!==xf.length) __argcMismatch(fArg, xf.length); if((null===resultType) && 0===xf.length){ /* Func taking no args with an as-is return. We don't need a wrapper. We forego the argc check here, though. */ return xf; } /*Verify the arg type conversions are valid...*/; if(undefined!==resultType && null!==resultType) __xResultAdapterCheck(resultType); for(const t of argTypes){ if(t instanceof AbstractArgAdapter) xArg.set(t, (...args)=>t.convertArg(...args)); else __xArgAdapterCheck(t); } const cxw = cache.xWrap; if(0===xf.length){ // No args to convert, so we can create a simpler wrapper... return (...args)=>(args.length ? __argcMismatch(fArg, xf.length) : cxw.convertResult(resultType, xf.call(null))); } return function(...args){ if(args.length!==xf.length) __argcMismatch(fArg, xf.length); const scope = target.scopedAllocPush(); try{ /* Maintenance reminder re. arguments passed to convertArgs(): The public interface of argument adapters is that they take ONE argument and return a (possibly) converted result for it. The passing-on of arguments after the first is an internal impl. detail for the sake of AbstractArgAdapter, and not to be relied on or documented for other cases. The fact that this is how AbstractArgAdapter.convertArgs() gets its 2nd+ arguments, and how FuncPtrAdapter.contextKey() gets its args, is also an implementation detail and subject to change. i.e. the public interface of 1 argument is stable. The fact that any arguments may be passed in after that one, and what those arguments are, is _not_ part of the public interface and is _not_ stable. */ for(const i in args) args[i] = cxw.convertArgNoCheck(argTypes[i], args[i], i, args); return cxw.convertResultNoCheck(resultType, xf.apply(null,args)); }finally{ target.scopedAllocPop(scope); } }; }/*xWrap()*/; /** Internal impl for xWrap.resultAdapter() and argAdapter(). */ const __xAdapter = function(func, argc, typeName, adapter, modeName, xcvPart){ if('string'===typeof typeName){ if(1===argc) return xcvPart.get(typeName); else if(2===argc){ if(!adapter){ delete xcvPart.get(typeName); return func; }else if(!(adapter instanceof Function)){ toss(modeName,"requires a function argument."); } xcvPart.set(typeName, adapter); return func; } } toss("Invalid arguments to",modeName); }; /** |
︙ | ︙ | |||
1617 1618 1619 1620 1621 1622 1623 | freed before because they would be freed before the wrapper returns, leading to chaos and undefined behavior. Except when called as a getter, this function returns itself. */ target.xWrap.resultAdapter = function f(typeName, adapter){ return __xAdapter(f, arguments.length, typeName, adapter, | | | 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 | freed before because they would be freed before the wrapper returns, leading to chaos and undefined behavior. Except when called as a getter, this function returns itself. */ target.xWrap.resultAdapter = function f(typeName, adapter){ return __xAdapter(f, arguments.length, typeName, adapter, 'resultAdapter()', xResult); }; /** Functions identically to xWrap.resultAdapter() but applies to call argument conversions instead of result value conversions. xWrap()-generated wrappers perform argument conversion in the |
︙ | ︙ | |||
1647 1648 1649 1650 1651 1652 1653 | Note that it is perfectly legitimate to use these adapters to perform argument validation, as opposed (or in addition) to conversion. */ target.xWrap.argAdapter = function f(typeName, adapter){ return __xAdapter(f, arguments.length, typeName, adapter, | | > > | < | | | | | | | | | > > > | 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 | Note that it is perfectly legitimate to use these adapters to perform argument validation, as opposed (or in addition) to conversion. */ target.xWrap.argAdapter = function f(typeName, adapter){ return __xAdapter(f, arguments.length, typeName, adapter, 'argAdapter()', xArg); }; target.xWrap.FuncPtrAdapter = xArg.FuncPtrAdapter; /** Functions like xCall() but performs argument and result type conversions as for xWrap(). The first, second, and third arguments are as documented for xWrap(), except that the 3rd argument may be either a falsy value or empty array to represent nullary functions. The 4th+ arguments are arguments for the call, with the special case that if the 4th argument is an array, it is used as the arguments for the call. Returns the converted result of the call. This is just a thin wrapper around xWrap(). If the given function is to be called more than once, it's more efficient to use xWrap() to create a wrapper, then to call that wrapper as many times as needed. For one-shot calls, however, this variant is arguably more efficient because it will hypothetically free the wrapper function quickly. */ target.xCallWrapped = function(fArg, resultType, argTypes, ...args){ if(Array.isArray(arguments[3])) args = arguments[3]; return target.xWrap(fArg, resultType, argTypes||[]).apply(null, args||[]); }; /** This function is ONLY exposed in the public API to facilitate testing. It should not be used in application-level code, only in test code. Expects to be given (typeName, value) and returns a conversion of that value as has been registered using argAdapter(). It throws if no adapter is found. ACHTUNG: the adapter may require that a scopedAllocPush() is active and it may allocate memory within that scope. It may also require additional arguments, depending on the type of conversion. */ target.xWrap.testConvertArg = cache.xWrap.convertArg; /** This function is ONLY exposed in the public API to facilitate testing. It should not be used in application-level code, only in test code. Expects to be given (typeName, value) and returns a conversion of that value as has been registered using resultAdapter(). |
︙ | ︙ |
Changes to ext/wasm/dist.make.
︙ | ︙ | |||
34 35 36 37 38 39 40 | # overall runtime speeds. The oz target provides slightly slower # speeds (roughly 10%) with significantly smaller WASM file # sizes. Note that -O2 (the o2 target) results in faster binaries than # both -O3 and -Os (the o3 and os targets) in all tests run to # date. Our general policy is that we want the smallest binaries for # dist zip files, so use the oz build unless there is a compelling # reason not to. | | | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | # overall runtime speeds. The oz target provides slightly slower # speeds (roughly 10%) with significantly smaller WASM file # sizes. Note that -O2 (the o2 target) results in faster binaries than # both -O3 and -Os (the o3 and os targets) in all tests run to # date. Our general policy is that we want the smallest binaries for # dist zip files, so use the oz build unless there is a compelling # reason not to. dist.build ?= qoz 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 \ |
︙ | ︙ | |||
59 60 61 62 63 64 65 | ######################################################################## # dist: create the end-user deliverable archive. # # Maintenance reminder: because dist depends on $(dist.build), and # $(dist.build) will depend on clean, having any deps on # $(dist-archive) which themselves may be cleaned up by the clean # target will lead to grief in parallel builds (-j #). Thus | | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | ######################################################################## # dist: create the end-user deliverable archive. # # Maintenance reminder: because dist depends on $(dist.build), and # $(dist.build) will depend on clean, having any deps on # $(dist-archive) which themselves may be cleaned up by the clean # target will lead to grief in parallel builds (-j #). Thus # dist's deps must be trimmed to non-generated files or # files which are _not_ cleaned up by the clean target. # # Note that we require $(bin.version-info) in order to figure out the # dist file's name, so cannot (without a recursive make) have the # target name equal to the archive name. dist: \ $(bin.stripccomments) $(bin.version-info) \ |
︙ | ︙ |
Changes to ext/wasm/fiddle.make.
︙ | ︙ | |||
35 36 37 38 39 40 41 42 43 44 45 46 47 48 | -sDYNAMIC_EXECUTION=0 \ -sWASM_BIGINT=$(emcc.WASM_BIGINT) \ -sEXPORT_NAME=$(sqlite3.js.init-func) \ -Wno-limited-postlink-optimizations \ $(sqlite3.js.flags.--post-js) \ $(emcc.exportedRuntimeMethods) \ -sEXPORTED_FUNCTIONS=@$(abspath $(EXPORTED_FUNCTIONS.fiddle)) \ $(SQLITE_OPT) $(SHELL_OPT) \ -DSQLITE_SHELL_FIDDLE # -D_POSIX_C_SOURCE is needed for strdup() with emcc fiddle.EXPORTED_FUNCTIONS.in := \ EXPORTED_FUNCTIONS.fiddle.in \ $(EXPORTED_FUNCTIONS.api) | > | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | -sDYNAMIC_EXECUTION=0 \ -sWASM_BIGINT=$(emcc.WASM_BIGINT) \ -sEXPORT_NAME=$(sqlite3.js.init-func) \ -Wno-limited-postlink-optimizations \ $(sqlite3.js.flags.--post-js) \ $(emcc.exportedRuntimeMethods) \ -sEXPORTED_FUNCTIONS=@$(abspath $(EXPORTED_FUNCTIONS.fiddle)) \ -sEXPORTED_RUNTIME_METHODS=FS,wasmMemory \ $(SQLITE_OPT) $(SHELL_OPT) \ -DSQLITE_SHELL_FIDDLE # -D_POSIX_C_SOURCE is needed for strdup() with emcc fiddle.EXPORTED_FUNCTIONS.in := \ EXPORTED_FUNCTIONS.fiddle.in \ $(EXPORTED_FUNCTIONS.api) |
︙ | ︙ |
Changes to ext/wasm/index.html.
︙ | ︙ | |||
82 83 84 85 86 87 88 | <li><a href='demo-worker1-promiser.html'>demo-worker1-promiser</a>: a demo of the Promise-based wrapper of the Worker1 API.</li> </ul> </li> <li>speedtest1 ports (sqlite3's primary benchmarking tool)... <ul> <li><a href='speedtest1.html'>speedtest1</a>: a main-thread WASM build of speedtest1.</li> | < < < < < < > > > > > > > > > > > > | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | <li><a href='demo-worker1-promiser.html'>demo-worker1-promiser</a>: a demo of the Promise-based wrapper of the Worker1 API.</li> </ul> </li> <li>speedtest1 ports (sqlite3's primary benchmarking tool)... <ul> <li><a href='speedtest1.html'>speedtest1</a>: a main-thread WASM build of speedtest1.</li> <li><a href='speedtest1.html?vfs=kvvfs'>speedtest1?vfs=kvvfs</a>: speedtest1 with the kvvfs.</li> <li><a href='speedtest1-worker.html?size=25'>speedtest1-worker</a>: an interactive Worker-thread variant of speedtest1.</li> <li><a href='speedtest1-worker.html?vfs=opfs&size=25'>speedtest1-worker?vfs=opfs</a>: speedtest1-worker with the OPFS VFS preselected and configured for a moderate workload.</li> </ul> </li> <li>The obligatory "misc." category... <ul> <li><a href='module-symbols.html'>module-symbols</a> gives a high-level overview of the symbols exposed by the JS module.</li> <li><a href='batch-runner.html'>batch-runner</a>: runs batches of SQL exported from speedtest1.</li> <li><a href='test-opfs-vfs.html'>test-opfs-vfs</a> (<a href='test-opfs-vfs.html?opfs-sanity-check&opfs-verbose'>same with verbose output and sanity-checking tests</a>) is an sqlite3_vfs OPFS proxy using SharedArrayBuffer and the Atomics APIs to regulate communication between the synchronous sqlite3_vfs interface and the async OPFS impl. </li> <li><a href='tests/opfs/concurrency/index.html'>OPFS concurrency</a> tests using multiple workers. </li> </ul> </li> <!--li>WASMFS-specific tests which currently do not work due to incompatible changes made to the WASMFS+OPFS combination. <ul> <li><a href='speedtest1-wasmfs.html?flags=--size,25'>speedtest1-wasmfs</a>: a variant of speedtest1 built solely for the wasmfs/opfs feature.</li> <li><a href='scratchpad-wasmfs-main.html'>scratchpad-wasmfs-main</a>: experimenting with WASMFS/OPFS-based persistence. Maintenance reminder: we cannot currently (2022-09-15) load WASMFS in a worker due to an Emscripten wasm loader limitation.</li> </ul> </li--> <!--li><a href='x.html'></a></li--> </ul> </div> <style> #test-list { font-size: 120%; } </style> <script>//Assign a distinct target tab name for each test page... |
︙ | ︙ |
Changes to ext/wasm/module-symbols.html.
︙ | ︙ | |||
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | <div id='list-compile-options' class='pseudolist wide2'></div> </div><!-- .initially-hidden --> <script src="jswasm/sqlite3.js">/* This tag MUST be inside the fossil-doc block so that this part can work without modification in the wasm docs repo. */</script> <script>(async function(){ const eNew = (tag,parent)=>{ const e = document.createElement(tag); if(parent) parent.appendChild(e); return e; }; const eLi = (label,parent)=>{ const e = eNew('span',parent); e.innerText = label; return e; }; const E = (sel)=>document.querySelector(sel); const EAll = (sel)=>document.querySelectorAll(sel); const eFuncs = E('#list-functions'), eConst = E('#list-constants'); const renderConst = function(name){ eLi(name, eConst); }; const renderFunc = function(name){ let lbl = name+'()'; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 | <div id='list-compile-options' class='pseudolist wide2'></div> </div><!-- .initially-hidden --> <script src="jswasm/sqlite3.js">/* This tag MUST be inside the fossil-doc block so that this part can work without modification in the wasm docs repo. */</script> <script>(async function(){ const apiLinks = Object.assign(Object.create(null),{ sqlite3_aggregate_context: 'www:/c3ref/aggregate_context.html', sqlite3_bind_blob: 'www:/c3ref/bind_blob.html', sqlite3_bind_double: 'www:/c3ref/bind_blob.html', sqlite3_bind_int: 'www:/c3ref/bind_blob.html', sqlite3_bind_int64: 'www:/c3ref/bind_blob.html', sqlite3_bind_null: 'www:/c3ref/bind_blob.html', sqlite3_bind_parameter_count: 'www:/c3ref/bind_parameter_count.html', sqlite3_bind_parameter_index: 'www:/c3ref/bind_parameter_index.html', sqlite3_bind_pointer: 'www:/c3ref/bind_blob.html', sqlite3_bind_text: 'www:/c3ref/bind_blob.html', sqlite3_busy_handler: 'www:/c3ref/busy_handler.html', sqlite3_busy_timeout: 'www:/c3ref/busy_timeout.html', sqlite3_changes: 'www:/c3ref/changes.html', sqlite3_changes64: 'www:/c3ref/changes.html', sqlite3_clear_bindings: 'www:/c3ref/clear_bindings.html', sqlite3_close_v2: 'www:/c3ref/close.html', sqlite3_collation_needed: 'www:/c3ref/collation_needed.html', sqlite3_column_blob: 'www:/c3ref/column_blob.html', sqlite3_column_bytes: 'www:/c3ref/column.html', sqlite3_column_count: 'www:/c3ref/column_count.html', sqlite3_column_double: 'www:/c3ref/column_blob.html', sqlite3_column_int: 'www:/c3ref/column_blob.html', sqlite3_column_int64: 'www:/c3ref/column_blob.html', sqlite3_column_name: 'www:/c3ref/column_name.html', sqlite3_column_text: 'www:/c3ref/column_blob.html', sqlite3_column_type: 'www:/c3ref/column_blob.html', sqlite3_column_value: 'www:/c3ref/column_blob.html', sqlite3_compileoption_get: 'www:/c3ref/compileoption_get.html', sqlite3_compileoption_used: 'www:/c3ref/compileoption_get.html', sqlite3_complete: 'www:/c3ref/complete.html', sqlite3_create_collation: 'www:/c3ref/create_collation.html', sqlite3_create_collation_v2: 'www:/c3ref/create_collation.html', sqlite3_create_function: 'wasm:/api-c-style.md#sqlite3_create_function', sqlite3_create_function_v2: 'wasm:/api-c-style.md#sqlite3_create_function', sqlite3_create_module: 'www:/c3ref/create_module.html', sqlite3_create_module_v2: 'www:/c3ref/create_module.html', sqlite3_create_window_function: 'wasm:/api-c-style.md#sqlite3_create_function', sqlite3_db_config: 'wasm:/api-c-style.md#sqlite3_db_config', sqlite3_data_count: 'www:/c3ref/data_count.html', sqlite3_db_filename: 'www:/c3ref/db_filename.html', sqlite3_db_handle: 'www:/c3ref/db_handle.html', sqlite3_db_name: 'www:/c3ref/db_name.html', sqlite3_db_status: 'www:/c3ref/db_status.html', sqlite3_declare_vtab: 'www:/c3ref/declare_vtab.html', sqlite3_deserialize: 'wasm:/api-c-style.md#sqlite3_deserialize', sqlite3_drop_modules: 'www:/c3ref/drop_modules.html', sqlite3_errcode: 'www:/c3ref/errcode.html', sqlite3_errmsg: 'www:/c3ref/errcode.html', sqlite3_error_offset: 'www:/c3ref/error_offset.html', sqlite3_errstr: 'www:/c3ref/errcode.html', sqlite3_exec: 'wasm:/api-c-style.md#sqlite3_exec', sqlite3_expanded_sql: 'www:/c3ref/expanded_sql.html', sqlite3_extended_errcode: 'www:/c3ref/errcode.html', sqlite3_extended_result_codes: 'www:/c3ref/extended_result_codes.html', sqlite3_file_control: 'www:/c3ref/file_control.html', sqlite3_finalize: 'www:/c3ref/finalize.html', sqlite3_free: 'www:/c3ref/free.html', sqlite3_get_auxdata: 'www:/c3ref/get_auxdata.html', sqlite3_initialize: 'www:/c3ref/initialize.html', sqlite3_keyword_check: 'www:/c3ref/keyword_check.html', sqlite3_keyword_count: 'www:/c3ref/keyword_check.html', sqlite3_keyword_name: 'www:/c3ref/keyword_check.html', sqlite3_last_insert_rowid: 'www:/c3ref/last_insert_rowid.html', sqlite3_libversion: 'www:/c3ref/libversion.html', sqlite3_libversion_number: 'www:/c3ref/libversion.html', sqlite3_limit: 'www:/c3ref/limit.html', sqlite3_malloc: 'www:/c3ref/free.html', sqlite3_malloc64: 'www:/c3ref/free.html', sqlite3_msize: 'www:/c3ref/free.html', sqlite3_open: 'www:/c3ref/open.html', sqlite3_open_v2: 'www:/c3ref/open.html', sqlite3_overload_function: 'www:/c3ref/overload_function.html', sqlite3_prepare_v2: 'wasm:/api-c-style.md#sqlite3_prepare_v2', sqlite3_prepare_v3: 'wasm:/api-c-style.md#sqlite3_prepare_v2', sqlite3_progress_handler: 'www:/c3ref/progress_handler.html', sqlite3_randomness: 'wasm:/api-c-style.md#sqlite3_randomness', sqlite3_realloc: 'www:/c3ref/free.html', sqlite3_realloc64: 'www:/c3ref/free.html', sqlite3_reset: 'www:/c3ref/reset.html', sqlite3_result_blob: 'www:/c3ref/result_blob.html', sqlite3_result_double: 'www:/c3ref/result_blob.html', sqlite3_result_error: 'www:/c3ref/result_blob.html', sqlite3_result_error_code: 'www:/c3ref/result_blob.html', sqlite3_result_error_nomem: 'www:/c3ref/result_blob.html', sqlite3_result_error_toobig: 'www:/c3ref/result_blob.html', sqlite3_result_int: 'www:/c3ref/result_blob.html', sqlite3_result_int64: 'www:/c3ref/result_blob.html', sqlite3_result_null: 'www:/c3ref/result_blob.html', sqlite3_result_pointer: 'www:/c3ref/result_blob.html', sqlite3_result_subtype: 'www:/c3ref/result_subtype.html', sqlite3_result_text: 'www:/c3ref/result_blob.html', sqlite3_result_zeroblob: 'www:/c3ref/result_blob.html', sqlite3_result_zeroblob64: 'www:/c3ref/result_blob.html', sqlite3_serialize: 'www:/c3ref/serialize.html', sqlite3_set_authorizer: 'wasm:/api-c-style.md#sqlite3_set_authorizer', sqlite3_set_auxdata: 'www:/c3ref/set_auxdata.html', sqlite3_set_last_insert_rowid: 'www:/c3ref/set_last_insert_rowid', sqlite3_shutdown: 'www:/c3ref/initialize.html', sqlite3_sourceid: 'www:/c3ref/libversion.html', sqlite3_sql: 'www:/c3ref/expanded_sql.html', sqlite3_status: 'www:/c3ref/status.html', sqlite3_status64: 'www:/c3ref/status.html', sqlite3_step: 'www:/c3ref/step.html', sqlite3_stmt_isexplain: 'www:/c3ref/stmt_isexplain.html', sqlite3_stmt_readonly: 'www:/c3ref/stmt_readonly.html', sqlite3_stmt_status: 'www:/c3ref/stmt_status.html', sqlite3_strglob: 'www:/c3ref/strglob.html', sqlite3_stricmp: 'www:/c3ref/stricmp.html', sqlite3_strlike: 'www:/c3ref/strlike.html', sqlite3_strnicmp: 'www:/c3ref/strnicmp.html', sqlite3_table_column_metadata: 'www:/c3ref/table_column_metadata.html', sqlite3_total_changes: 'www:/c3ref/total_changes.html', sqlite3_total_changes64: 'www:/c3ref/total_changes.html', sqlite3_trace_v2: 'www:/c3ref/trace_v2.html', sqlite3_txn_state: 'www:/c3ref/txn_state.html', sqlite3_uri_boolean: 'www:/c3ref/uri_boolean.html', sqlite3_uri_int64: 'www:/c3ref/uri_boolean.html', sqlite3_uri_key: 'www:/c3ref/uri_boolean.html', sqlite3_uri_parameter: 'www:/c3ref/uri_boolean.html', sqlite3_user_data: 'www:/c3ref/user_data.html', sqlite3_value_blob: 'www:/c3ref/value_blob.html', sqlite3_value_bytes: 'www:/c3ref/value_blob.html', sqlite3_value_double: 'www:/c3ref/value_blob.html', sqlite3_value_dup: 'www:/c3ref/value_dup.html', sqlite3_value_free: 'www:/c3ref/value_dup.html', sqlite3_value_frombind: 'www:/c3ref/value_blob.html', sqlite3_value_int: 'www:/c3ref/value_blob.html', sqlite3_value_int64: 'www:/c3ref/value_blob.html', sqlite3_value_nochange: 'www:/c3ref/value_blob.html', sqlite3_value_numeric_type: 'www:/c3ref/value_blob.html', sqlite3_value_pointer: 'www:/c3ref/value_blob.html', sqlite3_value_subtype: 'www:/c3ref/value_subtype.html', sqlite3_value_text: 'www:/c3ref/value_blob.html', sqlite3_value_type: 'www:/c3ref/value_blob.html', sqlite3_vfs_find: 'www:/c3ref/vfs_find.html', sqlite3_vfs_register: 'www:/c3ref/vfs_find.html', sqlite3_vfs_unregister: 'www:/c3ref/vfs_find.html', sqlite3_vtab_collation: 'www:/c3ref/vtab_collation.html', sqlite3_vtab_config: 'www:/c3ref/vtab_config.html', sqlite3_vtab_distinct: 'www:/c3ref/vtab_distinct.html', sqlite3_vtab_in: 'www:/c3ref/vtab_in.html', sqlite3_vtab_in_first: 'www:/c3ref/vtab_in_first.html', sqlite3_vtab_in_next: 'www:/c3ref/vtab_in_next.html', sqlite3_vtab_nochange: 'www:/c3ref/vtab_nochange.html', sqlite3_vtab_on_conflict: 'www:/c3ref/vtab_on_conflict.html', sqlite3_vtab_rhs_value: 'www:/c3ref/vtab_rhs_value.html', sqlite3_column_js: 'wasm:/api-c-style.md#sqlite3_column_js', sqlite3_js_aggregate_context: 'wasm:/api-c-style.md#sqlite3_js_aggregate_context', sqlite3_js_db_export: 'wasm:/api-c-style.md#sqlite3_js_db_export', sqlite3_js_db_uses_vfs: 'wasm:/api-c-style.md#sqlite3_js_db_uses_vfs', sqlite3_js_db_vfs: 'wasm:/api-c-style.md#sqlite3_js_db_vfs', sqlite3_js_kvvfs_clear: 'wasm:/api-c-style.md#sqlite3_js_kvvfs', sqlite3_js_kvvfs_size: 'wasm:/api-c-style.md#sqlite3_js_kvvfs', sqlite3_js_rc_str: 'wasm:/api-c-style.md#sqlite3_js_rc_str', sqlite3_js_vfs_create_file: 'wasm:/api-c-style.md#sqlite3_js_vfs_create_file', sqlite3_js_vfs_list: 'wasm:/api-c-style.md#sqlite3_js_vfs_list', sqlite3_result_error_js: 'wasm:/api-c-style.md#sqlite3_result_error_js', sqlite3_result_js: 'wasm:/api-c-style.md#sqlite3_result_js', sqlite3_value_to_js: 'wasm:/api-c-style.md#sqlite3_value_to_js', sqlite3_values_to_js: 'wasm:/api-c-style.md#sqlite3_values_to_js', xform: (v)=>{ if(v){ return v.replace('www:','https://sqlite.org') .replace('wasm:','https://sqlite.org/wasm/doc/trunk'); }else{ return undefined; } } }); const eNew = (tag,parent)=>{ const e = document.createElement(tag); if(parent) parent.appendChild(e); return e; }; const eLi = (label,parent)=>{ const e = eNew('span',parent); e.innerText = label; return e; }; const eLink = (label,url,parent)=>{ const w = eNew('span',parent); const e = eNew('a',w); if(url){ e.href = url; e.target = 'sqlite3-api-docs'; } e.innerText = label; return w; }; const E = (sel)=>document.querySelector(sel); const EAll = (sel)=>document.querySelectorAll(sel); const eFuncs = E('#list-functions'), eConst = E('#list-constants'); const renderConst = function(name){ eLi(name, eConst); }; const renderFunc = function(name){ let lbl = name+'()'; const e = eLink(lbl, apiLinks.xform(apiLinks[name]), eFuncs); if(name.indexOf('_js')>0 || name.indexOf('_wasm')>0){ e.classList.add('func-wasm'); } }; const renderGeneric = function(name,value,eParent){ let lbl; |
︙ | ︙ | |||
253 254 255 256 257 258 259 | ); renderX( E('#list-version'), sqlite3.version, Object.keys(sqlite3.version) ); /* sqlite3_...() and SQLITE_... */ | | | | < < > | > | > | > > > > > > > | | | 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 | ); renderX( E('#list-version'), sqlite3.version, Object.keys(sqlite3.version) ); /* sqlite3_...() and SQLITE_... */ const lists = {c: [/*constants*/], f: [/*functions*/], s: [/*structs*/]}; /* Exclude these from the function list... */ const excludeCapi = [ // WASMFS stuff: 'sqlite3_wasmfs_filename_is_persistent', 'sqlite3_wasmfs_opfs_dir' ]; for(const [k,v] of Object.entries(capi)){ if(k.startsWith('SQLITE_')){ lists.c.push(k); }else if(k.startsWith('sqlite3_')){ if(excludeCapi.indexOf(k)>=0) continue; if(v.structInfo){ // assume this is a StructType-type. continue; } lists.f.push(k); } } lists.c.sort().forEach(renderConst); lists.f.sort().forEach(renderFunc); lists.c = lists.f = null; renderX(E('#list-oo1'), sqlite3.oo1, Object.keys(sqlite3.oo1) ); const excludeWasm = ['ctype']; renderX(E('#list-wasm'), |
︙ | ︙ |
Changes to ext/wasm/speedtest1-wasmfs.html.
︙ | ︙ | |||
88 89 90 91 92 93 94 | const logErr = function(...args){ console.error(...args); logList.push('ERROR: '+args.join(' ')); }; const runTests = function(sqlite3){ console.log("Module inited."); | | | > | 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | const logErr = function(...args){ console.error(...args); logList.push('ERROR: '+args.join(' ')); }; const runTests = function(sqlite3){ console.log("Module inited."); const wasm = sqlite3.wasm; const __unlink = wasm.xWrap("sqlite3_wasm_vfs_unlink", "int", ["*","string"]); const unlink = (fn)=>__unlink(0,fn); const pDir = wasmfsDir(wasm); if(pDir) log2('',"Persistent storage:",pDir); else{ log2('error',"Expecting persistent storage in this build."); return; } const scope = wasm.scopedAllocPush(); |
︙ | ︙ |
Changes to ext/wasm/test-opfs-vfs.js.
︙ | ︙ | |||
24 25 26 27 28 29 30 | if(!sqlite3.opfs){ const e = toss("OPFS is not available."); error(e); throw e; } const capi = sqlite3.capi; const pVfs = capi.sqlite3_vfs_find("opfs") || toss("Missing 'opfs' VFS."); | | | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | if(!sqlite3.opfs){ const e = toss("OPFS is not available."); error(e); throw e; } const capi = sqlite3.capi; const pVfs = capi.sqlite3_vfs_find("opfs") || toss("Missing 'opfs' VFS."); const oVfs = new capi.sqlite3_vfs(pVfs); log("OPFS VFS:",pVfs, oVfs); const wait = async (ms)=>{ return new Promise((resolve)=>setTimeout(resolve, ms)); }; const urlArgs = new URL(self.location.href).searchParams; const dbFile = "my-persistent.db"; if(urlArgs.has('delete')) sqlite3.opfs.unlink(dbFile); const db = new sqlite3.oo1.OpfsDb(dbFile,'ct'); log("db file:",db.filename); try{ if(opfs.entryExists(dbFile)){ let n = db.selectValue("select count(*) from sqlite_schema"); log("Persistent data found. sqlite_schema entry count =",n); } db.transaction((db)=>{ |
︙ | ︙ |
Changes to ext/wasm/tester1.c-pp.js.
︙ | ︙ | |||
341 342 343 344 345 346 347 348 349 350 351 352 353 354 | //////////////////////////////////////////////////////////////////////// // End of infrastructure setup. Now define the tests... //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// T.g('Basic sanity checks') .t({ name: "JS wasm-side allocator", test: function(sqlite3){ if(sqlite3.config.useStdAlloc){ warn("Using system allocator. This violates the docs and", "may cause grief with certain APIs", "(e.g. sqlite3_deserialize())."); T.assert(wasm.alloc.impl === wasm.exports.malloc) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 | //////////////////////////////////////////////////////////////////////// // End of infrastructure setup. Now define the tests... //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// T.g('Basic sanity checks') .t({ name:'sqlite3_config()', test:function(sqlite3){ for(const k of [ 'SQLITE_CONFIG_GETMALLOC', 'SQLITE_CONFIG_URI' ]){ T.assert(capi[k] > 0); } T.assert(capi.SQLITE_MISUSE===capi.sqlite3_config( capi.SQLITE_CONFIG_URI, 1 ), "MISUSE because the library has already been initialized."); T.assert(capi.SQLITE_MISUSE === capi.sqlite3_config( // not enough args capi.SQLITE_CONFIG_GETMALLOC )); T.assert(capi.SQLITE_NOTFOUND === capi.sqlite3_config( // unhandled-in-JS config option capi.SQLITE_CONFIG_GETMALLOC, 1 )); if(0){ log("We cannot _fully_ test sqlite3_config() after the library", "has been initialized (which it necessarily has been to", "set up various bindings) and we cannot shut it down ", "without losing the VFS registrations."); T.assert(0 === capi.sqlite3_config( capi.SQLITE_CONFIG_URI, 1 )); } } })/*sqlite3_config()*/ //////////////////////////////////////////////////////////////////// .t({ name: "JS wasm-side allocator", test: function(sqlite3){ if(sqlite3.config.useStdAlloc){ warn("Using system allocator. This violates the docs and", "may cause grief with certain APIs", "(e.g. sqlite3_deserialize())."); T.assert(wasm.alloc.impl === wasm.exports.malloc) |
︙ | ︙ | |||
418 419 420 421 422 423 424 425 426 427 428 429 430 431 | //////////////////////////////////////////////////////////////////// .t('strglob/strlike', function(sqlite3){ T.assert(0===capi.sqlite3_strglob("*.txt", "foo.txt")). assert(0!==capi.sqlite3_strglob("*.txt", "foo.xtx")). assert(0===capi.sqlite3_strlike("%.txt", "foo.txt", 0)). assert(0!==capi.sqlite3_strlike("%.txt", "foo.xtx", 0)); }) //////////////////////////////////////////////////////////////////// ;/*end of basic sanity checks*/ //////////////////////////////////////////////////////////////////// T.g('C/WASM Utilities') .t('sqlite3.wasm namespace', function(sqlite3){ // TODO: break this into smaller individual test functions. | > | 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 | //////////////////////////////////////////////////////////////////// .t('strglob/strlike', function(sqlite3){ T.assert(0===capi.sqlite3_strglob("*.txt", "foo.txt")). assert(0!==capi.sqlite3_strglob("*.txt", "foo.xtx")). assert(0===capi.sqlite3_strlike("%.txt", "foo.txt", 0)). assert(0!==capi.sqlite3_strlike("%.txt", "foo.xtx", 0)); }) //////////////////////////////////////////////////////////////////// ;/*end of basic sanity checks*/ //////////////////////////////////////////////////////////////////// T.g('C/WASM Utilities') .t('sqlite3.wasm namespace', function(sqlite3){ // TODO: break this into smaller individual test functions. |
︙ | ︙ | |||
468 469 470 471 472 473 474 | // Check allocFromTypedArray()... const byteList = [11,22,33] const u = new Uint8Array(byteList); m = w.allocFromTypedArray(u); for(let i = 0; i < u.length; ++i){ T.assert(u[i] === byteList[i]) | | | > > > > > > > > > > > > > > > > > > > > | 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 | // Check allocFromTypedArray()... const byteList = [11,22,33] const u = new Uint8Array(byteList); m = w.allocFromTypedArray(u); for(let i = 0; i < u.length; ++i){ T.assert(u[i] === byteList[i]) .assert(u[i] === w.peek8(m + i)); } w.dealloc(m); m = w.allocFromTypedArray(u.buffer); for(let i = 0; i < u.length; ++i){ T.assert(u[i] === byteList[i]) .assert(u[i] === w.peek8(m + i)); } w.dealloc(m); T.mustThrowMatching( ()=>w.allocFromTypedArray(1), 'Value is not of a supported TypedArray type.' ); } { // Test peekXYZ()/pokeXYZ()... const m = w.alloc(8); T.assert( 17 === w.poke8(m,17).peek8(m) ) .assert( 31987 === w.poke16(m,31987).peek16(m) ) .assert( 345678 === w.poke32(m,345678).peek32(m) ) .assert( T.eqApprox( 345678.9, w.poke32f(m,345678.9).peek32f(m) ) ).assert( T.eqApprox( 4567890123.4, w.poke64f(m, 4567890123.4).peek64f(m) ) ); if(w.bigIntEnabled){ T.assert( BigInt(Number.MAX_SAFE_INTEGER) === w.poke64(m, Number.MAX_SAFE_INTEGER).peek64(m) ); } w.dealloc(m); } // isPtr32() { const ip = w.isPtr32; T.assert(ip(0)) .assert(!ip(-1)) .assert(!ip(1.1)) |
︙ | ︙ | |||
553 554 555 556 557 558 559 | try { let cStr = w.scopedAllocCString("hello"); const n = w.cstrlen(cStr); let cpy = w.scopedAlloc(n+10); let rc = w.cstrncpy(cpy, cStr, n+10); T.assert(n+1 === rc). assert("hello" === w.cstrToJs(cpy)). | | | | | | 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 | try { let cStr = w.scopedAllocCString("hello"); const n = w.cstrlen(cStr); let cpy = w.scopedAlloc(n+10); let rc = w.cstrncpy(cpy, cStr, n+10); T.assert(n+1 === rc). assert("hello" === w.cstrToJs(cpy)). assert(chr('o') === w.peek8(cpy+n-1)). assert(0 === w.peek8(cpy+n)); let cStr2 = w.scopedAllocCString("HI!!!"); rc = w.cstrncpy(cpy, cStr2, 3); T.assert(3===rc). assert("HI!lo" === w.cstrToJs(cpy)). assert(chr('!') === w.peek8(cpy+2)). assert(chr('l') === w.peek8(cpy+3)); }finally{ w.scopedAllocPop(scope); } } //log("jstrToUintArray()..."); { |
︙ | ︙ | |||
583 584 585 586 587 588 589 | } //log("allocCString()..."); { const jstr = "hällo, world!"; const [cstr, n] = w.allocCString(jstr, true); T.assert(14 === n) | | | | 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 | } //log("allocCString()..."); { const jstr = "hällo, world!"; const [cstr, n] = w.allocCString(jstr, true); T.assert(14 === n) .assert(0===w.peek8(cstr+n)) .assert(chr('!')===w.peek8(cstr+n-1)); w.dealloc(cstr); } //log("scopedAlloc() and friends..."); { const alloc = w.alloc, dealloc = w.dealloc; w.alloc = w.dealloc = null; |
︙ | ︙ | |||
620 621 622 623 624 625 626 | T.assert(2===w.scopedAlloc.level) .assert(Number.isFinite(p3)) .assert(2===asc.length) .assert(p3===asc2[0]); const [z1, z2, z3] = w.scopedAllocPtr(3); T.assert('number'===typeof z1).assert(z2>z1).assert(z3>z2) | | | | | | 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 | T.assert(2===w.scopedAlloc.level) .assert(Number.isFinite(p3)) .assert(2===asc.length) .assert(p3===asc2[0]); const [z1, z2, z3] = w.scopedAllocPtr(3); T.assert('number'===typeof z1).assert(z2>z1).assert(z3>z2) .assert(0===w.peek32(z1), 'allocPtr() must zero the targets') .assert(0===w.peek32(z3)); }finally{ // Pop them in "incorrect" order to make sure they behave: w.scopedAllocPop(asc); T.assert(0===asc.length); T.mustThrowMatching(()=>w.scopedAllocPop(asc), /^Invalid state object/); if(asc2){ T.assert(2===asc2.length,'Should be p3 and z1'); w.scopedAllocPop(asc2); T.assert(0===asc2.length); T.mustThrowMatching(()=>w.scopedAllocPop(asc2), /^Invalid state object/); } } T.assert(0===w.scopedAlloc.level); w.scopedAllocCall(function(){ T.assert(1===w.scopedAlloc.level); const [cstr, n] = w.scopedAllocCString("hello, world", true); T.assert(12 === n) .assert(0===w.peek8(cstr+n)) .assert(chr('d')===w.peek8(cstr+n-1)); }); }/*scopedAlloc()*/ //log("xCall()..."); { const pJson = w.xCall('sqlite3_wasm_enum_json'); T.assert(Number.isFinite(pJson)).assert(w.cstrlen(pJson)>300); |
︙ | ︙ | |||
685 686 687 688 689 690 691 692 693 694 695 696 697 698 | w.scopedAllocCall(()=>{ const argAd = w.xWrap.argAdapter('string:flexible'); const cj = (v)=>w.cstrToJs(argAd(v)); T.assert('Hi' === cj('Hi')) .assert('hi' === cj(['h','i'])) .assert('HI' === cj(new Uint8Array([72, 73]))); }); if(haveWasmCTests()){ if(!sqlite3.config.useStdAlloc){ fw = w.xWrap('sqlite3_wasm_test_str_hello', 'utf8:dealloc',['i32']); rc = fw(0); T.assert('hello'===rc); rc = fw(1); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 | w.scopedAllocCall(()=>{ const argAd = w.xWrap.argAdapter('string:flexible'); const cj = (v)=>w.cstrToJs(argAd(v)); T.assert('Hi' === cj('Hi')) .assert('hi' === cj(['h','i'])) .assert('HI' === cj(new Uint8Array([72, 73]))); }); // jsFuncToWasm() { const fsum3 = (x,y,z)=>x+y+z; fw = w.jsFuncToWasm('i(iii)', fsum3); T.assert(fw instanceof Function) .assert( fsum3 !== fw ) .assert( 3 === fw.length ) .assert( 6 === fw(1,2,3) ); T.mustThrowMatching( ()=>w.jsFuncToWasm('x()', function(){}), 'Invalid signature letter: x'); } // xWrap(Function,...) { let fp; try { const fmy = function fmy(i,s,d){ if(fmy.debug) log("fmy(",...arguments,")"); T.assert( 3 === i ) .assert( w.isPtr(s) ) .assert( w.cstrToJs(s) === 'a string' ) .assert( T.eqApprox(1.2, d) ); return w.allocCString("hi"); }; fmy.debug = false; const xwArgs = ['string:dealloc', ['i32', 'string', 'f64']]; fw = w.xWrap(fmy, ...xwArgs); const fmyArgs = [3, 'a string', 1.2]; let rc = fw(...fmyArgs); T.assert( 'hi' === rc ); if(0){ /* Retain this as a "reminder to self"... This extra level of indirection does not work: the string argument is ending up as a null in fmy() but the numeric arguments are making their ways through What's happening is: installFunction() is creating a WASM-compatible function instance. When we pass a JS string into there it's getting coerced into `null` before being passed on to the lower-level wrapper. */ fmy.debug = true; fp = wasm.installFunction('i(isd)', fw); fw = w.functionEntry(fp); rc = fw(...fmyArgs); log("rc =",rc); T.assert( 'hi' === rc ); // Similarly, this does not work: //let fpw = w.xWrap(fp, null, [null,null,null]); //rc = fpw(...fmyArgs); //log("rc =",rc); //T.assert( 'hi' === rc ); } }finally{ wasm.uninstallFunction(fp); } } if(haveWasmCTests()){ if(!sqlite3.config.useStdAlloc){ fw = w.xWrap('sqlite3_wasm_test_str_hello', 'utf8:dealloc',['i32']); rc = fw(0); T.assert('hello'===rc); rc = fw(1); |
︙ | ︙ | |||
706 707 708 709 710 711 712 | rc = fw(1); T.assert(12n===rc); w.scopedAllocCall(function(){ const pI1 = w.scopedAlloc(8), pI2 = pI1+4; w.pokePtr([pI1, pI2], 0); const f = w.xWrap('sqlite3_wasm_test_int64_minmax',undefined,['i64*','i64*']); | | | | 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 | rc = fw(1); T.assert(12n===rc); w.scopedAllocCall(function(){ const pI1 = w.scopedAlloc(8), pI2 = pI1+4; w.pokePtr([pI1, pI2], 0); const f = w.xWrap('sqlite3_wasm_test_int64_minmax',undefined,['i64*','i64*']); const [r1, r2] = w.peek64([pI1, pI2]); T.assert(!Number.isSafeInteger(r1)).assert(!Number.isSafeInteger(r2)); }); } } }/*xWrap()*/ }/*WhWasmUtil*/) //////////////////////////////////////////////////////////////////// .t('sqlite3.StructBinder (jaccwabyt🐇)', function(sqlite3){ const S = sqlite3, W = S.wasm; const MyStructDef = { sizeof: 16, |
︙ | ︙ | |||
940 941 942 943 944 945 946 | .assert(p3 === p2 + 8); p1 = P.allocPtr(); T.assert('number'===typeof p1); }finally{ P.restore(stack); } }/*pstack tests*/) | < | | | 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 | .assert(p3 === p2 + 8); p1 = P.allocPtr(); T.assert('number'===typeof p1); }finally{ P.restore(stack); } }/*pstack tests*/) //////////////////////////////////////////////////////////////////// ;/*end of C/WASM utils checks*/ T.g('sqlite3_randomness()') .t('To memory buffer', function(sqlite3){ const stack = wasm.pstack.pointer; try{ const n = 520; const p = wasm.pstack.alloc(n); T.assert(0===wasm.peek8(p)) .assert(0===wasm.peek8(p+n-1)); T.assert(undefined === capi.sqlite3_randomness(n - 10, p)); let j, check = 0; const heap = wasm.heap8u(); for(j = 0; j < 10 && 0===check; ++j){ check += heap[p + j]; } T.assert(check > 0); |
︙ | ︙ | |||
1050 1051 1052 1053 1054 1055 1056 | try{db.checkRc(rc)} catch(e){ex = e} T.assert(ex instanceof sqlite3.SQLite3Error) .assert(0===ex.message.indexOf("sqlite3 result code")) .assert(ex.message.indexOf("Invalid SQL")>0); T.assert(db === db.checkRc(0)) .assert(db === sqlite3.oo1.DB.checkRc(db,0)) | | > > > > > > | | | | | | < | | > | 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 | try{db.checkRc(rc)} catch(e){ex = e} T.assert(ex instanceof sqlite3.SQLite3Error) .assert(0===ex.message.indexOf("sqlite3 result code")) .assert(ex.message.indexOf("Invalid SQL")>0); T.assert(db === db.checkRc(0)) .assert(db === sqlite3.oo1.DB.checkRc(db,0)) .assert(null === sqlite3.oo1.DB.checkRc(null,0)); this.progressHandlerCount = 0; capi.sqlite3_progress_handler(db, 5, (p)=>{ ++this.progressHandlerCount; return 0; }, 0); }) //////////////////////////////////////////////////////////////////// .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); T.assert(0===rc); rc = capi.sqlite3_db_config(this.db, capi.SQLITE_DBCONFIG_MAX+1, 0); T.assert(capi.SQLITE_MISUSE === rc); rc = capi.sqlite3_db_config(this.db, capi.SQLITE_DBCONFIG_MAINDBNAME, "main"); T.assert(0 === rc); const stack = wasm.pstack.pointer; try { const [pCur, pHi] = wasm.pstack.allocChunks(2,8); rc = capi.sqlite3_db_status(this.db, capi.SQLITE_DBSTATUS_LOOKASIDE_USED, pCur, pHi, 0); T.assert(0===rc); if(wasm.peek32(pCur)){ warn("Cannot test db_config(SQLITE_DBCONFIG_LOOKASIDE)", "while lookaside memory is in use."); }else{ rc = capi.sqlite3_db_config(this.db, capi.SQLITE_DBCONFIG_LOOKASIDE, 0, 4096, 12); T.assert(0 === rc); } wasm.poke32([pCur, pHi], 0); let [vCur, vHi] = wasm.peek32(pCur, pHi); T.assert(0===vCur).assert(0===vHi); rc = capi.sqlite3_status(capi.SQLITE_STATUS_MEMORY_USED, pCur, pHi, 0); [vCur, vHi] = wasm.peek32(pCur, pHi); //console.warn("i32 vCur,vHi",vCur,vHi); T.assert(0 === rc).assert(vCur > 0).assert(vHi >= vCur); if(wasm.bigIntEnabled){ // Again in 64-bit. Recall that pCur and pHi are allocated // large enough to account for this re-use. wasm.poke64([pCur, pHi], 0); rc = capi.sqlite3_status64(capi.SQLITE_STATUS_MEMORY_USED, pCur, pHi, 0); [vCur, vHi] = wasm.peek64([pCur, pHi]); //console.warn("i64 vCur,vHi",vCur,vHi); T.assert(0 === rc).assert(vCur > 0).assert(vHi >= vCur); } }finally{ wasm.pstack.restore(stack); } }) //////////////////////////////////////////////////////////////////// .t('DB.Stmt', function(sqlite3){ let st = this.db.prepare( new TextEncoder('utf-8').encode("select 3 as a") ); //debug("statement =",st); this.progressHandlerCount = 0; try { T.assert(wasm.isPtr(st.pointer)) .mustThrowMatching(()=>st.pointer=1, /read-only/) .assert(1===this.db.openStatementCount()) .assert( capi.sqlite3_stmt_status( st, capi.SQLITE_STMTSTATUS_RUN, 0 |
︙ | ︙ | |||
1142 1143 1144 1145 1146 1147 1148 | .assert(false===st.step()) .assert(!st._mayGet) .assert( capi.sqlite3_stmt_status( st, capi.SQLITE_STMTSTATUS_RUN, 0 ) > 0); | > > | > > > > > > | 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 | .assert(false===st.step()) .assert(!st._mayGet) .assert( capi.sqlite3_stmt_status( st, capi.SQLITE_STMTSTATUS_RUN, 0 ) > 0); T.assert(this.progressHandlerCount > 0, "Expecting progress callback."). assert(0===capi.sqlite3_strglob("*.txt", "foo.txt")). assert(0!==capi.sqlite3_strglob("*.txt", "foo.xtx")). assert(0===capi.sqlite3_strlike("%.txt", "foo.txt", 0)). assert(0!==capi.sqlite3_strlike("%.txt", "foo.xtx", 0)); }finally{ st.finalize(); } T.assert(!st.pointer) .assert(0===this.db.openStatementCount()); T.mustThrowMatching(()=>new sqlite3.oo1.Stmt("hi"), function(err){ return (err instanceof sqlite3.SQLite3Error) && capi.SQLITE_MISUSE === err.resultCode && 0 < err.message.indexOf("Do not call the Stmt constructor directly.") }); }) //////////////////////////////////////////////////////////////////////// .t('sqlite3_js_...()', function(){ const db = this.db; if(1){ const vfsList = capi.sqlite3_js_vfs_list(); |
︙ | ︙ | |||
1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 | ; }/*sqlite3_js_...()*/) //////////////////////////////////////////////////////////////////// .t('Table t', function(sqlite3){ const db = this.db; let list = []; let rc = db.exec({ sql:['CREATE TABLE t(a,b);', // ^^^ using TEMP TABLE breaks the db export test "INSERT INTO t(a,b) VALUES(1,2),(3,4),", "(?,?),('blob',X'6869')"/*intentionally missing semicolon to test for off-by-one bug in string-to-WASM conversion*/], saveSql: list, bind: [5,6] }); //debug("Exec'd SQL:", list); T.assert(rc === db) .assert(2 === list.length) .assert('string'===typeof list[1]) | > | > > > > > > > > > > > | > | 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 | ; }/*sqlite3_js_...()*/) //////////////////////////////////////////////////////////////////// .t('Table t', function(sqlite3){ const db = this.db; let list = []; this.progressHandlerCount = 0; let rc = db.exec({ sql:['CREATE TABLE t(a,b);', // ^^^ using TEMP TABLE breaks the db export test "INSERT INTO t(a,b) VALUES(1,2),(3,4),", "(?,?),('blob',X'6869')"/*intentionally missing semicolon to test for off-by-one bug in string-to-WASM conversion*/], saveSql: list, bind: [5,6] }); //debug("Exec'd SQL:", list); T.assert(rc === db) .assert(2 === list.length) .assert('string'===typeof list[1]) .assert(4===db.changes()) .assert(this.progressHandlerCount > 0, "Expecting progress callback.") if(wasm.bigIntEnabled){ T.assert(4n===db.changes(false,true)); } let blob = db.selectValue("select b from t where a='blob'"); T.assert(blob instanceof Uint8Array). assert(0x68===blob[0] && 0x69===blob[1]); blob = null; let counter = 0, colNames = []; list.length = 0; db.exec(new TextEncoder('utf-8').encode("SELECT a a, b b FROM t"),{ rowMode: 'object', resultRows: list, columnNames: colNames, _myState: 3 /* Accessible from the callback */, callback: function(row,stmt){ ++counter; T.assert( 3 === this._myState /* Recall that "this" is the options object. */ ).assert( this.columnNames[0]==='a' && this.columnNames[1]==='b' /* options.columnNames is filled out before the first Stmt.step(). */ ).assert( (row.a%2 && row.a<6) || 'blob'===row.a ); } }); T.assert(2 === colNames.length) .assert('a' === colNames[0]) .assert(4 === counter) .assert(4 === list.length); list.length = 0; |
︙ | ︙ | |||
1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 | } }); T.assert(8 === counter); T.assert(Number.MIN_SAFE_INTEGER === db.selectValue("SELECT "+Number.MIN_SAFE_INTEGER)). assert(Number.MAX_SAFE_INTEGER === db.selectValue("SELECT "+Number.MAX_SAFE_INTEGER)); if(wasm.bigIntEnabled && haveWasmCTests()){ const mI = wasm.xCall('sqlite3_wasm_test_int64_max'); const b = BigInt(Number.MAX_SAFE_INTEGER * 2); T.assert(b === db.selectValue("SELECT "+b)). assert(b === db.selectValue("SELECT ?", b)). assert(mI == db.selectValue("SELECT $x", {$x:mI})); }else{ | > > > > > > > > | 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 | } }); T.assert(8 === counter); T.assert(Number.MIN_SAFE_INTEGER === db.selectValue("SELECT "+Number.MIN_SAFE_INTEGER)). assert(Number.MAX_SAFE_INTEGER === db.selectValue("SELECT "+Number.MAX_SAFE_INTEGER)); counter = 0; db.exec({ sql: "SELECT a FROM t", callback: ()=>(1===++counter), }); T.assert(2===counter, "Expecting exec step() loop to stop if callback returns false."); if(wasm.bigIntEnabled && haveWasmCTests()){ const mI = wasm.xCall('sqlite3_wasm_test_int64_max'); const b = BigInt(Number.MAX_SAFE_INTEGER * 2); T.assert(b === db.selectValue("SELECT "+b)). assert(b === db.selectValue("SELECT ?", b)). assert(mI == db.selectValue("SELECT $x", {$x:mI})); }else{ |
︙ | ︙ | |||
1286 1287 1288 1289 1290 1291 1292 | try { db.prepare("/*empty SQL*/"); toss("Must not be reached."); }catch(e){ T.assert(e instanceof sqlite3.SQLite3Error) .assert(0==e.message.indexOf('Cannot prepare empty')); } | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 | try { db.prepare("/*empty SQL*/"); toss("Must not be reached."); }catch(e){ T.assert(e instanceof sqlite3.SQLite3Error) .assert(0==e.message.indexOf('Cannot prepare empty')); } })/*setup table T*/ //////////////////////////////////////////////////////////////////// .t({ name: "sqlite3_set_authorizer()", test:function(sqlite3){ T.assert(capi.SQLITE_IGNORE>0) .assert(capi.SQLITE_DENY>0); const db = this.db; const ssa = capi.sqlite3_set_authorizer; const n = db.selectValue('select count(*) from t'); T.assert(n>0); let authCount = 0; let rc = ssa(db, function(pV, iCode, s0, s1, s2, s3){ ++authCount; return capi.SQLITE_IGNORE; }, 0); T.assert(0===rc) .assert( undefined === db.selectValue('select count(*) from t') /* Note that the count() never runs, so we get undefined instead of 0. */ ) .assert(authCount>0); authCount = 0; db.exec("update t set a=-9999"); T.assert(authCount>0); /* Reminder: we don't use DELETE because, from the C API docs: "If the action code is [SQLITE_DELETE] and the callback returns [SQLITE_IGNORE] then the [DELETE] operation proceeds but the [truncate optimization] is disabled and all rows are deleted individually." */ rc = ssa(db, null, 0); authCount = 0; T.assert(-9999 != db.selectValue('select a from t')) .assert(0===authCount); rc = ssa(db, function(pV, iCode, s0, s1, s2, s3){ ++authCount; return capi.SQLITE_DENY; }, 0); T.assert(0===rc); let err; try{ db.exec("select 1 from t") } catch(e){ err = e } T.assert(err instanceof sqlite3.SQLite3Error) .assert(err.message.indexOf('not authorized'>0)) .assert(1===authCount); authCount = 0; rc = ssa(db, function(...args){ ++authCount; return capi.SQLITE_OK; }, 0); T.assert(0===rc); T.assert(n === db.selectValue('select count(*) from t')) .assert(authCount>0); authCount = 0; rc = ssa(db, function(pV, iCode, s0, s1, s2, s3){ ++authCount; throw new Error("Testing catching of authorizer."); }, 0); T.assert(0===rc); authCount = 0; err = undefined; try{ db.exec("select 1 from t") } catch(e){err = e} T.assert(err instanceof Error) .assert(err.message.indexOf('not authorized')>0) /* Note that the thrown message is trumped/overwritten by the authorizer process. */ .assert(1===authCount); rc = ssa(db, 0, 0); authCount = 0; T.assert(0===rc); T.assert(n === db.selectValue('select count(*) from t')) .assert(0===authCount); } })/*sqlite3_set_authorizer()*/ //////////////////////////////////////////////////////////////////////// .t("sqlite3_table_column_metadata()", function(sqlite3){ const stack = wasm.pstack.pointer; try{ const [pzDT, pzColl, pNotNull, pPK, pAuto] = wasm.pstack.allocPtr(5); const rc = capi.sqlite3_table_column_metadata( this.db, "main", "t", "rowid", pzDT, pzColl, pNotNull, pPK, pAuto ); T.assert(0===rc) .assert("INTEGER"===wasm.cstrToJs(wasm.peekPtr(pzDT))) .assert("BINARY"===wasm.cstrToJs(wasm.peekPtr(pzColl))) .assert(0===wasm.peek32(pNotNull)) .assert(1===wasm.peek32(pPK)) .assert(0===wasm.peek32(pAuto)) }finally{ wasm.pstack.restore(stack); } }) //////////////////////////////////////////////////////////////////////// .t('selectArray/Object()', function(sqlite3){ |
︙ | ︙ | |||
1384 1385 1386 1387 1388 1389 1390 | db2.close(); wasm.sqlite3_wasm_vfs_unlink(pVfs, filename); } } }/*sqlite3_js_vfs_create_file()*/) //////////////////////////////////////////////////////////////////// | > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > | | | | | | | | | | | | | | > > > > > > > > > > > > > > > | | | | | | 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 | db2.close(); wasm.sqlite3_wasm_vfs_unlink(pVfs, filename); } } }/*sqlite3_js_vfs_create_file()*/) //////////////////////////////////////////////////////////////////// .t({ name:'Scalar UDFs', //predicate: ()=>false, test: function(sqlite3){ const db = this.db; db.createFunction("foo",(pCx,a,b)=>a+b); T.assert(7===db.selectValue("select foo(3,4)")). assert(5===db.selectValue("select foo(3,?)",2)). assert(5===db.selectValue("select foo(?,?2)",[1,4])). assert(5===db.selectValue("select foo($a,$b)",{$a:0,$b:5})); db.createFunction("bar", { arity: -1, xFunc: (pCx,...args)=>{ let rc = 0; for(const v of args) rc += v; return rc; } }).createFunction({ name: "asis", xFunc: (pCx,arg)=>arg }); T.assert(0===db.selectValue("select bar()")). assert(1===db.selectValue("select bar(1)")). assert(3===db.selectValue("select bar(1,2)")). assert(-1===db.selectValue("select bar(1,2,-4)")). assert('hi' === db.selectValue("select asis('hi')")). assert('hi' === db.selectValue("select ?",'hi')). assert(null === db.selectValue("select null")). assert(null === db.selectValue("select asis(null)")). assert(1 === db.selectValue("select ?",1)). assert(2 === db.selectValue("select ?",[2])). assert(3 === db.selectValue("select $a",{$a:3})). assert(T.eqApprox(3.1,db.selectValue("select 3.0 + 0.1"))). assert(T.eqApprox(1.3,db.selectValue("select asis(1 + 0.3)"))); let blobArg = new Uint8Array([0x68, 0x69]); let blobRc = db.selectValue( "select asis(?1)", blobArg.buffer/*confirm that ArrayBuffer is handled as a Uint8Array*/ ); T.assert(blobRc instanceof Uint8Array). assert(2 === blobRc.length). assert(0x68==blobRc[0] && 0x69==blobRc[1]); blobRc = db.selectValue("select asis(X'6869')"); T.assert(blobRc instanceof Uint8Array). assert(2 === blobRc.length). assert(0x68==blobRc[0] && 0x69==blobRc[1]); blobArg = new Int8Array([0x68, 0x69]); //debug("blobArg=",blobArg); blobRc = db.selectValue("select asis(?1)", blobArg); T.assert(blobRc instanceof Uint8Array). assert(2 === blobRc.length); //debug("blobRc=",blobRc); T.assert(0x68==blobRc[0] && 0x69==blobRc[1]); let rc = sqlite3.capi.sqlite3_create_function_v2( this.db, "foo", 0, -1, 0, 0, 0, 0, 0 ); T.assert( sqlite3.capi.SQLITE_FORMAT === rc, "For invalid eTextRep argument." ); rc = sqlite3.capi.sqlite3_create_function_v2(this.db, "foo", 0); T.assert( sqlite3.capi.SQLITE_MISUSE === rc, "For invalid arg count." ); } }) //////////////////////////////////////////////////////////////////// .t({ name: 'Aggregate UDFs', //predicate: ()=>false, test: function(sqlite3){ const db = this.db; const sjac = capi.sqlite3_js_aggregate_context; db.createFunction({ name: 'summer', xStep: (pCtx, n)=>{ const ac = sjac(pCtx, 4); wasm.poke32(ac, wasm.peek32(ac) + Number(n)); }, xFinal: (pCtx)=>{ const ac = sjac(pCtx, 0); return ac ? wasm.peek32(ac) : 0; } }); let v = db.selectValue([ "with cte(v) as (", "select 3 union all select 5 union all select 7", ") select summer(v), summer(v+1) from cte" /* ------------------^^^^^^^^^^^ ensures that we're handling sqlite3_aggregate_context() properly. */ ]); T.assert(15===v); T.mustThrowMatching(()=>db.selectValue("select summer(1,2)"), /wrong number of arguments/); db.createFunction({ name: 'summerN', arity: -1, xStep: (pCtx, ...args)=>{ const ac = sjac(pCtx, 4); let sum = wasm.peek32(ac); for(const v of args) sum += Number(v); wasm.poke32(ac, sum); }, xFinal: (pCtx)=>{ const ac = sjac(pCtx, 0); capi.sqlite3_result_int( pCtx, ac ? wasm.peek32(ac) : 0 ); // xFinal() may either return its value directly or call // sqlite3_result_xyz() and return undefined. Both are // functionally equivalent. } }); T.assert(18===db.selectValue('select summerN(1,8,9), summerN(2,3,4)')); T.mustThrowMatching(()=>{ |
︙ | ︙ | |||
1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 | } }/*aggregate UDFs*/) //////////////////////////////////////////////////////////////////////// .t({ name: 'Aggregate UDFs (64-bit)', predicate: ()=>wasm.bigIntEnabled, test: function(sqlite3){ const db = this.db; const sjac = capi.sqlite3_js_aggregate_context; db.createFunction({ name: 'summer64', xStep: (pCtx, n)=>{ const ac = sjac(pCtx, 8); | > | | > | | | 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 | } }/*aggregate UDFs*/) //////////////////////////////////////////////////////////////////////// .t({ name: 'Aggregate UDFs (64-bit)', predicate: ()=>wasm.bigIntEnabled, //predicate: ()=>false, test: function(sqlite3){ const db = this.db; const sjac = capi.sqlite3_js_aggregate_context; db.createFunction({ name: 'summer64', xStep: (pCtx, n)=>{ const ac = sjac(pCtx, 8); wasm.poke64(ac, wasm.peek64(ac) + BigInt(n)); }, xFinal: (pCtx)=>{ const ac = sjac(pCtx, 0); return ac ? wasm.peek64(ac) : 0n; } }); let v = db.selectValue([ "with cte(v) as (", "select 9007199254740991 union all select 1 union all select 2", ") select summer64(v), summer64(v+1) from cte" ]); T.assert(9007199254740994n===v); } }/*aggregate UDFs*/) //////////////////////////////////////////////////////////////////// .t({ name: 'Window UDFs', //predicate: ()=>false, test: function(){ /* Example window function, table, and results taken from: https://sqlite.org/windowfunctions.html#udfwinfunc */ const db = this.db; const sjac = (cx,n=4)=>capi.sqlite3_js_aggregate_context(cx,n); const xValueFinal = (pCtx)=>{ const ac = sjac(pCtx, 0); return ac ? wasm.peek32(ac) : 0; }; const xStepInverse = (pCtx, n)=>{ const ac = sjac(pCtx); wasm.poke32(ac, wasm.peek32(ac) + Number(n)); }; db.createFunction({ name: 'winsumint', xStep: (pCtx, n)=>xStepInverse(pCtx, n), xInverse: (pCtx, n)=>xStepInverse(pCtx, -n), xFinal: xValueFinal, xValue: xValueFinal |
︙ | ︙ | |||
1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 | resultRows }); T.assert(3===resultRows.length) .assert(2===resultRows[1]); T.assert(2===db.selectValue('select a from foo.bar where a>1 order by a')); let colCount = 0, rowCount = 0; const execCallback = function(pVoid, nCols, aVals, aNames){ colCount = nCols; ++rowCount; T.assert(2===aVals.length) .assert(2===aNames.length) .assert(+(aVals[1]) === 2 * +(aVals[0])); }; let rc = capi.sqlite3_exec( | > | 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 | resultRows }); T.assert(3===resultRows.length) .assert(2===resultRows[1]); T.assert(2===db.selectValue('select a from foo.bar where a>1 order by a')); let colCount = 0, rowCount = 0; const execCallback = function(pVoid, nCols, aVals, aNames){ //console.warn("execCallback(",arguments,")"); colCount = nCols; ++rowCount; T.assert(2===aVals.length) .assert(2===aNames.length) .assert(+(aVals[1]) === 2 * +(aVals[0])); }; let rc = capi.sqlite3_exec( |
︙ | ︙ | |||
1663 1664 1665 1666 1667 1668 1669 | name: 'C-side WASM tests', predicate: ()=>(haveWasmCTests() || "Not compiled in."), test: function(){ const w = wasm, db = this.db; const stack = w.scopedAllocPush(); let ptrInt; const origValue = 512; | < | < < | < < < | < | | < | < | | | | 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 | name: 'C-side WASM tests', predicate: ()=>(haveWasmCTests() || "Not compiled in."), test: function(){ const w = wasm, db = this.db; const stack = w.scopedAllocPush(); let ptrInt; const origValue = 512; try{ ptrInt = w.scopedAlloc(4); w.poke32(ptrInt,origValue); const cf = w.xGet('sqlite3_wasm_test_intptr'); const oldPtrInt = ptrInt; T.assert(origValue === w.peek32(ptrInt)); const rc = cf(ptrInt); T.assert(2*origValue === rc). assert(rc === w.peek32(ptrInt)). assert(oldPtrInt === ptrInt); const pi64 = w.scopedAlloc(8)/*ptr to 64-bit integer*/; const o64 = 0x010203040506/*>32-bit integer*/; if(w.bigIntEnabled){ w.poke64(pi64, o64); //log("pi64 =",pi64, "o64 = 0x",o64.toString(16), o64); const v64 = ()=>w.peek64(pi64) T.assert(v64() == o64); //T.assert(o64 === w.peek64(pi64)); const cf64w = w.xGet('sqlite3_wasm_test_int64ptr'); cf64w(pi64); T.assert(v64() == BigInt(2 * o64)); cf64w(pi64); T.assert(v64() == BigInt(4 * o64)); const biTimes2 = w.xGet('sqlite3_wasm_test_int64_times2'); T.assert(BigInt(2 * o64) === biTimes2(BigInt(o64)/*explicit conv. required to avoid TypeError in the call :/ */)); const pMin = w.scopedAlloc(16); const pMax = pMin + 8; const g64 = (p)=>w.peek64(p); w.poke64([pMin, pMax], 0); const minMaxI64 = [ w.xCall('sqlite3_wasm_test_int64_min'), w.xCall('sqlite3_wasm_test_int64_max') ]; T.assert(minMaxI64[0] < BigInt(Number.MIN_SAFE_INTEGER)). assert(minMaxI64[1] > BigInt(Number.MAX_SAFE_INTEGER)); //log("int64_min/max() =",minMaxI64, typeof minMaxI64[0]); w.xCall('sqlite3_wasm_test_int64_minmax', pMin, pMax); T.assert(g64(pMin) === minMaxI64[0], "int64 mismatch"). assert(g64(pMax) === minMaxI64[1], "int64 mismatch"); //log("pMin",g64(pMin), "pMax",g64(pMax)); w.poke64(pMin, minMaxI64[0]); T.assert(g64(pMin) === minMaxI64[0]). assert(minMaxI64[0] === db.selectValue("select ?",g64(pMin))). assert(minMaxI64[1] === db.selectValue("select ?",g64(pMax))); const rxRange = /too big/; T.mustThrowMatching(()=>{db.prepare("select ?").bind(minMaxI64[0] - BigInt(1))}, rxRange). mustThrowMatching(()=>{db.prepare("select ?").bind(minMaxI64[1] + BigInt(1))}, |
︙ | ︙ | |||
1744 1745 1746 1747 1748 1749 1750 | }/* jaccwabyt-specific tests */) //////////////////////////////////////////////////////////////////////// .t({ name: 'virtual table #1: eponymous w/ manual exception handling', predicate: ()=>!!capi.sqlite3_index_info, test: function(sqlite3){ | < | | 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 | }/* jaccwabyt-specific tests */) //////////////////////////////////////////////////////////////////////// .t({ name: 'virtual table #1: eponymous w/ manual exception handling', predicate: ()=>!!capi.sqlite3_index_info, test: function(sqlite3){ const VT = sqlite3.vtab; const tmplCols = Object.assign(Object.create(null),{ A: 0, B: 1 }); /** The vtab demonstrated here is a JS-ification of ext/misc/templatevtab.c. */ const tmplMod = new sqlite3.capi.sqlite3_module(); T.assert(0===tmplMod.$xUpdate); tmplMod.setupModule({ catchExceptions: false, methods: { xConnect: function(pDb, pAux, argc, argv, ppVtab, pzErr){ try{ const args = wasm.cArgvToJs(argc, argv); T.assert(args.length>=3) .assert(args[0] === 'testvtab') .assert(args[1] === 'main') .assert(args[2] === 'testvtab'); //console.debug("xConnect() args =",args); const rc = capi.sqlite3_declare_vtab( pDb, "CREATE TABLE ignored(a,b)" ); if(0===rc){ const t = VT.xVtab.create(ppVtab); T.assert(t === VT.xVtab.get(wasm.peekPtr(ppVtab))); } |
︙ | ︙ | |||
1852 1853 1854 1855 1856 1857 1858 | }catch(e){ return VT.xError('xRowid',e); } }, xEof: function(pCursor){ const c = VT.xCursor.get(pCursor), rc = c._rowId>=10; | < | < | 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 | }catch(e){ return VT.xError('xRowid',e); } }, xEof: function(pCursor){ const c = VT.xCursor.get(pCursor), rc = c._rowId>=10; return rc; }, xFilter: function(pCursor, idxNum, idxCStr, argc, argv/* [sqlite3_value* ...] */){ try{ const c = VT.xCursor.get(pCursor); c._rowId = 0; const list = capi.sqlite3_values_to_js(argc, argv); T.assert(argc === list.length); //log(argc,"xFilter value(s):",list); return 0; }catch(e){ return VT.xError('xFilter',e); } }, xBestIndex: function(pVtab, pIdxInfo){ try{ |
︙ | ︙ | |||
1944 1945 1946 1947 1948 1949 1950 | })/*custom vtab #1*/ //////////////////////////////////////////////////////////////////////// .t({ name: 'virtual table #2: non-eponymous w/ automated exception wrapping', predicate: ()=>!!capi.sqlite3_index_info, test: function(sqlite3){ | < | 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 | })/*custom vtab #1*/ //////////////////////////////////////////////////////////////////////// .t({ name: 'virtual table #2: non-eponymous w/ automated exception wrapping', predicate: ()=>!!capi.sqlite3_index_info, test: function(sqlite3){ const VT = sqlite3.vtab; const tmplCols = Object.assign(Object.create(null),{ A: 0, B: 1 }); /** The vtab demonstrated here is a JS-ification of ext/misc/templatevtab.c. |
︙ | ︙ | |||
2040 2041 2042 2043 2044 2045 2046 | return VT.xCursor.get(pCursor)._rowId>=10; }, xFilter: function(pCursor, idxNum, idxCStr, argc, argv/* [sqlite3_value* ...] */){ vtabTrace("xFilter",...arguments); const c = VT.xCursor.get(pCursor); c._rowId = 0; | | | 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 | return VT.xCursor.get(pCursor)._rowId>=10; }, xFilter: function(pCursor, idxNum, idxCStr, argc, argv/* [sqlite3_value* ...] */){ vtabTrace("xFilter",...arguments); const c = VT.xCursor.get(pCursor); c._rowId = 0; const list = capi.sqlite3_values_to_js(argc, argv); T.assert(argc === list.length); }, xBestIndex: function(pVtab, pIdxInfo){ vtabTrace("xBestIndex",...arguments); //const t = VT.xVtab.get(pVtab); const pii = VT.xIndexInfo(pIdxInfo); pii.$estimatedRows = 10; |
︙ | ︙ | |||
2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 | T.assert(1===list.length) .assert(1000===list[0][0]) .assert(2000===list[0][1]); } })/*custom vtab #2*/ //////////////////////////////////////////////////////////////////////// .t('Custom collation', function(sqlite3){ let myCmp = function(pArg,n1,p1,n2,p2){ //int (*)(void*,int,const void*,int,const void*) const rc = wasm.exports.sqlite3_strnicmp(p1,p2,(n1<n2?n1:n2)); return rc ? rc : (n1 - n2); }; let rc = capi.sqlite3_create_collation_v2(this.db, "mycollation", capi.SQLITE_UTF8, 0, myCmp, 0); this.db.checkRc(rc); rc = this.db.selectValue("select 'hi' = 'HI' collate mycollation"); | > > | | | | > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > | 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 | T.assert(1===list.length) .assert(1000===list[0][0]) .assert(2000===list[0][1]); } })/*custom vtab #2*/ //////////////////////////////////////////////////////////////////////// .t('Custom collation', function(sqlite3){ let collationCounter = 0; let myCmp = function(pArg,n1,p1,n2,p2){ //int (*)(void*,int,const void*,int,const void*) ++collationCounter; const rc = wasm.exports.sqlite3_strnicmp(p1,p2,(n1<n2?n1:n2)); return rc ? rc : (n1 - n2); }; let rc = capi.sqlite3_create_collation_v2(this.db, "mycollation", capi.SQLITE_UTF8, 0, myCmp, 0); this.db.checkRc(rc); rc = this.db.selectValue("select 'hi' = 'HI' collate mycollation"); T.assert(1===rc).assert(1===collationCounter); rc = this.db.selectValue("select 'hii' = 'HI' collate mycollation"); T.assert(0===rc).assert(2===collationCounter); rc = this.db.selectValue("select 'hi' = 'HIi' collate mycollation"); T.assert(0===rc).assert(3===collationCounter); rc = capi.sqlite3_create_collation(this.db,"hi",capi.SQLITE_UTF8/*not enough args*/); T.assert(capi.SQLITE_MISUSE === rc); rc = capi.sqlite3_create_collation_v2(this.db,"hi",capi.SQLITE_UTF8+1/*invalid encoding*/,0,0,0); T.assert(capi.SQLITE_FORMAT === rc) .mustThrowMatching(()=>this.db.checkRc(rc), /SQLITE_UTF8 is the only supported encoding./); /* We need to ensure that replacing that collation function does the right thing. We don't have a handle to the underlying WASM pointer from here, so cannot verify (without digging through internal state) that the old one gets uninstalled, but we can verify that a new one properly replaces it. (That said, console.warn() output has shown that the uninstallation does happen.) */ collationCounter = 0; myCmp = function(pArg,n1,p1,n2,p2){ --collationCounter; return 0; }; rc = capi.sqlite3_create_collation_v2(this.db, "MYCOLLATION", capi.SQLITE_UTF8, 0, myCmp, 0); this.db.checkRc(rc); rc = this.db.selectValue("select 'hi' = 'HI' collate mycollation"); T.assert(rc>0).assert(-1===collationCounter); rc = this.db.selectValue("select 'a' = 'b' collate mycollation"); T.assert(rc>0).assert(-2===collationCounter); rc = capi.sqlite3_create_collation_v2(this.db, "MYCOLLATION", capi.SQLITE_UTF8, 0, null, 0); this.db.checkRc(rc); rc = 0; try { this.db.selectValue("select 'a' = 'b' collate mycollation"); }catch(e){ /* Why is e.resultCode not automatically an extended result code? The DB() class enables those automatically. */ rc = sqlite3.capi.sqlite3_extended_errcode(this.db); } T.assert(capi.SQLITE_ERROR_MISSING_COLLSEQ === rc); })/*custom collation*/ //////////////////////////////////////////////////////////////////////// .t('Close db', function(){ T.assert(this.db).assert(wasm.isPtr(this.db.pointer)); //wasm.sqlite3_wasm_db_reset(this.db); // will leak virtual tables! this.db.close(); T.assert(!this.db.pointer); |
︙ | ︙ | |||
2298 2299 2300 2301 2302 2303 2304 | sh = undefined; unlink(); T.mustThrowMatching(()=>{ capi.sqlite3_js_vfs_create_file( "no-such-vfs", filename, ba ); | | | 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 | sh = undefined; unlink(); T.mustThrowMatching(()=>{ capi.sqlite3_js_vfs_create_file( "no-such-vfs", filename, ba ); }, "SQLITE_NOTFOUND: Unknown sqlite3_vfs name: no-such-vfs"); }finally{ if(sh) await sh.close(); unlink(); } // Some sanity checks of the opfs utility functions... const testDir = '/sqlite3-opfs-'+opfs.randomFilename(12); |
︙ | ︙ |
Changes to ext/wasm/wasmfs.make.
︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 | # subdirectory because loading of the auxiliary # sqlite3-wasmfs.worker.js file it creates fails if sqlite3-wasmfs.js # is loaded from any directory other than the one in which the # containing HTML lives. Similarly, they cannot be loaded from a # Worker to an Emscripten quirk regarding loading nested Workers. dir.wasmfs := $(dir.wasm) sqlite3-wasmfs.js := $(dir.wasmfs)/sqlite3-wasmfs.js sqlite3-wasmfs.wasm := $(dir.wasmfs)/sqlite3-wasmfs.wasm CLEAN_FILES += $(sqlite3-wasmfs.js) $(sqlite3-wasmfs.wasm) \ | > | > > | | | | | | | | | > | | | > | | | | | < < < < < < < < < | | | > | | | | | > > | | > | > > | | > > > | | > > > > | > | > > > | > > > | | | | | | | | | | < | | > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | # subdirectory because loading of the auxiliary # sqlite3-wasmfs.worker.js file it creates fails if sqlite3-wasmfs.js # is loaded from any directory other than the one in which the # containing HTML lives. Similarly, they cannot be loaded from a # Worker to an Emscripten quirk regarding loading nested Workers. dir.wasmfs := $(dir.wasm) sqlite3-wasmfs.js := $(dir.wasmfs)/sqlite3-wasmfs.js sqlite3-wasmfs.mjs := $(dir.wasmfs)/sqlite3-wasmfs.mjs sqlite3-wasmfs.wasm := $(dir.wasmfs)/sqlite3-wasmfs.wasm CLEAN_FILES += $(sqlite3-wasmfs.js) $(sqlite3-wasmfs.wasm) \ $(subst .js,.worker.js,$(sqlite3-wasmfs.js)) \ $(sqlite3-wasmfs.mjs) \ $(subst .mjs,.worker.mjs,$(sqlite3-wasmfs.mjs)) ######################################################################## # emcc flags for .c/.o. cflags.sqlite3-wasmfs := cflags.sqlite3-wasmfs += -std=c99 -fPIC cflags.sqlite3-wasmfs += -pthread cflags.sqlite3-wasmfs += $(cflags.speedtest1) cflags.sqlite3-wasmfs += $(SQLITE_OPT) -DSQLITE_ENABLE_WASMFS ######################################################################## # emcc flags specific to building the final .js/.wasm file... emcc.flags.sqlite3-wasmfs := -fPIC emcc.flags.sqlite3-wasmfs += --no-entry emcc.flags.sqlite3-wasmfs += --minify 0 emcc.flags.sqlite3-wasmfs += -sMODULARIZE emcc.flags.sqlite3-wasmfs += -sEXPORT_NAME=$(sqlite3.js.init-func) emcc.flags.sqlite3-wasmfs += -sSTRICT_JS emcc.flags.sqlite3-wasmfs += -sDYNAMIC_EXECUTION=0 emcc.flags.sqlite3-wasmfs += -sNO_POLYFILL emcc.flags.sqlite3-wasmfs += -sWASM_BIGINT=$(emcc.WASM_BIGINT) emcc.flags.sqlite3-wasmfs += -sEXPORTED_FUNCTIONS=@$(abspath $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-api) emcc.flags.sqlite3-wasmfs += -sEXPORTED_RUNTIME_METHODS=FS,wasmMemory,allocateUTF8OnStack # wasmMemory ==> for -sIMPORTED_MEMORY # allocateUTF8OnStack ==> wasmfs internals emcc.flags.sqlite3-wasmfs += -sUSE_CLOSURE_COMPILER=0 emcc.flags.sqlite3-wasmfs += -Wno-limited-postlink-optimizations # ^^^^^ it likes to warn when we have "limited optimizations" via the -g3 flag. emcc.flags.sqlite3-wasmfs += -sALLOW_TABLE_GROWTH emcc.flags.sqlite3-wasmfs += -sSTACK_SIZE=512KB emcc.flags.sqlite3-wasmfs += -sGLOBAL_BASE=4096 # HYPOTHETICALLY keep func table indexes from overlapping w/ heap addr. emcc.flags.sqlite3-wasmfs += -sMEMORY64=0 emcc.flags.sqlite3-wasmfs += -sIMPORTED_MEMORY 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 \ -sPTHREAD_POOL_SIZE=2 -sENVIRONMENT=web,worker \ -sERROR_ON_UNDEFINED_SYMBOLS=0 -sLLD_REPORT_UNDEFINED # ^^^^^ why undefined symbols are necessary for the wasmfs build is anyone's guess. emcc.flags.sqlite3-wasmfs += $(sqlite3-wasmfs.fsflags) #emcc.flags.sqlite3-wasmfs += -sALLOW_MEMORY_GROWTH #^^^ using ALLOW_MEMORY_GROWTH produces a warning from emcc: # 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 $(eval $(call call-make-pre-js,sqlite3-wasmfs,vanilla)) $(eval $(call call-make-pre-js,sqlite3-wasmfs,esm)) Xemcc.flags.sqlite3-wasmfs.vanilla += \ $(pre-post-common.flags.vanilla) \ $(pre-post-sqlite3-wasmfs.flags.vanilla) Xemcc.flags.sqlite3-wasmfs.esm += \ $(pre-post-common.flags.esm) \ $(pre-post-sqlite3-wasmfs.flags.esm) $(sqlite3-wasmfs.js) $(sqlite3-wasmfs.mjs): $(sqlite3-wasm.c) \ $(EXPORTED_FUNCTIONS.api) $(MAKEFILE) $(MAKEFILE.wasmfs) $(sqlite3-wasmfs.js): $(pre-post-sqlite3-wasmfs.deps.vanilla) $(sqlite3-wasmfs.mjs): $(pre-post-sqlite3-wasmfs.deps.esm) # SQLITE3-WASMFS.xJS.RECIPE is the wasmfs-specific counterpart # of SQLITE3.xJS.RECIPE from the main makefile. define SQLITE3-WASMFS.xJS.RECIPE @echo "Building $@ ..." $(emcc.bin) -o $@ $(emcc_opt_full) $(emcc.flags) \ $(cflags.sqlite3-wasmfs) \ $(emcc.flags.sqlite3-wasmfs) $(emcc.flags.sqlite3-wasmfs.$(1)) \ $(pre-post-sqlite3-wasmfs.flags.$(1)) \ $(sqlite3-wasm.c) @$(call SQLITE3.xJS.ESM-EXPORT-DEFAULT,$(1)) chmod -x $(sqlite3-wasmfs.wasm) $(maybe-wasm-strip) $(sqlite3-wasmfs.wasm) @ls -la $(sqlite3-wasmfs.wasm) sqlite3-wasmfs*js endef $(sqlite3-wasmfs.js): $(call SQLITE3-WASMFS.xJS.RECIPE,vanilla) $(sqlite3-wasmfs.mjs): $(sqlite3-wasmfs.js) $(call SQLITE3-WASMFS.xJS.RECIPE,esm) $(sqlite3-wasmfs.wasm): $(sqlite3-wasmfs.js) wasmfs: $(sqlite3-wasmfs.js) $(sqlite3-wasmfs.mjs) #all: wasmfs ######################################################################## # speedtest1 for wasmfs. speedtest1-wasmfs.js := $(dir.wasmfs)/speedtest1-wasmfs.js speedtest1-wasmfs.wasm := $(subst .js,.wasm,$(speedtest1-wasmfs.js)) emcc.flags.speedtest1-wasmfs := $(sqlite3-wasmfs.fsflags) emcc.flags.speedtest1-wasmfs += $(SQLITE_OPT) -DSQLITE_ENABLE_WASMFS 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,vanilla)) $(speedtest1-wasmfs.js): $(speedtest1.cses) $(sqlite3-wasmfs.js) \ $(MAKEFILE) $(MAKEFILE.wasmfs) \ $(pre-post-sqlite3-wasmfs.deps) \ $(EXPORTED_FUNCTIONS.speedtest1) @echo "Building $@ ..." $(emcc.bin) \ $(emcc.speedtest1.common) $(emcc.flags.speedtest1-wasmfs) \ $(pre-post-sqlite3-wasmfs.flags.vanilla) \ $(cflags.sqlite3-wasmfs) \ -o $@ $(speedtest1.cses) -lm $(maybe-wasm-strip) $(speedtest1-wasmfs.wasm) ls -la $@ $(speedtest1-wasmfs.wasm) #speedtest1: $(speedtest1-wasmfs.js) wasmfs: $(speedtest1-wasmfs.js) CLEAN_FILES += $(speedtest1-wasmfs.js) $(speedtest1-wasmfs.wasm) \ $(subst .js,.worker.js,$(speedtest1-wasmfs.js)) # end speedtest1.js ######################################################################## |
Changes to main.mk.
︙ | ︙ | |||
754 755 756 757 758 759 760 761 762 763 764 765 766 767 | ./mkkeywordhash >keywordhash.h # Source files that go into making shell.c SHELL_SRC = \ $(TOP)/src/shell.c.in \ $(TOP)/ext/misc/appendvfs.c \ $(TOP)/ext/misc/completion.c \ $(TOP)/ext/misc/decimal.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/series.c \ $(TOP)/ext/misc/shathree.c \ $(TOP)/ext/misc/sqlar.c \ | > > | 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 | ./mkkeywordhash >keywordhash.h # Source files that go into making shell.c SHELL_SRC = \ $(TOP)/src/shell.c.in \ $(TOP)/ext/misc/appendvfs.c \ $(TOP)/ext/misc/completion.c \ $(TOP)/ext/misc/base64.c \ $(TOP)/ext/misc/base85.c \ $(TOP)/ext/misc/decimal.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/series.c \ $(TOP)/ext/misc/shathree.c \ $(TOP)/ext/misc/sqlar.c \ |
︙ | ︙ |
Changes to src/alter.c.
︙ | ︙ | |||
737 738 739 740 741 742 743 | ** following a valid object, it may not be used in comparison operations. */ static void renameTokenCheckAll(Parse *pParse, const void *pPtr){ assert( pParse==pParse->db->pParse ); assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 ); if( pParse->nErr==0 ){ const RenameToken *p; | | | > | 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 | ** following a valid object, it may not be used in comparison operations. */ static void renameTokenCheckAll(Parse *pParse, const void *pPtr){ assert( pParse==pParse->db->pParse ); assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 ); if( pParse->nErr==0 ){ const RenameToken *p; u32 i = 1; for(p=pParse->pRename; p; p=p->pNext){ if( p->p ){ assert( p->p!=pPtr ); i += *(u8*)(p->p) | 1; } } assert( i>0 ); } } #else # define renameTokenCheckAll(x,y) #endif /* |
︙ | ︙ |
Changes to src/build.c.
︙ | ︙ | |||
2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 | pCol->colFlags |= eType; assert( TF_HasVirtual==COLFLAG_VIRTUAL ); assert( TF_HasStored==COLFLAG_STORED ); pTab->tabFlags |= eType; if( pCol->colFlags & COLFLAG_PRIMKEY ){ makeColumnPartOfPrimaryKey(pParse, pCol); /* For the error message */ } sqlite3ColumnSetExpr(pParse, pTab, pCol, pExpr); pExpr = 0; goto generated_done; generated_error: sqlite3ErrorMsg(pParse, "error in generated column \"%s\"", pCol->zCnName); | > > > > > > > | 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 | pCol->colFlags |= eType; assert( TF_HasVirtual==COLFLAG_VIRTUAL ); assert( TF_HasStored==COLFLAG_STORED ); pTab->tabFlags |= eType; if( pCol->colFlags & COLFLAG_PRIMKEY ){ makeColumnPartOfPrimaryKey(pParse, pCol); /* For the error message */ } if( ALWAYS(pExpr) && pExpr->op==TK_ID ){ /* The value of a generated column needs to be a real expression, not ** just a reference to another column, in order for covering index ** optimizations to work correctly. So if the value is not an expression, ** turn it into one by adding a unary "+" operator. */ pExpr = sqlite3PExpr(pParse, TK_UPLUS, pExpr, 0); } sqlite3ColumnSetExpr(pParse, pTab, pCol, pExpr); pExpr = 0; goto generated_done; generated_error: sqlite3ErrorMsg(pParse, "error in generated column \"%s\"", pCol->zCnName); |
︙ | ︙ | |||
2136 2137 2138 2139 2140 2141 2142 | zStmt[k++] = '('; for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){ static const char * const azType[] = { /* SQLITE_AFF_BLOB */ "", /* SQLITE_AFF_TEXT */ " TEXT", /* SQLITE_AFF_NUMERIC */ " NUM", /* SQLITE_AFF_INTEGER */ " INT", | | > > | > | 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 | zStmt[k++] = '('; for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){ static const char * const azType[] = { /* SQLITE_AFF_BLOB */ "", /* SQLITE_AFF_TEXT */ " TEXT", /* SQLITE_AFF_NUMERIC */ " NUM", /* SQLITE_AFF_INTEGER */ " INT", /* SQLITE_AFF_REAL */ " REAL", /* SQLITE_AFF_FLEXNUM */ " NUM", }; int len; const char *zType; sqlite3_snprintf(n-k, &zStmt[k], zSep); k += sqlite3Strlen30(&zStmt[k]); zSep = zSep2; identPut(zStmt, &k, pCol->zCnName); assert( pCol->affinity-SQLITE_AFF_BLOB >= 0 ); assert( pCol->affinity-SQLITE_AFF_BLOB < ArraySize(azType) ); testcase( pCol->affinity==SQLITE_AFF_BLOB ); testcase( pCol->affinity==SQLITE_AFF_TEXT ); testcase( pCol->affinity==SQLITE_AFF_NUMERIC ); testcase( pCol->affinity==SQLITE_AFF_INTEGER ); testcase( pCol->affinity==SQLITE_AFF_REAL ); testcase( pCol->affinity==SQLITE_AFF_FLEXNUM ); zType = azType[pCol->affinity - SQLITE_AFF_BLOB]; len = sqlite3Strlen30(zType); assert( pCol->affinity==SQLITE_AFF_BLOB || pCol->affinity==SQLITE_AFF_FLEXNUM || pCol->affinity==sqlite3AffinityType(zType, 0) ); memcpy(&zStmt[k], zType, len); k += len; assert( k<=n ); } sqlite3_snprintf(n-k, &zStmt[k], "%s", zEnd); return zStmt; |
︙ | ︙ | |||
2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 | /* ** Mark all nodes of an expression as EP_Immutable, indicating that ** they should not be changed. Expressions attached to a table or ** index definition are tagged this way to help ensure that we do ** not pass them into code generator routines by mistake. */ static int markImmutableExprStep(Walker *pWalker, Expr *pExpr){ ExprSetVVAProperty(pExpr, EP_Immutable); return WRC_Continue; } static void markExprListImmutable(ExprList *pList){ if( pList ){ Walker w; memset(&w, 0, sizeof(w)); | > | 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 | /* ** Mark all nodes of an expression as EP_Immutable, indicating that ** they should not be changed. Expressions attached to a table or ** index definition are tagged this way to help ensure that we do ** not pass them into code generator routines by mistake. */ static int markImmutableExprStep(Walker *pWalker, Expr *pExpr){ (void)pWalker; ExprSetVVAProperty(pExpr, EP_Immutable); return WRC_Continue; } static void markExprListImmutable(ExprList *pList){ if( pList ){ Walker w; memset(&w, 0, sizeof(w)); |
︙ | ︙ | |||
3136 3137 3138 3139 3140 3141 3142 | */ sqlite3ColumnsFromExprList(pParse, pTable->pCheck, &pTable->nCol, &pTable->aCol); if( pParse->nErr==0 && pTable->nCol==pSel->pEList->nExpr ){ assert( db->mallocFailed==0 ); | < | | 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 | */ sqlite3ColumnsFromExprList(pParse, pTable->pCheck, &pTable->nCol, &pTable->aCol); if( pParse->nErr==0 && pTable->nCol==pSel->pEList->nExpr ){ assert( db->mallocFailed==0 ); sqlite3SubqueryColumnTypes(pParse, pTable, pSel, SQLITE_AFF_NONE); } }else{ /* CREATE VIEW name AS... without an argument list. Construct ** the column names from the SELECT statement that defines the view. */ assert( pTable->aCol==0 ); pTable->nCol = pSelTab->nCol; |
︙ | ︙ |
Changes to src/dbpage.c.
︙ | ︙ | |||
68 69 70 71 72 73 74 75 76 77 78 79 80 81 | void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ DbpageTable *pTab = 0; int rc = SQLITE_OK; sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY); rc = sqlite3_declare_vtab(db, "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)"); if( rc==SQLITE_OK ){ pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable)); if( pTab==0 ) rc = SQLITE_NOMEM_BKPT; | > > > > | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ DbpageTable *pTab = 0; int rc = SQLITE_OK; (void)pAux; (void)argc; (void)argv; (void)pzErr; sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY); rc = sqlite3_declare_vtab(db, "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)"); if( rc==SQLITE_OK ){ pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable)); if( pTab==0 ) rc = SQLITE_NOMEM_BKPT; |
︙ | ︙ | |||
106 107 108 109 110 111 112 113 114 115 116 117 118 119 | ** 1 schema=main, pgno=?1 ** 2 schema=?1, full table scan ** 3 schema=?1, pgno=?2 */ static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int i; int iPlan = 0; /* If there is a schema= constraint, it must be honored. Report a ** ridiculously large estimated cost if the schema= constraint is ** unavailable */ for(i=0; i<pIdxInfo->nConstraint; i++){ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i]; | > | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | ** 1 schema=main, pgno=?1 ** 2 schema=?1, full table scan ** 3 schema=?1, pgno=?2 */ static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int i; int iPlan = 0; (void)tab; /* If there is a schema= constraint, it must be honored. Report a ** ridiculously large estimated cost if the schema= constraint is ** unavailable */ for(i=0; i<pIdxInfo->nConstraint; i++){ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i]; |
︙ | ︙ | |||
221 222 223 224 225 226 227 228 229 230 231 232 233 234 | ){ DbpageCursor *pCsr = (DbpageCursor *)pCursor; DbpageTable *pTab = (DbpageTable *)pCursor->pVtab; int rc; sqlite3 *db = pTab->db; Btree *pBt; /* Default setting is no rows of result */ pCsr->pgno = 1; pCsr->mxPgno = 0; if( idxNum & 2 ){ const char *zSchema; assert( argc>=1 ); | > > | 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | ){ DbpageCursor *pCsr = (DbpageCursor *)pCursor; DbpageTable *pTab = (DbpageTable *)pCursor->pVtab; int rc; sqlite3 *db = pTab->db; Btree *pBt; (void)idxStr; /* Default setting is no rows of result */ pCsr->pgno = 1; pCsr->mxPgno = 0; if( idxNum & 2 ){ const char *zSchema; assert( argc>=1 ); |
︙ | ︙ | |||
316 317 318 319 320 321 322 323 324 325 326 327 328 329 | char *zErr = 0; const char *zSchema; int iDb; Btree *pBt; Pager *pPager; int szPage; if( pTab->db->flags & SQLITE_Defensive ){ zErr = "read-only"; goto update_fail; } if( argc==1 ){ zErr = "cannot delete"; goto update_fail; | > | 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 | char *zErr = 0; const char *zSchema; int iDb; Btree *pBt; Pager *pPager; int szPage; (void)pRowid; if( pTab->db->flags & SQLITE_Defensive ){ zErr = "read-only"; goto update_fail; } if( argc==1 ){ zErr = "cannot delete"; goto update_fail; |
︙ | ︙ |
Changes to src/dbstat.c.
︙ | ︙ | |||
159 160 161 162 163 164 165 166 167 168 169 170 171 172 | int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ StatTable *pTab = 0; int rc = SQLITE_OK; int iDb; if( argc>=4 ){ Token nm; sqlite3TokenInit(&nm, (char*)argv[3]); iDb = sqlite3FindDb(db, &nm); if( iDb<0 ){ *pzErr = sqlite3_mprintf("no such database: %s", argv[3]); | > | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ StatTable *pTab = 0; int rc = SQLITE_OK; int iDb; (void)pAux; if( argc>=4 ){ Token nm; sqlite3TokenInit(&nm, (char*)argv[3]); iDb = sqlite3FindDb(db, &nm); if( iDb<0 ){ *pzErr = sqlite3_mprintf("no such database: %s", argv[3]); |
︙ | ︙ | |||
212 213 214 215 216 217 218 219 220 221 222 223 224 225 | ** 0x08 Output should be ordered by name and path */ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int i; int iSchema = -1; int iName = -1; int iAgg = -1; /* Look for a valid schema=? constraint. If found, change the idxNum to ** 1 and request the value of that constraint be sent to xFilter. And ** lower the cost estimate to encourage the constrained version to be ** used. */ for(i=0; i<pIdxInfo->nConstraint; i++){ | > | 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | ** 0x08 Output should be ordered by name and path */ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int i; int iSchema = -1; int iName = -1; int iAgg = -1; (void)tab; /* Look for a valid schema=? constraint. If found, change the idxNum to ** 1 and request the value of that constraint be sent to xFilter. And ** lower the cost estimate to encourage the constrained version to be ** used. */ for(i=0; i<pIdxInfo->nConstraint; i++){ |
︙ | ︙ | |||
737 738 739 740 741 742 743 744 745 746 747 748 749 750 | StatCursor *pCsr = (StatCursor *)pCursor; StatTable *pTab = (StatTable*)(pCursor->pVtab); sqlite3_str *pSql; /* Query of btrees to analyze */ char *zSql; /* String value of pSql */ int iArg = 0; /* Count of argv[] parameters used so far */ int rc = SQLITE_OK; /* Result of this operation */ const char *zName = 0; /* Only provide analysis of this table */ statResetCsr(pCsr); sqlite3_finalize(pCsr->pStmt); pCsr->pStmt = 0; if( idxNum & 0x01 ){ /* schema=? constraint is present. Get its value */ const char *zDbase = (const char*)sqlite3_value_text(argv[iArg++]); | > > | 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 | StatCursor *pCsr = (StatCursor *)pCursor; StatTable *pTab = (StatTable*)(pCursor->pVtab); sqlite3_str *pSql; /* Query of btrees to analyze */ char *zSql; /* String value of pSql */ int iArg = 0; /* Count of argv[] parameters used so far */ int rc = SQLITE_OK; /* Result of this operation */ const char *zName = 0; /* Only provide analysis of this table */ (void)argc; (void)idxStr; statResetCsr(pCsr); sqlite3_finalize(pCsr->pStmt); pCsr->pStmt = 0; if( idxNum & 0x01 ){ /* schema=? constraint is present. Get its value */ const char *zDbase = (const char*)sqlite3_value_text(argv[iArg++]); |
︙ | ︙ |
Changes to src/expr.c.
︙ | ︙ | |||
40 41 42 43 44 45 46 | ** CREATE TABLE t1(a); ** SELECT * FROM t1 WHERE a; ** SELECT a AS b FROM t1 WHERE b; ** SELECT * FROM t1 WHERE (select a from t1); */ char sqlite3ExprAffinity(const Expr *pExpr){ int op; | < < < < < < < < > | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | ** CREATE TABLE t1(a); ** SELECT * FROM t1 WHERE a; ** SELECT a AS b FROM t1 WHERE b; ** SELECT * FROM t1 WHERE (select a from t1); */ char sqlite3ExprAffinity(const Expr *pExpr){ int op; op = pExpr->op; while( 1 /* exit-by-break */ ){ if( op==TK_COLUMN || (op==TK_AGG_COLUMN && pExpr->y.pTab!=0) ){ assert( ExprUseYTab(pExpr) ); assert( pExpr->y.pTab!=0 ); return sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); } if( op==TK_SELECT ){ assert( ExprUseXSelect(pExpr) ); assert( pExpr->x.pSelect!=0 ); assert( pExpr->x.pSelect->pEList!=0 ); assert( pExpr->x.pSelect->pEList->a[0].pExpr!=0 ); return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr); } #ifndef SQLITE_OMIT_CAST if( op==TK_CAST ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); return sqlite3AffinityType(pExpr->u.zToken, 0); } #endif if( op==TK_SELECT_COLUMN ){ assert( pExpr->pLeft!=0 && ExprUseXSelect(pExpr->pLeft) ); assert( pExpr->iColumn < pExpr->iTable ); assert( pExpr->iTable==pExpr->pLeft->x.pSelect->pEList->nExpr ); return sqlite3ExprAffinity( pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr ); } if( op==TK_VECTOR ){ assert( ExprUseXList(pExpr) ); return sqlite3ExprAffinity(pExpr->x.pList->a[0].pExpr); } if( ExprHasProperty(pExpr, EP_Skip|EP_IfNullRow) ){ assert( pExpr->op==TK_COLLATE || pExpr->op==TK_IF_NULL_ROW || (pExpr->op==TK_REGISTER && pExpr->op2==TK_IF_NULL_ROW) ); pExpr = pExpr->pLeft; op = pExpr->op; continue; } if( op!=TK_REGISTER || (op = pExpr->op2)==TK_REGISTER ) break; } return pExpr->affExpr; } /* ** Make a guess at all the possible datatypes of the result that could ** be returned by an expression. Return a bitmask indicating the answer: ** ** 0x01 Numeric ** 0x02 Text ** 0x04 Blob ** ** If the expression must return NULL, then 0x00 is returned. */ int sqlite3ExprDataType(const Expr *pExpr){ while( pExpr ){ switch( pExpr->op ){ case TK_COLLATE: case TK_IF_NULL_ROW: case TK_UPLUS: { pExpr = pExpr->pLeft; break; } case TK_NULL: { pExpr = 0; break; } case TK_STRING: { return 0x02; } case TK_BLOB: { return 0x04; } case TK_CONCAT: { return 0x06; } case TK_VARIABLE: case TK_AGG_FUNCTION: case TK_FUNCTION: { return 0x07; } case TK_COLUMN: case TK_AGG_COLUMN: case TK_SELECT: case TK_CAST: case TK_SELECT_COLUMN: case TK_VECTOR: { int aff = sqlite3ExprAffinity(pExpr); if( aff>=SQLITE_AFF_NUMERIC ) return 0x05; if( aff==SQLITE_AFF_TEXT ) return 0x06; return 0x07; } case TK_CASE: { int res = 0; int ii; ExprList *pList = pExpr->x.pList; assert( ExprUseXList(pExpr) && pList!=0 ); assert( pList->nExpr > 0); for(ii=1; ii<pList->nExpr; ii+=2){ res |= sqlite3ExprDataType(pList->a[ii].pExpr); } if( pList->nExpr % 2 ){ res |= sqlite3ExprDataType(pList->a[pList->nExpr-1].pExpr); } return res; } default: { return 0x01; } } /* End of switch(op) */ } /* End of while(pExpr) */ return 0x00; } /* ** Set the collating sequence for expression pExpr to be the collating ** sequence named by pToken. Return a pointer to a new Expr node that ** implements the COLLATE operator. ** ** If a memory allocation error occurs, that fact is recorded in pParse->db |
︙ | ︙ | |||
4173 4174 4175 4176 4177 4178 4179 | */ int aff; iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target); assert( ExprUseYTab(pExpr) ); assert( pExpr->y.pTab!=0 ); aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); if( aff>SQLITE_AFF_BLOB ){ | | | 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 | */ int aff; iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target); assert( ExprUseYTab(pExpr) ); assert( pExpr->y.pTab!=0 ); aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); if( aff>SQLITE_AFF_BLOB ){ static const char zAff[] = "B\000C\000D\000E\000F"; assert( SQLITE_AFF_BLOB=='A' ); assert( SQLITE_AFF_TEXT=='B' ); sqlite3VdbeAddOp4(v, OP_Affinity, iReg, 1, 0, &zAff[(aff-'B')*2], P4_STATIC); } return iReg; } |
︙ | ︙ | |||
6170 6171 6172 6173 6174 6175 6176 | ** This is a Walker expression node callback. ** ** For Expr nodes that contain pAggInfo pointers, make sure the AggInfo ** object that is referenced does not refer directly to the Expr. If ** it does, make a copy. This is done because the pExpr argument is ** subject to change. ** | | < < | < | 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 | ** This is a Walker expression node callback. ** ** For Expr nodes that contain pAggInfo pointers, make sure the AggInfo ** object that is referenced does not refer directly to the Expr. If ** it does, make a copy. This is done because the pExpr argument is ** subject to change. ** ** The copy is scheduled for deletion using the sqlite3ExprDeferredDelete() ** which builds on the sqlite3ParserAddCleanup() mechanism. */ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){ if( ALWAYS(!ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced)) && pExpr->pAggInfo!=0 ){ AggInfo *pAggInfo = pExpr->pAggInfo; int iAgg = pExpr->iAgg; Parse *pParse = pWalker->pParse; sqlite3 *db = pParse->db; if( pExpr->op!=TK_AGG_FUNCTION ){ assert( iAgg>=0 && iAgg<pAggInfo->nColumn ); if( pAggInfo->aCol[iAgg].pCExpr==pExpr ){ pExpr = sqlite3ExprDup(db, pExpr, 0); if( pExpr ){ pAggInfo->aCol[iAgg].pCExpr = pExpr; sqlite3ExprDeferredDelete(pParse, pExpr); } |
︙ | ︙ | |||
6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 | } } if( pCol->iSorterColumn<0 ){ pCol->iSorterColumn = pAggInfo->nSortingColumn++; } fix_up_expr: ExprSetVVAProperty(pExpr, EP_NoReduce); pExpr->pAggInfo = pAggInfo; if( pExpr->op==TK_COLUMN ){ pExpr->op = TK_AGG_COLUMN; } pExpr->iAgg = (i16)k; } | > | 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 | } } if( pCol->iSorterColumn<0 ){ pCol->iSorterColumn = pAggInfo->nSortingColumn++; } fix_up_expr: ExprSetVVAProperty(pExpr, EP_NoReduce); assert( pExpr->pAggInfo==0 || pExpr->pAggInfo==pAggInfo ); pExpr->pAggInfo = pAggInfo; if( pExpr->op==TK_COLUMN ){ pExpr->op = TK_AGG_COLUMN; } pExpr->iAgg = (i16)k; } |
︙ | ︙ | |||
6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 | for(pIEpr=pParse->pIdxEpr; pIEpr; pIEpr=pIEpr->pIENext){ int iDataCur = pIEpr->iDataCur; if( iDataCur<0 ) continue; if( sqlite3ExprCompare(0, pExpr, pIEpr->pExpr, iDataCur)==0 ) break; } if( pIEpr==0 ) break; if( NEVER(!ExprUseYTab(pExpr)) ) break; /* If we reach this point, it means that expression pExpr can be ** translated into a reference to an index column as described by ** pIEpr. */ memset(&tmp, 0, sizeof(tmp)); tmp.op = TK_AGG_COLUMN; | > | 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 | for(pIEpr=pParse->pIdxEpr; pIEpr; pIEpr=pIEpr->pIENext){ int iDataCur = pIEpr->iDataCur; if( iDataCur<0 ) continue; if( sqlite3ExprCompare(0, pExpr, pIEpr->pExpr, iDataCur)==0 ) break; } if( pIEpr==0 ) break; if( NEVER(!ExprUseYTab(pExpr)) ) break; if( pExpr->pAggInfo!=0 ) break; /* Already resolved by outer context */ /* If we reach this point, it means that expression pExpr can be ** translated into a reference to an index column as described by ** pIEpr. */ memset(&tmp, 0, sizeof(tmp)); tmp.op = TK_AGG_COLUMN; |
︙ | ︙ |
Changes to src/func.c.
︙ | ︙ | |||
1078 1079 1080 1081 1082 1083 1084 | } case SQLITE_INTEGER: { sqlite3_str_appendf(pStr, "%lld", sqlite3_value_int64(pValue)); break; } case SQLITE_BLOB: { char const *zBlob = sqlite3_value_blob(pValue); | | | 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 | } case SQLITE_INTEGER: { sqlite3_str_appendf(pStr, "%lld", sqlite3_value_int64(pValue)); break; } case SQLITE_BLOB: { char const *zBlob = sqlite3_value_blob(pValue); i64 nBlob = sqlite3_value_bytes(pValue); assert( zBlob==sqlite3_value_blob(pValue) ); /* No encoding change */ sqlite3StrAccumEnlarge(pStr, nBlob*2 + 4); if( pStr->accError==0 ){ char *zText = pStr->zText; int i; for(i=0; i<nBlob; i++){ zText[(i*2)+2] = hexdigits[(zBlob[i]>>4)&0x0F]; |
︙ | ︙ | |||
1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 | */ static void unknownFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ /* no-op */ } #endif /*SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION*/ /* IMP: R-25361-16150 This function is omitted from SQLite by default. It ** is only available if the SQLITE_SOUNDEX compile-time option is used ** when SQLite is built. | > > > | 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 | */ static void unknownFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ /* no-op */ (void)context; (void)argc; (void)argv; } #endif /*SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION*/ /* IMP: R-25361-16150 This function is omitted from SQLite by default. It ** is only available if the SQLITE_SOUNDEX compile-time option is used ** when SQLite is built. |
︙ | ︙ | |||
2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 | */ static void piFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ assert( argc==0 ); sqlite3_result_double(context, M_PI); } #endif /* SQLITE_ENABLE_MATH_FUNCTIONS */ /* ** Implementation of sign(X) function. | > | 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 | */ static void piFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ assert( argc==0 ); (void)argv; sqlite3_result_double(context, M_PI); } #endif /* SQLITE_ENABLE_MATH_FUNCTIONS */ /* ** Implementation of sign(X) function. |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 | case SQLITE_RANGE: zName = "SQLITE_RANGE"; break; case SQLITE_NOTADB: zName = "SQLITE_NOTADB"; break; case SQLITE_ROW: zName = "SQLITE_ROW"; break; case SQLITE_NOTICE: zName = "SQLITE_NOTICE"; break; case SQLITE_NOTICE_RECOVER_WAL: zName = "SQLITE_NOTICE_RECOVER_WAL";break; case SQLITE_NOTICE_RECOVER_ROLLBACK: zName = "SQLITE_NOTICE_RECOVER_ROLLBACK"; break; case SQLITE_WARNING: zName = "SQLITE_WARNING"; break; case SQLITE_WARNING_AUTOINDEX: zName = "SQLITE_WARNING_AUTOINDEX"; break; case SQLITE_DONE: zName = "SQLITE_DONE"; break; } } if( zName==0 ){ static char zBuf[50]; | > | 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 | case SQLITE_RANGE: zName = "SQLITE_RANGE"; break; case SQLITE_NOTADB: zName = "SQLITE_NOTADB"; break; case SQLITE_ROW: zName = "SQLITE_ROW"; break; case SQLITE_NOTICE: zName = "SQLITE_NOTICE"; break; case SQLITE_NOTICE_RECOVER_WAL: zName = "SQLITE_NOTICE_RECOVER_WAL";break; case SQLITE_NOTICE_RECOVER_ROLLBACK: zName = "SQLITE_NOTICE_RECOVER_ROLLBACK"; break; case SQLITE_NOTICE_RBU: zName = "SQLITE_NOTICE_RBU"; break; case SQLITE_WARNING: zName = "SQLITE_WARNING"; break; case SQLITE_WARNING_AUTOINDEX: zName = "SQLITE_WARNING_AUTOINDEX"; break; case SQLITE_DONE: zName = "SQLITE_DONE"; break; } } if( zName==0 ){ static char zBuf[50]; |
︙ | ︙ | |||
2114 2115 2116 2117 2118 2119 2120 | return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); rc = sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)!=0; sqlite3_mutex_leave(db->mutex); if( rc ) return SQLITE_OK; | | | 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 | return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); rc = sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)!=0; sqlite3_mutex_leave(db->mutex); if( rc ) return SQLITE_OK; zCopy = sqlite3_mprintf("%s", zName); if( zCopy==0 ) return SQLITE_NOMEM; return sqlite3_create_function_v2(db, zName, nArg, SQLITE_UTF8, zCopy, sqlite3InvalidFunction, 0, 0, sqlite3_free); } #ifndef SQLITE_OMIT_TRACE /* |
︙ | ︙ |
Changes to src/memdb.c.
︙ | ︙ | |||
105 106 107 108 109 110 111 112 113 114 115 116 117 118 | static int memdbClose(sqlite3_file*); static int memdbRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); static int memdbWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); static int memdbTruncate(sqlite3_file*, sqlite3_int64 size); static int memdbSync(sqlite3_file*, int flags); static int memdbFileSize(sqlite3_file*, sqlite3_int64 *pSize); static int memdbLock(sqlite3_file*, int); /* static int memdbCheckReservedLock(sqlite3_file*, int *pResOut);// not used */ static int memdbFileControl(sqlite3_file*, int op, void *pArg); /* static int memdbSectorSize(sqlite3_file*); // not used */ static int memdbDeviceCharacteristics(sqlite3_file*); static int memdbFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); static int memdbUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p); | > | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | static int memdbClose(sqlite3_file*); static int memdbRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); static int memdbWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); static int memdbTruncate(sqlite3_file*, sqlite3_int64 size); static int memdbSync(sqlite3_file*, int flags); static int memdbFileSize(sqlite3_file*, sqlite3_int64 *pSize); static int memdbLock(sqlite3_file*, int); static int memdbUnlock(sqlite3_file*, int); /* static int memdbCheckReservedLock(sqlite3_file*, int *pResOut);// not used */ static int memdbFileControl(sqlite3_file*, int op, void *pArg); /* static int memdbSectorSize(sqlite3_file*); // not used */ static int memdbDeviceCharacteristics(sqlite3_file*); static int memdbFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); static int memdbUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p); |
︙ | ︙ | |||
163 164 165 166 167 168 169 | memdbClose, /* xClose */ memdbRead, /* xRead */ memdbWrite, /* xWrite */ memdbTruncate, /* xTruncate */ memdbSync, /* xSync */ memdbFileSize, /* xFileSize */ memdbLock, /* xLock */ | | | 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | memdbClose, /* xClose */ memdbRead, /* xRead */ memdbWrite, /* xWrite */ memdbTruncate, /* xTruncate */ memdbSync, /* xSync */ memdbFileSize, /* xFileSize */ memdbLock, /* xLock */ memdbUnlock, /* xUnlock */ 0, /* memdbCheckReservedLock, */ /* xCheckReservedLock */ memdbFileControl, /* xFileControl */ 0, /* memdbSectorSize,*/ /* xSectorSize */ memdbDeviceCharacteristics, /* xDeviceCharacteristics */ 0, /* xShmMap */ 0, /* xShmLock */ 0, /* xShmBarrier */ |
︙ | ︙ | |||
364 365 366 367 368 369 370 | /* ** Lock an memdb-file. */ static int memdbLock(sqlite3_file *pFile, int eLock){ MemFile *pThis = (MemFile*)pFile; MemStore *p = pThis->pStore; int rc = SQLITE_OK; | | > | | | > | | | | < | | < < < < < < < < < < | < | | | | > > | | < > > > | | | | | | > > > > | | < < | | | | | | < < < < | < < > > > > > > > > > > > > > > > > > > > > > > > > > > > | 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 | /* ** Lock an memdb-file. */ static int memdbLock(sqlite3_file *pFile, int eLock){ MemFile *pThis = (MemFile*)pFile; MemStore *p = pThis->pStore; int rc = SQLITE_OK; if( eLock<=pThis->eLock ) return SQLITE_OK; memdbEnter(p); assert( p->nWrLock==0 || p->nWrLock==1 ); assert( pThis->eLock<=SQLITE_LOCK_SHARED || p->nWrLock==1 ); assert( pThis->eLock==SQLITE_LOCK_NONE || p->nRdLock>=1 ); if( eLock>SQLITE_LOCK_SHARED && (p->mFlags & SQLITE_DESERIALIZE_READONLY) ){ rc = SQLITE_READONLY; }else{ switch( eLock ){ case SQLITE_LOCK_SHARED: { assert( pThis->eLock==SQLITE_LOCK_NONE ); if( p->nWrLock>0 ){ rc = SQLITE_BUSY; }else{ p->nRdLock++; } break; }; case SQLITE_LOCK_RESERVED: case SQLITE_LOCK_PENDING: { assert( pThis->eLock>=SQLITE_LOCK_SHARED ); if( ALWAYS(pThis->eLock==SQLITE_LOCK_SHARED) ){ if( p->nWrLock>0 ){ rc = SQLITE_BUSY; }else{ p->nWrLock = 1; } } break; } default: { assert( eLock==SQLITE_LOCK_EXCLUSIVE ); assert( pThis->eLock>=SQLITE_LOCK_SHARED ); if( p->nRdLock>1 ){ rc = SQLITE_BUSY; }else if( pThis->eLock==SQLITE_LOCK_SHARED ){ p->nWrLock = 1; } break; } } } if( rc==SQLITE_OK ) pThis->eLock = eLock; memdbLeave(p); return rc; } /* ** Unlock an memdb-file. */ static int memdbUnlock(sqlite3_file *pFile, int eLock){ MemFile *pThis = (MemFile*)pFile; MemStore *p = pThis->pStore; if( eLock>=pThis->eLock ) return SQLITE_OK; memdbEnter(p); assert( eLock==SQLITE_LOCK_SHARED || eLock==SQLITE_LOCK_NONE ); if( eLock==SQLITE_LOCK_SHARED ){ if( ALWAYS(pThis->eLock>SQLITE_LOCK_SHARED) ){ p->nWrLock--; } }else{ if( pThis->eLock>SQLITE_LOCK_SHARED ){ p->nWrLock--; } p->nRdLock--; } pThis->eLock = eLock; memdbLeave(p); return SQLITE_OK; } #if 0 /* ** This interface is only used for crash recovery, which does not ** occur on an in-memory database. */ static int memdbCheckReservedLock(sqlite3_file *pFile, int *pResOut){ |
︙ | ︙ | |||
531 532 533 534 535 536 537 | MemFile *pFile = (MemFile*)pFd; MemStore *p = 0; int szName; UNUSED_PARAMETER(pVfs); memset(pFile, 0, sizeof(*pFile)); szName = sqlite3Strlen30(zName); | | | 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 | MemFile *pFile = (MemFile*)pFd; MemStore *p = 0; int szName; UNUSED_PARAMETER(pVfs); memset(pFile, 0, sizeof(*pFile)); szName = sqlite3Strlen30(zName); if( szName>1 && (zName[0]=='/' || zName[0]=='\\') ){ int i; #ifndef SQLITE_MUTEX_OMIT sqlite3_mutex *pVfsMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); #endif sqlite3_mutex_enter(pVfsMutex); for(i=0; i<memdb_g.nMemStore; i++){ if( strcmp(memdb_g.apMemStore[i]->zFName,zName)==0 ){ |
︙ | ︙ |
Changes to src/printf.c.
︙ | ︙ | |||
732 733 734 735 736 737 738 739 740 741 742 743 | buf[1] = 0x80 + (u8)((ch>>12) & 0x3f); buf[2] = 0x80 + (u8)((ch>>6) & 0x3f); buf[3] = 0x80 + (u8)(ch & 0x3f); length = 4; } } if( precision>1 ){ width -= precision-1; if( width>1 && !flag_leftjustify ){ sqlite3_str_appendchar(pAccum, width-1, ' '); width = 0; } | > > > | > > > > > > > | > > > | 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 | buf[1] = 0x80 + (u8)((ch>>12) & 0x3f); buf[2] = 0x80 + (u8)((ch>>6) & 0x3f); buf[3] = 0x80 + (u8)(ch & 0x3f); length = 4; } } if( precision>1 ){ i64 nPrior = 1; width -= precision-1; if( width>1 && !flag_leftjustify ){ sqlite3_str_appendchar(pAccum, width-1, ' '); width = 0; } sqlite3_str_append(pAccum, buf, length); precision--; while( precision > 1 ){ i64 nCopyBytes; if( nPrior > precision-1 ) nPrior = precision - 1; nCopyBytes = length*nPrior; if( nCopyBytes + pAccum->nChar >= pAccum->nAlloc ){ sqlite3StrAccumEnlarge(pAccum, nCopyBytes); } if( pAccum->accError ) break; sqlite3_str_append(pAccum, &pAccum->zText[pAccum->nChar-nCopyBytes], nCopyBytes); precision -= nPrior; nPrior *= 2; } } bufpt = buf; flag_altform2 = 1; goto adjust_width_for_utf8; case etSTRING: case etDYNSTRING: |
︙ | ︙ | |||
966 967 968 969 970 971 972 | /* ** Enlarge the memory allocation on a StrAccum object so that it is ** able to accept at least N more bytes of text. ** ** Return the number of bytes of text that StrAccum is able to accept ** after the attempted enlargement. The value returned might be zero. */ | | | | < | 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 | /* ** Enlarge the memory allocation on a StrAccum object so that it is ** able to accept at least N more bytes of text. ** ** Return the number of bytes of text that StrAccum is able to accept ** after the attempted enlargement. The value returned might be zero. */ int sqlite3StrAccumEnlarge(StrAccum *p, i64 N){ char *zNew; assert( p->nChar+N >= p->nAlloc ); /* Only called if really needed */ if( p->accError ){ testcase(p->accError==SQLITE_TOOBIG); testcase(p->accError==SQLITE_NOMEM); return 0; } if( p->mxAlloc==0 ){ sqlite3StrAccumSetError(p, SQLITE_TOOBIG); return p->nAlloc - p->nChar - 1; }else{ char *zOld = isMalloced(p) ? p->zText : 0; i64 szNew = p->nChar + N + 1; if( szNew+p->nChar<=p->mxAlloc ){ /* Force exponential buffer size growth as long as it does not overflow, ** to avoid having to call this routine too often */ szNew += p->nChar; } if( szNew > p->mxAlloc ){ sqlite3_str_reset(p); |
︙ | ︙ | |||
1010 1011 1012 1013 1014 1015 1016 | p->printfFlags |= SQLITE_PRINTF_MALLOCED; }else{ sqlite3_str_reset(p); sqlite3StrAccumSetError(p, SQLITE_NOMEM); return 0; } } | > | | 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 | p->printfFlags |= SQLITE_PRINTF_MALLOCED; }else{ sqlite3_str_reset(p); sqlite3StrAccumSetError(p, SQLITE_NOMEM); return 0; } } assert( N>=0 && N<=0x7fffffff ); return (int)N; } /* ** Append N copies of character c to the given string buffer. */ void sqlite3_str_appendchar(sqlite3_str *p, int N, char c){ testcase( p->nChar + (i64)N > 0x7fffffff ); |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
1294 1295 1296 1297 1298 1299 1300 | case SRT_EphemTab: { int r1 = sqlite3GetTempRange(pParse, nPrefixReg+1); testcase( eDest==SRT_Table ); testcase( eDest==SRT_EphemTab ); testcase( eDest==SRT_Fifo ); testcase( eDest==SRT_DistFifo ); sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1+nPrefixReg); | < < < | 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 | case SRT_EphemTab: { int r1 = sqlite3GetTempRange(pParse, nPrefixReg+1); testcase( eDest==SRT_Table ); testcase( eDest==SRT_EphemTab ); testcase( eDest==SRT_Fifo ); testcase( eDest==SRT_DistFifo ); sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1+nPrefixReg); #ifndef SQLITE_OMIT_CTE if( eDest==SRT_DistFifo ){ /* If the destination is DistFifo, then cursor (iParm+1) is open ** on an ephemeral index. If the current row is already present ** in the index, do not write it to the output. If not, add the ** current row to the index and proceed with writing it to the ** output table as well. */ |
︙ | ︙ | |||
1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 | ** the SQLITE_ENABLE_COLUMN_METADATA compile-time option is used. */ #ifdef SQLITE_ENABLE_COLUMN_METADATA # define columnType(A,B,C,D,E) columnTypeImpl(A,B,C,D,E) #else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */ # define columnType(A,B,C,D,E) columnTypeImpl(A,B) #endif static const char *columnTypeImpl( NameContext *pNC, #ifndef SQLITE_ENABLE_COLUMN_METADATA Expr *pExpr #else Expr *pExpr, const char **pzOrigDb, | > | 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 | ** the SQLITE_ENABLE_COLUMN_METADATA compile-time option is used. */ #ifdef SQLITE_ENABLE_COLUMN_METADATA # define columnType(A,B,C,D,E) columnTypeImpl(A,B,C,D,E) #else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */ # define columnType(A,B,C,D,E) columnTypeImpl(A,B) #endif #ifndef SQLITE_OMIT_DECLTYPE static const char *columnTypeImpl( NameContext *pNC, #ifndef SQLITE_ENABLE_COLUMN_METADATA Expr *pExpr #else Expr *pExpr, const char **pzOrigDb, |
︙ | ︙ | |||
1899 1900 1901 1902 1903 1904 1905 | /* The expression is a column. Locate the table the column is being ** extracted from in NameContext.pSrcList. This table may be real ** database table or a subquery. */ Table *pTab = 0; /* Table structure column is extracted from */ Select *pS = 0; /* Select the column is extracted from */ int iCol = pExpr->iColumn; /* Index of column in pTab */ | | | | 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 | /* The expression is a column. Locate the table the column is being ** extracted from in NameContext.pSrcList. This table may be real ** database table or a subquery. */ Table *pTab = 0; /* Table structure column is extracted from */ Select *pS = 0; /* Select the column is extracted from */ int iCol = pExpr->iColumn; /* Index of column in pTab */ while( ALWAYS(pNC) && !pTab ){ SrcList *pTabList = pNC->pSrcList; for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++); if( j<pTabList->nSrc ){ pTab = pTabList->a[j].pTab; pS = pTabList->a[j].pSelect; }else{ pNC = pNC->pNext; } } if( NEVER(pTab==0) ){ /* At one time, code such as "SELECT new.x" within a trigger would ** cause this condition to run. Since then, we have restructured how ** trigger code is generated and so this condition is no longer ** possible. However, it can still be true for statements like ** the following: ** ** CREATE TABLE t1(col INTEGER); |
︙ | ︙ | |||
2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 | *pzOrigDb = zOrigDb; *pzOrigTab = zOrigTab; *pzOrigCol = zOrigCol; } #endif return zType; } /* ** Generate code that will tell the VDBE the declaration types of columns ** in the result set. */ static void generateColumnTypes( Parse *pParse, /* Parser context */ | > | 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 | *pzOrigDb = zOrigDb; *pzOrigTab = zOrigTab; *pzOrigCol = zOrigCol; } #endif return zType; } #endif /* !defined(SQLITE_OMIT_DECLTYPE) */ /* ** Generate code that will tell the VDBE the declaration types of columns ** in the result set. */ static void generateColumnTypes( Parse *pParse, /* Parser context */ |
︙ | ︙ | |||
2286 2287 2288 2289 2290 2291 2292 | *pnCol = 0; return SQLITE_NOMEM_BKPT; } return SQLITE_OK; } /* | | | | | | < > | | | | | | | < | > < | | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 | *pnCol = 0; return SQLITE_NOMEM_BKPT; } return SQLITE_OK; } /* ** pTab is a transient Table object that represents a subquery of some ** kind (maybe a parenthesized subquery in the FROM clause of a larger ** query, or a VIEW, or a CTE). This routine computes type information ** for that Table object based on the Select object that implements the ** subquery. For the purposes of this routine, "type infomation" means: ** ** * The datatype name, as it might appear in a CREATE TABLE statement ** * Which collating sequence to use for the column ** * The affinity of the column */ void sqlite3SubqueryColumnTypes( Parse *pParse, /* Parsing contexts */ Table *pTab, /* Add column type information to this table */ Select *pSelect, /* SELECT used to determine types and collations */ char aff /* Default affinity. */ ){ sqlite3 *db = pParse->db; Column *pCol; CollSeq *pColl; int i,j; Expr *p; struct ExprList_item *a; assert( pSelect!=0 ); assert( (pSelect->selFlags & SF_Resolved)!=0 ); assert( pTab->nCol==pSelect->pEList->nExpr || db->mallocFailed ); assert( aff==SQLITE_AFF_NONE || aff==SQLITE_AFF_BLOB ); if( db->mallocFailed ) return; while( pSelect->pPrior ) pSelect = pSelect->pPrior; a = pSelect->pEList->a; for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){ const char *zType; i64 n; pTab->tabFlags |= (pCol->colFlags & COLFLAG_NOINSERT); p = a[i].pExpr; /* pCol->szEst = ... // Column size est for SELECT tables never used */ pCol->affinity = sqlite3ExprAffinity(p); if( pCol->affinity<=SQLITE_AFF_NONE ){ pCol->affinity = aff; }else if( pCol->affinity>=SQLITE_AFF_NUMERIC && p->op==TK_CAST ){ pCol->affinity = SQLITE_AFF_FLEXNUM; } if( pCol->affinity>=SQLITE_AFF_TEXT && pSelect->pNext ){ int m = 0; Select *pS2; for(m=0, pS2=pSelect->pNext; pS2; pS2=pS2->pNext){ m |= sqlite3ExprDataType(pS2->pEList->a[i].pExpr); } if( pCol->affinity==SQLITE_AFF_TEXT && (m&0x01)!=0 ){ pCol->affinity = SQLITE_AFF_BLOB; }else if( pCol->affinity>=SQLITE_AFF_NUMERIC && (m&0x02)!=0 ){ pCol->affinity = SQLITE_AFF_BLOB; } } if( pCol->affinity==SQLITE_AFF_NUMERIC || pCol->affinity==SQLITE_AFF_FLEXNUM ){ zType = "NUM"; }else{ zType = 0; for(j=1; j<SQLITE_N_STDTYPE; j++){ if( sqlite3StdTypeAffinity[j]==pCol->affinity ){ zType = sqlite3StdType[j]; break; } } } if( zType ){ i64 m = sqlite3Strlen30(zType); n = sqlite3Strlen30(pCol->zCnName); pCol->zCnName = sqlite3DbReallocOrFree(db, pCol->zCnName, n+m+2); if( pCol->zCnName ){ memcpy(&pCol->zCnName[n+1], zType, m+1); pCol->colFlags |= COLFLAG_HASTYPE; }else{ testcase( pCol->colFlags & COLFLAG_HASTYPE ); pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL); } } pColl = sqlite3ExprCollSeq(pParse, p); if( pColl ){ assert( pTab->pIndex==0 ); sqlite3ColumnSetColl(db, pCol, pColl->zName); } } pTab->szTabRow = 1; /* Any non-zero value works */ |
︙ | ︙ | |||
2371 2372 2373 2374 2375 2376 2377 | if( pTab==0 ){ return 0; } pTab->nTabRef = 1; pTab->zName = 0; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol); | | | 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 | if( pTab==0 ){ return 0; } pTab->nTabRef = 1; pTab->zName = 0; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol); sqlite3SubqueryColumnTypes(pParse, pTab, pSelect, aff); pTab->iPKey = -1; if( db->mallocFailed ){ sqlite3DeleteTable(db, pTab); return 0; } return pTab; } |
︙ | ︙ | |||
6182 6183 6184 6185 6186 6187 6188 | #ifndef SQLITE_OMIT_SUBQUERY /* ** This is a Walker.xSelectCallback callback for the sqlite3SelectTypeInfo() ** interface. ** | | | | | | | < < | | 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 | #ifndef SQLITE_OMIT_SUBQUERY /* ** This is a Walker.xSelectCallback callback for the sqlite3SelectTypeInfo() ** interface. ** ** For each FROM-clause subquery, add Column.zType, Column.zColl, and ** Column.affinity information to the Table structure that represents ** the result set of that subquery. ** ** The Table structure that represents the result set was constructed ** by selectExpander() but the type and collation and affinity information ** was omitted at that point because identifiers had not yet been resolved. ** This routine is called after identifier resolution. */ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){ Parse *pParse; int i; SrcList *pTabList; SrcItem *pFrom; assert( p->selFlags & SF_Resolved ); if( p->selFlags & SF_HasTypeInfo ) return; p->selFlags |= SF_HasTypeInfo; pParse = pWalker->pParse; pTabList = p->pSrc; for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){ Table *pTab = pFrom->pTab; assert( pTab!=0 ); if( (pTab->tabFlags & TF_Ephemeral)!=0 ){ /* A sub-query in the FROM clause of a SELECT */ Select *pSel = pFrom->pSelect; if( pSel ){ sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE); } } } } #endif |
︙ | ︙ | |||
6285 6286 6287 6288 6289 6290 6291 | pCol->iTable, pCol->iColumn, pAggInfo->iFirstReg+ii, pCol->iSorterColumn, ii>=pAggInfo->nAccumulator ? "" : " Accumulator"); sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pCExpr, 0); } for(ii=0; ii<pAggInfo->nFunc; ii++){ sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n", | | | 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 | pCol->iTable, pCol->iColumn, pAggInfo->iFirstReg+ii, pCol->iSorterColumn, ii>=pAggInfo->nAccumulator ? "" : " Accumulator"); sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pCExpr, 0); } for(ii=0; ii<pAggInfo->nFunc; ii++){ sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n", ii, pAggInfo->iFirstReg+pAggInfo->nColumn+ii); sqlite3TreeViewExpr(0, pAggInfo->aFunc[ii].pFExpr, 0); } } #endif /* TREETRACE_ENABLED */ /* ** Analyze the arguments to aggregate functions. Create new pAggInfo->aCol[] |
︙ | ︙ | |||
6693 6694 6695 6696 6697 6698 6699 | TREETRACE(0x100,pParse,p,("Move HAVING terms into WHERE:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif } /* | | > > > | | | > | > | 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 | TREETRACE(0x100,pParse,p,("Move HAVING terms into WHERE:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif } /* ** Check to see if the pThis entry of pTabList is a self-join of another view. ** Search FROM-clause entries in the range of iFirst..iEnd, including iFirst ** but stopping before iEnd. ** ** If pThis is a self-join, then return the SrcItem for the first other ** instance of that view found. If pThis is not a self-join then return 0. */ static SrcItem *isSelfJoinView( SrcList *pTabList, /* Search for self-joins in this FROM clause */ SrcItem *pThis, /* Search for prior reference to this subquery */ int iFirst, int iEnd /* Range of FROM-clause entries to search. */ ){ SrcItem *pItem; assert( pThis->pSelect!=0 ); if( pThis->pSelect->selFlags & SF_PushDown ) return 0; while( iFirst<iEnd ){ Select *pS1; pItem = &pTabList->a[iFirst++]; if( pItem->pSelect==0 ) continue; if( pItem->fg.viaCoroutine ) continue; if( pItem->zName==0 ) continue; assert( pItem->pTab!=0 ); assert( pThis->pTab!=0 ); if( pItem->pTab->pSchema!=pThis->pTab->pSchema ) continue; if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue; |
︙ | ︙ | |||
6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 | && sameSrcAlias(p0, p1->pSelect->pSrc) ){ return 1; } } return 0; } /* ** Generate code for the SELECT statement given in the p argument. ** ** The results are returned according to the SelectDest structure. ** See comments in sqliteInt.h for further information. ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 | && sameSrcAlias(p0, p1->pSelect->pSrc) ){ return 1; } } return 0; } /* ** Return TRUE (non-zero) if the i-th entry in the pTabList SrcList can ** be implemented as a co-routine. The i-th entry is guaranteed to be ** a subquery. ** ** The subquery is implemented as a co-routine if all of the following are ** true: ** ** (1) The subquery will likely be implemented in the outer loop of ** the query. This will be the case if any one of the following ** conditions hold: ** (a) The subquery is the only term in the FROM clause ** (b) The subquery is the left-most term and a CROSS JOIN or similar ** requires it to be the outer loop ** (c) All of the following are true: ** (i) The subquery is the left-most subquery in the FROM clause ** (ii) There is nothing that would prevent the subquery from ** being used as the outer loop if the sqlite3WhereBegin() ** routine nominates it to that position. ** (iii) The query is not a UPDATE ... FROM ** (2) The subquery is not a CTE that should be materialized because of ** the AS MATERIALIZED keywords ** (3) The subquery is not part of a left operand for a RIGHT JOIN ** (4) The SQLITE_Coroutine optimization disable flag is not set ** (5) The subquery is not self-joined */ static int fromClauseTermCanBeCoroutine( Parse *pParse, /* Parsing context */ SrcList *pTabList, /* FROM clause */ int i, /* Which term of the FROM clause holds the subquery */ int selFlags /* Flags on the SELECT statement */ ){ SrcItem *pItem = &pTabList->a[i]; if( pItem->fg.isCte && pItem->u2.pCteUse->eM10d==M10d_Yes ) return 0;/* (2) */ if( pTabList->a[0].fg.jointype & JT_LTORJ ) return 0; /* (3) */ if( OptimizationDisabled(pParse->db, SQLITE_Coroutines) ) return 0; /* (4) */ if( isSelfJoinView(pTabList, pItem, i+1, pTabList->nSrc)!=0 ){ return 0; /* (5) */ } if( i==0 ){ if( pTabList->nSrc==1 ) return 1; /* (1a) */ if( pTabList->a[1].fg.jointype & JT_CROSS ) return 1; /* (1b) */ if( selFlags & SF_UpdateFrom ) return 0; /* (1c-iii) */ return 1; } if( selFlags & SF_UpdateFrom ) return 0; /* (1c-iii) */ while( 1 /*exit-by-break*/ ){ if( pItem->fg.jointype & (JT_OUTER|JT_CROSS) ) return 0; /* (1c-ii) */ if( i==0 ) break; i--; pItem--; if( pItem->pSelect!=0 ) return 0; /* (1c-i) */ } return 1; } /* ** Generate code for the SELECT statement given in the p argument. ** ** The results are returned according to the SelectDest structure. ** See comments in sqliteInt.h for further information. ** |
︙ | ︙ | |||
7237 7238 7239 7240 7241 7242 7243 | TREETRACE(0x4000,pParse,p,("Push-down not possible\n")); } zSavedAuthContext = pParse->zAuthContext; pParse->zAuthContext = pItem->zName; /* Generate code to implement the subquery | < < < < < < < < < | < < < < < < < | < < < < | | 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 | TREETRACE(0x4000,pParse,p,("Push-down not possible\n")); } zSavedAuthContext = pParse->zAuthContext; pParse->zAuthContext = pItem->zName; /* Generate code to implement the subquery */ if( fromClauseTermCanBeCoroutine(pParse, pTabList, i, p->selFlags) ){ /* Implement a co-routine that will return a single row of the result ** set on each invocation. */ int addrTop = sqlite3VdbeCurrentAddr(v)+1; pItem->regReturn = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); VdbeComment((v, "%!S", pItem)); pItem->addrFillSub = addrTop; sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); ExplainQueryPlan((pParse, 1, "CO-ROUTINE %!S", pItem)); sqlite3Select(pParse, pSub, &dest); pItem->pTab->nRowLogEst = pSub->nSelectRow; pItem->fg.viaCoroutine = 1; pItem->regResult = dest.iSdst; sqlite3VdbeEndCoroutine(v, pItem->regReturn); sqlite3VdbeJumpHere(v, addrTop-1); sqlite3ClearTempRegCache(pParse); }else if( pItem->fg.isCte && pItem->u2.pCteUse->addrM9e>0 ){ /* This is a CTE for which materialization code has already been ** generated. Invoke the subroutine to compute the materialization, ** the make the pItem->iCursor be a copy of the ephemerial table that ** holds the result of the materialization. */ CteUse *pCteUse = pItem->u2.pCteUse; sqlite3VdbeAddOp2(v, OP_Gosub, pCteUse->regRtn, pCteUse->addrM9e); if( pItem->iCursor!=pCteUse->iCur ){ sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pCteUse->iCur); VdbeComment((v, "%!S", pItem)); } pSub->nSelectRow = pCteUse->nRowEst; }else if( (pPrior = isSelfJoinView(pTabList, pItem, 0, i))!=0 ){ /* This view has already been materialized by a prior entry in ** this same FROM clause. Reuse it. */ if( pPrior->addrFillSub ){ sqlite3VdbeAddOp2(v, OP_Gosub, pPrior->regReturn, pPrior->addrFillSub); } sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor); pSub->nSelectRow = pPrior->pSelect->nSelectRow; |
︙ | ︙ | |||
7323 7324 7325 7326 7327 7328 7329 | VdbeComment((v, "materialize %!S", pItem)); }else{ VdbeNoopComment((v, "materialize %!S", pItem)); } sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); ExplainQueryPlan2(addrExplain, (pParse, 1, "MATERIALIZE %!S", pItem)); | < < < > < < < | 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 | VdbeComment((v, "materialize %!S", pItem)); }else{ VdbeNoopComment((v, "materialize %!S", pItem)); } sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); ExplainQueryPlan2(addrExplain, (pParse, 1, "MATERIALIZE %!S", pItem)); sqlite3Select(pParse, pSub, &dest); pItem->pTab->nRowLogEst = pSub->nSelectRow; if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr); sqlite3VdbeAddOp2(v, OP_Return, pItem->regReturn, topAddr+1); VdbeComment((v, "end %!S", pItem)); sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1); sqlite3VdbeJumpHere(v, topAddr); sqlite3ClearTempRegCache(pParse); if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){ CteUse *pCteUse = pItem->u2.pCteUse; pCteUse->addrM9e = pItem->addrFillSub; pCteUse->regRtn = pItem->regReturn; pCteUse->iCur = pItem->iCursor; pCteUse->nRowEst = pSub->nSelectRow; } } if( db->mallocFailed ) goto select_end; pParse->nHeight -= sqlite3SelectExprHeight(p); pParse->zAuthContext = zSavedAuthContext; #endif } |
︙ | ︙ | |||
7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632 7633 | (void(*)(sqlite3*,void*))agginfoFree, pAggInfo); testcase( pParse->earlyCleanup ); } if( db->mallocFailed ){ goto select_end; } pAggInfo->selId = p->selId; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; sNC.pSrcList = pTabList; sNC.uNC.pAggInfo = pAggInfo; VVA_ONLY( sNC.ncFlags = NC_UAggInfo; ) pAggInfo->nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0; pAggInfo->pGroupBy = pGroupBy; | > > > | 7681 7682 7683 7684 7685 7686 7687 7688 7689 7690 7691 7692 7693 7694 7695 7696 7697 | (void(*)(sqlite3*,void*))agginfoFree, pAggInfo); testcase( pParse->earlyCleanup ); } if( db->mallocFailed ){ goto select_end; } pAggInfo->selId = p->selId; #ifdef SQLITE_DEBUG pAggInfo->pSelect = p; #endif memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; sNC.pSrcList = pTabList; sNC.uNC.pAggInfo = pAggInfo; VVA_ONLY( sNC.ncFlags = NC_UAggInfo; ) pAggInfo->nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0; pAggInfo->pGroupBy = pGroupBy; |
︙ | ︙ |
Changes to src/shell.c.in.
︙ | ︙ | |||
17 18 19 20 21 22 23 | #define _CRT_SECURE_NO_WARNINGS #endif typedef unsigned int u32; typedef unsigned short int u16; /* ** Optionally #include a user-defined header, whereby compilation options | | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #define _CRT_SECURE_NO_WARNINGS #endif typedef unsigned int u32; typedef unsigned short int u16; /* ** Optionally #include a user-defined header, whereby compilation options ** may be set prior to where they take effect, but after platform setup. ** If SQLITE_CUSTOM_INCLUDE=? is defined, its value names the #include ** file. Note that this macro has a like effect on sqlite3.c compilation. */ # define SHELL_STRINGIFY_(f) #f # define SHELL_STRINGIFY(f) SHELL_STRINGIFY_(f) #ifdef SQLITE_CUSTOM_INCLUDE # include SHELL_STRINGIFY(SQLITE_CUSTOM_INCLUDE) |
︙ | ︙ | |||
531 532 533 534 535 536 537 | /* Upon demand, derive the continuation prompt to display. */ static char *dynamicContinuePrompt(void){ if( continuePrompt[0]==0 || (dynPrompt.zScannerAwaits==0 && dynPrompt.inParenLevel == 0) ){ return continuePrompt; }else{ if( dynPrompt.zScannerAwaits ){ | > | | | | | | | 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 | /* Upon demand, derive the continuation prompt to display. */ static char *dynamicContinuePrompt(void){ if( continuePrompt[0]==0 || (dynPrompt.zScannerAwaits==0 && dynPrompt.inParenLevel == 0) ){ return continuePrompt; }else{ if( dynPrompt.zScannerAwaits ){ size_t ncp = strlen(continuePrompt); size_t ndp = strlen(dynPrompt.zScannerAwaits); if( ndp > ncp-3 ) return continuePrompt; strcpy(dynPrompt.dynamicPrompt, dynPrompt.zScannerAwaits); while( ndp<3 ) dynPrompt.dynamicPrompt[ndp++] = ' '; strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3, PROMPT_LEN_MAX-4); }else{ if( dynPrompt.inParenLevel>9 ){ strncpy(dynPrompt.dynamicPrompt, "(..", 4); }else if( dynPrompt.inParenLevel<0 ){ strncpy(dynPrompt.dynamicPrompt, ")x!", 4); }else{ strncpy(dynPrompt.dynamicPrompt, "(x.", 4); dynPrompt.dynamicPrompt[2] = (char)('0'+dynPrompt.inParenLevel); } strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3, PROMPT_LEN_MAX-4); } } return dynPrompt.dynamicPrompt; } #endif /* !defined(SQLITE_OMIT_DYNAPROMPT) */ |
︙ | ︙ | |||
1029 1030 1031 1032 1033 1034 1035 | int nVal, sqlite3_value **apVal ){ const char *zName; char *zFake; UNUSED_PARAMETER(nVal); zName = (const char*)sqlite3_value_text(apVal[0]); | | | 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 | int nVal, sqlite3_value **apVal ){ const char *zName; char *zFake; UNUSED_PARAMETER(nVal); zName = (const char*)sqlite3_value_text(apVal[0]); zFake = zName? shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName) : 0; if( zFake ){ sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake), -1, sqlite3_free); free(zFake); } } |
︙ | ︙ | |||
1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 | INCLUDE test_windirent.c #define dirent DIRENT #endif INCLUDE ../ext/misc/memtrace.c INCLUDE ../ext/misc/shathree.c INCLUDE ../ext/misc/uint.c INCLUDE ../ext/misc/decimal.c INCLUDE ../ext/misc/ieee754.c INCLUDE ../ext/misc/series.c INCLUDE ../ext/misc/regexp.c #ifndef SQLITE_SHELL_FIDDLE INCLUDE ../ext/misc/fileio.c INCLUDE ../ext/misc/completion.c INCLUDE ../ext/misc/appendvfs.c | > > > > > > > | 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 | INCLUDE test_windirent.c #define dirent DIRENT #endif INCLUDE ../ext/misc/memtrace.c INCLUDE ../ext/misc/shathree.c INCLUDE ../ext/misc/uint.c INCLUDE ../ext/misc/decimal.c #undef sqlite3_base_init #define sqlite3_base_init sqlite3_base64_init INCLUDE ../ext/misc/base64.c #undef sqlite3_base_init #define sqlite3_base_init sqlite3_base85_init #define OMIT_BASE85_CHECKER INCLUDE ../ext/misc/base85.c INCLUDE ../ext/misc/ieee754.c INCLUDE ../ext/misc/series.c INCLUDE ../ext/misc/regexp.c #ifndef SQLITE_SHELL_FIDDLE INCLUDE ../ext/misc/fileio.c INCLUDE ../ext/misc/completion.c INCLUDE ../ext/misc/appendvfs.c |
︙ | ︙ | |||
1584 1585 1586 1587 1588 1589 1590 | ** \r\n back into \n */ for(i=j=0; i<sz; i++){ if( p[i]=='\r' && p[i+1]=='\n' ) i++; p[j++] = p[i]; } sz = j; p[sz] = 0; | | | 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 | ** \r\n back into \n */ for(i=j=0; i<sz; i++){ if( p[i]=='\r' && p[i+1]=='\n' ) i++; p[j++] = p[i]; } sz = j; p[sz] = 0; } sqlite3_result_text64(context, (const char*)p, sz, sqlite3_free, SQLITE_UTF8); } p = 0; edit_func_end: if( f ) fclose(f); |
︙ | ︙ | |||
2759 2760 2761 2762 2763 2764 2765 | len = 78; while( (zSql[len]&0xc0)==0x80 ) len--; } zCode = sqlite3_mprintf("%.*s", len, zSql); shell_check_oom(zCode); for(i=0; zCode[i]; i++){ if( IsSpace(zSql[i]) ) zCode[i] = ' '; } if( iOffset<25 ){ | | | | 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 | len = 78; while( (zSql[len]&0xc0)==0x80 ) len--; } zCode = sqlite3_mprintf("%.*s", len, zSql); shell_check_oom(zCode); for(i=0; zCode[i]; i++){ if( IsSpace(zSql[i]) ) zCode[i] = ' '; } if( iOffset<25 ){ zMsg = sqlite3_mprintf("\n %z\n %*s^--- error here", zCode,iOffset,""); }else{ zMsg = sqlite3_mprintf("\n %z\n %*serror here ---^", zCode,iOffset-14,""); } return zMsg; } /* ** Execute a query statement that will generate SQL output. Print |
︙ | ︙ | |||
2949 2950 2951 2952 2953 2954 2955 | utf8_printf(out, "%-36s %s\n", z, sqlite3_column_origin_name(pStmt,i)); #endif } } if( pArg->statsOn==3 ){ if( pArg->pStmt ){ | | | 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 | utf8_printf(out, "%-36s %s\n", z, sqlite3_column_origin_name(pStmt,i)); #endif } } if( pArg->statsOn==3 ){ if( pArg->pStmt ){ iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP,bReset); raw_printf(pArg->out, "VM-steps: %d\n", iCur); } return 0; } displayStatLine(pArg, "Memory Used:", "%lld (max %lld) bytes", SQLITE_STATUS_MEMORY_USED, bReset); |
︙ | ︙ | |||
3030 3031 3032 3033 3034 3035 3036 | iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset); raw_printf(pArg->out, "Fullscan Steps: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset); raw_printf(pArg->out, "Sort Operations: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset); raw_printf(pArg->out, "Autoindex Inserts: %d\n", iCur); | | > | > | 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 | iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset); raw_printf(pArg->out, "Fullscan Steps: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset); raw_printf(pArg->out, "Sort Operations: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset); raw_printf(pArg->out, "Autoindex Inserts: %d\n", iCur); iHit = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_HIT, bReset); iMiss = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_MISS, bReset); if( iHit || iMiss ){ raw_printf(pArg->out, "Bloom filter bypass taken: %d/%d\n", iHit, iHit+iMiss); } iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset); raw_printf(pArg->out, "Virtual Machine Steps: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_REPREPARE,bReset); |
︙ | ︙ | |||
3060 3061 3062 3063 3064 3065 3066 | } #ifdef SQLITE_ENABLE_STMT_SCANSTATUS static int scanStatsHeight(sqlite3_stmt *p, int iEntry){ int iPid = 0; int ret = 1; | | | | | 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 | } #ifdef SQLITE_ENABLE_STMT_SCANSTATUS static int scanStatsHeight(sqlite3_stmt *p, int iEntry){ int iPid = 0; int ret = 1; sqlite3_stmt_scanstatus_v2(p, iEntry, SQLITE_SCANSTAT_SELECTID, SQLITE_SCANSTAT_COMPLEX, (void*)&iPid ); while( iPid!=0 ){ int ii; for(ii=0; 1; ii++){ int iId; int res; res = sqlite3_stmt_scanstatus_v2(p, ii, SQLITE_SCANSTAT_SELECTID, SQLITE_SCANSTAT_COMPLEX, (void*)&iId ); if( res ) break; if( iId==iPid ){ sqlite3_stmt_scanstatus_v2(p, ii, SQLITE_SCANSTAT_PARENTID, SQLITE_SCANSTAT_COMPLEX, (void*)&iPid ); } } ret++; } return ret; |
︙ | ︙ | |||
3405 3406 3407 3408 3409 3410 3411 | #define BOX_124 "\342\224\264" /* U+2534 -'- */ #define BOX_1234 "\342\224\274" /* U+253c -|- */ /* Draw horizontal line N characters long using unicode box ** characters */ static void print_box_line(FILE *out, int N){ | | | 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 | #define BOX_124 "\342\224\264" /* U+2534 -'- */ #define BOX_1234 "\342\224\274" /* U+253c -|- */ /* Draw horizontal line N characters long using unicode box ** characters */ static void print_box_line(FILE *out, int N){ const char zDash[] = BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24; const int nDash = sizeof(zDash) - 1; N *= 3; while( N>nDash ){ utf8_printf(out, zDash); N -= nDash; |
︙ | ︙ | |||
3534 3535 3536 3537 3538 3539 3540 | }while( (n&7)!=0 && n<mxWidth ); i++; continue; } break; } zOut[j] = 0; | | | 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 | }while( (n&7)!=0 && n<mxWidth ); i++; continue; } break; } zOut[j] = 0; return (char*)zOut; } /* Extract the value of the i-th current column for pStmt as an SQL literal ** value. Memory is obtained from sqlite3_malloc64() and must be freed by ** the caller. */ static char *quoted_column(sqlite3_stmt *pStmt, int i){ |
︙ | ︙ | |||
3895 3896 3897 3898 3899 3900 3901 | ** ** If successful, SQLITE_OK is returned. Otherwise, an SQLite error ** code. In this case, (*pzErr) may be set to point to a buffer containing ** an English language error message. It is the responsibility of the ** caller to eventually free this buffer using sqlite3_free(). */ static int expertHandleSQL( | | | | | 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 | ** ** If successful, SQLITE_OK is returned. Otherwise, an SQLite error ** code. In this case, (*pzErr) may be set to point to a buffer containing ** an English language error message. It is the responsibility of the ** caller to eventually free this buffer using sqlite3_free(). */ static int expertHandleSQL( ShellState *pState, const char *zSql, char **pzErr ){ assert( pState->expert.pExpert ); assert( pzErr==0 || *pzErr==0 ); return sqlite3_expert_sql(pState->expert.pExpert, zSql, pzErr); } /* ** This function is called either to silently clean up the object ** created by the ".expert" command (if bCancel==1), or to generate a ** report from it and then clean it up (if bCancel==0). ** ** If successful, SQLITE_OK is returned. Otherwise, an SQLite error ** code. In this case, (*pzErr) may be set to point to a buffer containing ** an English language error message. It is the responsibility of the ** caller to eventually free this buffer using sqlite3_free(). */ |
︙ | ︙ | |||
4001 4002 4003 4004 4005 4006 4007 | rc = SQLITE_ERROR; } } if( rc==SQLITE_OK ){ pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr); if( pState->expert.pExpert==0 ){ | | > | 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 | rc = SQLITE_ERROR; } } if( rc==SQLITE_OK ){ pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr); if( pState->expert.pExpert==0 ){ raw_printf(stderr, "sqlite3_expert_new: %s\n", zErr ? zErr : "out of memory"); rc = SQLITE_ERROR; }else{ sqlite3_expert_config( pState->expert.pExpert, EXPERT_CONFIG_SAMPLE, iSample ); } } |
︙ | ︙ | |||
4962 4963 4964 4965 4966 4967 4968 | && zBuf[3]==0x06 ){ rc = SHELL_OPEN_ZIPFILE; }else if( n==0 && dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){ rc = SHELL_OPEN_ZIPFILE; } } fclose(f); | | | 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 | && zBuf[3]==0x06 ){ rc = SHELL_OPEN_ZIPFILE; }else if( n==0 && dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){ rc = SHELL_OPEN_ZIPFILE; } } fclose(f); return rc; } #ifndef SQLITE_OMIT_DESERIALIZE /* ** Reconstruct an in-memory database using the output from the "dbtotxt" ** program. Read content from the file in p->aAuxDb[].zDbFilename. ** If p->aAuxDb[].zDbFilename is 0, then read from standard input. |
︙ | ︙ | |||
5061 5062 5063 5064 5065 5066 5067 | /* ** Scalar function "shell_int32". The first argument to this function ** must be a blob. The second a non-negative integer. This function ** reads and returns a 32-bit big-endian integer from byte ** offset (4*<arg2>) of the blob. */ static void shellInt32( | | | | 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 | /* ** Scalar function "shell_int32". The first argument to this function ** must be a blob. The second a non-negative integer. This function ** reads and returns a 32-bit big-endian integer from byte ** offset (4*<arg2>) of the blob. */ static void shellInt32( sqlite3_context *context, int argc, sqlite3_value **argv ){ const unsigned char *pBlob; int nBlob; int iInt; UNUSED_PARAMETER(argc); |
︙ | ︙ | |||
5089 5090 5091 5092 5093 5094 5095 | } /* ** Scalar function "shell_idquote(X)" returns string X quoted as an identifier, ** using "..." with internal double-quote characters doubled. */ static void shellIdQuote( | | | | | | | | | 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 | } /* ** Scalar function "shell_idquote(X)" returns string X quoted as an identifier, ** using "..." with internal double-quote characters doubled. */ static void shellIdQuote( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zName = (const char*)sqlite3_value_text(argv[0]); UNUSED_PARAMETER(argc); if( zName ){ char *z = sqlite3_mprintf("\"%w\"", zName); sqlite3_result_text(context, z, -1, sqlite3_free); } } /* ** Scalar function "usleep(X)" invokes sqlite3_sleep(X) and returns X. */ static void shellUSleepFunc( sqlite3_context *context, int argcUnused, sqlite3_value **argv ){ int sleep = sqlite3_value_int(argv[0]); (void)argcUnused; sqlite3_sleep(sleep/1000); sqlite3_result_int(context, sleep); } /* ** Scalar function "shell_escape_crnl" used by the .recover command. ** The argument passed to this function is the output of built-in ** function quote(). If the first character of the input is "'", ** indicating that the value passed to quote() was a text value, ** then this function searches the input for "\n" and "\r" characters ** and adds a wrapper similar to the following: ** ** replace(replace(<input>, '\n', char(10), '\r', char(13)); ** ** Or, if the first character of the input is not "'", then a copy ** of the input is returned. */ static void shellEscapeCrnl( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zText = (const char*)sqlite3_value_text(argv[0]); UNUSED_PARAMETER(argc); if( zText && zText[0]=='\'' ){ i64 nText = sqlite3_value_bytes(argv[0]); i64 i; |
︙ | ︙ | |||
5230 5231 5232 5233 5234 5235 5236 | static void open_db(ShellState *p, int openFlags){ if( p->db==0 ){ const char *zDbFilename = p->pAuxDb->zDbFilename; if( p->openMode==SHELL_OPEN_UNSPEC ){ if( zDbFilename==0 || zDbFilename[0]==0 ){ p->openMode = SHELL_OPEN_NORMAL; }else{ | | | | 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 | static void open_db(ShellState *p, int openFlags){ if( p->db==0 ){ const char *zDbFilename = p->pAuxDb->zDbFilename; if( p->openMode==SHELL_OPEN_UNSPEC ){ if( zDbFilename==0 || zDbFilename[0]==0 ){ p->openMode = SHELL_OPEN_NORMAL; }else{ p->openMode = (u8)deduceDatabaseType(zDbFilename, (openFlags & OPEN_DB_ZIPFILE)!=0); } } switch( p->openMode ){ case SHELL_OPEN_APPENDVFS: { sqlite3_open_v2(zDbFilename, &p->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, "apndvfs"); break; } case SHELL_OPEN_HEXDB: case SHELL_OPEN_DESERIALIZE: { sqlite3_open(0, &p->db); break; |
︙ | ︙ | |||
5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 | #ifndef SQLITE_OMIT_LOAD_EXTENSION sqlite3_enable_load_extension(p->db, 1); #endif sqlite3_shathree_init(p->db, 0, 0); sqlite3_uint_init(p->db, 0, 0); sqlite3_decimal_init(p->db, 0, 0); sqlite3_regexp_init(p->db, 0, 0); sqlite3_ieee_init(p->db, 0, 0); sqlite3_series_init(p->db, 0, 0); #ifndef SQLITE_SHELL_FIDDLE sqlite3_fileio_init(p->db, 0, 0); sqlite3_completion_init(p->db, 0, 0); #endif | > > | 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 | #ifndef SQLITE_OMIT_LOAD_EXTENSION sqlite3_enable_load_extension(p->db, 1); #endif sqlite3_shathree_init(p->db, 0, 0); sqlite3_uint_init(p->db, 0, 0); sqlite3_decimal_init(p->db, 0, 0); sqlite3_base64_init(p->db, 0, 0); sqlite3_base85_init(p->db, 0, 0); sqlite3_regexp_init(p->db, 0, 0); sqlite3_ieee_init(p->db, 0, 0); sqlite3_series_init(p->db, 0, 0); #ifndef SQLITE_SHELL_FIDDLE sqlite3_fileio_init(p->db, 0, 0); sqlite3_completion_init(p->db, 0, 0); #endif |
︙ | ︙ | |||
5389 5390 5391 5392 5393 5394 5395 | ** Attempt to close the databaes connection. Report errors. */ void close_db(sqlite3 *db){ int rc = sqlite3_close(db); if( rc ){ utf8_printf(stderr, "Error: sqlite3_close() returns %d: %s\n", rc, sqlite3_errmsg(db)); | | | 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 | ** Attempt to close the databaes connection. Report errors. */ void close_db(sqlite3 *db){ int rc = sqlite3_close(db); if( rc ){ utf8_printf(stderr, "Error: sqlite3_close() returns %d: %s\n", rc, sqlite3_errmsg(db)); } } #if HAVE_READLINE || HAVE_EDITLINE /* ** Readline completion callbacks */ static char *readline_completion_generator(const char *text, int state){ |
︙ | ︙ | |||
5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 | sqlite3_finalize(pStmt); pStmt = 0; zRet = 0; } return zRet; } static char **readline_completion(const char *zText, int iStart, int iEnd){ rl_attempted_completion_over = 1; return rl_completion_matches(zText, readline_completion_generator); } #elif HAVE_LINENOISE /* ** Linenoise completion callback | > > | 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 | sqlite3_finalize(pStmt); pStmt = 0; zRet = 0; } return zRet; } static char **readline_completion(const char *zText, int iStart, int iEnd){ (void)iStart; (void)iEnd; rl_attempted_completion_over = 1; return rl_completion_matches(zText, readline_completion_generator); } #elif HAVE_LINENOISE /* ** Linenoise completion callback |
︙ | ︙ | |||
6630 6631 6632 6633 6634 6635 6636 | raw_printf(stderr, "Where sub-commands are:\n"); raw_printf(stderr, " fkey-indexes\n"); return SQLITE_ERROR; } #if !defined SQLITE_OMIT_VIRTUALTABLE static void shellPrepare( | | | | | | | | | 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 | raw_printf(stderr, "Where sub-commands are:\n"); raw_printf(stderr, " fkey-indexes\n"); return SQLITE_ERROR; } #if !defined SQLITE_OMIT_VIRTUALTABLE static void shellPrepare( sqlite3 *db, int *pRc, const char *zSql, sqlite3_stmt **ppStmt ){ *ppStmt = 0; if( *pRc==SQLITE_OK ){ int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0); if( rc!=SQLITE_OK ){ raw_printf(stderr, "sql error: %s (%d)\n", sqlite3_errmsg(db), sqlite3_errcode(db) ); *pRc = rc; } } } /* ** Create a prepared statement using printf-style arguments for the SQL. ** ** This routine is could be marked "static". But it is not always used, ** depending on compile-time options. By omitting the "static", we avoid ** nuisance compiler warnings about "defined but not used". */ void shellPreparePrintf( sqlite3 *db, int *pRc, sqlite3_stmt **ppStmt, const char *zFmt, ... ){ *ppStmt = 0; if( *pRc==SQLITE_OK ){ va_list ap; char *z; va_start(ap, zFmt); |
︙ | ︙ | |||
6684 6685 6686 6687 6688 6689 6690 | /* Finalize the prepared statement created using shellPreparePrintf(). ** ** This routine is could be marked "static". But it is not always used, ** depending on compile-time options. By omitting the "static", we avoid ** nuisance compiler warnings about "defined but not used". */ void shellFinalize( | | | 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 | /* Finalize the prepared statement created using shellPreparePrintf(). ** ** This routine is could be marked "static". But it is not always used, ** depending on compile-time options. By omitting the "static", we avoid ** nuisance compiler warnings about "defined but not used". */ void shellFinalize( int *pRc, sqlite3_stmt *pStmt ){ if( pStmt ){ sqlite3 *db = sqlite3_db_handle(pStmt); int rc = sqlite3_finalize(pStmt); if( *pRc==SQLITE_OK ){ if( rc!=SQLITE_OK ){ |
︙ | ︙ | |||
6706 6707 6708 6709 6710 6711 6712 | /* Reset the prepared statement created using shellPreparePrintf(). ** ** This routine is could be marked "static". But it is not always used, ** depending on compile-time options. By omitting the "static", we avoid ** nuisance compiler warnings about "defined but not used". */ void shellReset( | | | 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 | /* Reset the prepared statement created using shellPreparePrintf(). ** ** This routine is could be marked "static". But it is not always used, ** depending on compile-time options. By omitting the "static", we avoid ** nuisance compiler warnings about "defined but not used". */ void shellReset( int *pRc, sqlite3_stmt *pStmt ){ int rc = sqlite3_reset(pStmt); if( *pRc==SQLITE_OK ){ if( rc!=SQLITE_OK ){ sqlite3 *db = sqlite3_db_handle(pStmt); raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db)); |
︙ | ︙ | |||
6754 6755 6756 6757 6758 6759 6760 | */ static int arUsage(FILE *f){ showHelp(f,"archive"); return SQLITE_ERROR; } /* | | | 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 | */ static int arUsage(FILE *f){ showHelp(f,"archive"); return SQLITE_ERROR; } /* ** Print an error message for the .ar command to stderr and return ** SQLITE_ERROR. */ static int arErrorMsg(ArCommand *pAr, const char *zFmt, ...){ va_list ap; char *z; va_start(ap, zFmt); z = sqlite3_vmprintf(zFmt, ap); |
︙ | ︙ | |||
6835 6836 6837 6838 6839 6840 6841 | return SQLITE_OK; } /* ** Parse the command line for an ".ar" command. The results are written into ** structure (*pAr). SQLITE_OK is returned if the command line is parsed | | | 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 | return SQLITE_OK; } /* ** Parse the command line for an ".ar" command. The results are written into ** structure (*pAr). SQLITE_OK is returned if the command line is parsed ** successfully, otherwise an error message is written to stderr and ** SQLITE_ERROR returned. */ static int arParseCommand( char **azArg, /* Array of arguments passed to dot command */ int nArg, /* Number of entries in azArg[] */ ArCommand *pAr /* Populate this object */ ){ |
︙ | ︙ | |||
7031 7032 7033 7034 7035 7036 7037 | ** identify all archive members that match the command arguments held ** in (*pAr). Leave this WHERE clause in (*pzWhere) before returning. ** The caller is responsible for eventually calling sqlite3_free() on ** any non-NULL (*pzWhere) value. Here, "match" means strict equality ** when pAr->bGlob is false and GLOB match when pAr->bGlob is true. */ static void arWhereClause( | | | | | | 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 | ** identify all archive members that match the command arguments held ** in (*pAr). Leave this WHERE clause in (*pzWhere) before returning. ** The caller is responsible for eventually calling sqlite3_free() on ** any non-NULL (*pzWhere) value. Here, "match" means strict equality ** when pAr->bGlob is false and GLOB match when pAr->bGlob is true. */ static void arWhereClause( int *pRc, ArCommand *pAr, char **pzWhere /* OUT: New WHERE clause */ ){ char *zWhere = 0; const char *zSameOp = (pAr->bGlob)? "GLOB" : "="; if( *pRc==SQLITE_OK ){ if( pAr->nArg==0 ){ zWhere = sqlite3_mprintf("1"); }else{ int i; const char *zSep = ""; for(i=0; i<pAr->nArg; i++){ const char *z = pAr->azArg[i]; zWhere = sqlite3_mprintf( "%z%s name %s '%q' OR substr(name,1,%d) %s '%q/'", zWhere, zSep, zSameOp, z, strlen30(z)+1, zSameOp, z ); if( zWhere==0 ){ *pRc = SQLITE_NOMEM; break; } zSep = " OR "; } } } *pzWhere = zWhere; } /* ** Implementation of .ar "lisT" command. */ static int arListCommand(ArCommand *pAr){ const char *zSql = "SELECT %s FROM %s WHERE %s"; const char *azCols[] = { "name", "lsmode(mode), sz, datetime(mtime, 'unixepoch'), name" }; char *zWhere = 0; sqlite3_stmt *pSql = 0; |
︙ | ︙ | |||
7086 7087 7088 7089 7090 7091 7092 | if( pAr->bDryRun ){ utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql)); }else{ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ if( pAr->bVerbose ){ utf8_printf(pAr->p->out, "%s % 10d %s %s\n", sqlite3_column_text(pSql, 0), | | | 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 | if( pAr->bDryRun ){ utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql)); }else{ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ if( pAr->bVerbose ){ utf8_printf(pAr->p->out, "%s % 10d %s %s\n", sqlite3_column_text(pSql, 0), sqlite3_column_int(pSql, 1), sqlite3_column_text(pSql, 2), sqlite3_column_text(pSql, 3) ); }else{ utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0)); } } |
︙ | ︙ | |||
7143 7144 7145 7146 7147 7148 7149 | } sqlite3_free(zWhere); sqlite3_free(zSql); return rc; } /* | | | | | 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 | } sqlite3_free(zWhere); sqlite3_free(zSql); return rc; } /* ** Implementation of .ar "eXtract" command. */ static int arExtractCommand(ArCommand *pAr){ const char *zSql1 = "SELECT " " ($dir || name)," " writefile(($dir || name), %s, mode, mtime) " "FROM %s WHERE (%s) AND (data IS NULL OR $dirOnly = 0)" " AND name NOT GLOB '*..[/\\]*'"; const char *azExtraArg[] = { "sqlar_uncompress(data, sz)", "data" }; sqlite3_stmt *pSql = 0; int rc = SQLITE_OK; char *zDir = 0; |
︙ | ︙ | |||
7179 7180 7181 7182 7183 7184 7185 | zDir = sqlite3_mprintf("%s/", pAr->zDir); }else{ zDir = sqlite3_mprintf(""); } if( zDir==0 ) rc = SQLITE_NOMEM; } | | | 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 | zDir = sqlite3_mprintf("%s/", pAr->zDir); }else{ zDir = sqlite3_mprintf(""); } if( zDir==0 ) rc = SQLITE_NOMEM; } shellPreparePrintf(pAr->db, &rc, &pSql, zSql1, azExtraArg[pAr->bZip], pAr->zSrcTable, zWhere ); if( rc==SQLITE_OK ){ j = sqlite3_bind_parameter_index(pSql, "$dir"); sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC); |
︙ | ︙ | |||
7257 7258 7259 7260 7261 7262 7263 | ** "update" only overwrites if the size or mtime or mode has changed. */ static int arCreateOrUpdateCommand( ArCommand *pAr, /* Command arguments and options */ int bUpdate, /* true for a --create. */ int bOnlyIfChanged /* Only update if file has changed */ ){ | | | 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 | ** "update" only overwrites if the size or mtime or mode has changed. */ static int arCreateOrUpdateCommand( ArCommand *pAr, /* Command arguments and options */ int bUpdate, /* true for a --create. */ int bOnlyIfChanged /* Only update if file has changed */ ){ const char *zCreate = "CREATE TABLE IF NOT EXISTS sqlar(\n" " name TEXT PRIMARY KEY, -- name of the file\n" " mode INT, -- access permissions\n" " mtime INT, -- last modification time\n" " sz INT, -- original file size\n" " data BLOB -- compressed content\n" ")"; |
︙ | ︙ | |||
7299 7300 7301 7302 7303 7304 7305 | char *zSql; char zTemp[50]; char *zExists = 0; arExecSql(pAr, "PRAGMA page_size=512"); rc = arExecSql(pAr, "SAVEPOINT ar;"); if( rc!=SQLITE_OK ) return rc; | | | 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 | char *zSql; char zTemp[50]; char *zExists = 0; arExecSql(pAr, "PRAGMA page_size=512"); rc = arExecSql(pAr, "SAVEPOINT ar;"); if( rc!=SQLITE_OK ) return rc; zTemp[0] = 0; if( pAr->bZip ){ /* Initialize the zipfile virtual table, if necessary */ if( pAr->zFile ){ sqlite3_uint64 r; sqlite3_randomness(sizeof(r),&r); sqlite3_snprintf(sizeof(zTemp),zTemp,"zip%016llx",r); zTab = zTemp; |
︙ | ︙ | |||
7393 7394 7395 7396 7397 7398 7399 | cmd.zSrcTable = sqlite3_mprintf("zipfile(%Q)", cmd.zFile); } } cmd.bZip = 1; }else if( cmd.zFile ){ int flags; if( cmd.bAppend ) eDbType = SHELL_OPEN_APPENDVFS; | | | | | 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 | cmd.zSrcTable = sqlite3_mprintf("zipfile(%Q)", cmd.zFile); } } cmd.bZip = 1; }else if( cmd.zFile ){ int flags; if( cmd.bAppend ) eDbType = SHELL_OPEN_APPENDVFS; if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_INSERT || cmd.eCmd==AR_CMD_REMOVE || cmd.eCmd==AR_CMD_UPDATE ){ flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; }else{ flags = SQLITE_OPEN_READONLY; } cmd.db = 0; if( cmd.bDryRun ){ utf8_printf(pState->out, "-- open database '%s'%s\n", cmd.zFile, eDbType==SHELL_OPEN_APPENDVFS ? " using 'apndvfs'" : ""); } rc = sqlite3_open_v2(cmd.zFile, &cmd.db, flags, eDbType==SHELL_OPEN_APPENDVFS ? "apndvfs" : 0); if( rc!=SQLITE_OK ){ utf8_printf(stderr, "cannot open file: %s (%s)\n", cmd.zFile, sqlite3_errmsg(cmd.db) ); goto end_ar_command; } sqlite3_fileio_init(cmd.db, 0, 0); sqlite3_sqlar_init(cmd.db, 0, 0); sqlite3_create_function(cmd.db, "shell_putsnl", 1, SQLITE_UTF8, cmd.p, |
︙ | ︙ | |||
7523 7524 7525 7526 7527 7528 7529 | i++; zLAF = azArg[i]; }else if( n<=10 && memcmp("-no-rowids", z, n)==0 ){ bRowids = 0; } else{ | | | 7538 7539 7540 7541 7542 7543 7544 7545 7546 7547 7548 7549 7550 7551 7552 | i++; zLAF = azArg[i]; }else if( n<=10 && memcmp("-no-rowids", z, n)==0 ){ bRowids = 0; } else{ utf8_printf(stderr, "unexpected option: %s\n", azArg[i]); showHelp(pState->out, azArg[0]); return 1; } } p = sqlite3_recover_init_sql( pState->db, "main", recoverSqlCb, (void*)pState |
︙ | ︙ | |||
7886 7887 7888 7889 7890 7891 7892 | } } if( zDestFile==0 ){ raw_printf(stderr, "missing FILENAME argument on .backup\n"); return 1; } if( zDb==0 ) zDb = "main"; | | | 7901 7902 7903 7904 7905 7906 7907 7908 7909 7910 7911 7912 7913 7914 7915 | } } if( zDestFile==0 ){ raw_printf(stderr, "missing FILENAME argument on .backup\n"); return 1; } if( zDb==0 ) zDb = "main"; rc = sqlite3_open_v2(zDestFile, &pDest, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs); if( rc!=SQLITE_OK ){ utf8_printf(stderr, "Error: cannot open \"%s\"\n", zDestFile); close_db(pDest); return 1; } if( bAsync ){ |
︙ | ︙ | |||
8136 8137 8138 8139 8140 8141 8142 | sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v); utf8_printf(p->out, "%19s %s\n", aDbConfig[ii].zName, v ? "on" : "off"); if( nArg>1 ) break; } if( nArg>1 && ii==ArraySize(aDbConfig) ){ utf8_printf(stderr, "Error: unknown dbconfig \"%s\"\n", azArg[1]); utf8_printf(stderr, "Enter \".dbconfig\" with no arguments for a list\n"); | | | 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 | sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v); utf8_printf(p->out, "%19s %s\n", aDbConfig[ii].zName, v ? "on" : "off"); if( nArg>1 ) break; } if( nArg>1 && ii==ArraySize(aDbConfig) ){ utf8_printf(stderr, "Error: unknown dbconfig \"%s\"\n", azArg[1]); utf8_printf(stderr, "Enter \".dbconfig\" with no arguments for a list\n"); } }else #if SQLITE_SHELL_HAVE_RECOVER if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbinfo", n)==0 ){ rc = shell_dbinfo_command(p, nArg, azArg); }else |
︙ | ︙ | |||
8203 8204 8205 8206 8207 8208 8209 | "name LIKE %Q ESCAPE '\\' OR EXISTS (" " SELECT 1 FROM sqlite_schema WHERE " " name LIKE %Q ESCAPE '\\' AND" " sql LIKE 'CREATE VIRTUAL TABLE%%' AND" " substr(o.name, 1, length(name)+1) == (name||'_')" ")", azArg[i], azArg[i] ); | | | 8218 8219 8220 8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231 8232 | "name LIKE %Q ESCAPE '\\' OR EXISTS (" " SELECT 1 FROM sqlite_schema WHERE " " name LIKE %Q ESCAPE '\\' AND" " sql LIKE 'CREATE VIRTUAL TABLE%%' AND" " substr(o.name, 1, length(name)+1) == (name||'_')" ")", azArg[i], azArg[i] ); if( zLike ){ zLike = sqlite3_mprintf("%z OR %z", zLike, zExpr); }else{ zLike = zExpr; } } } |
︙ | ︙ | |||
8336 8337 8338 8339 8340 8341 8342 | p->autoExplain = 1; } }else #ifndef SQLITE_OMIT_VIRTUALTABLE if( c=='e' && cli_strncmp(azArg[0], "expert", n)==0 ){ if( p->bSafeMode ){ | | | | | 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 8368 8369 8370 8371 8372 8373 8374 8375 8376 8377 8378 8379 8380 8381 8382 8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 | p->autoExplain = 1; } }else #ifndef SQLITE_OMIT_VIRTUALTABLE if( c=='e' && cli_strncmp(azArg[0], "expert", n)==0 ){ if( p->bSafeMode ){ raw_printf(stderr, "Cannot run experimental commands such as \"%s\" in safe mode\n", azArg[0]); rc = 1; }else{ open_db(p, 0); expertDotCommand(p, azArg, nArg); } }else #endif if( c=='f' && cli_strncmp(azArg[0], "filectrl", n)==0 ){ static const struct { const char *zCtrlName; /* Name of a test-control option */ int ctrlCode; /* Integer code for that option */ const char *zUsage; /* Usage notes */ } aCtrl[] = { { "chunk_size", SQLITE_FCNTL_CHUNK_SIZE, "SIZE" }, { "data_version", SQLITE_FCNTL_DATA_VERSION, "" }, { "has_moved", SQLITE_FCNTL_HAS_MOVED, "" }, { "lock_timeout", SQLITE_FCNTL_LOCK_TIMEOUT, "MILLISEC" }, { "persist_wal", SQLITE_FCNTL_PERSIST_WAL, "[BOOLEAN]" }, /* { "pragma", SQLITE_FCNTL_PRAGMA, "NAME ARG" },*/ { "psow", SQLITE_FCNTL_POWERSAFE_OVERWRITE, "[BOOLEAN]" }, { "reserve_bytes", SQLITE_FCNTL_RESERVE_BYTES, "[N]" }, { "size_limit", SQLITE_FCNTL_SIZE_LIMIT, "[LIMIT]" }, { "tempfilename", SQLITE_FCNTL_TEMPFILENAME, "" }, /* { "win32_av_retry", SQLITE_FCNTL_WIN32_AV_RETRY, "COUNT DELAY" },*/ }; int filectrl = -1; int iCtrl = -1; sqlite3_int64 iRes = 0; /* Integer result to display if rc2==1 */ int isOk = 0; /* 0: usage 1: %lld 2: no-result */ int n2, i; const char *zCmd = 0; const char *zSchema = 0; open_db(p, 0); zCmd = nArg>=2 ? azArg[1] : "help"; if( zCmd[0]=='-' && (cli_strcmp(zCmd,"--schema")==0 || cli_strcmp(zCmd,"-schema")==0) && nArg>=4 ){ zSchema = azArg[2]; for(i=3; i<nArg; i++) azArg[i-2] = azArg[i]; nArg -= 2; zCmd = azArg[1]; |
︙ | ︙ | |||
9754 9755 9756 9757 9758 9759 9760 | }else if( azArg[ii][0]=='-' ){ utf8_printf(stderr, "Unknown option: \"%s\"\n", azArg[ii]); rc = 1; goto meta_command_exit; }else if( zName==0 ){ zName = azArg[ii]; }else{ | > | | 9769 9770 9771 9772 9773 9774 9775 9776 9777 9778 9779 9780 9781 9782 9783 9784 | }else if( azArg[ii][0]=='-' ){ utf8_printf(stderr, "Unknown option: \"%s\"\n", azArg[ii]); rc = 1; goto meta_command_exit; }else if( zName==0 ){ zName = azArg[ii]; }else{ raw_printf(stderr, "Usage: .schema ?--indent? ?--nosys? ?LIKE-PATTERN?\n"); rc = 1; goto meta_command_exit; } } if( zName!=0 ){ int isSchema = sqlite3_strlike(zName, "sqlite_master", '\\')==0 || sqlite3_strlike(zName, "sqlite_schema", '\\')==0 |
︙ | ︙ | |||
9870 9871 9872 9873 9874 9875 9876 | rc = 0; } }else if( (c=='s' && n==11 && cli_strncmp(azArg[0], "selecttrace", n)==0) || (c=='t' && n==9 && cli_strncmp(azArg[0], "treetrace", n)==0) ){ | | | 9886 9887 9888 9889 9890 9891 9892 9893 9894 9895 9896 9897 9898 9899 9900 | rc = 0; } }else if( (c=='s' && n==11 && cli_strncmp(azArg[0], "selecttrace", n)==0) || (c=='t' && n==9 && cli_strncmp(azArg[0], "treetrace", n)==0) ){ unsigned int x = nArg>=2? (unsigned int)integerValue(azArg[1]) : 0xffffffff; sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &x); }else #if defined(SQLITE_ENABLE_SESSION) if( c=='s' && cli_strncmp(azArg[0],"session",n)==0 && n>=3 ){ struct AuxDb *pAuxDb = p->pAuxDb; OpenSession *pSession = &pAuxDb->aSession[0]; |
︙ | ︙ | |||
10055 10056 10057 10058 10059 10060 10061 | for(i=0; i<pAuxDb->nSession; i++){ if( cli_strcmp(pAuxDb->aSession[i].zName,zName)==0 ){ utf8_printf(stderr, "Session \"%s\" already exists\n", zName); goto meta_command_exit; } } if( pAuxDb->nSession>=ArraySize(pAuxDb->aSession) ){ | > | | 10071 10072 10073 10074 10075 10076 10077 10078 10079 10080 10081 10082 10083 10084 10085 10086 | for(i=0; i<pAuxDb->nSession; i++){ if( cli_strcmp(pAuxDb->aSession[i].zName,zName)==0 ){ utf8_printf(stderr, "Session \"%s\" already exists\n", zName); goto meta_command_exit; } } if( pAuxDb->nSession>=ArraySize(pAuxDb->aSession) ){ raw_printf(stderr, "Maximum of %d sessions\n", ArraySize(pAuxDb->aSession)); goto meta_command_exit; } pSession = &pAuxDb->aSession[pAuxDb->nSession]; rc = sqlite3session_create(p->db, azCmd[1], &pSession->p); if( rc ){ raw_printf(stderr, "Cannot open session: error code=%d\n", rc); rc = 0; |
︙ | ︙ | |||
10339 10340 10341 10342 10343 10344 10345 | }else{ shell_exec(p, zSql, 0); } #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && !defined(SQLITE_OMIT_VIRTUALTABLE) { int lrc; char *zRevText = /* Query for reversible to-blob-to-text check */ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 10356 10357 10358 10359 10360 10361 10362 10363 10364 10365 10366 10367 10368 10369 10370 10371 10372 10373 10374 10375 10376 10377 10378 10379 10380 10381 10382 10383 10384 10385 10386 10387 10388 10389 10390 10391 10392 10393 10394 10395 10396 10397 10398 10399 10400 10401 10402 10403 10404 10405 10406 10407 10408 10409 10410 10411 | }else{ shell_exec(p, zSql, 0); } #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && !defined(SQLITE_OMIT_VIRTUALTABLE) { int lrc; char *zRevText = /* Query for reversible to-blob-to-text check */ "SELECT lower(name) as tname FROM sqlite_schema\n" "WHERE type='table' AND coalesce(rootpage,0)>1\n" "AND name NOT LIKE 'sqlite_%%'%s\n" "ORDER BY 1 collate nocase"; zRevText = sqlite3_mprintf(zRevText, zLike? " AND name LIKE $tspec" : ""); zRevText = sqlite3_mprintf( /* lower-case query is first run, producing upper-case query. */ "with tabcols as materialized(\n" "select tname, cname\n" "from (" " select ss.tname as tname, ti.name as cname\n" " from (%z) ss\n inner join pragma_table_info(tname) ti))\n" "select 'SELECT total(bad_text_count) AS bad_text_count\n" "FROM ('||group_concat(query, ' UNION ALL ')||')' as btc_query\n" " from (select 'SELECT COUNT(*) AS bad_text_count\n" "FROM '||tname||' WHERE '\n" "||group_concat('CAST(CAST('||cname||' AS BLOB) AS TEXT)<>'||cname\n" "|| ' AND typeof('||cname||')=''text'' ',\n" "' OR ') as query, tname from tabcols group by tname)" , zRevText); shell_check_oom(zRevText); if( bDebug ) utf8_printf(p->out, "%s\n", zRevText); lrc = sqlite3_prepare_v2(p->db, zRevText, -1, &pStmt, 0); assert(lrc==SQLITE_OK); if( zLike ) sqlite3_bind_text(pStmt,1,zLike,-1,SQLITE_STATIC); lrc = SQLITE_ROW==sqlite3_step(pStmt); if( lrc ){ const char *zGenQuery = (char*)sqlite3_column_text(pStmt,0); sqlite3_stmt *pCheckStmt; lrc = sqlite3_prepare_v2(p->db, zGenQuery, -1, &pCheckStmt, 0); if( bDebug ) utf8_printf(p->out, "%s\n", zGenQuery); if( SQLITE_OK==lrc ){ if( SQLITE_ROW==sqlite3_step(pCheckStmt) ){ double countIrreversible = sqlite3_column_double(pCheckStmt, 0); if( countIrreversible>0 ){ int sz = (int)(countIrreversible + 0.5); utf8_printf(stderr, "Digest includes %d invalidly encoded text field%s.\n", sz, (sz>1)? "s": ""); } } sqlite3_finalize(pCheckStmt); } sqlite3_finalize(pStmt); } sqlite3_free(zRevText); } #endif /* !defined(*_OMIT_SCHEMA_PRAGMAS) && !defined(*_OMIT_VIRTUALTABLE) */ sqlite3_free(zSql); |
︙ | ︙ | |||
10616 10617 10618 10619 10620 10621 10622 | if( c=='t' && n>=8 && cli_strncmp(azArg[0], "testctrl", n)==0 ){ static const struct { const char *zCtrlName; /* Name of a test-control option */ int ctrlCode; /* Integer code for that option */ int unSafe; /* Not valid for --safe mode */ const char *zUsage; /* Usage notes */ } aCtrl[] = { | | | | | | | | | | | | | | | | | | | | | | 10633 10634 10635 10636 10637 10638 10639 10640 10641 10642 10643 10644 10645 10646 10647 10648 10649 10650 10651 10652 10653 10654 10655 10656 10657 10658 10659 10660 10661 10662 10663 10664 10665 10666 10667 10668 | if( c=='t' && n>=8 && cli_strncmp(azArg[0], "testctrl", n)==0 ){ static const struct { const char *zCtrlName; /* Name of a test-control option */ int ctrlCode; /* Integer code for that option */ int unSafe; /* Not valid for --safe mode */ const char *zUsage; /* Usage notes */ } aCtrl[] = { {"always", SQLITE_TESTCTRL_ALWAYS, 1, "BOOLEAN" }, {"assert", SQLITE_TESTCTRL_ASSERT, 1, "BOOLEAN" }, /*{"benign_malloc_hooks",SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,1, "" },*/ /*{"bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST, 1, "" },*/ {"byteorder", SQLITE_TESTCTRL_BYTEORDER, 0, "" }, {"extra_schema_checks",SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS,0,"BOOLEAN" }, /*{"fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, 1,"" },*/ {"imposter", SQLITE_TESTCTRL_IMPOSTER,1,"SCHEMA ON/OFF ROOTPAGE"}, {"internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS,0,"" }, {"localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,0,"BOOLEAN" }, {"never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT,1, "BOOLEAN" }, {"optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS,0,"DISABLE-MASK" }, #ifdef YYCOVERAGE {"parser_coverage", SQLITE_TESTCTRL_PARSER_COVERAGE,0,"" }, #endif {"pending_byte", SQLITE_TESTCTRL_PENDING_BYTE,0, "OFFSET " }, {"prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE,0, "" }, {"prng_save", SQLITE_TESTCTRL_PRNG_SAVE, 0, "" }, {"prng_seed", SQLITE_TESTCTRL_PRNG_SEED, 0, "SEED ?db?" }, {"seek_count", SQLITE_TESTCTRL_SEEK_COUNT, 0, "" }, {"sorter_mmap", SQLITE_TESTCTRL_SORTER_MMAP, 0, "NMAX" }, {"tune", SQLITE_TESTCTRL_TUNE, 1, "ID VALUE" }, }; int testctrl = -1; int iCtrl = -1; int rc2 = 0; /* 0: usage. 1: %d 2: %x 3: no-output */ int isOk = 0; int i, n2; const char *zCmd = 0; |
︙ | ︙ | |||
11062 11063 11064 11065 11066 11067 11068 | utf8_printf(p->out, "%s\n", zVfsName); sqlite3_free(zVfsName); } } }else if( c=='w' && cli_strncmp(azArg[0], "wheretrace", n)==0 ){ | | | 11079 11080 11081 11082 11083 11084 11085 11086 11087 11088 11089 11090 11091 11092 11093 | utf8_printf(p->out, "%s\n", zVfsName); sqlite3_free(zVfsName); } } }else if( c=='w' && cli_strncmp(azArg[0], "wheretrace", n)==0 ){ unsigned int x = nArg>=2? (unsigned int)integerValue(azArg[1]) : 0xffffffff; sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &x); }else if( c=='w' && cli_strncmp(azArg[0], "width", n)==0 ){ int j; assert( nArg<=ArraySize(azArg) ); p->nWidth = nArg-1; |
︙ | ︙ | |||
11115 11116 11117 11118 11119 11120 11121 | /* ** Scan line for classification to guide shell's handling. ** The scan is resumable for subsequent lines when prior ** return values are passed as the 2nd argument. */ static QuickScanState quickscan(char *zLine, QuickScanState qss, | | | 11132 11133 11134 11135 11136 11137 11138 11139 11140 11141 11142 11143 11144 11145 11146 | /* ** Scan line for classification to guide shell's handling. ** The scan is resumable for subsequent lines when prior ** return values are passed as the 2nd argument. */ static QuickScanState quickscan(char *zLine, QuickScanState qss, SCAN_TRACKER_REFTYPE pst){ char cin; char cWait = (char)qss; /* intentional narrowing loss */ if( cWait==0 ){ PlainScan: assert( cWait==0 ); while( (cin = *zLine++)!=0 ){ if( IsSpace(cin) ) |
︙ | ︙ | |||
11139 11140 11141 11142 11143 11144 11145 | case ';': qss |= QSS_EndingSemi; continue; case '/': if( *zLine=='*' ){ ++zLine; cWait = '*'; | | | | | | | | | | | 11156 11157 11158 11159 11160 11161 11162 11163 11164 11165 11166 11167 11168 11169 11170 11171 11172 11173 11174 11175 11176 11177 11178 11179 11180 11181 11182 11183 11184 11185 11186 11187 11188 11189 11190 11191 11192 11193 11194 11195 11196 11197 11198 11199 11200 11201 11202 11203 11204 11205 11206 11207 11208 11209 11210 11211 11212 11213 11214 11215 11216 | case ';': qss |= QSS_EndingSemi; continue; case '/': if( *zLine=='*' ){ ++zLine; cWait = '*'; CONTINUE_PROMPT_AWAITS(pst, "/*"); qss = QSS_SETV(qss, cWait); goto TermScan; } break; case '[': cin = ']'; /* fall thru */ case '`': case '\'': case '"': cWait = cin; qss = QSS_HasDark | cWait; CONTINUE_PROMPT_AWAITC(pst, cin); goto TermScan; case '(': CONTINUE_PAREN_INCR(pst, 1); break; case ')': CONTINUE_PAREN_INCR(pst, -1); break; default: break; } qss = (qss & ~QSS_EndingSemi) | QSS_HasDark; } }else{ TermScan: while( (cin = *zLine++)!=0 ){ if( cin==cWait ){ switch( cWait ){ case '*': if( *zLine != '/' ) continue; ++zLine; cWait = 0; CONTINUE_PROMPT_AWAITC(pst, 0); qss = QSS_SETV(qss, 0); goto PlainScan; case '`': case '\'': case '"': if(*zLine==cWait){ /* Swallow doubled end-delimiter.*/ ++zLine; continue; } /* fall thru */ case ']': cWait = 0; CONTINUE_PROMPT_AWAITC(pst, 0); qss = QSS_SETV(qss, 0); goto PlainScan; default: assert(0); } } } } |
︙ | ︙ | |||
11290 11291 11292 11293 11294 11295 11296 | static void echo_group_input(ShellState *p, const char *zDo){ if( ShellHasFlag(p, SHFLG_Echo) ) utf8_printf(p->out, "%s\n", zDo); } #ifdef SQLITE_SHELL_FIDDLE /* | | | | | 11307 11308 11309 11310 11311 11312 11313 11314 11315 11316 11317 11318 11319 11320 11321 11322 11323 | static void echo_group_input(ShellState *p, const char *zDo){ if( ShellHasFlag(p, SHFLG_Echo) ) utf8_printf(p->out, "%s\n", zDo); } #ifdef SQLITE_SHELL_FIDDLE /* ** Alternate one_input_line() impl for wasm mode. This is not in the primary ** impl because we need the global shellState and cannot access it from that ** function without moving lots of code around (creating a larger/messier diff). */ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){ /* Parse the next line from shellState.wasm.zInput. */ const char *zBegin = shellState.wasm.zPos; const char *z = zBegin; char *zLine = 0; i64 nZ = 0; |
︙ | ︙ | |||
12111 12112 12113 12114 12115 12116 12117 | #endif }else if( cli_strcmp(z,"-readonly")==0 ){ data.openMode = SHELL_OPEN_READONLY; }else if( cli_strcmp(z,"-nofollow")==0 ){ data.openFlags |= SQLITE_OPEN_NOFOLLOW; }else if( cli_strcmp(z,"-ascii")==0 ){ data.mode = MODE_Ascii; | | | | | | 12128 12129 12130 12131 12132 12133 12134 12135 12136 12137 12138 12139 12140 12141 12142 12143 12144 12145 12146 12147 | #endif }else if( cli_strcmp(z,"-readonly")==0 ){ data.openMode = SHELL_OPEN_READONLY; }else if( cli_strcmp(z,"-nofollow")==0 ){ data.openFlags |= SQLITE_OPEN_NOFOLLOW; }else if( cli_strcmp(z,"-ascii")==0 ){ data.mode = MODE_Ascii; sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,SEP_Unit); sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,SEP_Record); }else if( cli_strcmp(z,"-tabs")==0 ){ data.mode = MODE_List; sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,SEP_Tab); sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,SEP_Row); }else if( cli_strcmp(z,"-separator")==0 ){ sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, "%s",cmdline_option_value(argc,argv,++i)); }else if( cli_strcmp(z,"-newline")==0 ){ sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, "%s",cmdline_option_value(argc,argv,++i)); }else if( cli_strcmp(z,"-nullvalue")==0 ){ |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
559 560 561 562 563 564 565 566 567 568 569 570 571 572 | #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) #define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) #define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT |(11<<8)) #define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT |(12<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) #define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) #define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */ /* ** CAPI3REF: Flags For File Open Operations | > | 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 | #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) #define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) #define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT |(11<<8)) #define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT |(12<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_NOTICE_RBU (SQLITE_NOTICE | (3<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) #define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) #define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */ /* ** CAPI3REF: Flags For File Open Operations |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
969 970 971 972 973 974 975 | ** all alignment restrictions correct. ** ** Except, if SQLITE_4_BYTE_ALIGNED_MALLOC is defined, then the ** underlying malloc() implementation might return us 4-byte aligned ** pointers. In that case, only verify 4-byte alignment. */ #ifdef SQLITE_4_BYTE_ALIGNED_MALLOC | | | | 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 | ** all alignment restrictions correct. ** ** Except, if SQLITE_4_BYTE_ALIGNED_MALLOC is defined, then the ** underlying malloc() implementation might return us 4-byte aligned ** pointers. In that case, only verify 4-byte alignment. */ #ifdef SQLITE_4_BYTE_ALIGNED_MALLOC # define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&3)==0) #else # define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0) #endif /* ** Disable MMAP on platforms where it is known to not work */ #if defined(__OpenBSD__) || defined(__QNXNTO__) # undef SQLITE_MAX_MMAP_SIZE |
︙ | ︙ | |||
1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 | #define SQLITE_BloomFilter 0x00080000 /* Use a Bloom filter on searches */ #define SQLITE_BloomPulldown 0x00100000 /* Run Bloom filters early */ #define SQLITE_BalancedMerge 0x00200000 /* Balance multi-way merges */ #define SQLITE_ReleaseReg 0x00400000 /* Use OP_ReleaseReg for testing */ #define SQLITE_FlttnUnionAll 0x00800000 /* Disable the UNION ALL flattener */ /* TH3 expects this value ^^^^^^^^^^ See flatten04.test */ #define SQLITE_IndexedExpr 0x01000000 /* Pull exprs from index when able */ #define SQLITE_AllOpts 0xffffffff /* All optimizations */ /* ** Macros for testing whether or not optimizations are enabled or disabled. */ #define OptimizationDisabled(db, mask) (((db)->dbOptFlags&(mask))!=0) #define OptimizationEnabled(db, mask) (((db)->dbOptFlags&(mask))==0) | > | 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 | #define SQLITE_BloomFilter 0x00080000 /* Use a Bloom filter on searches */ #define SQLITE_BloomPulldown 0x00100000 /* Run Bloom filters early */ #define SQLITE_BalancedMerge 0x00200000 /* Balance multi-way merges */ #define SQLITE_ReleaseReg 0x00400000 /* Use OP_ReleaseReg for testing */ #define SQLITE_FlttnUnionAll 0x00800000 /* Disable the UNION ALL flattener */ /* TH3 expects this value ^^^^^^^^^^ See flatten04.test */ #define SQLITE_IndexedExpr 0x01000000 /* Pull exprs from index when able */ #define SQLITE_Coroutines 0x02000000 /* Co-routines for subqueries */ #define SQLITE_AllOpts 0xffffffff /* All optimizations */ /* ** Macros for testing whether or not optimizations are enabled or disabled. */ #define OptimizationDisabled(db, mask) (((db)->dbOptFlags&(mask))!=0) #define OptimizationEnabled(db, mask) (((db)->dbOptFlags&(mask))==0) |
︙ | ︙ | |||
2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 | */ #define SQLITE_AFF_NONE 0x40 /* '@' */ #define SQLITE_AFF_BLOB 0x41 /* 'A' */ #define SQLITE_AFF_TEXT 0x42 /* 'B' */ #define SQLITE_AFF_NUMERIC 0x43 /* 'C' */ #define SQLITE_AFF_INTEGER 0x44 /* 'D' */ #define SQLITE_AFF_REAL 0x45 /* 'E' */ #define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC) /* ** The SQLITE_AFF_MASK values masks off the significant bits of an ** affinity value. */ | > | 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 | */ #define SQLITE_AFF_NONE 0x40 /* '@' */ #define SQLITE_AFF_BLOB 0x41 /* 'A' */ #define SQLITE_AFF_TEXT 0x42 /* 'B' */ #define SQLITE_AFF_NUMERIC 0x43 /* 'C' */ #define SQLITE_AFF_INTEGER 0x44 /* 'D' */ #define SQLITE_AFF_REAL 0x45 /* 'E' */ #define SQLITE_AFF_FLEXNUM 0x46 /* 'F' */ #define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC) /* ** The SQLITE_AFF_MASK values masks off the significant bits of an ** affinity value. */ |
︙ | ︙ | |||
2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 | Expr *pFExpr; /* Expression encoding the function */ FuncDef *pFunc; /* The aggregate function implementation */ int iDistinct; /* Ephemeral table used to enforce DISTINCT */ int iDistAddr; /* Address of OP_OpenEphemeral */ } *aFunc; int nFunc; /* Number of entries in aFunc[] */ u32 selId; /* Select to which this AggInfo belongs */ }; /* ** Macros to compute aCol[] and aFunc[] register numbers. ** ** These macros should not be used prior to the call to ** assignAggregateRegisters() that computes the value of pAggInfo->iFirstReg. | > > > | 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 | Expr *pFExpr; /* Expression encoding the function */ FuncDef *pFunc; /* The aggregate function implementation */ int iDistinct; /* Ephemeral table used to enforce DISTINCT */ int iDistAddr; /* Address of OP_OpenEphemeral */ } *aFunc; int nFunc; /* Number of entries in aFunc[] */ u32 selId; /* Select to which this AggInfo belongs */ #ifdef SQLITE_DEBUG Select *pSelect; /* SELECT statement that this AggInfo supports */ #endif }; /* ** Macros to compute aCol[] and aFunc[] register numbers. ** ** These macros should not be used prior to the call to ** assignAggregateRegisters() that computes the value of pAggInfo->iFirstReg. |
︙ | ︙ | |||
3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 | #define SF_View 0x0200000 /* SELECT statement is a view */ #define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */ #define SF_UFSrcCheck 0x0800000 /* Check pSrc as required by UPDATE...FROM */ #define SF_PushDown 0x1000000 /* SELECT has be modified by push-down opt */ #define SF_MultiPart 0x2000000 /* Has multiple incompatible PARTITIONs */ #define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */ #define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */ /* True if S exists and has SF_NestedFrom */ #define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0) /* ** The results of a SELECT can be distributed in several ways, as defined ** by one of the following macros. The "SRT" prefix means "SELECT Result | > | 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 | #define SF_View 0x0200000 /* SELECT statement is a view */ #define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */ #define SF_UFSrcCheck 0x0800000 /* Check pSrc as required by UPDATE...FROM */ #define SF_PushDown 0x1000000 /* SELECT has be modified by push-down opt */ #define SF_MultiPart 0x2000000 /* Has multiple incompatible PARTITIONs */ #define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */ #define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */ #define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */ /* True if S exists and has SF_NestedFrom */ #define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0) /* ** The results of a SELECT can be distributed in several ways, as defined ** by one of the following macros. The "SRT" prefix means "SELECT Result |
︙ | ︙ | |||
3569 3570 3571 3572 3573 3574 3575 | */ struct SelectDest { u8 eDest; /* How to dispose of the results. One of SRT_* above. */ int iSDParm; /* A parameter used by the eDest disposal method */ int iSDParm2; /* A second parameter for the eDest disposal method */ int iSdst; /* Base register where results are written */ int nSdst; /* Number of registers allocated */ | | | 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 | */ struct SelectDest { u8 eDest; /* How to dispose of the results. One of SRT_* above. */ int iSDParm; /* A parameter used by the eDest disposal method */ int iSDParm2; /* A second parameter for the eDest disposal method */ int iSdst; /* Base register where results are written */ int nSdst; /* Number of registers allocated */ char *zAffSdst; /* Affinity used for SRT_Set */ ExprList *pOrderBy; /* Key columns for SRT_Queue and SRT_DistQueue */ }; /* ** During code generation of statements that do inserts into AUTOINCREMENT ** tables, the following information is attached to the Table.u.autoInc.p ** pointer of each autoincrement table to record some side information that |
︙ | ︙ | |||
3628 3629 3630 3631 3632 3633 3634 | # define DbMaskZero(M) memset((M),0,sizeof(M)) # define DbMaskSet(M,I) (M)[(I)/8]|=(1<<((I)&7)) # define DbMaskAllZero(M) sqlite3DbMaskAllZero(M) # define DbMaskNonZero(M) (sqlite3DbMaskAllZero(M)==0) #else typedef unsigned int yDbMask; # define DbMaskTest(M,I) (((M)&(((yDbMask)1)<<(I)))!=0) | | | | | | 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 | # define DbMaskZero(M) memset((M),0,sizeof(M)) # define DbMaskSet(M,I) (M)[(I)/8]|=(1<<((I)&7)) # define DbMaskAllZero(M) sqlite3DbMaskAllZero(M) # define DbMaskNonZero(M) (sqlite3DbMaskAllZero(M)==0) #else typedef unsigned int yDbMask; # define DbMaskTest(M,I) (((M)&(((yDbMask)1)<<(I)))!=0) # define DbMaskZero(M) ((M)=0) # define DbMaskSet(M,I) ((M)|=(((yDbMask)1)<<(I))) # define DbMaskAllZero(M) ((M)==0) # define DbMaskNonZero(M) ((M)!=0) #endif /* ** For each index X that has as one of its arguments either an expression ** or the name of a virtual generated column, and if X is in scope such that ** the value of the expression can simply be read from the index, then ** there is an instance of this object on the Parse.pIdxExpr list. |
︙ | ︙ | |||
4674 4675 4676 4677 4678 4679 4680 | void sqlite3ColumnSetExpr(Parse*,Table*,Column*,Expr*); Expr *sqlite3ColumnExpr(Table*,Column*); void sqlite3ColumnSetColl(sqlite3*,Column*,const char*zColl); const char *sqlite3ColumnColl(Column*); void sqlite3DeleteColumnNames(sqlite3*,Table*); void sqlite3GenerateColumnNames(Parse *pParse, Select *pSelect); int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**); | | | 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 | void sqlite3ColumnSetExpr(Parse*,Table*,Column*,Expr*); Expr *sqlite3ColumnExpr(Table*,Column*); void sqlite3ColumnSetColl(sqlite3*,Column*,const char*zColl); const char *sqlite3ColumnColl(Column*); void sqlite3DeleteColumnNames(sqlite3*,Table*); void sqlite3GenerateColumnNames(Parse *pParse, Select *pSelect); int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**); void sqlite3SubqueryColumnTypes(Parse*,Table*,Select*,char); Table *sqlite3ResultSetOfSelect(Parse*,Select*,char); void sqlite3OpenSchemaTable(Parse *, int); Index *sqlite3PrimaryKeyIndex(Table*); i16 sqlite3TableColumnToIndex(Index*, i16); #ifdef SQLITE_OMIT_GENERATED_COLUMNS # define sqlite3TableColumnToStorage(T,X) (X) /* No-op pass-through */ # define sqlite3StorageColumnToTable(T,X) (X) /* No-op pass-through */ |
︙ | ︙ | |||
5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 | const char *sqlite3IndexAffinityStr(sqlite3*, Index*); char *sqlite3TableAffinityStr(sqlite3*,const Table*); void sqlite3TableAffinity(Vdbe*, Table*, int); char sqlite3CompareAffinity(const Expr *pExpr, char aff2); int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity); char sqlite3TableColumnAffinity(const Table*,int); char sqlite3ExprAffinity(const Expr *pExpr); int sqlite3Atoi64(const char*, i64*, int, u8); int sqlite3DecOrHexToI64(const char*, i64*); void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...); void sqlite3Error(sqlite3*,int); void sqlite3ErrorClear(sqlite3*); void sqlite3SystemError(sqlite3*,int); void *sqlite3HexToBlob(sqlite3*, const char *z, int n); | > | 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 | const char *sqlite3IndexAffinityStr(sqlite3*, Index*); char *sqlite3TableAffinityStr(sqlite3*,const Table*); void sqlite3TableAffinity(Vdbe*, Table*, int); char sqlite3CompareAffinity(const Expr *pExpr, char aff2); int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity); char sqlite3TableColumnAffinity(const Table*,int); char sqlite3ExprAffinity(const Expr *pExpr); int sqlite3ExprDataType(const Expr *pExpr); int sqlite3Atoi64(const char*, i64*, int, u8); int sqlite3DecOrHexToI64(const char*, i64*); void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...); void sqlite3Error(sqlite3*,int); void sqlite3ErrorClear(sqlite3*); void sqlite3SystemError(sqlite3*,int); void *sqlite3HexToBlob(sqlite3*, const char *z, int n); |
︙ | ︙ | |||
5203 5204 5205 5206 5207 5208 5209 | void sqlite3NoopDestructor(void*); void *sqlite3OomFault(sqlite3*); void sqlite3OomClear(sqlite3*); int sqlite3ApiExit(sqlite3 *db, int); int sqlite3OpenTempDatabase(Parse *); void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int); | | | 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 | void sqlite3NoopDestructor(void*); void *sqlite3OomFault(sqlite3*); void sqlite3OomClear(sqlite3*); int sqlite3ApiExit(sqlite3 *db, int); int sqlite3OpenTempDatabase(Parse *); void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int); int sqlite3StrAccumEnlarge(StrAccum*, i64); char *sqlite3StrAccumFinish(StrAccum*); void sqlite3StrAccumSetError(StrAccum*, u8); void sqlite3ResultStrAccum(sqlite3_context*,StrAccum*); void sqlite3SelectDestInit(SelectDest*,int,int); Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int); void sqlite3RecordErrorByteOffset(sqlite3*,const char*); void sqlite3RecordErrorOffsetOfExpr(sqlite3*,const Expr*); |
︙ | ︙ |
Changes to src/update.c.
︙ | ︙ | |||
259 260 261 262 263 264 265 | for(i=0; i<pChanges->nExpr; i++){ pList = sqlite3ExprListAppend(pParse, pList, sqlite3ExprDup(db, pChanges->a[i].pExpr, 0) ); } } pSelect = sqlite3SelectNew(pParse, pList, | | > | 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | for(i=0; i<pChanges->nExpr; i++){ pList = sqlite3ExprListAppend(pParse, pList, sqlite3ExprDup(db, pChanges->a[i].pExpr, 0) ); } } pSelect = sqlite3SelectNew(pParse, pList, pSrc, pWhere2, pGrp, 0, pOrderBy2, SF_UFSrcCheck|SF_IncludeHidden|SF_UpdateFrom, pLimit2 ); if( pSelect ) pSelect->selFlags |= SF_OrderByReqd; sqlite3SelectDestInit(&dest, eDest, iEph); dest.iSDParm2 = (pPk ? pPk->nKeyCol : -1); sqlite3Select(pParse, pSelect, &dest); sqlite3SelectDelete(db, pSelect); } |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
129 130 131 132 133 134 135 136 137 138 139 140 141 142 | ** test_addop_breakpoint(pc,pOp) ** sqlite3CorruptError(lineno) ** sqlite3MisuseError(lineno) ** sqlite3CantopenError(lineno) */ static void test_trace_breakpoint(int pc, Op *pOp, Vdbe *v){ static int n = 0; n++; } #endif /* ** Invoke the VDBE coverage callback, if that callback is defined. This ** feature is used for test suite validation only and does not appear an | > > > | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | ** test_addop_breakpoint(pc,pOp) ** sqlite3CorruptError(lineno) ** sqlite3MisuseError(lineno) ** sqlite3CantopenError(lineno) */ static void test_trace_breakpoint(int pc, Op *pOp, Vdbe *v){ static int n = 0; (void)pc; (void)pOp; (void)v; n++; } #endif /* ** Invoke the VDBE coverage callback, if that callback is defined. This ** feature is used for test suite validation only and does not appear an |
︙ | ︙ | |||
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 | ** SQLITE_AFF_NUMERIC: ** Try to convert pRec to an integer representation or a ** floating-point representation if an integer representation ** is not possible. Note that the integer representation is ** always preferred, even if the affinity is REAL, because ** an integer representation is more space efficient on disk. ** ** SQLITE_AFF_TEXT: ** Convert pRec to a text representation. ** ** SQLITE_AFF_BLOB: ** SQLITE_AFF_NONE: ** No-op. pRec is unchanged. */ static void applyAffinity( Mem *pRec, /* The value to apply affinity to */ char affinity, /* The affinity to be applied */ u8 enc /* Use this text encoding */ ){ if( affinity>=SQLITE_AFF_NUMERIC ){ assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL | > > > > | | | 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 | ** SQLITE_AFF_NUMERIC: ** Try to convert pRec to an integer representation or a ** floating-point representation if an integer representation ** is not possible. Note that the integer representation is ** always preferred, even if the affinity is REAL, because ** an integer representation is more space efficient on disk. ** ** SQLITE_AFF_FLEXNUM: ** If the value is text, then try to convert it into a number of ** some kind (integer or real) but do not make any other changes. ** ** SQLITE_AFF_TEXT: ** Convert pRec to a text representation. ** ** SQLITE_AFF_BLOB: ** SQLITE_AFF_NONE: ** No-op. pRec is unchanged. */ static void applyAffinity( Mem *pRec, /* The value to apply affinity to */ char affinity, /* The affinity to be applied */ u8 enc /* Use this text encoding */ ){ if( affinity>=SQLITE_AFF_NUMERIC ){ assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL || affinity==SQLITE_AFF_NUMERIC || affinity==SQLITE_AFF_FLEXNUM ); if( (pRec->flags & MEM_Int)==0 ){ /*OPTIMIZATION-IF-FALSE*/ if( (pRec->flags & MEM_Real)==0 ){ if( pRec->flags & MEM_Str ) applyNumericAffinity(pRec,1); }else if( affinity<=SQLITE_AFF_REAL ){ sqlite3VdbeIntegerAffinity(pRec); } } }else if( affinity==SQLITE_AFF_TEXT ){ /* Only attempt the conversion to TEXT if there is an integer or real ** representation (blob and NULL do not get converted) but no string ** representation. It would be harmless to repeat the conversion if |
︙ | ︙ | |||
705 706 707 708 709 710 711 712 713 714 715 716 717 718 | Vdbe *p /* The VDBE */ ){ Op *aOp = p->aOp; /* Copy of p->aOp */ Op *pOp = aOp; /* Current operation */ #ifdef SQLITE_DEBUG Op *pOrigOp; /* Value of pOp at the top of the loop */ int nExtraDelete = 0; /* Verifies FORDELETE and AUXDELETE flags */ #endif int rc = SQLITE_OK; /* Value to return */ sqlite3 *db = p->db; /* The database */ u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */ u8 encoding = ENC(db); /* The database encoding */ int iCompare = 0; /* Result of last comparison */ u64 nVmStep = 0; /* Number of virtual machine steps */ | > | 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 | Vdbe *p /* The VDBE */ ){ Op *aOp = p->aOp; /* Copy of p->aOp */ Op *pOp = aOp; /* Current operation */ #ifdef SQLITE_DEBUG Op *pOrigOp; /* Value of pOp at the top of the loop */ int nExtraDelete = 0; /* Verifies FORDELETE and AUXDELETE flags */ u8 iCompareIsInit = 0; /* iCompare is initialized */ #endif int rc = SQLITE_OK; /* Value to return */ sqlite3 *db = p->db; /* The database */ u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */ u8 encoding = ENC(db); /* The database encoding */ int iCompare = 0; /* Result of last comparison */ u64 nVmStep = 0; /* Number of virtual machine steps */ |
︙ | ︙ | |||
726 727 728 729 730 731 732 | Mem *pOut = 0; /* Output operand */ #if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE) u64 *pnCycle = 0; #endif /*** INSERT STACK UNION HERE ***/ assert( p->eVdbeState==VDBE_RUN_STATE ); /* sqlite3_step() verifies this */ | > | > < | 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 | Mem *pOut = 0; /* Output operand */ #if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE) u64 *pnCycle = 0; #endif /*** INSERT STACK UNION HERE ***/ assert( p->eVdbeState==VDBE_RUN_STATE ); /* sqlite3_step() verifies this */ if( DbMaskNonZero(p->lockMask) ){ sqlite3VdbeEnter(p); } #ifndef SQLITE_OMIT_PROGRESS_CALLBACK if( db->xProgress ){ u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP]; assert( 0 < db->nProgressOps ); nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps); }else{ nProgressLimit = LARGEST_UINT64; } #endif if( p->rc==SQLITE_NOMEM ){ /* This happens if a malloc() inside a call to sqlite3_column_text() or ** sqlite3_column_text16() failed. */ goto no_mem; } assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY ); testcase( p->rc!=SQLITE_OK ); p->rc = SQLITE_OK; assert( p->bIsReader || p->readOnly!=0 ); p->iCurrentTime = 0; assert( p->explain==0 ); db->busyHandler.nBusy = 0; if( AtomicLoad(&db->u1.isInterrupted) ) goto abort_due_to_interrupt; sqlite3VdbeIOTraceSql(p); #ifdef SQLITE_DEBUG sqlite3BeginBenignMalloc(); if( p->pc==0 && (p->db->flags & (SQLITE_VdbeListing|SQLITE_VdbeEQP|SQLITE_VdbeTrace))!=0 |
︙ | ︙ | |||
1578 1579 1580 1581 1582 1583 1584 | */ case OP_ResultRow: { assert( p->nResColumn==pOp->p2 ); assert( pOp->p1>0 || CORRUPT_DB ); assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 ); p->cacheCtr = (p->cacheCtr + 2)|1; | | | | 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 | */ case OP_ResultRow: { assert( p->nResColumn==pOp->p2 ); assert( pOp->p1>0 || CORRUPT_DB ); assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 ); p->cacheCtr = (p->cacheCtr + 2)|1; p->pResultRow = &aMem[pOp->p1]; #ifdef SQLITE_DEBUG { Mem *pMem = p->pResultRow; int i; for(i=0; i<pOp->p2; i++){ assert( memIsValid(&pMem[i]) ); REGISTER_TRACE(pOp->p1+i, &pMem[i]); /* The registers in the result will not be used again when the ** prepared statement restarts. This is because sqlite3_column() ** APIs might have caused type conversions of made other changes to |
︙ | ︙ | |||
2111 2112 2113 2114 2115 2116 2117 | u16 flags3; /* Copy of initial value of pIn3->flags */ pIn1 = &aMem[pOp->p1]; pIn3 = &aMem[pOp->p3]; flags1 = pIn1->flags; flags3 = pIn3->flags; if( (flags1 & flags3 & MEM_Int)!=0 ){ | < > > > | 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 | u16 flags3; /* Copy of initial value of pIn3->flags */ pIn1 = &aMem[pOp->p1]; pIn3 = &aMem[pOp->p3]; flags1 = pIn1->flags; flags3 = pIn3->flags; if( (flags1 & flags3 & MEM_Int)!=0 ){ /* Common case of comparison of two integers */ if( pIn3->u.i > pIn1->u.i ){ if( sqlite3aGTb[pOp->opcode] ){ VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3); goto jump_to_p2; } iCompare = +1; VVA_ONLY( iCompareIsInit = 1; ) }else if( pIn3->u.i < pIn1->u.i ){ if( sqlite3aLTb[pOp->opcode] ){ VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3); goto jump_to_p2; } iCompare = -1; VVA_ONLY( iCompareIsInit = 1; ) }else{ if( sqlite3aEQb[pOp->opcode] ){ VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3); goto jump_to_p2; } iCompare = 0; VVA_ONLY( iCompareIsInit = 1; ) } VdbeBranchTaken(0, (pOp->p5 & SQLITE_NULLEQ)?2:3); break; } if( (flags1 | flags3)&MEM_Null ){ /* One or both operands are NULL */ if( pOp->p5 & SQLITE_NULLEQ ){ |
︙ | ︙ | |||
2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 | ** The jump is taken if the SQLITE_JUMPIFNULL bit is set. */ VdbeBranchTaken(2,3); if( pOp->p5 & SQLITE_JUMPIFNULL ){ goto jump_to_p2; } iCompare = 1; /* Operands are not equal */ break; } }else{ /* Neither operand is NULL and we couldn't do the special high-speed ** integer comparison case. So do a general-case comparison. */ affinity = pOp->p5 & SQLITE_AFF_MASK; if( affinity>=SQLITE_AFF_NUMERIC ){ if( (flags1 | flags3)&MEM_Str ){ if( (flags1 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn1,0); testcase( flags3==pIn3->flags ); flags3 = pIn3->flags; } if( (flags3 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3,0); } } | > | | | 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 | ** The jump is taken if the SQLITE_JUMPIFNULL bit is set. */ VdbeBranchTaken(2,3); if( pOp->p5 & SQLITE_JUMPIFNULL ){ goto jump_to_p2; } iCompare = 1; /* Operands are not equal */ VVA_ONLY( iCompareIsInit = 1; ) break; } }else{ /* Neither operand is NULL and we couldn't do the special high-speed ** integer comparison case. So do a general-case comparison. */ affinity = pOp->p5 & SQLITE_AFF_MASK; if( affinity>=SQLITE_AFF_NUMERIC ){ if( (flags1 | flags3)&MEM_Str ){ if( (flags1 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn1,0); testcase( flags3==pIn3->flags ); flags3 = pIn3->flags; } if( (flags3 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3,0); } } }else if( affinity==SQLITE_AFF_TEXT && ((flags1 | flags3) & MEM_Str)!=0 ){ if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ testcase( pIn1->flags & MEM_Int ); testcase( pIn1->flags & MEM_Real ); testcase( pIn1->flags & MEM_IntReal ); sqlite3VdbeMemStringify(pIn1, encoding, 1); testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) ); flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask); if( NEVER(pIn1==pIn3) ) flags3 = flags1 | MEM_Str; } if( (flags3 & MEM_Str)==0 && (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ testcase( pIn3->flags & MEM_Int ); testcase( pIn3->flags & MEM_Real ); testcase( pIn3->flags & MEM_IntReal ); sqlite3VdbeMemStringify(pIn3, encoding, 1); testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn) ); |
︙ | ︙ | |||
2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 | res2 = sqlite3aLTb[pOp->opcode]; }else if( res==0 ){ res2 = sqlite3aEQb[pOp->opcode]; }else{ res2 = sqlite3aGTb[pOp->opcode]; } iCompare = res; /* Undo any changes made by applyAffinity() to the input registers. */ assert( (pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn) ); pIn3->flags = flags3; assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) ); pIn1->flags = flags1; | > | 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 | res2 = sqlite3aLTb[pOp->opcode]; }else if( res==0 ){ res2 = sqlite3aEQb[pOp->opcode]; }else{ res2 = sqlite3aGTb[pOp->opcode]; } iCompare = res; VVA_ONLY( iCompareIsInit = 1; ) /* Undo any changes made by applyAffinity() to the input registers. */ assert( (pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn) ); pIn3->flags = flags3; assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) ); pIn1->flags = flags1; |
︙ | ︙ | |||
2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 | int iAddr; for(iAddr = (int)(pOp - aOp) - 1; ALWAYS(iAddr>=0); iAddr--){ if( aOp[iAddr].opcode==OP_ReleaseReg ) continue; assert( aOp[iAddr].opcode==OP_Lt || aOp[iAddr].opcode==OP_Gt ); break; } #endif /* SQLITE_DEBUG */ VdbeBranchTaken(iCompare==0, 2); if( iCompare==0 ) goto jump_to_p2; break; } /* Opcode: Permutation * * * P4 * | > | 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 | int iAddr; for(iAddr = (int)(pOp - aOp) - 1; ALWAYS(iAddr>=0); iAddr--){ if( aOp[iAddr].opcode==OP_ReleaseReg ) continue; assert( aOp[iAddr].opcode==OP_Lt || aOp[iAddr].opcode==OP_Gt ); break; } #endif /* SQLITE_DEBUG */ assert( iCompareIsInit ); VdbeBranchTaken(iCompare==0, 2); if( iCompare==0 ) goto jump_to_p2; break; } /* Opcode: Permutation * * * P4 * |
︙ | ︙ | |||
2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 | assert( memIsValid(&aMem[p2+idx]) ); REGISTER_TRACE(p1+idx, &aMem[p1+idx]); REGISTER_TRACE(p2+idx, &aMem[p2+idx]); assert( i<pKeyInfo->nKeyField ); pColl = pKeyInfo->aColl[i]; bRev = (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_DESC); iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl); if( iCompare ){ if( (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_BIGNULL) && ((aMem[p1+idx].flags & MEM_Null) || (aMem[p2+idx].flags & MEM_Null)) ){ iCompare = -iCompare; } if( bRev ) iCompare = -iCompare; | > | 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 | assert( memIsValid(&aMem[p2+idx]) ); REGISTER_TRACE(p1+idx, &aMem[p1+idx]); REGISTER_TRACE(p2+idx, &aMem[p2+idx]); assert( i<pKeyInfo->nKeyField ); pColl = pKeyInfo->aColl[i]; bRev = (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_DESC); iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl); VVA_ONLY( iCompareIsInit = 1; ) if( iCompare ){ if( (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_BIGNULL) && ((aMem[p1+idx].flags & MEM_Null) || (aMem[p2+idx].flags & MEM_Null)) ){ iCompare = -iCompare; } if( bRev ) iCompare = -iCompare; |
︙ | ︙ | |||
2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 | ** in the most recent OP_Compare instruction the P1 vector was less than ** equal to, or greater than the P2 vector, respectively. ** ** This opcode must immediately follow an OP_Compare opcode. */ case OP_Jump: { /* jump */ assert( pOp>aOp && pOp[-1].opcode==OP_Compare ); if( iCompare<0 ){ VdbeBranchTaken(0,4); pOp = &aOp[pOp->p1 - 1]; }else if( iCompare==0 ){ VdbeBranchTaken(1,4); pOp = &aOp[pOp->p2 - 1]; }else{ VdbeBranchTaken(2,4); pOp = &aOp[pOp->p3 - 1]; } | > | 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 | ** in the most recent OP_Compare instruction the P1 vector was less than ** equal to, or greater than the P2 vector, respectively. ** ** This opcode must immediately follow an OP_Compare opcode. */ case OP_Jump: { /* jump */ assert( pOp>aOp && pOp[-1].opcode==OP_Compare ); assert( iCompareIsInit ); if( iCompare<0 ){ VdbeBranchTaken(0,4); pOp = &aOp[pOp->p1 - 1]; }else if( iCompare==0 ){ VdbeBranchTaken(1,4); pOp = &aOp[pOp->p2 - 1]; }else{ VdbeBranchTaken(2,4); pOp = &aOp[pOp->p3 - 1]; } |
︙ | ︙ | |||
5552 5553 5554 5555 5556 5557 5558 | /* Prevent post-update hook from running in cases when it should not */ pTab = 0; } } if( pOp->p5 & OPFLAG_ISNOOP ) break; #endif | > | > | > | 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 | /* Prevent post-update hook from running in cases when it should not */ pTab = 0; } } if( pOp->p5 & OPFLAG_ISNOOP ) break; #endif assert( (pOp->p5 & OPFLAG_LASTROWID)==0 || (pOp->p5 & OPFLAG_NCHANGE)!=0 ); if( pOp->p5 & OPFLAG_NCHANGE ){ p->nChange++; if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey; } assert( (pData->flags & (MEM_Blob|MEM_Str))!=0 || pData->n==0 ); x.pData = pData->z; x.nData = pData->n; seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0); if( pData->flags & MEM_Zero ){ x.nZero = pData->u.nZero; }else{ |
︙ | ︙ | |||
8820 8821 8822 8823 8824 8825 8826 | nProgressLimit = LARGEST_UINT64; rc = SQLITE_INTERRUPT; goto abort_due_to_error; } } #endif p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep; | > | > | 8839 8840 8841 8842 8843 8844 8845 8846 8847 8848 8849 8850 8851 8852 8853 8854 8855 | nProgressLimit = LARGEST_UINT64; rc = SQLITE_INTERRUPT; goto abort_due_to_error; } } #endif p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep; if( DbMaskNonZero(p->lockMask) ){ sqlite3VdbeLeave(p); } assert( rc!=SQLITE_OK || nExtraDelete==0 || sqlite3_strlike("DELETE%",p->zSql,0)!=0 ); return rc; /* Jump to here if a string or blob larger than SQLITE_MAX_LENGTH ** is encountered. |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
450 451 452 453 454 455 456 | /* When allocating a new Vdbe object, all of the fields below should be ** initialized to zero or NULL */ Op *aOp; /* Space to hold the virtual machine's program */ int nOp; /* Number of instructions in the program */ int nOpAlloc; /* Slots allocated for aOp[] */ Mem *aColName; /* Column names to return */ | | | 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 | /* When allocating a new Vdbe object, all of the fields below should be ** initialized to zero or NULL */ Op *aOp; /* Space to hold the virtual machine's program */ int nOp; /* Number of instructions in the program */ int nOpAlloc; /* Slots allocated for aOp[] */ Mem *aColName; /* Column names to return */ Mem *pResultRow; /* Current output row */ char *zErrMsg; /* Error message written here */ VList *pVList; /* Name of variables */ #ifndef SQLITE_OMIT_TRACE i64 startTime; /* Time when query started - used for profiling */ #endif #ifdef SQLITE_DEBUG int rcApp; /* errcode set by sqlite3_result_error_code() */ |
︙ | ︙ |
Changes to src/vdbeapi.c.
︙ | ︙ | |||
749 750 751 752 753 754 755 | db->errCode = SQLITE_ROW; return SQLITE_ROW; }else{ #ifndef SQLITE_OMIT_TRACE /* If the statement completed successfully, invoke the profile callback */ checkProfileCallback(db, p); #endif | | | 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 | db->errCode = SQLITE_ROW; return SQLITE_ROW; }else{ #ifndef SQLITE_OMIT_TRACE /* If the statement completed successfully, invoke the profile callback */ checkProfileCallback(db, p); #endif p->pResultRow = 0; if( rc==SQLITE_DONE && db->autoCommit ){ assert( p->rc==SQLITE_OK ); p->rc = doWalCallbacks(db); if( p->rc!=SQLITE_OK ){ rc = SQLITE_ERROR; } }else if( rc!=SQLITE_DONE && (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ){ |
︙ | ︙ | |||
1113 1114 1115 1116 1117 1118 1119 | /* ** Return the number of values available from the current row of the ** currently executing statement pStmt. */ int sqlite3_data_count(sqlite3_stmt *pStmt){ Vdbe *pVm = (Vdbe *)pStmt; | | | 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 | /* ** Return the number of values available from the current row of the ** currently executing statement pStmt. */ int sqlite3_data_count(sqlite3_stmt *pStmt){ Vdbe *pVm = (Vdbe *)pStmt; if( pVm==0 || pVm->pResultRow==0 ) return 0; return pVm->nResColumn; } /* ** Return a pointer to static memory containing an SQL NULL value. */ static const Mem *columnNullValue(void){ |
︙ | ︙ | |||
1168 1169 1170 1171 1172 1173 1174 | Vdbe *pVm; Mem *pOut; pVm = (Vdbe *)pStmt; if( pVm==0 ) return (Mem*)columnNullValue(); assert( pVm->db ); sqlite3_mutex_enter(pVm->db->mutex); | | | | 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 | Vdbe *pVm; Mem *pOut; pVm = (Vdbe *)pStmt; if( pVm==0 ) return (Mem*)columnNullValue(); assert( pVm->db ); sqlite3_mutex_enter(pVm->db->mutex); if( pVm->pResultRow!=0 && i<pVm->nResColumn && i>=0 ){ pOut = &pVm->pResultRow[i]; }else{ sqlite3Error(pVm->db, SQLITE_RANGE); pOut = (Mem*)columnNullValue(); } return pOut; } |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
208 209 210 211 212 213 214 215 216 217 218 219 220 221 | ** test_trace_breakpoint(pc,pOp) ** sqlite3CorruptError(lineno) ** sqlite3MisuseError(lineno) ** sqlite3CantopenError(lineno) */ static void test_addop_breakpoint(int pc, Op *pOp){ static int n = 0; n++; } #endif /* ** Add a new instruction to the list of instructions current in the ** VDBE. Return the address of the new instruction. | > > | 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | ** test_trace_breakpoint(pc,pOp) ** sqlite3CorruptError(lineno) ** sqlite3MisuseError(lineno) ** sqlite3CantopenError(lineno) */ static void test_addop_breakpoint(int pc, Op *pOp){ static int n = 0; (void)pc; (void)pOp; n++; } #endif /* ** Add a new instruction to the list of instructions current in the ** VDBE. Return the address of the new instruction. |
︙ | ︙ | |||
2312 2313 2314 2315 2316 2317 2318 | assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY || p->rc==SQLITE_NOMEM ); /* Even though this opcode does not use dynamic strings for ** the result, result columns may become dynamic if the user calls ** sqlite3_column_text16(), causing a translation to UTF-16 encoding. */ releaseMemArray(pMem, 8); | < | 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 | assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY || p->rc==SQLITE_NOMEM ); /* Even though this opcode does not use dynamic strings for ** the result, result columns may become dynamic if the user calls ** sqlite3_column_text16(), causing a translation to UTF-16 encoding. */ releaseMemArray(pMem, 8); if( p->rc==SQLITE_NOMEM ){ /* This happens if a malloc() inside a call to sqlite3_column_text() or ** sqlite3_column_text16() failed. */ sqlite3OomFault(db); return SQLITE_ERROR; } |
︙ | ︙ | |||
2369 2370 2371 2372 2373 2374 2375 | } #else sqlite3VdbeMemSetNull(pMem+7); #endif sqlite3VdbeMemSetStr(pMem+5, zP4, -1, SQLITE_UTF8, sqlite3_free); p->nResColumn = 8; } | | | 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 | } #else sqlite3VdbeMemSetNull(pMem+7); #endif sqlite3VdbeMemSetStr(pMem+5, zP4, -1, SQLITE_UTF8, sqlite3_free); p->nResColumn = 8; } p->pResultRow = pMem; if( db->mallocFailed ){ p->rc = SQLITE_NOMEM; rc = SQLITE_ERROR; }else{ p->rc = SQLITE_OK; rc = SQLITE_ROW; } |
︙ | ︙ | |||
3501 3502 3503 3504 3505 3506 3507 | for(i=0; i<p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined ); } #endif if( p->zErrMsg ){ sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = 0; } | | | 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 | for(i=0; i<p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined ); } #endif if( p->zErrMsg ){ sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = 0; } p->pResultRow = 0; #ifdef SQLITE_DEBUG p->nWrite = 0; #endif /* Save profiling information from this VDBE run. */ #ifdef VDBE_PROFILE |
︙ | ︙ |
Changes to src/vdbevtab.c.
︙ | ︙ | |||
79 80 81 82 83 84 85 86 87 88 89 90 91 92 | "name TEXT," "wr INT," "subprog TEXT," "stmt HIDDEN" ");" }; rc = sqlite3_declare_vtab(db, azSchema[isTabUsed]); if( rc==SQLITE_OK ){ pNew = sqlite3_malloc( sizeof(*pNew) ); *ppVtab = (sqlite3_vtab*)pNew; if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); pNew->db = db; | > > > | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | "name TEXT," "wr INT," "subprog TEXT," "stmt HIDDEN" ");" }; (void)argc; (void)argv; (void)pzErr; rc = sqlite3_declare_vtab(db, azSchema[isTabUsed]); if( rc==SQLITE_OK ){ pNew = sqlite3_malloc( sizeof(*pNew) ); *ppVtab = (sqlite3_vtab*)pNew; if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); pNew->db = db; |
︙ | ︙ | |||
314 315 316 317 318 319 320 321 322 323 324 325 326 327 | sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ bytecodevtab_cursor *pCur = (bytecodevtab_cursor *)pVtabCursor; bytecodevtab *pVTab = (bytecodevtab *)pVtabCursor->pVtab; int rc = SQLITE_OK; bytecodevtabCursorClear(pCur); pCur->iRowid = 0; pCur->iAddr = 0; pCur->showSubprograms = idxNum==0; assert( argc==1 ); if( sqlite3_value_type(argv[0])==SQLITE_TEXT ){ | > | 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 | sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ bytecodevtab_cursor *pCur = (bytecodevtab_cursor *)pVtabCursor; bytecodevtab *pVTab = (bytecodevtab *)pVtabCursor->pVtab; int rc = SQLITE_OK; (void)idxStr; bytecodevtabCursorClear(pCur); pCur->iRowid = 0; pCur->iAddr = 0; pCur->showSubprograms = idxNum==0; assert( argc==1 ); if( sqlite3_value_type(argv[0])==SQLITE_TEXT ){ |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
832 833 834 835 836 837 838 | int *pAddrExplain /* OUT: Address of OP_Explain */ ){ if( pParse->explain!=2 ){ Table *pTab = pIdx->pTable; const char *zSep = ""; char *zText = 0; int ii = 0; | > | | > > > > | | | | > | 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 | int *pAddrExplain /* OUT: Address of OP_Explain */ ){ if( pParse->explain!=2 ){ Table *pTab = pIdx->pTable; const char *zSep = ""; char *zText = 0; int ii = 0; sqlite3_str *pStr = sqlite3_str_new(pParse->db); sqlite3_str_appendf(pStr,"CREATE AUTOMATIC INDEX ON %s(", pTab->zName); assert( pIdx->nColumn>1 ); assert( pIdx->aiColumn[pIdx->nColumn-1]==XN_ROWID ); for(ii=0; ii<(pIdx->nColumn-1); ii++){ const char *zName = 0; int iCol = pIdx->aiColumn[ii]; zName = pTab->aCol[iCol].zCnName; sqlite3_str_appendf(pStr, "%s%s", zSep, zName); zSep = ", "; } zText = sqlite3_str_finish(pStr); if( zText==0 ){ sqlite3OomFault(pParse->db); }else{ *pAddrExplain = sqlite3VdbeExplain( pParse, 0, "%s)%s", zText, (bPartial ? " WHERE <expr>" : "") ); sqlite3_free(zText); } } } #else # define explainAutomaticIndex(a,b,c,d) #endif /* |
︙ | ︙ | |||
5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 | }else{ continue; } if( sqlite3ExprIsConstant(pExpr) ) continue; p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr)); if( p==0 ) break; p->pIENext = pParse->pIdxEpr; p->pExpr = sqlite3ExprDup(pParse->db, pExpr, 0); p->iDataCur = pTabItem->iCursor; p->iIdxCur = iIdxCur; p->iIdxCol = i; p->bMaybeNullRow = bMaybeNullRow; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS p->zIdxName = pIdx->zName; | > > > > > > | 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 | }else{ continue; } if( sqlite3ExprIsConstant(pExpr) ) continue; p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr)); if( p==0 ) break; p->pIENext = pParse->pIdxEpr; #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace & 0x200 ){ sqlite3DebugPrintf("New pParse->pIdxEpr term {%d,%d}\n", iIdxCur, i); if( sqlite3WhereTrace & 0x5000 ) sqlite3ShowExpr(pExpr); } #endif p->pExpr = sqlite3ExprDup(pParse->db, pExpr, 0); p->iDataCur = pTabItem->iCursor; p->iIdxCur = iIdxCur; p->iIdxCol = i; p->bMaybeNullRow = bMaybeNullRow; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS p->zIdxName = pIdx->zName; |
︙ | ︙ | |||
6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 | }else{ last = pWInfo->iEndWhere; } if( pIdx->bHasExpr ){ IndexedExpr *p = pParse->pIdxEpr; while( p ){ if( p->iIdxCur==pLevel->iIdxCur ){ p->iDataCur = -1; p->iIdxCur = -1; } p = p->pIENext; } } k = pLevel->addrBody + 1; | > > > > > > > | 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 | }else{ last = pWInfo->iEndWhere; } if( pIdx->bHasExpr ){ IndexedExpr *p = pParse->pIdxEpr; while( p ){ if( p->iIdxCur==pLevel->iIdxCur ){ #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace & 0x200 ){ sqlite3DebugPrintf("Disable pParse->pIdxEpr term {%d,%d}\n", p->iIdxCur, p->iIdxCol); if( sqlite3WhereTrace & 0x5000 ) sqlite3ShowExpr(p->pExpr); } #endif p->iDataCur = -1; p->iIdxCur = -1; } p = p->pIENext; } } k = pLevel->addrBody + 1; |
︙ | ︙ |
Changes to test/affinity3.test.
︙ | ︙ | |||
100 101 102 103 104 105 106 | INSERT INTO data VALUES('4','xyz'); CREATE VIEW idmap as SELECT * FROM map_integer UNION SELECT * FROM map_text; CREATE TABLE mzed AS SELECT * FROM idmap; } | | | | | | | | | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | INSERT INTO data VALUES('4','xyz'); CREATE VIEW idmap as SELECT * FROM map_integer UNION SELECT * FROM map_text; CREATE TABLE mzed AS SELECT * FROM idmap; } do_execsql_test affinity3-210 { PRAGMA automatic_index=ON; SELECT * FROM data JOIN idmap USING(id); } {4 xyz e} do_execsql_test affinity3-220 { SELECT * FROM data JOIN mzed USING(id); } {4 xyz e} do_execsql_test affinity3-250 { PRAGMA automatic_index=OFF; SELECT * FROM data JOIN idmap USING(id); } {4 xyz e} do_execsql_test affinity3-260 { SELECT * FROM data JOIN mzed USING(id); } {4 xyz e} finish_test |
Changes to test/cast.test.
︙ | ︙ | |||
477 478 479 480 481 482 483 | reset_db do_execsql_test cast-9.0 { CREATE TABLE t0(c0); INSERT INTO t0(c0) VALUES (0); CREATE VIEW v1(c0, c1) AS SELECT CAST(0.0 AS NUMERIC), COUNT(*) OVER () FROM t0; SELECT v1.c0 FROM v1, t0 WHERE v1.c0=0; | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 | reset_db do_execsql_test cast-9.0 { CREATE TABLE t0(c0); INSERT INTO t0(c0) VALUES (0); CREATE VIEW v1(c0, c1) AS SELECT CAST(0.0 AS NUMERIC), COUNT(*) OVER () FROM t0; SELECT v1.c0 FROM v1, t0 WHERE v1.c0=0; } {0.0} # Set the 2022-12-10 "reopen" of ticket [https://sqlite.org/src/tktview/57c47526c3] # do_execsql_test cast-9.1 { CREATE TABLE dual(dummy TEXT); INSERT INTO dual VALUES('X'); SELECT CAST(4 AS NUMERIC); } {4} do_execsql_test cast-9.2 { SELECT CAST(4.0 AS NUMERIC); } {4.0} do_execsql_test cast-9.3 { SELECT CAST(4.5 AS NUMERIC); } {4.5} do_execsql_test cast-9.4 { SELECT x, typeof(x) FROM (SELECT CAST(4 AS NUMERIC) AS x) JOIN dual; } {4 integer} do_execsql_test cast-9.5 { SELECT x, typeof(x) FROM dual CROSS JOIN (SELECT CAST(4 AS NUMERIC) AS x); } {4 integer} do_execsql_test cast-9.10 { SELECT x, typeof(x) FROM (SELECT CAST(4.0 AS NUMERIC) AS x) JOIN dual; } {4.0 real} do_execsql_test cast-9.11 { SELECT x, typeof(x) FROM dual CROSS JOIN (SELECT CAST(4.0 AS NUMERIC) AS x); } {4.0 real} do_execsql_test cast-9.12 { SELECT x, typeof(x) FROM (SELECT CAST(4.5 AS NUMERIC) AS x) JOIN dual; } {4.5 real} do_execsql_test cast-9.13 { SELECT x, typeof(x) FROM dual CROSS JOIN (SELECT CAST(4.5 AS NUMERIC) AS x); } {4.5 real} # 2022-12-15 dbsqlfuzz c9ee6f9a0a8b8fefb02cf69de2a8b67ca39525c8 # # Added a new SQLITE_AFF_FLEXNUM that does not try to convert int to real or # real to int. # do_execsql_test cast-10.1 { VALUES(CAST(44 AS REAL)),(55); } {44.0 55} do_execsql_test cast-10.2 { SELECT CAST(44 AS REAL) AS 'm' UNION ALL SELECT 55; } {44.0 55} do_execsql_test cast-10.3 { SELECT * FROM (VALUES(CAST(44 AS REAL)),(55)); } {44.0 55} do_execsql_test cast-10.4 { SELECT * FROM (SELECT CAST(44 AS REAL) AS 'm' UNION ALL SELECT 55); } {44.0 55} do_execsql_test cast-10.5 { SELECT * FROM dual CROSS JOIN (VALUES(CAST(44 AS REAL)),(55)); } {X 44.0 X 55} do_execsql_test cast-10.6 { SELECT * FROM dual CROSS JOIN (SELECT CAST(44 AS REAL) AS 'm' UNION ALL SELECT 55); } {X 44.0 X 55} do_execsql_test cast-10.7 { DROP VIEW v1; CREATE VIEW v1 AS SELECT CAST(44 AS REAL) AS 'm' UNION ALL SELECT 55; SELECT name, type FROM pragma_table_info('v1'); } {m NUM} do_execsql_test cast-10.8 { CREATE VIEW v2 AS VALUES(CAST(44 AS REAL)),(55); SELECT type FROM pragma_table_info('v2'); } {NUM} do_execsql_test cast-10.9 { SELECT * FROM v1; } {44.0 55} do_execsql_test cast-10.10 { SELECT * FROM v2; } {44.0 55} finish_test |
Changes to test/eqp.test.
︙ | ︙ | |||
90 91 92 93 94 95 96 | `--USE TEMP B-TREE FOR DISTINCT } do_eqp_test 1.7.1 { SELECT * FROM t3 JOIN (SELECT 1) } { QUERY PLAN | | | | | | | | | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | `--USE TEMP B-TREE FOR DISTINCT } do_eqp_test 1.7.1 { SELECT * FROM t3 JOIN (SELECT 1) } { QUERY PLAN |--CO-ROUTINE (subquery-xxxxxx) | `--SCAN CONSTANT ROW |--SCAN (subquery-xxxxxx) `--SCAN t3 } do_eqp_test 1.7.2 { SELECT * FROM t3 JOIN (SELECT 1) AS v1 } { QUERY PLAN |--CO-ROUTINE v1 | `--SCAN CONSTANT ROW |--SCAN v1 `--SCAN t3 } do_eqp_test 1.7.3 { SELECT * FROM t3 AS xx JOIN (SELECT 1) AS yy } { QUERY PLAN |--CO-ROUTINE yy | `--SCAN CONSTANT ROW |--SCAN yy `--SCAN xx } do_eqp_test 1.8 { SELECT * FROM t3 JOIN (SELECT 1 UNION SELECT 2) } { QUERY PLAN |--CO-ROUTINE (subquery-xxxxxx) | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SCAN CONSTANT ROW | `--UNION USING TEMP B-TREE | `--SCAN CONSTANT ROW |--SCAN (subquery-xxxxxx) `--SCAN t3 } do_eqp_test 1.9 { SELECT * FROM t3 JOIN (SELECT 1 EXCEPT SELECT a FROM t3 LIMIT 17) AS abc } { QUERY PLAN |--CO-ROUTINE abc | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SCAN CONSTANT ROW | `--EXCEPT USING TEMP B-TREE | `--SCAN t3 |--SCAN abc `--SCAN t3 } do_eqp_test 1.10 { SELECT * FROM t3 JOIN (SELECT 1 INTERSECT SELECT a FROM t3 LIMIT 17) AS abc } { QUERY PLAN |--CO-ROUTINE abc | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SCAN CONSTANT ROW | `--INTERSECT USING TEMP B-TREE | `--SCAN t3 |--SCAN abc `--SCAN t3 } do_eqp_test 1.11 { SELECT * FROM t3 JOIN (SELECT 1 UNION ALL SELECT a FROM t3 LIMIT 17) abc } { QUERY PLAN |--CO-ROUTINE abc | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SCAN CONSTANT ROW | `--UNION ALL | `--SCAN t3 |--SCAN abc `--SCAN t3 |
︙ | ︙ | |||
291 292 293 294 295 296 297 | det 3.2.2 { SELECT * FROM (SELECT * FROM t1 ORDER BY x LIMIT 10) AS x1, (SELECT * FROM t2 ORDER BY x LIMIT 10) AS x2 ORDER BY x2.y LIMIT 5 } { QUERY PLAN | | | 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 | det 3.2.2 { SELECT * FROM (SELECT * FROM t1 ORDER BY x LIMIT 10) AS x1, (SELECT * FROM t2 ORDER BY x LIMIT 10) AS x2 ORDER BY x2.y LIMIT 5 } { QUERY PLAN |--CO-ROUTINE x1 | |--SCAN t1 | `--USE TEMP B-TREE FOR ORDER BY |--MATERIALIZE x2 | `--SCAN t2 USING INDEX t2i1 |--SCAN x1 |--SCAN x2 `--USE TEMP B-TREE FOR ORDER BY |
︙ | ︙ | |||
830 831 832 833 834 835 836 | substr(event.comment,instr(event.comment,':')+1) FROM thread, blob, event WHERE blob.rid=thread.last AND event.objid=thread.last ORDER BY 1; } { QUERY PLAN | | | 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 | substr(event.comment,instr(event.comment,':')+1) FROM thread, blob, event WHERE blob.rid=thread.last AND event.objid=thread.last ORDER BY 1; } { QUERY PLAN |--CO-ROUTINE thread | |--SCAN x USING INDEX forumthread | |--USING ROWID SEARCH ON TABLE private FOR IN-OPERATOR | |--CORRELATED SCALAR SUBQUERY xxxxxx | | |--SEARCH forumpost USING COVERING INDEX forumthread (froot=?) | | `--USING ROWID SEARCH ON TABLE private FOR IN-OPERATOR | `--USE TEMP B-TREE FOR ORDER BY |--SCAN thread |--SEARCH blob USING INTEGER PRIMARY KEY (rowid=?) |--SEARCH event USING INTEGER PRIMARY KEY (rowid=?) `--USE TEMP B-TREE FOR ORDER BY } finish_test |
Changes to test/fuzzdata8.db.
cannot compute difference between binary files
Changes to test/fuzzinvariants.c.
︙ | ︙ | |||
132 133 134 135 136 137 138 | *pbCorrupt = 1; sqlite3_finalize(pCk); sqlite3_finalize(pTestStmt); return SQLITE_CORRUPT; } sqlite3_finalize(pCk); | | | < < | < < > | < < | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | *pbCorrupt = 1; sqlite3_finalize(pCk); sqlite3_finalize(pTestStmt); return SQLITE_CORRUPT; } sqlite3_finalize(pCk); if( sqlite3_strlike("%group%by%",sqlite3_sql(pStmt),0)==0 ){ /* ** If there is a GROUP BY clause, it might not cover every term in the ** output. And then non-covered terms can take on a value from any ** row in the result set. This can cause differing answers. */ goto not_a_fault; } if( sqlite3_strlike("%limit%)%order%by%", sqlite3_sql(pTestStmt),0)==0 ){ /* crash-89bd6a6f8c6166e9a4c5f47b3e70b225f69b76c6 ** Original statement is: |
︙ | ︙ | |||
232 233 234 235 236 237 238 | ** ORDER BY N ** */ static char *fuzz_invariant_sql(sqlite3_stmt *pStmt, int iCnt){ const char *zIn; size_t nIn; const char *zAnd = "WHERE"; | | | 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | ** ORDER BY N ** */ static char *fuzz_invariant_sql(sqlite3_stmt *pStmt, int iCnt){ const char *zIn; size_t nIn; const char *zAnd = "WHERE"; int i, j; sqlite3_str *pTest; sqlite3_stmt *pBase = 0; sqlite3 *db = sqlite3_db_handle(pStmt); int rc; int nCol = sqlite3_column_count(pStmt); int mxCnt; int bDistinct = 0; |
︙ | ︙ | |||
276 277 278 279 280 281 282 283 284 285 286 287 288 289 | if( zSuffix && isdigit(zSuffix[1]) && (zSuffix[1]>'3' || isdigit(zSuffix[2])) ){ /* This is a randomized column name and so cannot be used in the ** WHERE clause. */ continue; } if( iCnt==0 ) continue; if( iCnt>1 && i+2!=iCnt ) continue; if( zColName==0 ) continue; if( sqlite3_column_type(pStmt, i)==SQLITE_NULL ){ sqlite3_str_appendf(pTest, " %s \"%w\" ISNULL", zAnd, zColName); }else{ | > > > > > > > > | 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 | if( zSuffix && isdigit(zSuffix[1]) && (zSuffix[1]>'3' || isdigit(zSuffix[2])) ){ /* This is a randomized column name and so cannot be used in the ** WHERE clause. */ continue; } for(j=0; j<i; j++){ const char *zPrior = sqlite3_column_name(pBase, j); if( sqlite3_stricmp(zPrior, zColName)==0 ) break; } if( j<i ){ /* Duplicate column name */ continue; } if( iCnt==0 ) continue; if( iCnt>1 && i+2!=iCnt ) continue; if( zColName==0 ) continue; if( sqlite3_column_type(pStmt, i)==SQLITE_NULL ){ sqlite3_str_appendf(pTest, " %s \"%w\" ISNULL", zAnd, zColName); }else{ |
︙ | ︙ |
Changes to test/memdb2.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 | #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is the "memdb" VFS # set testdir [file dirname $argv0] source $testdir/tester.tcl | | > | | > > > > > | | | | | | | | | | | | | < | > | | | | | | | | | | | | | | | | > > > > > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is the "memdb" VFS # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix memdb2 do_not_use_codec ifcapable !deserialize { finish_test return } db close #------------------------------------------------------------------------- # Test that when using a memdb database, it is not possible to upgrade # to an EXCLUSIVE lock if some other client is holding SHARED. # foreach {tn fname} { 1 file:/test.db?vfs=memdb 2 file:\\test.db?vfs=memdb } { if {$tn==2} breakpoint sqlite3 db $fname -uri 1 sqlite3 db2 $fname -uri 1 do_execsql_test 1.$tn.1 { CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(1, 2); } do_execsql_test -db db2 1.$tn.2 { BEGIN; SELECT * FROM t1; } {1 2} do_execsql_test 1.$tn.3 { BEGIN; INSERT INTO t1 VALUES(3, 4); } do_catchsql_test 1.$tn.4 { COMMIT } {1 {database is locked}} do_execsql_test -db db2 1.$tn.5 { SELECT * FROM t1; END; } {1 2} do_execsql_test 1.$tn.6 { COMMIT } {} do_execsql_test -db db2 1.$tn.7 { SELECT * FROM t1 } {1 2 3 4} db close db2 close } finish_test |
Changes to test/misc1.test.
︙ | ︙ | |||
601 602 603 604 605 606 607 | SELECT * FROM t19; } {1 2 3} do_execsql_test misc1-19.2 { CREATE TABLE t19b AS SELECT 4 AS '', 5 AS '', 6 AS ''; SELECT * FROM t19b; } {4 5 6} | | > > > | | | | 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 | SELECT * FROM t19; } {1 2 3} do_execsql_test misc1-19.2 { CREATE TABLE t19b AS SELECT 4 AS '', 5 AS '', 6 AS ''; SELECT * FROM t19b; } {4 5 6} # 2015-05-20: CREATE TABLE AS should not store INT value in a TEXT # column. # # 2022-12-14: Change: The column is not TEXT if the AS SELECT is # a compound with different types on each arm. # do_execsql_test misc1-19.3 { CREATE TABLE t19c(x TEXT); CREATE TABLE t19d AS SELECT * FROM t19c UNION ALL SELECT 1234; SELECT x, typeof(x) FROM t19d; } {1234 integer} # 2014-05-16: Tests for the SQLITE_TESTCTRL_FAULT_INSTALL feature. # unset -nocomplain fault_callbacks set fault_callbacks {} proc fault_callback {n} { lappend ::fault_callbacks $n return 0 } do_test misc1-19.11 { sqlite3_test_control_fault_install fault_callback set fault_callbacks } {0} do_test misc1-19.12 { sqlite3_test_control_fault_install set fault_callbacks } {0} # 2015-01-26: Valgrind-detected over-read. # Reported on sqlite-users@sqlite.org by Michal Zalewski. Found by afl-fuzz # presumably. |
︙ | ︙ |
Changes to test/pushdown.test.
︙ | ︙ | |||
91 92 93 94 95 96 97 | # arm of the compound has an incompatible affinity. # reset_db do_execsql_test 3.1 { CREATE TABLE t0(c0 INT); INSERT INTO t0 VALUES(0); CREATE TABLE t1_a(a INTEGER PRIMARY KEY, b TEXT); | | | | | | | > > > > > > > > > > | | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | # arm of the compound has an incompatible affinity. # reset_db do_execsql_test 3.1 { CREATE TABLE t0(c0 INT); INSERT INTO t0 VALUES(0); CREATE TABLE t1_a(a INTEGER PRIMARY KEY, b TEXT); INSERT INTO t1_a VALUES(1,'one'); CREATE TABLE t1_b(c INTEGER PRIMARY KEY, d TEXT); INSERT INTO t1_b VALUES(2,'two'); CREATE VIEW v0 AS SELECT CAST(t0.c0 AS INTEGER) AS c0 FROM t0; CREATE VIEW v1(a,b) AS SELECT a, b FROM t1_a UNION ALL SELECT c, 0 FROM t1_b; SELECT v1.a, quote(v1.b), t0.c0 AS cd FROM t0 LEFT JOIN v0 ON v0.c0!=0,v1; } { 1 'one' 0 2 0 0 } do_execsql_test 3.2 { SELECT a, quote(b), cd FROM ( SELECT v1.a, v1.b, t0.c0 AS cd FROM t0 LEFT JOIN v0 ON v0.c0!=0, v1 ) WHERE a=2 AND b='0' AND cd=0; } {} do_execsql_test 3.3 { SELECT a, quote(b), cd FROM ( SELECT v1.a, v1.b, t0.c0 AS cd FROM t0 LEFT JOIN v0 ON v0.c0!=0, v1 ) WHERE a=1 AND b='one' AND cd=0; } {1 'one' 0} do_execsql_test 3.4 { SELECT a, quote(b), cd FROM ( SELECT v1.a, v1.b, t0.c0 AS cd FROM t0 LEFT JOIN v0 ON v0.c0!=0, v1 ) WHERE a=2 AND b=0 AND cd=0; } { 2 0 0 } finish_test |
Changes to test/scanstatus2.test.
︙ | ︙ | |||
218 219 220 221 222 223 224 | do_graph_test 4.5 { SELECT v1.cnt FROM rt1, ( SELECT count(*) AS cnt, rt2.x1 AS x1 FROM rt2 GROUP BY x1 ) AS v1 WHERE rt1.x1=v1.x1 } { QUERY (nCycle=nnn) | | | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | do_graph_test 4.5 { SELECT v1.cnt FROM rt1, ( SELECT count(*) AS cnt, rt2.x1 AS x1 FROM rt2 GROUP BY x1 ) AS v1 WHERE rt1.x1=v1.x1 } { QUERY (nCycle=nnn) --CO-ROUTINE v1 ----SCAN rt2 (nCycle=nnn) ----USE TEMP B-TREE FOR GROUP BY --SCAN rt1 (nCycle=nnn) --CREATE AUTOMATIC INDEX ON v1(x1, cnt) (nCycle=nnn) --SEARCH v1 USING AUTOMATIC COVERING INDEX (x1=?) (nCycle=nnn) } |
︙ | ︙ |
Changes to test/sessionfuzz.c.
︙ | ︙ | |||
695 696 697 698 699 700 701 | " sessionfuzz run SQLAR ... -- Run against all files in the SQL Archive\n" ; #include <stdio.h> #include <string.h> #include <assert.h> #ifndef OMIT_ZLIB | | | 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 | " sessionfuzz run SQLAR ... -- Run against all files in the SQL Archive\n" ; #include <stdio.h> #include <string.h> #include <assert.h> #ifndef OMIT_ZLIB #include <zlib.h> #endif /* ** Implementation of the "sqlar_uncompress(X,SZ)" SQL function ** ** Parameter SZ is interpreted as an integer. If it is less than or ** equal to zero, then this function returns a copy of X. Or, if |
︙ | ︙ |
Changes to test/shell1.test.
︙ | ︙ | |||
1252 1253 1254 1255 1256 1257 1258 1259 1260 | .mode csv --x select 2,1; select 3,4; } } {0 {1,2 2,1 3,4}} finish_test | > > > > > > > > > > > > | 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 | .mode csv --x select 2,1; select 3,4; } } {0 {1,2 2,1 3,4}} #---------------------------------------------------------------------------- # Test cases shell1-10.*: Test that certain static extensions are there. # do_test shell1-10.1 { catchcmd :memory: { .mode list .header off select base64(base64(cast('digity-doo' as blob))), base85(base85(cast('digity-doo' as blob))); } } {0 digity-doo|digity-doo} finish_test |
Changes to test/tkt-99378177930f87bd.test.
︙ | ︙ | |||
144 145 146 147 148 149 150 | SUM(c) AS t3, SUM(CASE WHEN b->>'x'=1 THEN c END) AS t4 FROM t1 WHERE d BETWEEN 0 and 10 GROUP BY a; } {~/Function/} | > | > > > > > > > > > > | > > > > > > > > > > > > > > | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | SUM(c) AS t3, SUM(CASE WHEN b->>'x'=1 THEN c END) AS t4 FROM t1 WHERE d BETWEEN 0 and 10 GROUP BY a; } {~/Function/} # 2022-12-20 dbsqlfuzz a644e70d7683a7ca59c71861a153c1dccf8850b9 # do_execsql_test tkt-99378-300 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a INT); CREATE INDEX i1 ON t1(a,a=a); INSERT INTO t1 VALUES(1),(2),(3),(4); SELECT * FROM t1 NATURAL JOIN t1 WHERE a==1 OR ( (SELECT avg( (SELECT sum((SELECT 1 FROM t1 NATURAL RIGHT JOIN t1 WHERE a=a)))) AS xyz ) AND a==2 ); } {1 2} do_execsql_test tkt-99378-310 { DROP INDEX i1; SELECT * FROM t1 NATURAL JOIN t1 WHERE a==1 OR ( (SELECT avg( (SELECT sum((SELECT 1 FROM t1 NATURAL RIGHT JOIN t1 WHERE a=a)))) AS xyz ) AND a==2 ); } {1 2} finish_test |
Changes to test/unionall.test.
︙ | ︙ | |||
404 405 406 407 408 409 410 | INSERT INTO t1_c VALUES(3,'three'); INSERT INTO t1_c VALUES(6,'six'); CREATE VIEW v0(c0) AS SELECT CAST(t0.c0 AS INTEGER) FROM t0; CREATE VIEW t1 AS SELECT a, b FROM t1_a UNION ALL SELECT c, c FROM t1_b UNION ALL SELECT e, f FROM t1_c; | > > | | | | | | | | 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 | INSERT INTO t1_c VALUES(3,'three'); INSERT INTO t1_c VALUES(6,'six'); CREATE VIEW v0(c0) AS SELECT CAST(t0.c0 AS INTEGER) FROM t0; CREATE VIEW t1 AS SELECT a, b FROM t1_a UNION ALL SELECT c, c FROM t1_b UNION ALL SELECT e, f FROM t1_c; SELECT t1.a, t1.b, t0.c0 AS c, v0.c0 AS d FROM t0 LEFT JOIN v0 ON v0.c0>'0',t1; } {1 one 0 {} 4 four 0 {} 2 2 0 {} 5 5 0 {} 3 three 0 {} 6 six 0 {}} optimization_control db all 1 do_execsql_test 8.2 { SELECT * FROM (SELECT t1.a, t1.b, t0.c0 AS c, v0.c0 AS d FROM t0 LEFT JOIN v0 ON v0.c0>'0',t1) WHERE b=2; } {2 2 0 {}} do_execsql_test 8.3 { SELECT * FROM (SELECT t1.a, t1.b, t0.c0 AS c, v0.c0 AS d FROM t0 LEFT JOIN v0 ON v0.c0>'0',t1) WHERE b=2.0; } {2 2 0 {}} do_execsql_test 8.4 { SELECT * FROM (SELECT t1.a, t1.b, t0.c0 AS c, v0.c0 AS d FROM t0 LEFT JOIN v0 ON v0.c0>'0',t1) WHERE b='2'; } {} optimization_control db query-flattener,push-down 0 do_execsql_test 8.5 { SELECT * FROM (SELECT t1.a, t1.b, t0.c0 AS c, v0.c0 AS d FROM t0 LEFT JOIN v0 ON v0.c0>'0',t1) WHERE b=2; } {2 2 0 {}} do_execsql_test 8.6 { SELECT * FROM (SELECT t1.a, t1.b, t0.c0 AS c, v0.c0 AS d FROM t0 LEFT JOIN v0 ON v0.c0>'0',t1) WHERE b=2.0; } {2 2 0 {}} do_execsql_test 8.7 { SELECT * FROM (SELECT t1.a, t1.b, t0.c0 AS c, v0.c0 AS d FROM t0 LEFT JOIN v0 ON v0.c0>'0',t1) WHERE b='2'; } {} optimization_control db all 0 do_execsql_test 8.8 { SELECT * FROM (SELECT t1.a, t1.b, t0.c0 AS c, v0.c0 AS d FROM t0 LEFT JOIN v0 ON v0.c0>'0',t1) WHERE b=2; } {2 2 0 {}} do_execsql_test 8.9 { SELECT * FROM (SELECT t1.a, t1.b, t0.c0 AS c, v0.c0 AS d FROM t0 LEFT JOIN v0 ON v0.c0>'0',t1) WHERE b=2.0; } {2 2 0 {}} do_execsql_test 8.10 { SELECT * FROM (SELECT t1.a, t1.b, t0.c0 AS c, v0.c0 AS d FROM t0 LEFT JOIN v0 ON v0.c0>'0',t1) WHERE b='2'; } {} finish_test |
Changes to test/view.test.
︙ | ︙ | |||
119 120 121 122 123 124 125 | CREATE VIEW v9a AS SELECT x FROM t9; CREATE VIEW v9b AS SELECT * FROM t9; CREATE VIEW v9c(x) AS SELECT x FROM t9; CREATE VIEW v9d(x) AS SELECT * FROM t9; } {} do_execsql_test view-1.11 { PRAGMA table_info(v9a); | | | | | | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | CREATE VIEW v9a AS SELECT x FROM t9; CREATE VIEW v9b AS SELECT * FROM t9; CREATE VIEW v9c(x) AS SELECT x FROM t9; CREATE VIEW v9d(x) AS SELECT * FROM t9; } {} do_execsql_test view-1.11 { PRAGMA table_info(v9a); } {0 x INT 0 {} 0} do_execsql_test view-1.12 { PRAGMA table_info(v9b); } {0 x INT 0 {} 0} do_execsql_test view-1.13 { PRAGMA table_info(v9c); } {0 x INT 0 {} 0} do_execsql_test view-1.14 { PRAGMA table_info(v9d); } {0 x INT 0 {} 0} do_test view-2.1 { execsql { CREATE VIEW v2 AS SELECT * FROM t1 WHERE a>5 }; # No semicolon execsql2 { SELECT * FROM v2; |
︙ | ︙ | |||
771 772 773 774 775 776 777 | CREATE VIEW IF NOT EXISTS IF AS SELECT null; } {1 {malformed database schema (IF) - near "AS": syntax error}} do_catchsql_test view-29.1 { CREATE TABLE t2(c,d,e); SELECT name FROM sqlite_schema ORDER BY name; } {0 {t1 t2}} | > > | > > > > > > > > > > > > > > > > > > > > > > > | 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 | CREATE VIEW IF NOT EXISTS IF AS SELECT null; } {1 {malformed database schema (IF) - near "AS": syntax error}} do_catchsql_test view-29.1 { CREATE TABLE t2(c,d,e); SELECT name FROM sqlite_schema ORDER BY name; } {0 {t1 t2}} #------------------------------------------------------------------------- # 2022-12-11. https://sqlite.org/src/info/679ed6a2 # # 2022-12-14 change: If the AS SELECT of a VIEW is a compound where # the datatypes on each arm of the compound are different, then the # datatype of the overall column is BLOB (ANY). # reset_db do_execsql_test view-30.0 { CREATE TABLE t0(a INT, b TEXT); INSERT INTO t0 VALUES(1,'one'); CREATE VIEW t1 AS SELECT a, b FROM t0 UNION ALL SELECT 2, 2; CREATE VIEW t2(a,b) AS SELECT a, b FROM t0 UNION ALL SELECT 2, 2; } ifcapable schema_pragmas { do_execsql_test view-30.1 { PRAGMA table_info = t1; } { 0 a INT 0 {} 0 1 b BLOB 0 {} 0 } do_execsql_test view-30.2 { PRAGMA table_info = t2; } { 0 a INT 0 {} 0 1 b BLOB 0 {} 0 } } finish_test |
Changes to test/with3.test.
︙ | ︙ | |||
85 86 87 88 89 90 91 | } do_eqp_test 3.1.2 { WITH cnt(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM cnt LIMIT 1) SELECT * FROM cnt, y1 WHERE i=a } [string map {"\n " \n} { QUERY PLAN | | | | 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | } do_eqp_test 3.1.2 { WITH cnt(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM cnt LIMIT 1) SELECT * FROM cnt, y1 WHERE i=a } [string map {"\n " \n} { QUERY PLAN |--CO-ROUTINE cnt | |--SETUP | | `--SCAN CONSTANT ROW | `--RECURSIVE STEP | `--SCAN cnt |--SCAN cnt `--SEARCH y1 USING INDEX y1a (a=?) }] do_eqp_test 3.1.3 { WITH cnt(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM cnt LIMIT 1000000) SELECT * FROM cnt, y1 WHERE i=a } [string map {"\n " \n} { QUERY PLAN |--CO-ROUTINE cnt | |--SETUP | | `--SCAN CONSTANT ROW | `--RECURSIVE STEP | `--SCAN cnt |--SCAN y1 `--SEARCH cnt USING AUTOMATIC COVERING INDEX (i=?) }] |
︙ | ︙ | |||
121 122 123 124 125 126 127 | do_eqp_test 3.2.2 { WITH RECURSIVE c(w,id) AS (SELECT 0, (SELECT pk FROM w2 LIMIT 1) UNION ALL SELECT c.w + 1, x FROM w1, c LIMIT 1) SELECT * FROM c, w2, w1 WHERE c.id=w2.pk AND c.id=w1.pk; } { QUERY PLAN | | | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | do_eqp_test 3.2.2 { WITH RECURSIVE c(w,id) AS (SELECT 0, (SELECT pk FROM w2 LIMIT 1) UNION ALL SELECT c.w + 1, x FROM w1, c LIMIT 1) SELECT * FROM c, w2, w1 WHERE c.id=w2.pk AND c.id=w1.pk; } { QUERY PLAN |--CO-ROUTINE c | |--SETUP | | |--SCAN CONSTANT ROW | | `--SCALAR SUBQUERY xxxxxx | | `--SCAN w2 | `--RECURSIVE STEP | |--SCAN c | `--SCAN w1 |
︙ | ︙ |
Changes to test/with6.test.
︙ | ︙ | |||
83 84 85 86 87 88 89 | WITH c(x) AS NOT MATERIALIZED (VALUES(0),(1)) SELECT c1.x||c2.x||c3.x FROM (SELECT x FROM c LIMIT 5) AS c1, (SELECT x FROM c LIMIT 5) AS c2, (SELECT x FROM c LIMIT 5) AS c3; } { QUERY PLAN | | | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | WITH c(x) AS NOT MATERIALIZED (VALUES(0),(1)) SELECT c1.x||c2.x||c3.x FROM (SELECT x FROM c LIMIT 5) AS c1, (SELECT x FROM c LIMIT 5) AS c2, (SELECT x FROM c LIMIT 5) AS c3; } { QUERY PLAN |--CO-ROUTINE c1 | |--CO-ROUTINE c | | `--SCAN 2 CONSTANT ROWS | `--SCAN c |--MATERIALIZE c2 | |--CO-ROUTINE c | | `--SCAN 2 CONSTANT ROWS | `--SCAN c |
︙ | ︙ | |||
119 120 121 122 123 124 125 | WITH c(x) AS MATERIALIZED (VALUES(0),(1)) SELECT c1.x||c2.x||c3.x FROM (SELECT x FROM c LIMIT 5) AS c1, (SELECT x FROM c LIMIT 6) AS c2, (SELECT x FROM c LIMIT 7) AS c3; } { QUERY PLAN | | | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | WITH c(x) AS MATERIALIZED (VALUES(0),(1)) SELECT c1.x||c2.x||c3.x FROM (SELECT x FROM c LIMIT 5) AS c1, (SELECT x FROM c LIMIT 6) AS c2, (SELECT x FROM c LIMIT 7) AS c3; } { QUERY PLAN |--CO-ROUTINE c1 | |--MATERIALIZE c | | `--SCAN 2 CONSTANT ROWS | `--SCAN c |--MATERIALIZE c2 | `--SCAN c |--MATERIALIZE c3 | `--SCAN c |
︙ | ︙ | |||
147 148 149 150 151 152 153 | WITH c(x) AS (VALUES(0),(1)) SELECT c1.x||c2.x||c3.x FROM (SELECT x FROM c LIMIT 5) AS c1, (SELECT x FROM c LIMIT 6) AS c2, (SELECT x FROM c LIMIT 7) AS c3; } { QUERY PLAN | | | 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | WITH c(x) AS (VALUES(0),(1)) SELECT c1.x||c2.x||c3.x FROM (SELECT x FROM c LIMIT 5) AS c1, (SELECT x FROM c LIMIT 6) AS c2, (SELECT x FROM c LIMIT 7) AS c3; } { QUERY PLAN |--CO-ROUTINE c1 | |--MATERIALIZE c | | `--SCAN 2 CONSTANT ROWS | `--SCAN c |--MATERIALIZE c2 | `--SCAN c |--MATERIALIZE c3 | `--SCAN c |
︙ | ︙ | |||
224 225 226 227 228 229 230 | (SELECT z FROM c LIMIT 5) AS c2; SELECT y FROM t2 ORDER BY y; } {40404 40405 40406 40504 40505 40506 40604 40605 40606} do_eqp_test 211 { SELECT y FROM t2 ORDER BY y; } { QUERY PLAN | | | 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | (SELECT z FROM c LIMIT 5) AS c2; SELECT y FROM t2 ORDER BY y; } {40404 40405 40406 40504 40505 40506 40604 40605 40606} do_eqp_test 211 { SELECT y FROM t2 ORDER BY y; } { QUERY PLAN |--CO-ROUTINE c1 | |--CO-ROUTINE c | | `--SCAN 3 CONSTANT ROWS | `--SCAN c |--MATERIALIZE c2 | |--CO-ROUTINE c | | `--SCAN 3 CONSTANT ROWS | `--SCAN c |
︙ | ︙ |
Changes to tool/mkshellc.tcl.
︙ | ︙ | |||
51 52 53 54 55 56 57 | set cfile [lindex $lx 1] puts $out "/************************* Begin $cfile ******************/" # puts $out "#line 1 \"$cfile\"" set in2 [open $topdir/src/$cfile] fconfigure $in2 -translation binary while {![eof $in2]} { set lx [omit_redundant_typedefs [gets $in2]] | | | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | set cfile [lindex $lx 1] puts $out "/************************* Begin $cfile ******************/" # puts $out "#line 1 \"$cfile\"" set in2 [open $topdir/src/$cfile] fconfigure $in2 -translation binary while {![eof $in2]} { set lx [omit_redundant_typedefs [gets $in2]] if {[regexp {^# *include "sqlite} $lx]} { set lx "/* $lx */" } if {[regexp {^# *include "test_windirent.h"} $lx]} { set lx "/* $lx */" } set lx [string map [list __declspec(dllexport) {}] $lx] puts $out $lx |
︙ | ︙ |