aboutsummaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rwxr-xr-xext/consio/console_io.c678
-rw-r--r--ext/consio/console_io.h280
-rw-r--r--ext/fts5/fts5_index.c22
-rw-r--r--ext/fts5/test/fts5corrupt5.test85
-rw-r--r--ext/fts5/test/fts5secure8.test51
-rw-r--r--ext/wasm/api/sqlite3-worker1-promiser.c-pp.js13
6 files changed, 1116 insertions, 13 deletions
diff --git a/ext/consio/console_io.c b/ext/consio/console_io.c
new file mode 100755
index 000000000..da62321da
--- /dev/null
+++ b/ext/consio/console_io.c
@@ -0,0 +1,678 @@
+/*
+** 2023 November 4
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+********************************************************************************
+** This file implements various interfaces used for console and stream I/O
+** by the SQLite project command-line tools, as explained in console_io.h .
+** Functions prefixed by "SQLITE_INTERNAL_LINKAGE" behave as described there.
+*/
+
+#ifndef SQLITE_CDECL
+# define SQLITE_CDECL
+#endif
+
+#ifndef SHELL_NO_SYSINC
+# include <stdarg.h>
+# include <string.h>
+# include <stdlib.h>
+# include <limits.h>
+# include <assert.h>
+# include "console_io.h"
+# include "sqlite3.h"
+#endif
+
+#ifndef SQLITE_CIO_NO_TRANSLATE
+# if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT
+# ifndef SHELL_NO_SYSINC
+# include <io.h>
+# include <fcntl.h>
+# undef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# endif
+# define CIO_WIN_WC_XLATE 1 /* Use WCHAR Windows APIs for console I/O */
+# else
+# ifndef SHELL_NO_SYSINC
+# include <unistd.h>
+# endif
+# define CIO_WIN_WC_XLATE 0 /* Use plain C library stream I/O at console */
+# endif
+#else
+# define CIO_WIN_WC_XLATE 0 /* Not exposing translation routines at all */
+#endif
+
+#if CIO_WIN_WC_XLATE
+/* Character used to represent a known-incomplete UTF-8 char group (�) */
+static WCHAR cBadGroup = 0xfffd;
+#endif
+
+#if CIO_WIN_WC_XLATE
+static HANDLE handleOfFile(FILE *pf){
+ int fileDesc = _fileno(pf);
+ union { intptr_t osfh; HANDLE fh; } fid = {
+ (fileDesc>=0)? _get_osfhandle(fileDesc) : (intptr_t)INVALID_HANDLE_VALUE
+ };
+ return fid.fh;
+}
+#endif
+
+#ifndef SQLITE_CIO_NO_TRANSLATE
+typedef struct PerStreamTags {
+# if CIO_WIN_WC_XLATE
+ HANDLE hx;
+ DWORD consMode;
+ char acIncomplete[4];
+# else
+ short reachesConsole;
+# endif
+ FILE *pf;
+} PerStreamTags;
+
+/* Define NULL-like value for things which can validly be 0. */
+# define SHELL_INVALID_FILE_PTR ((FILE *)~0)
+# if CIO_WIN_WC_XLATE
+# define SHELL_INVALID_CONS_MODE 0xFFFF0000
+# endif
+
+# if CIO_WIN_WC_XLATE
+# define PST_INITIALIZER { INVALID_HANDLE_VALUE, SHELL_INVALID_CONS_MODE, \
+ {0,0,0,0}, SHELL_INVALID_FILE_PTR }
+# else
+# define PST_INITIALIZER { 0, SHELL_INVALID_FILE_PTR }
+# endif
+
+/* Quickly say whether a known output is going to the console. */
+# if CIO_WIN_WC_XLATE
+static short pstReachesConsole(PerStreamTags *ppst){
+ return (ppst->hx != INVALID_HANDLE_VALUE);
+}
+# else
+# define pstReachesConsole(ppst) 0
+# endif
+
+# if CIO_WIN_WC_XLATE
+static void restoreConsoleArb(PerStreamTags *ppst){
+ if( pstReachesConsole(ppst) ) SetConsoleMode(ppst->hx, ppst->consMode);
+}
+# else
+# define restoreConsoleArb(ppst)
+# endif
+
+/* Say whether FILE* appears to be a console, collect associated info. */
+static short streamOfConsole(FILE *pf, /* out */ PerStreamTags *ppst){
+# if CIO_WIN_WC_XLATE
+ short rv = 0;
+ DWORD dwCM = SHELL_INVALID_CONS_MODE;
+ HANDLE fh = handleOfFile(pf);
+ ppst->pf = pf;
+ if( INVALID_HANDLE_VALUE != fh ){
+ rv = (GetFileType(fh) == FILE_TYPE_CHAR && GetConsoleMode(fh,&dwCM));
+ }
+ ppst->hx = (rv)? fh : INVALID_HANDLE_VALUE;
+ ppst->consMode = dwCM;
+ return rv;
+# else
+ ppst->pf = pf;
+ ppst->reachesConsole = ( (short)isatty(fileno(pf)) );
+ return ppst->reachesConsole;
+# endif
+}
+
+# if CIO_WIN_WC_XLATE
+/* Define console modes for use with the Windows Console API. */
+# define SHELL_CONI_MODE \
+ (ENABLE_ECHO_INPUT | ENABLE_INSERT_MODE | ENABLE_LINE_INPUT | 0x80 \
+ | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS | ENABLE_PROCESSED_INPUT)
+# define SHELL_CONO_MODE (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT \
+ | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+# endif
+
+typedef struct ConsoleInfo {
+ PerStreamTags pstSetup[3];
+ PerStreamTags pstDesignated[3];
+ StreamsAreConsole sacSetup;
+} ConsoleInfo;
+
+static short isValidStreamInfo(PerStreamTags *ppst){
+ return (ppst->pf != SHELL_INVALID_FILE_PTR);
+}
+
+static ConsoleInfo consoleInfo = {
+ { /* pstSetup */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER },
+ { /* pstDesignated[] */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER },
+ SAC_NoConsole /* sacSetup */
+};
+
+SQLITE_INTERNAL_LINKAGE FILE* invalidFileStream = (FILE *)~0;
+
+# if CIO_WIN_WC_XLATE
+static void maybeSetupAsConsole(PerStreamTags *ppst, short odir){
+ if( pstReachesConsole(ppst) ){
+ DWORD cm = odir? SHELL_CONO_MODE : SHELL_CONI_MODE;
+ SetConsoleMode(ppst->hx, cm);
+ }
+}
+# else
+# define maybeSetupAsConsole(ppst,odir)
+# endif
+
+SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void){
+# if CIO_WIN_WC_XLATE
+ int ix = 0;
+ while( ix < 6 ){
+ PerStreamTags *ppst = (ix<3)?
+ &consoleInfo.pstSetup[ix] : &consoleInfo.pstDesignated[ix-3];
+ maybeSetupAsConsole(ppst, (ix % 3)>0);
+ ++ix;
+ }
+# endif
+}
+
+SQLITE_INTERNAL_LINKAGE StreamsAreConsole
+consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr ){
+ StreamsAreConsole rv = SAC_NoConsole;
+ FILE* apf[3] = { pfIn, pfOut, pfErr };
+ int ix;
+ for( ix = 2; ix >= 0; --ix ){
+ PerStreamTags *ppst = &consoleInfo.pstSetup[ix];
+ if( streamOfConsole(apf[ix], ppst) ){
+ rv |= (SAC_InConsole<<ix);
+ }
+ consoleInfo.pstDesignated[ix] = *ppst;
+ if( ix > 0 ) fflush(apf[ix]);
+ }
+ consoleInfo.sacSetup = rv;
+ consoleRenewSetup();
+ return rv;
+}
+
+SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void ){
+# if CIO_WIN_WC_XLATE
+ static ConsoleInfo *pci = &consoleInfo;
+ if( pci->sacSetup ){
+ int ix;
+ for( ix=0; ix<3; ++ix ){
+ if( pci->sacSetup & (SAC_InConsole<<ix) ){
+ PerStreamTags *ppst = &pci->pstSetup[ix];
+ SetConsoleMode(ppst->hx, ppst->consMode);
+ }
+ }
+ }
+# endif
+}
+#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
+
+#ifdef SQLITE_CIO_INPUT_REDIR
+/* Say whether given FILE* is among those known, via either
+** consoleClassifySetup() or set{Output,Error}Stream, as
+** readable, and return an associated PerStreamTags pointer
+** if so. Otherwise, return 0.
+*/
+static PerStreamTags * isKnownReadable(FILE *pf){
+ static PerStreamTags *apst[] = {
+ &consoleInfo.pstDesignated[0], &consoleInfo.pstSetup[0], 0
+ };
+ int ix = 0;
+ do {
+ if( apst[ix]->pf == pf ) break;
+ } while( apst[++ix] != 0 );
+ return apst[ix];
+}
+#endif
+
+#ifndef SQLITE_CIO_NO_TRANSLATE
+/* Say whether given FILE* is among those known, via either
+** consoleClassifySetup() or set{Output,Error}Stream, as
+** writable, and return an associated PerStreamTags pointer
+** if so. Otherwise, return 0.
+*/
+static PerStreamTags * isKnownWritable(FILE *pf){
+ static PerStreamTags *apst[] = {
+ &consoleInfo.pstDesignated[1], &consoleInfo.pstDesignated[2],
+ &consoleInfo.pstSetup[1], &consoleInfo.pstSetup[2], 0
+ };
+ int ix = 0;
+ do {
+ if( apst[ix]->pf == pf ) break;
+ } while( apst[++ix] != 0 );
+ return apst[ix];
+}
+
+static FILE *designateEmitStream(FILE *pf, unsigned chix){
+ FILE *rv = consoleInfo.pstDesignated[chix].pf;
+ if( pf == invalidFileStream ) return rv;
+ else{
+ /* Setting a possibly new output stream. */
+ PerStreamTags *ppst = isKnownWritable(pf);
+ if( ppst != 0 ){
+ PerStreamTags pst = *ppst;
+ consoleInfo.pstDesignated[chix] = pst;
+ }else streamOfConsole(pf, &consoleInfo.pstDesignated[chix]);
+ }
+ return rv;
+}
+
+SQLITE_INTERNAL_LINKAGE FILE *setOutputStream(FILE *pf){
+ return designateEmitStream(pf, 1);
+}
+# ifdef CONSIO_SET_ERROR_STREAM
+SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf){
+ return designateEmitStream(pf, 2);
+}
+# endif
+#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
+
+#ifndef SQLITE_CIO_NO_SETMODE
+# if CIO_WIN_WC_XLATE
+static void setModeFlushQ(FILE *pf, short bFlush, int mode){
+ if( bFlush ) fflush(pf);
+ _setmode(_fileno(pf), mode);
+}
+# else
+# define setModeFlushQ(f, b, m) if(b) fflush(f)
+# endif
+
+SQLITE_INTERNAL_LINKAGE void setBinaryMode(FILE *pf, short bFlush){
+ setModeFlushQ(pf, bFlush, _O_BINARY);
+}
+SQLITE_INTERNAL_LINKAGE void setTextMode(FILE *pf, short bFlush){
+ setModeFlushQ(pf, bFlush, _O_TEXT);
+}
+# undef setModeFlushQ
+
+#else /* defined(SQLITE_CIO_NO_SETMODE) */
+# define setBinaryMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0)
+# define setTextMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0)
+#endif /* defined(SQLITE_CIO_NO_SETMODE) */
+
+#ifndef SQLITE_CIO_NO_TRANSLATE
+# if CIO_WIN_WC_XLATE
+/* Write buffer cBuf as output to stream known to reach console,
+** limited to ncTake char's. Return ncTake on success, else 0. */
+static int conZstrEmit(PerStreamTags *ppst, const char *z, int ncTake){
+ int rv = 0;
+ if( z!=NULL ){
+ int nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, 0,0);
+ if( nwc > 0 ){
+ WCHAR *zw = sqlite3_malloc64(nwc*sizeof(WCHAR));
+ if( zw!=NULL ){
+ nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, zw,nwc);
+ if( nwc > 0 ){
+ /* Translation from UTF-8 to UTF-16, then WCHARs out. */
+ if( WriteConsoleW(ppst->hx, zw,nwc, 0, NULL) ){
+ rv = ncTake;
+ }
+ }
+ sqlite3_free(zw);
+ }
+ }
+ }
+ return rv;
+}
+
+/* For {f,o,e}PrintfUtf8() when stream is known to reach console. */
+static int conioVmPrintf(PerStreamTags *ppst, const char *zFormat, va_list ap){
+ char *z = sqlite3_vmprintf(zFormat, ap);
+ if( z ){
+ int rv = conZstrEmit(ppst, z, (int)strlen(z));
+ sqlite3_free(z);
+ return rv;
+ }else return 0;
+}
+# endif /* CIO_WIN_WC_XLATE */
+
+# ifdef CONSIO_GET_EMIT_STREAM
+static PerStreamTags * getDesignatedEmitStream(FILE *pf, unsigned chix,
+ PerStreamTags *ppst){
+ PerStreamTags *rv = isKnownWritable(pf);
+ short isValid = (rv!=0)? isValidStreamInfo(rv) : 0;
+ if( rv != 0 && isValid ) return rv;
+ streamOfConsole(pf, ppst);
+ return ppst;
+}
+# endif
+
+/* Get stream info, either for designated output or error stream when
+** chix equals 1 or 2, or for an arbitrary stream when chix == 0.
+** In either case, ppst references a caller-owned PerStreamTags
+** struct which may be filled in if none of the known writable
+** streams is being held by consoleInfo. The ppf parameter is a
+** byref output when chix!=0 and a byref input when chix==0.
+ */
+static PerStreamTags *
+getEmitStreamInfo(unsigned chix, PerStreamTags *ppst,
+ /* in/out */ FILE **ppf){
+ PerStreamTags *ppstTry;
+ FILE *pfEmit;
+ if( chix > 0 ){
+ ppstTry = &consoleInfo.pstDesignated[chix];
+ if( !isValidStreamInfo(ppstTry) ){
+ ppstTry = &consoleInfo.pstSetup[chix];
+ pfEmit = ppst->pf;
+ }else pfEmit = ppstTry->pf;
+ if( !isValidStreamInfo(ppstTry) ){
+ pfEmit = (chix > 1)? stderr : stdout;
+ ppstTry = ppst;
+ streamOfConsole(pfEmit, ppstTry);
+ }
+ *ppf = pfEmit;
+ }else{
+ ppstTry = isKnownWritable(*ppf);
+ if( ppstTry != 0 ) return ppstTry;
+ streamOfConsole(*ppf, ppst);
+ return ppst;
+ }
+ return ppstTry;
+}
+
+SQLITE_INTERNAL_LINKAGE int oPrintfUtf8(const char *zFormat, ...){
+ va_list ap;
+ int rv;
+ FILE *pfOut;
+ PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
+# if CIO_WIN_WC_XLATE
+ PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
+# else
+ getEmitStreamInfo(1, &pst, &pfOut);
+# endif
+ assert(zFormat!=0);
+ va_start(ap, zFormat);
+# if CIO_WIN_WC_XLATE
+ if( pstReachesConsole(ppst) ){
+ rv = conioVmPrintf(ppst, zFormat, ap);
+ }else{
+# endif
+ rv = vfprintf(pfOut, zFormat, ap);
+# if CIO_WIN_WC_XLATE
+ }
+# endif
+ va_end(ap);
+ return rv;
+}
+
+SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...){
+ va_list ap;
+ int rv;
+ FILE *pfErr;
+ PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
+# if CIO_WIN_WC_XLATE
+ PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
+# else
+ getEmitStreamInfo(2, &pst, &pfErr);
+# endif
+ assert(zFormat!=0);
+ va_start(ap, zFormat);
+# if CIO_WIN_WC_XLATE
+ if( pstReachesConsole(ppst) ){
+ rv = conioVmPrintf(ppst, zFormat, ap);
+ }else{
+# endif
+ rv = vfprintf(pfErr, zFormat, ap);
+# if CIO_WIN_WC_XLATE
+ }
+# endif
+ va_end(ap);
+ return rv;
+}
+
+SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...){
+ va_list ap;
+ int rv;
+ PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
+# if CIO_WIN_WC_XLATE
+ PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
+# else
+ getEmitStreamInfo(0, &pst, &pfO);
+# endif
+ assert(zFormat!=0);
+ va_start(ap, zFormat);
+# if CIO_WIN_WC_XLATE
+ if( pstReachesConsole(ppst) ){
+ maybeSetupAsConsole(ppst, 1);
+ rv = conioVmPrintf(ppst, zFormat, ap);
+ if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
+ }else{
+# endif
+ rv = vfprintf(pfO, zFormat, ap);
+# if CIO_WIN_WC_XLATE
+ }
+# endif
+ va_end(ap);
+ return rv;
+}
+
+SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO){
+ PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
+# if CIO_WIN_WC_XLATE
+ PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
+# else
+ getEmitStreamInfo(0, &pst, &pfO);
+# endif
+ assert(z!=0);
+# if CIO_WIN_WC_XLATE
+ if( pstReachesConsole(ppst) ){
+ int rv;
+ maybeSetupAsConsole(ppst, 1);
+ rv = conZstrEmit(ppst, z, (int)strlen(z));
+ if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
+ return rv;
+ }else {
+# endif
+ return (fputs(z, pfO)<0)? 0 : (int)strlen(z);
+# if CIO_WIN_WC_XLATE
+ }
+# endif
+}
+
+SQLITE_INTERNAL_LINKAGE int ePutsUtf8(const char *z){
+ FILE *pfErr;
+ PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
+# if CIO_WIN_WC_XLATE
+ PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
+# else
+ getEmitStreamInfo(2, &pst, &pfErr);
+# endif
+ assert(z!=0);
+# if CIO_WIN_WC_XLATE
+ if( pstReachesConsole(ppst) ) return conZstrEmit(ppst, z, (int)strlen(z));
+ else {
+# endif
+ return (fputs(z, pfErr)<0)? 0 : (int)strlen(z);
+# if CIO_WIN_WC_XLATE
+ }
+# endif
+}
+
+SQLITE_INTERNAL_LINKAGE int oPutsUtf8(const char *z){
+ FILE *pfOut;
+ PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
+# if CIO_WIN_WC_XLATE
+ PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
+# else
+ getEmitStreamInfo(1, &pst, &pfOut);
+# endif
+ assert(z!=0);
+# if CIO_WIN_WC_XLATE
+ if( pstReachesConsole(ppst) ) return conZstrEmit(ppst, z, (int)strlen(z));
+ else {
+# endif
+ return (fputs(z, pfOut)<0)? 0 : (int)strlen(z);
+# if CIO_WIN_WC_XLATE
+ }
+# endif
+}
+
+#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
+
+#if !(defined(SQLITE_CIO_NO_UTF8SCAN) && defined(SQLITE_CIO_NO_TRANSLATE))
+/* Skip over as much z[] input char sequence as is valid UTF-8,
+** limited per nAccept char's or whole characters and containing
+** no char cn such that ((1<<cn) & ccm)!=0. On return, the
+** sequence z:return (inclusive:exclusive) is validated UTF-8.
+** Limit: nAccept>=0 => char count, nAccept<0 => character
+ */
+SQLITE_INTERNAL_LINKAGE const char*
+zSkipValidUtf8(const char *z, int nAccept, long ccm){
+ int ng = (nAccept<0)? -nAccept : 0;
+ const char *pcLimit = (nAccept>=0)? z+nAccept : 0;
+ assert(z!=0);
+ while( (pcLimit)? (z<pcLimit) : (ng-- != 0) ){
+ char c = *z;
+ if( (c & 0x80) == 0 ){
+ if( ccm != 0L && c < 0x20 && ((1L<<c) & ccm) != 0 ) return z;
+ ++z; /* ASCII */
+ }else if( (c & 0xC0) != 0xC0 ) return z; /* not a lead byte */
+ else{
+ const char *zt = z+1; /* Got lead byte, look at trail bytes.*/
+ do{
+ if( pcLimit && zt >= pcLimit ) return z;
+ else{
+ char ct = *zt++;
+ if( ct==0 || (zt-z)>4 || (ct & 0xC0)!=0x80 ){
+ /* Trailing bytes are too few, too many, or invalid. */
+ return z;
+ }
+ }
+ } while( ((c <<= 1) & 0x40) == 0x40 ); /* Eat lead byte's count. */
+ z = zt;
+ }
+ }
+ return z;
+}
+#endif /*!(defined(SQLITE_CIO_NO_UTF8SCAN)&&defined(SQLITE_CIO_NO_TRANSLATE))*/
+
+#ifndef SQLITE_CIO_NO_TRANSLATE
+# ifdef CONSIO_SPUTB
+SQLITE_INTERNAL_LINKAGE int
+fPutbUtf8(FILE *pfO, const char *cBuf, int nAccept){
+ assert(pfO!=0);
+# if CIO_WIN_WC_XLATE
+ PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
+ PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
+ if( pstReachesConsole(ppst) ){
+ int rv;
+ maybeSetupAsConsole(ppst, 1);
+ rv = conZstrEmit(ppst, cBuf, nAccept);
+ if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
+ return rv;
+ }else {
+# endif
+ return (int)fwrite(cBuf, 1, nAccept, pfO);
+# if CIO_WIN_WC_XLATE
+ }
+# endif
+}
+# endif
+
+SQLITE_INTERNAL_LINKAGE int
+oPutbUtf8(const char *cBuf, int nAccept){
+ FILE *pfOut;
+ PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
+# if CIO_WIN_WC_XLATE
+ PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
+# else
+ getEmitStreamInfo(1, &pst, &pfOut);
+# endif
+# if CIO_WIN_WC_XLATE
+ if( pstReachesConsole(ppst) ){
+ return conZstrEmit(ppst, cBuf, nAccept);
+ }else {
+# endif
+ return (int)fwrite(cBuf, 1, nAccept, pfOut);
+# if CIO_WIN_WC_XLATE
+ }
+# endif
+}
+
+# ifdef CONSIO_EPUTB
+SQLITE_INTERNAL_LINKAGE int
+ePutbUtf8(const char *cBuf, int nAccept){
+ FILE *pfErr;
+ PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
+ PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
+# if CIO_WIN_WC_XLATE
+ if( pstReachesConsole(ppst) ){
+ return conZstrEmit(ppst, cBuf, nAccept);
+ }else {
+# endif
+ return (int)fwrite(cBuf, 1, nAccept, pfErr);
+# if CIO_WIN_WC_XLATE
+ }
+# endif
+}
+# endif /* defined(CONSIO_EPUTB) */
+
+SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn){
+ if( pfIn==0 ) pfIn = stdin;
+# if CIO_WIN_WC_XLATE
+ if( pfIn == consoleInfo.pstSetup[0].pf
+ && (consoleInfo.sacSetup & SAC_InConsole)!=0 ){
+# if CIO_WIN_WC_XLATE==1
+# define SHELL_GULP 150 /* Count of WCHARS to be gulped at a time */
+ WCHAR wcBuf[SHELL_GULP+1];
+ int lend = 0, noc = 0;
+ if( ncMax > 0 ) cBuf[0] = 0;
+ while( noc < ncMax-8-1 && !lend ){
+ /* There is room for at least 2 more characters and a 0-terminator. */
+ int na = (ncMax > SHELL_GULP*4+1 + noc)? SHELL_GULP : (ncMax-1 - noc)/4;
+# undef SHELL_GULP
+ DWORD nbr = 0;
+ BOOL bRC = ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf, na, &nbr, 0);
+ if( bRC && nbr>0 && (wcBuf[nbr-1]&0xF800)==0xD800 ){
+ /* Last WHAR read is first of a UTF-16 surrogate pair. Grab its mate. */
+ DWORD nbrx;
+ bRC &= ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf+nbr, 1, &nbrx, 0);
+ if( bRC ) nbr += nbrx;
+ }
+ if( !bRC || (noc==0 && nbr==0) ) return 0;
+ if( nbr > 0 ){
+ int nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,0,0,0,0);
+ if( nmb != 0 && noc+nmb <= ncMax ){
+ int iseg = noc;
+ nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,cBuf+noc,nmb,0,0);
+ noc += nmb;
+ /* Fixup line-ends as coded by Windows for CR (or "Enter".)
+ ** This is done without regard for any setMode{Text,Binary}()
+ ** call that might have been done on the interactive input.
+ */
+ if( noc > 0 ){
+ if( cBuf[noc-1]=='\n' ){
+ lend = 1;
+ if( noc > 1 && cBuf[noc-2]=='\r' ) cBuf[--noc-1] = '\n';
+ }
+ }
+ /* Check for ^Z (anywhere in line) too, to act as EOF. */
+ while( iseg < noc ){
+ if( cBuf[iseg]=='\x1a' ){
+ noc = iseg; /* Chop ^Z and anything following. */
+ lend = 1; /* Counts as end of line too. */
+ break;
+ }
+ ++iseg;
+ }
+ }else break; /* Drop apparent garbage in. (Could assert.) */
+ }else break;
+ }
+ /* If got nothing, (after ^Z chop), must be at end-of-file. */
+ if( noc > 0 ){
+ cBuf[noc] = 0;
+ return cBuf;
+ }else return 0;
+# endif
+ }else{
+# endif
+ return fgets(cBuf, ncMax, pfIn);
+# if CIO_WIN_WC_XLATE
+ }
+# endif
+}
+#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
+
+#undef SHELL_INVALID_FILE_PTR
diff --git a/ext/consio/console_io.h b/ext/consio/console_io.h
new file mode 100644
index 000000000..98a87db3d
--- /dev/null
+++ b/ext/consio/console_io.h
@@ -0,0 +1,280 @@
+/*
+** 2023 November 1
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+********************************************************************************
+** This file exposes various interfaces used for console and other I/O
+** by the SQLite project command-line tools. These interfaces are used
+** at either source conglomeration time, compilation time, or run time.
+** This source provides for either inclusion into conglomerated,
+** "single-source" forms or separate compilation then linking.
+**
+** Platform dependencies are "hidden" here by various stratagems so
+** that, provided certain conditions are met, the programs using this
+** source or object code compiled from it need no explicit conditional
+** compilation in their source for their console and stream I/O.
+**
+** The symbols and functionality exposed here are not a public API.
+** This code may change in tandem with other project code as needed.
+**
+** When this .h file and its companion .c are directly incorporated into
+** a source conglomeration (such as shell.c), the preprocessor symbol
+** CIO_WIN_WC_XLATE is defined as 0 or 1, reflecting whether console I/O
+** translation for Windows is effected for the build.
+*/
+
+#ifndef SQLITE_INTERNAL_LINKAGE
+# define SQLITE_INTERNAL_LINKAGE extern /* external to translation unit */
+# include <stdio.h>
+#else
+# define SHELL_NO_SYSINC /* Better yet, modify mkshellc.tcl for this. */
+#endif
+
+#ifndef SQLITE3_H
+# include "sqlite3.h"
+#endif
+
+#ifndef SQLITE_CIO_NO_CLASSIFY
+
+/* Define enum for use with following function. */
+typedef enum StreamsAreConsole {
+ SAC_NoConsole = 0,
+ SAC_InConsole = 1, SAC_OutConsole = 2, SAC_ErrConsole = 4,
+ SAC_AnyConsole = 0x7
+} StreamsAreConsole;
+
+/*
+** Classify the three standard I/O streams according to whether
+** they are connected to a console attached to the process.
+**
+** Returns the bit-wise OR of SAC_{In,Out,Err}Console values,
+** or SAC_NoConsole if none of the streams reaches a console.
+**
+** This function should be called before any I/O is done with
+** the given streams. As a side-effect, the given inputs are
+** recorded so that later I/O operations on them may be done
+** differently than the C library FILE* I/O would be done,
+** iff the stream is used for the I/O functions that follow,
+** and to support the ones that use an implicit stream.
+**
+** On some platforms, stream or console mode alteration (aka
+** "Setup") may be made which is undone by consoleRestore().
+*/
+SQLITE_INTERNAL_LINKAGE StreamsAreConsole
+consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr );
+/* A usual call for convenience: */
+#define SQLITE_STD_CONSOLE_INIT() consoleClassifySetup(stdin,stdout,stderr)
+
+/*
+** After an initial call to consoleClassifySetup(...), renew
+** the same setup it effected. (A call not after is an error.)
+** This will restore state altered by consoleRestore();
+**
+** Applications which run an inferior (child) process which
+** inherits the same I/O streams may call this function after
+** such a process exits to guard against console mode changes.
+*/
+SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void);
+
+/*
+** Undo any side-effects left by consoleClassifySetup(...).
+**
+** This should be called after consoleClassifySetup() and
+** before the process terminates normally. It is suitable
+** for use with the atexit() C library procedure. After
+** this call, no console I/O should be done until one of
+** console{Classify or Renew}Setup(...) is called again.
+**
+** Applications which run an inferior (child) process that
+** inherits the same I/O streams might call this procedure
+** before so that said process will have a console setup
+** however users have configured it or come to expect.
+*/
+SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void );
+
+#else /* defined(SQLITE_CIO_NO_CLASSIFY) */
+# define consoleClassifySetup(i,o,e)
+# define consoleRenewSetup()
+# define consoleRestore()
+#endif /* defined(SQLITE_CIO_NO_CLASSIFY) */
+
+#ifndef SQLITE_CIO_NO_REDIRECT
+/*
+** Set stream to be used for the functions below which write
+** to "the designated X stream", where X is Output or Error.
+** Returns the previous value.
+**
+** Alternatively, pass the special value, invalidFileStream,
+** to get the designated stream value without setting it.
+**
+** Before the designated streams are set, they default to
+** those passed to consoleClassifySetup(...), and before
+** that is called they default to stdout and stderr.
+**
+** It is error to close a stream so designated, then, without
+** designating another, use the corresponding {o,e}Emit(...).
+*/
+SQLITE_INTERNAL_LINKAGE FILE *invalidFileStream;
+SQLITE_INTERNAL_LINKAGE FILE *setOutputStream(FILE *pf);
+# ifdef CONSIO_SET_ERROR_STREAM
+SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf);
+# endif
+#else
+# define setOutputStream(pf)
+# define setErrorStream(pf)
+#endif /* !defined(SQLITE_CIO_NO_REDIRECT) */
+
+#ifndef SQLITE_CIO_NO_TRANSLATE
+/*
+** Emit output like fprintf(). If the output is going to the
+** console and translation from UTF-8 is necessary, perform
+** the needed translation. Otherwise, write formatted output
+** to the provided stream almost as-is, possibly with newline
+** translation as specified by set{Binary,Text}Mode().
+*/
+SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...);
+/* Like fPrintfUtf8 except stream is always the designated output. */
+SQLITE_INTERNAL_LINKAGE int oPrintfUtf8(const char *zFormat, ...);
+/* Like fPrintfUtf8 except stream is always the designated error. */
+SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...);
+
+/*
+** Emit output like fputs(). If the output is going to the
+** console and translation from UTF-8 is necessary, perform
+** the needed translation. Otherwise, write given text to the
+** provided stream almost as-is, possibly with newline
+** translation as specified by set{Binary,Text}Mode().
+*/
+SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO);
+/* Like fPutsUtf8 except stream is always the designated output. */
+SQLITE_INTERNAL_LINKAGE int oPutsUtf8(const char *z);
+/* Like fPutsUtf8 except stream is always the designated error. */
+SQLITE_INTERNAL_LINKAGE int ePutsUtf8(const char *z);
+
+/*
+** Emit output like fPutsUtf8(), except that the length of the
+** accepted char or character sequence is limited by nAccept.
+**
+** Returns the number of accepted char values.
+*/
+#ifdef CONSIO_SPUTB
+SQLITE_INTERNAL_LINKAGE int
+fPutbUtf8(FILE *pfOut, const char *cBuf, int nAccept);
+/* Like fPutbUtf8 except stream is always the designated output. */
+#endif
+SQLITE_INTERNAL_LINKAGE int
+oPutbUtf8(const char *cBuf, int nAccept);
+/* Like fPutbUtf8 except stream is always the designated error. */
+#ifdef CONSIO_EPUTB
+SQLITE_INTERNAL_LINKAGE int
+ePutbUtf8(const char *cBuf, int nAccept);
+#endif
+
+/*
+** Collect input like fgets(...) with special provisions for input
+** from the console on platforms that require same. Defers to the
+** C library fgets() when input is not from the console. Newline
+** translation may be done as set by set{Binary,Text}Mode(). As a
+** convenience, pfIn==NULL is treated as stdin.
+*/
+SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn);
+/* Like fGetsUtf8 except stream is always the designated input. */
+/* SQLITE_INTERNAL_LINKAGE char* iGetsUtf8(char *cBuf, int ncMax); */
+
+#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
+
+#ifndef SQLITE_CIO_NO_SETMODE
+/*
+** Set given stream for binary mode, where newline translation is
+** not done, or for text mode where, for some platforms, newlines
+** are translated to the platform's conventional char sequence.
+** If bFlush true, flush the stream.
+**
+** An additional side-effect is that if the stream is one passed
+** to consoleClassifySetup() as an output, it is flushed first.
+**
+** Note that binary/text mode has no effect on console I/O
+** translation. On all platforms, newline to the console starts
+** a new line and CR,LF chars from the console become a newline.
+*/
+SQLITE_INTERNAL_LINKAGE void setBinaryMode(FILE *, short bFlush);
+SQLITE_INTERNAL_LINKAGE void setTextMode(FILE *, short bFlush);
+#endif
+
+#ifdef SQLITE_CIO_PROMPTED_IN
+typedef struct Prompts {
+ int numPrompts;
+ const char **azPrompts;
+} Prompts;
+
+/*
+** Macros for use of a line editor.
+**
+** The following macros define operations involving use of a
+** line-editing library or simple console interaction.
+** A "T" argument is a text (char *) buffer or filename.
+** A "N" argument is an integer.
+**
+** SHELL_ADD_HISTORY(T) // Record text as line(s) of history.
+** SHELL_READ_HISTORY(T) // Read history from file named by T.
+** SHELL_WRITE_HISTORY(T) // Write history to file named by T.
+** SHELL_STIFLE_HISTORY(N) // Limit history to N entries.
+**
+** A console program which does interactive console input is
+** expected to call:
+** SHELL_READ_HISTORY(T) before collecting such input;
+** SHELL_ADD_HISTORY(T) as record-worthy input is taken;
+** SHELL_STIFLE_HISTORY(N) after console input ceases; then
+** SHELL_WRITE_HISTORY(T) before the program exits.
+*/
+
+/*
+** Retrieve a single line of input text from an input stream.
+**
+** If pfIn is the input stream passed to consoleClassifySetup(),
+** and azPrompt is not NULL, then a prompt is issued before the
+** line is collected, as selected by the isContinuation flag.
+** Array azPrompt[{0,1}] holds the {main,continuation} prompt.
+**
+** If zBufPrior is not NULL then it is a buffer from a prior
+** call to this routine that can be reused, or will be freed.
+**
+** The result is stored in space obtained from malloc() and
+** must either be freed by the caller or else passed back to
+** this function as zBufPrior for reuse.
+**
+** This function may call upon services of a line-editing
+** library to interactively collect line edited input.
+*/
+SQLITE_INTERNAL_LINKAGE char *
+shellGetLine(FILE *pfIn, char *zBufPrior, int nLen,
+ short isContinuation, Prompts azPrompt);
+#endif /* defined(SQLITE_CIO_PROMPTED_IN) */
+/*
+** TBD: Define an interface for application(s) to generate
+** completion candidates for use by the line-editor.
+**
+** This may be premature; the CLI is the only application
+** that does this. Yet, getting line-editing melded into
+** console I/O is desirable because a line-editing library
+** may have to establish console operating mode, possibly
+** in a way that interferes with the above functionality.
+*/
+
+#if !(defined(SQLITE_CIO_NO_UTF8SCAN)&&defined(SQLITE_CIO_NO_TRANSLATE))
+/* Skip over as much z[] input char sequence as is valid UTF-8,
+** limited per nAccept char's or whole characters and containing
+** no char cn such that ((1<<cn) & ccm)!=0. On return, the
+** sequence z:return (inclusive:exclusive) is validated UTF-8.
+** Limit: nAccept>=0 => char count, nAccept<0 => character
+ */
+SQLITE_INTERNAL_LINKAGE const char*
+zSkipValidUtf8(const char *z, int nAccept, long ccm);
+
+#endif
diff --git a/ext/fts5/fts5_index.c b/ext/fts5/fts5_index.c
index ba3ce6536..c467addb8 100644
--- a/ext/fts5/fts5_index.c
+++ b/ext/fts5/fts5_index.c
@@ -5137,18 +5137,24 @@ static void fts5DoSecureDelete(
iOff = iStart;
- /* Set variable bLastInDoclist to true if this entry happens to be
- ** the last rowid in the doclist for its term. */
+ /* If the position-list for the entry being removed flows over past
+ ** the end of this page, delete the portion of the position-list on the
+ ** next page and beyond.
+ **
+ ** Set variable bLastInDoclist to true if this entry happens
+ ** to be the last rowid in the doclist for its term. */
+ if( iNextOff>=iPgIdx ){
+ int pgno = pSeg->iLeafPgno+1;
+ fts5SecureDeleteOverflow(p, pSeg->pSeg, pgno, &bLastInDoclist);
+ iNextOff = iPgIdx;
+ }
+
if( pSeg->bDel==0 ){
- if( iNextOff>=iPgIdx ){
- int pgno = pSeg->iLeafPgno+1;
- fts5SecureDeleteOverflow(p, pSeg->pSeg, pgno, &bLastInDoclist);
- iNextOff = iPgIdx;
- }else{
+ if( iNextOff!=iPgIdx ){
/* Loop through the page-footer. If iNextOff (offset of the
** entry following the one we are removing) is equal to the
** offset of a key on this page, then the entry is the last
- ** in its doclist. */
+ ** in its doclist. */
int iKeyOff = 0;
for(iIdx=0; iIdx<nIdx; /* no-op */){
u32 iVal = 0;
diff --git a/ext/fts5/test/fts5corrupt5.test b/ext/fts5/test/fts5corrupt5.test
index efbe2e13e..60910dce7 100644
--- a/ext/fts5/test/fts5corrupt5.test
+++ b/ext/fts5/test/fts5corrupt5.test
@@ -880,6 +880,91 @@ do_catchsql_test 5.4 {
UPDATE t1 SET content=randomblob(500);
} {1 {database disk image is malformed}}
+#-------------------------------------------------------------------------
+reset_db
+do_test 6.0 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+.open --hexdb
+| size 32768 pagesize 4096 filename crash-42fa37b694d45a.db
+| page 1 offset 0
+| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
+| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 07 .....@ ........
+| 96: 00 00 00 00 0d 00 00 00 07 0d d2 00 0f c4 0f 6d ...............m
+| 112: 0f 02 0e ab 0e 4e 0d f6 0d d2 00 00 00 00 00 00 .....N..........
+| 3536: 00 00 22 07 06 17 11 11 01 31 74 61 62 6c 65 74 .........1tablet
+| 3552: 32 74 32 07 43 52 45 41 54 45 20 54 41 42 4c 45 2t2.CREATE TABLE
+| 3568: 20 74 32 28 78 29 56 06 06 17 1f 1f 01 7d 74 61 t2(x)V.......ta
+| 3584: 62 6c 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 blet1_configt1_c
+| 3600: 6f 6e 66 69 67 06 43 52 45 41 54 45 20 54 41 42 onfig.CREATE TAB
+| 3616: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b LE 't1_config'(k
+| 3632: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 PRIMARY KEY, v)
+| 3648: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 05 WITHOUT ROWID[.
+| 3664: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64 ..!!...tablet1_d
+| 3680: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 ocsizet1_docsize
+| 3696: 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 .CREATE TABLE 't
+| 3712: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 1_docsize'(id IN
+| 3728: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 TEGER PRIMARY KE
+| 3744: 59 2c 20 73 7a 20 42 4c 4f 42 29 55 04 06 17 21 Y, sz BLOB)U...!
+| 3760: 21 01 77 74 61 62 6c 65 74 31 5f 63 6f 6e 74 65 !.wtablet1_conte
+| 3776: 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 04 43 52 45 ntt1_content.CRE
+| 3792: 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 6f ATE TABLE 't1_co
+| 3808: 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47 45 ntent'(id INTEGE
+| 3824: 52 20 50 52 49 4d 41 52 49 20 4b 45 59 2c 20 63 R PRIMARI KEY, c
+| 3840: 30 29 69 03 07 17 19 19 01 81 2d 74 61 62 6c 65 0)i.......-table
+| 3856: 74 31 5f 69 64 78 74 31 5f 69 64 78 03 43 52 45 t1_idxt1_idx.CRE
+| 3872: 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 69 64 ATE TABLE 't1_id
+| 3888: 78 27 28 73 65 67 69 64 2c 20 74 65 72 6d 2c 20 x'(segid, term,
+| 3904: 70 67 6e 6f 2c 20 50 52 49 4d 41 52 59 20 4b 45 pgno, PRIMARY KE
+| 3920: 59 28 73 65 67 69 64 2c 20 74 65 72 6d 29 29 20 Y(segid, term))
+| 3936: 57 49 54 48 4f 55 54 20 52 4f 57 49 44 55 02 07 WITHOUT ROWIDU..
+| 3952: 17 1b 1b 01 81 01 74 61 62 6c 65 74 31 5f 64 61 ......tablet1_da
+| 3968: 74 61 74 31 5f 64 61 74 61 02 43 52 45 41 54 45 tat1_data.CREATE
+| 3984: 20 54 41 42 4c 45 20 27 74 31 5f 64 61 74 61 27 TABLE 't1_data'
+| 4000: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d (id INTEGER PRIM
+| 4016: 41 52 b9 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 AR. KEY, block B
+| 4032: 4c 4f 42 29 3a 01 06 17 11 11 08 63 74 61 62 6c LOB):......ctabl
+| 4048: 65 74 31 74 31 43 52 45 41 54 45 20 56 49 52 54 et1t1CREATE VIRT
+| 4064: 55 41 4c 20 54 41 42 4c 45 20 74 31 20 55 53 49 UAL TABLE t1 USI
+| 4080: 4e 47 20 66 74 73 35 28 63 6f 6e 74 65 6e 74 29 NG fts5(content)
+| page 2 offset 4096
+| 0: 0d 00 00 00 03 0f bd 00 0f e8 0f ef 0f bd f0 00 ................
+| 16: 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+| 4016: 00 00 00 00 00 00 00 00 00 00 00 00 00 24 84 80 .............$..
+| 4032: 80 80 80 01 03 00 4e 00 10 00 1e 06 30 61 62 61 ......N.....0aba
+| 4048: 63 6c 01 02 02 04 02 66 74 02 5f 02 04 04 6e 64 cl.....ft._...nd
+| 4064: 6f 6e 02 02 02 04 0a 07 05 01 03 00 10 03 03 0f on..............
+| 4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 11 ...$............
+| page 3 offset 8192
+| 0: 0a 00 00 00 01 0f 00 01 00 00 00 00 00 00 00 00 ................
+| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
+| page 4 offset 12288
+| 0: 0d 00 00 00 03 0f e0 00 0f f6 0f ec 0f e0 00 00 ................
+| 4064: 0a 03 03 00 1b 61 62 61 6e 64 6f 6e 08 02 03 00 .....abandon....
+| 4080: 17 61 62 61 66 74 08 01 03 00 17 61 62 61 63 6b .abaft.....aback
+| page 5 offset 16384
+| 0: 0d 00 00 00 03 0f ee 00 0f fa 0f 00 00 00 00 00 ................
+| 4064: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 03 ................
+| 4080: 03 00 0e 01 04 02 03 00 0e 01 04 01 03 00 0e 01 ................
+| page 6 offset 20480
+| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
+| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
+| page 7 offset 24576
+| 0: 0d 00 00 10 03 0f d6 00 0f 00 00 00 00 00 00 00 ................
+| 4048: 00 00 00 00 00 00 09 03 02 1b 72 65 62 75 69 6c ..........rebuil
+| 4064: 64 11 02 02 2b 69 6e 74 65 67 72 69 74 79 2d 63 d...+integrity-c
+| 4080: 68 65 63 6b 0a 01 02 1d 6f 70 74 69 6d 00 00 00 heck....optim...
+| page 8 offset 28672
+| 0: 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+| end crash-42fa37b694d45a.db
+}]} {}
+
+do_execsql_test 6.1 {
+ INSERT INTO t1(t1,rank) VALUES('secure-delete',1);
+}
+do_catchsql_test 6.2 {
+ UPDATE t1 SET content=randomblob(500) WHERE t1;
+} {1 {constraint failed}}
sqlite3_fts5_may_be_corrupt 0
finish_test
diff --git a/ext/fts5/test/fts5secure8.test b/ext/fts5/test/fts5secure8.test
new file mode 100644
index 000000000..8ceb9630a
--- /dev/null
+++ b/ext/fts5/test/fts5secure8.test
@@ -0,0 +1,51 @@
+# 2023 Nov 23
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#*************************************************************************
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+ifcapable !fts5 { finish_test ; return }
+set ::testprefix fts5secure8
+
+proc sql_repeat {txt n} {
+ string repeat $txt $n
+}
+db func repeat sql_repeat
+
+do_execsql_test 1.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(x);
+
+ INSERT INTO ft(ft, rank) VALUES('pgsz', 64);
+
+ INSERT INTO ft(rowid, x) VALUES(100, 'hello world');
+ INSERT INTO ft(rowid, x) VALUES(200, 'one day');
+
+ BEGIN;
+ INSERT INTO ft(rowid, x) VALUES(45, 'one two three');
+ UPDATE ft SET x = repeat('hello world ', 500) WHERE rowid=100;
+ COMMIT
+}
+
+do_execsql_test 1.1 {
+ INSERT INTO ft(ft, rank) VALUES('secure-delete', 1);
+ DELETE FROM ft WHERE rowid=100;
+}
+
+do_execsql_test 1.2 {
+ PRAGMA integrity_check;
+} {ok}
+
+
+
+
+
+finish_test
+
+
diff --git a/ext/wasm/api/sqlite3-worker1-promiser.c-pp.js b/ext/wasm/api/sqlite3-worker1-promiser.c-pp.js
index bad599673..1f88b713a 100644
--- a/ext/wasm/api/sqlite3-worker1-promiser.c-pp.js
+++ b/ext/wasm/api/sqlite3-worker1-promiser.c-pp.js
@@ -247,9 +247,8 @@ globalThis.sqlite3Worker1Promiser = function callee(config = callee.defaultConfi
globalThis.sqlite3Worker1Promiser.defaultConfig = {
worker: function(){
//#if target=es6-bundler-friendly
- return new Worker("sqlite3-worker1-bundler-friendly.mjs",{
- type: 'module' /* Noting that neither Firefox nor Safari suppor this,
- as of this writing. */
+ return new Worker(new URL("sqlite3-worker1-bundler-friendly.mjs", import.meta.url),{
+ type: 'module'
});
//#else
let theJs = "sqlite3-worker1.js";
@@ -267,8 +266,12 @@ globalThis.sqlite3Worker1Promiser.defaultConfig = {
}
return new Worker(theJs + globalThis.location.search);
//#endif
- }.bind({
+ }
+//#ifnot target=es6-bundler-friendly
+ .bind({
currentScript: globalThis?.document?.currentScript
- }),
+ })
+//#endif
+ ,
onerror: (...args)=>console.error('worker1 promiser error',...args)
};