SQLite

Changes On Branch branch-3.48
Login

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

Changes In Branch branch-3.48 Excluding Merge-Ins

This is equivalent to a diff from d2fe6b05f3 to fddcfbcafd

2025-02-05
12:49
Upstream JimTCL patch and minor tcl script tweaks to support (fconfigure -translation binary) for better cross-platform build portability. (check-in: 0974a17c45 user: stephan tags: trunk)
12:15
Portability tweaks to the code generators so that they produce identical output with JimTCL on Windows and Unix systems (that is: no Windows-style line endings). (Leaf check-in: fddcfbcafd user: stephan tags: branch-3.48)
2025-02-03
17:45
New test case for test/fuzzdata8.db (check-in: 8a882f976e user: drh tags: fuzz-data)
14:44
Fix the build process on Windows so that it generates identical sqlite3.c, sqlite3.h, and shell.c files on Windows and Unix. This patch also includes a change to JS bindings that got caught up in the branch. (check-in: 91ef45fc29 user: drh tags: trunk)
2025-01-31
18:34
Remove an assert() that is not true if a trace-callback is deregistered while there are active statements. (check-in: d53c58243d user: dan tags: branch-3.48)
2025-01-15
14:31
Disable the C-style comment stripper in the JS dist build, as explained in forum post 529c20d344. (check-in: 76ffc70f13 user: stephan tags: branch-3.48)
2025-01-14
16:10
Trying to remove a warning from some compiler that I do not have access to. (check-in: bc6de90c70 user: drh tags: trunk)
12:43
Version 3.48.0 for the reuse-schema branch. (check-in: 1a031a536b user: drh tags: reuse-schema)
12:21
Version 3.48.0 for the wal2 branch. (check-in: ef970ef037 user: drh tags: wal2)
12:15
Version 3.48.0 for the begin-concurrent branch. (check-in: 56d110b636 user: drh tags: begin-concurrent)
11:05
Version 3.48.0 (check-in: d2fe6b05f3 user: drh tags: trunk, release, major-release, version-3.48.0)
2025-01-13
13:32
Remove a stray tab character from a comment. (check-in: 315079b150 user: drh tags: trunk)

Changes to Makefile.in.
331
332
333
334
335
336
337

338
#
# tool/version-info: a utility for emitting sqlite3 version info
# in various forms.
#
version-info$(T.exe): $(TOP)/tool/version-info.c Makefile sqlite3.h
	$(T.link) $(ST_OPT) -o $@ $(TOP)/tool/version-info.c


include $(TOP)/main.mk







>

331
332
333
334
335
336
337
338
339
#
# tool/version-info: a utility for emitting sqlite3 version info
# in various forms.
#
version-info$(T.exe): $(TOP)/tool/version-info.c Makefile sqlite3.h
	$(T.link) $(ST_OPT) -o $@ $(TOP)/tool/version-info.c

IS_CROSS_COMPILING = @IS_CROSS_COMPILING@
include $(TOP)/main.mk
Changes to Makefile.msc.
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
parse.c:	$(TOP)\src\parse.y lemon.exe
	del /Q parse.y parse.h parse.h.temp 2>NUL
	copy /Y $(TOP)\src\parse.y .
	copy /B parse.y +,,
	.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) -S parse.y

$(SQLITE3H):	$(TOP)\src\sqlite.h.in $(TOP)\manifest mksourceid.exe $(TOP)\VERSION $(JIM_TCLSH)
	$(JIM_TCLSH) $(TOP)\tool\mksqlite3h.tcl "$(TOP:\=/)" > $(SQLITE3H) $(MKSQLITE3H_ARGS)

sqlite3ext.h:	.target_source
!IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0
	type tsrc\sqlite3ext.h | $(TCLSH_CMD) $(TOP)\tool\replace.tcl regsub "\(\*\)" "(SQLITE_CALLBACK *)" \
		| $(TCLSH_CMD) $(TOP)\tool\replace.tcl regsub "\(\*" "(SQLITE_APICALL *" > sqlite3ext.h
	copy /Y sqlite3ext.h tsrc\sqlite3ext.h
!ELSE







|







2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
parse.c:	$(TOP)\src\parse.y lemon.exe
	del /Q parse.y parse.h parse.h.temp 2>NUL
	copy /Y $(TOP)\src\parse.y .
	copy /B parse.y +,,
	.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) -S parse.y

$(SQLITE3H):	$(TOP)\src\sqlite.h.in $(TOP)\manifest mksourceid.exe $(TOP)\VERSION $(JIM_TCLSH)
	$(JIM_TCLSH) $(TOP)\tool\mksqlite3h.tcl "$(TOP:\=/)" -o $(SQLITE3H) $(MKSQLITE3H_ARGS)

sqlite3ext.h:	.target_source
!IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0
	type tsrc\sqlite3ext.h | $(TCLSH_CMD) $(TOP)\tool\replace.tcl regsub "\(\*\)" "(SQLITE_CALLBACK *)" \
		| $(TCLSH_CMD) $(TOP)\tool\replace.tcl regsub "\(\*" "(SQLITE_APICALL *" > sqlite3ext.h
	copy /Y sqlite3ext.h tsrc\sqlite3ext.h
!ELSE
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
#
!IF $(USE_ZLIB)!=0
SHELL_DEP = $(SHELL_DEP) $(TOP)\ext\misc\sqlar.c
SHELL_DEP = $(SHELL_DEP) $(TOP)\ext\misc\zipfile.c
!ENDIF

shell.c:	$(SHELL_DEP) $(TOP)\tool\mkshellc.tcl $(JIM_TCLSH)
	$(JIM_TCLSH) $(TOP)\tool\mkshellc.tcl > shell.c

zlib:
	pushd $(ZLIBDIR) && $(MAKE) /f win32\Makefile.msc clean $(ZLIBLIB) && popd

# Rules to build the extension objects.
#
icu.lo:	$(TOP)\ext\icu\icu.c $(HDR) $(EXTHDR)







|







2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
#
!IF $(USE_ZLIB)!=0
SHELL_DEP = $(SHELL_DEP) $(TOP)\ext\misc\sqlar.c
SHELL_DEP = $(SHELL_DEP) $(TOP)\ext\misc\zipfile.c
!ENDIF

shell.c:	$(SHELL_DEP) $(TOP)\tool\mkshellc.tcl $(JIM_TCLSH)
	$(JIM_TCLSH) $(TOP)\tool\mkshellc.tcl shell.c

zlib:
	pushd $(ZLIBDIR) && $(MAKE) /f win32\Makefile.msc clean $(ZLIBLIB) && popd

# Rules to build the extension objects.
#
icu.lo:	$(TOP)\ext\icu\icu.c $(HDR) $(EXTHDR)
2807
2808
2809
2810
2811
2812
2813
2814

2815
2816
2817
2818
2819
2820
2821

moreclean:	clean
	del /Q $(SQLITE3C) $(SQLITE3H) 2>NUL
# <</mark>>

clean:
	del /Q *.exp *.lo *.ilk *.lib *.obj *.ncb *.pdb *.sdf *.suo 2>NUL
	del /Q *.bsc *.def *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL

	del /Q $(SQLITE3EXE) $(SQLITE3DLL) Replace.exe 2>NUL
# <<mark>>
	del /Q $(SQLITE3TCLDLL) pkgIndex.tcl 2>NUL
	del /Q opcodes.c opcodes.h 2>NUL
	del /Q lemon.* lempar.c parse.* 2>NUL
	del /Q mksourceid.* mkkeywordhash.* keywordhash.h 2>NUL
	del /Q notasharedlib.* 2>NUL







|
>







2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822

moreclean:	clean
	del /Q $(SQLITE3C) $(SQLITE3H) 2>NUL
# <</mark>>

clean:
	del /Q *.exp *.lo *.ilk *.lib *.obj *.ncb *.pdb *.sdf *.suo 2>NUL
	del /Q *.bsc *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL
	del /Q sqlite3.def tclsqlite3.def 2>NUL
	del /Q $(SQLITE3EXE) $(SQLITE3DLL) Replace.exe 2>NUL
# <<mark>>
	del /Q $(SQLITE3TCLDLL) pkgIndex.tcl 2>NUL
	del /Q opcodes.c opcodes.h 2>NUL
	del /Q lemon.* lempar.c parse.* 2>NUL
	del /Q mksourceid.* mkkeywordhash.* keywordhash.h 2>NUL
	del /Q notasharedlib.* 2>NUL
Changes to VERSION.
1
3.48.0
|
1
3.48.1
Changes to auto.def.
321
322
323
324
325
326
327








328

329

330
331
332
333
334
335
336
337


338
339
340
341
342
343
344
########################################################################
# We differentiate between two C compilers: the one used for binaries
# which are to run on the build system (in autosetup it's called
# CC_FOR_BUILD and in Makefile.in it's $(B.cc)) and the one used for
# compiling binaries for the target system (CC a.k.a. $(T.cc)).
# Normally they're the same, but they will differ when
# cross-compiling.








define CFLAGS [proj-get-env CFLAGS {-g -O2}]

define BUILD_CFLAGS [proj-get-env BUILD_CFLAGS {-g}]


proj-if-opt-truthy dev {
  # --enable-dev needs to come early so that the downstream tests
  # which check for the following flags use their updated state.
  proj-opt-set all 1
  proj-opt-set debug 1
  proj-opt-set amalgamation 0
  define CFLAGS [get-env CFLAGS {-O0 -g}]


}

########################################################################
# Handle --with-wasi-sdk=DIR
#
# This must be run relatively early on because it may change the
# toolchain and disable a number of config options.







>
>
>
>
>
>
>
>
|
>

>








>
>







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
########################################################################
# We differentiate between two C compilers: the one used for binaries
# which are to run on the build system (in autosetup it's called
# CC_FOR_BUILD and in Makefile.in it's $(B.cc)) and the one used for
# compiling binaries for the target system (CC a.k.a. $(T.cc)).
# Normally they're the same, but they will differ when
# cross-compiling.
#
# When cross-compiling we default to not using the -g flag, based on a
# /chat discussion prompted by
# https://sqlite.org/forum/forumpost/9a67df63eda9925c
set defaultCFlags {-O2}
if {!$isCrossCompiling} {
  lappend defaultCFlags -g
}
define CFLAGS [proj-get-env CFLAGS $defaultCFlags]
# BUILD_CFLAGS is the CFLAGS for CC_FOR_BUILD.
define BUILD_CFLAGS [proj-get-env BUILD_CFLAGS {-g}]
unset defaultCFlags

proj-if-opt-truthy dev {
  # --enable-dev needs to come early so that the downstream tests
  # which check for the following flags use their updated state.
  proj-opt-set all 1
  proj-opt-set debug 1
  proj-opt-set amalgamation 0
  define CFLAGS [get-env CFLAGS {-O0 -g}]
  # -------------^^^^^^^ intentionally using [get-env] instead of
  # [proj-get-env] here.
}

########################################################################
# Handle --with-wasi-sdk=DIR
#
# This must be run relatively early on because it may change the
# toolchain and disable a number of config options.
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
    # and this project has no direct use for soname, so default to
    # none. Package maintainers, on the other hand, like to have an
    # soname.
    set soname none
  }
  switch -exact -- $soname {
    none - "" { return 0 }
    auto      { set soname libsqlite3.so.3 }
    legacy    { set soname libsqlite3.so.0 }
    default {
      if {[string match libsqlite3.* $soname]} {
        # use it as-is
      } else {
        # Assume it's a suffix
        set soname "libsqlite3.so.${soname}"







<







483
484
485
486
487
488
489

490
491
492
493
494
495
496
    # and this project has no direct use for soname, so default to
    # none. Package maintainers, on the other hand, like to have an
    # soname.
    set soname none
  }
  switch -exact -- $soname {
    none - "" { return 0 }

    legacy    { set soname libsqlite3.so.0 }
    default {
      if {[string match libsqlite3.* $soname]} {
        # use it as-is
      } else {
        # Assume it's a suffix
        set soname "libsqlite3.so.${soname}"
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
    msg-debug "sqlite-check-tcl: with_tclsh=${with_tclsh}"
  }

  set doConfigLookup 1 ; # set to 0 to test the tclConfig.sh-not-found cases
  if {"" ne $with_tclsh} {
    # --with-tclsh was provided or found above. Validate it and use it
    # to trump any value passed via --with-tcl=DIR.
    if {![file isfile $with_tclsh]} {
      proj-fatal "TCL shell $with_tclsh is not a file"
    } elseif {![file-isexec $with_tclsh]} {
      proj-fatal "TCL shell $with_tclsh is not executable"
    } else {
      define TCLSH_CMD $with_tclsh
      #msg-result "Using tclsh: $with_tclsh"
    }
    if {$doConfigLookup &&
        [catch {exec $with_tclsh $srcdir/tool/find_tclconfig.tcl} result] == 0} {







<
<
|







611
612
613
614
615
616
617


618
619
620
621
622
623
624
625
    msg-debug "sqlite-check-tcl: with_tclsh=${with_tclsh}"
  }

  set doConfigLookup 1 ; # set to 0 to test the tclConfig.sh-not-found cases
  if {"" ne $with_tclsh} {
    # --with-tclsh was provided or found above. Validate it and use it
    # to trump any value passed via --with-tcl=DIR.


    if {![file-isexec $with_tclsh]} {
      proj-fatal "TCL shell $with_tclsh is not executable"
    } else {
      define TCLSH_CMD $with_tclsh
      #msg-result "Using tclsh: $with_tclsh"
    }
    if {$doConfigLookup &&
        [catch {exec $with_tclsh $srcdir/tool/find_tclconfig.tcl} result] == 0} {
666
667
668
669
670
671
672
673


674
675
676
677
678
679
680
    msg-result "Using tclConfig.sh: $cfg"
    break
  }
  define TCL_CONFIG_SH $cfg
  # Export a subset of tclConfig.sh to the current TCL-space.  If $cfg
  # is an empty string, this emits empty-string entries for the
  # various options we're interested in.
  eval [exec "${srcdir}/tool/tclConfigShToAutoDef.sh" "$cfg"]



  if {"" eq $with_tclsh && $cfg ne ""} {
    # We have tclConfig.sh but no tclsh. Attempt to locate a tclsh
    # based on info from tclConfig.sh.
    proj-assert {"" ne [get-define TCL_EXEC_PREFIX]}
    set with_tclsh [get-define TCL_EXEC_PREFIX]/bin/tclsh[get-define TCL_VERSION]
    if {![file-isexec $with_tclsh]} {







|
>
>







675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
    msg-result "Using tclConfig.sh: $cfg"
    break
  }
  define TCL_CONFIG_SH $cfg
  # Export a subset of tclConfig.sh to the current TCL-space.  If $cfg
  # is an empty string, this emits empty-string entries for the
  # various options we're interested in.
  eval [exec sh "$srcdir/tool/tclConfigShToAutoDef.sh" "$cfg"]
  # ---------^^ a Windows/msys workaround, without which it cannot
  # exec a .sh file: https://sqlite.org/forum/forumpost/befb352a42a7cd6d

  if {"" eq $with_tclsh && $cfg ne ""} {
    # We have tclConfig.sh but no tclsh. Attempt to locate a tclsh
    # based on info from tclConfig.sh.
    proj-assert {"" ne [get-define TCL_EXEC_PREFIX]}
    set with_tclsh [get-define TCL_EXEC_PREFIX]/bin/tclsh[get-define TCL_VERSION]
    if {![file-isexec $with_tclsh]} {
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
  if {[proj-opt-truthy $boolFlag]} {
    msg-result "  + $boolFlag"
  } else {
    sqlite-add-feature-flag $featureFlag
    msg-result "  - $boolFlag"
  }
}




















#########################################################################
# Show the final feature flag sets:

apply {{} {
  set oFF [get-define OPT_FEATURE_FLAGS]
  if {"" ne $oFF} {
    define OPT_FEATURE_FLAGS [lsort -unique $oFF]
    msg-result "Library feature flags: [get-define OPT_FEATURE_FLAGS]"
  }
  set oFF [get-define OPT_SHELL]
  if {"" ne $oFF} {
    define OPT_SHELL [lsort -unique $oFF]
    msg-result "Shell options: [get-define OPT_SHELL]"
  }
  unset oFF
}}






########################################################################
# "Re-export" the autoconf-conventional --XYZdir flags into something
# which is more easily overridable from a make invocation. See the docs
# for [proj-remap-autoconf-dir-vars] for the explanation of why.
#
# We do this late in the config process, immediately before we export








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

|
>











<

>
>
>
>
>







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
  if {[proj-opt-truthy $boolFlag]} {
    msg-result "  + $boolFlag"
  } else {
    sqlite-add-feature-flag $featureFlag
    msg-result "  - $boolFlag"
  }
}

########################################################################
# Copy all CFLAGS entries matching -DSQLITE_OMIT* and
# -DSQLITE_ENABLE* to OPT_FEATURE_FLAGS. This behavior is derived
# from the legacy build and was missing the 3.48.0 release (the
# initial Autosetup port).
# https://sqlite.org/forum/forumpost/9801e54665afd728
#
# If any configure flags for features are in conflict with
# CFLAGS-specified feature flags, all bets are off.  There are no
# guarantees about which one will take precedence.
foreach cf [get-define CFLAGS ""] {
  switch -glob -- $cf {
    -DSQLITE_OMIT* -
    -DSQLITE_ENABLE* {
      sqlite-add-feature-flag $cf
    }
  }
}

#########################################################################
# Remove duplicates from the final feature flag sets and show them to
# the user:
apply {{} {
  set oFF [get-define OPT_FEATURE_FLAGS]
  if {"" ne $oFF} {
    define OPT_FEATURE_FLAGS [lsort -unique $oFF]
    msg-result "Library feature flags: [get-define OPT_FEATURE_FLAGS]"
  }
  set oFF [get-define OPT_SHELL]
  if {"" ne $oFF} {
    define OPT_SHELL [lsort -unique $oFF]
    msg-result "Shell options: [get-define OPT_SHELL]"
  }

}}

########################################################################
# When cross-compiling, we have to avoid using the -s flag to
# /usr/bin/install: https://sqlite.org/forum/forumpost/9a67df63eda9925c
define IS_CROSS_COMPILING $isCrossCompiling

########################################################################
# "Re-export" the autoconf-conventional --XYZdir flags into something
# which is more easily overridable from a make invocation. See the docs
# for [proj-remap-autoconf-dir-vars] for the explanation of why.
#
# We do this late in the config process, immediately before we export
Changes to autoconf/Makefile.msc.
1083
1084
1085
1086
1087
1088
1089
1090

1091
	echo #endif >> sqlite3rc.h
	$(LTRCOMPILE) -fo $(LIBRESOBJS) -DRC_VERONLY $(TOP)\sqlite3.rc
!ENDIF


clean:
	del /Q *.exp *.lo *.ilk *.lib *.obj *.ncb *.pdb *.sdf *.suo 2>NUL
	del /Q *.bsc *.def *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL

	del /Q $(SQLITE3EXE) $(SQLITE3DLL) Replace.exe 2>NUL







|
>

1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
	echo #endif >> sqlite3rc.h
	$(LTRCOMPILE) -fo $(LIBRESOBJS) -DRC_VERONLY $(TOP)\sqlite3.rc
!ENDIF


clean:
	del /Q *.exp *.lo *.ilk *.lib *.obj *.ncb *.pdb *.sdf *.suo 2>NUL
	del /Q *.bsc *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL
	del /Q sqlite3.def tclsqlite3.def 2>NUL
	del /Q $(SQLITE3EXE) $(SQLITE3DLL) Replace.exe 2>NUL
Changes to autoconf/tea/configure.ac.
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION
# set as provided.  These will also be added as -D defs in your Makefile
# so you can encode the package version directly into the source files.
# This will also define a special symbol for Windows (BUILD_<PACKAGE_NAME>
# so that we create the export library with the dll.
#-----------------------------------------------------------------------

AC_INIT([sqlite],[3.48.0])

#--------------------------------------------------------------------
# Call TEA_INIT as the first TEA_ macro to set up initial vars.
# This will define a ${TEA_PLATFORM} variable == "unix" or "windows"
# as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE.
#--------------------------------------------------------------------








|







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION
# set as provided.  These will also be added as -D defs in your Makefile
# so you can encode the package version directly into the source files.
# This will also define a special symbol for Windows (BUILD_<PACKAGE_NAME>
# so that we create the export library with the dll.
#-----------------------------------------------------------------------

AC_INIT([sqlite],[3.48.1])

#--------------------------------------------------------------------
# Call TEA_INIT as the first TEA_ macro to set up initial vars.
# This will define a ${TEA_PLATFORM} variable == "unix" or "windows"
# as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE.
#--------------------------------------------------------------------

Changes to autosetup/jimsh0.c.
71
72
73
74
75
76
77



78
79
80
81
82
83
84
#ifdef __cplusplus
extern "C" {
#endif


#if defined(_WIN32) || defined(WIN32)




#define HAVE_DLOPEN
void *dlopen(const char *path, int mode);
int dlclose(void *handle);
void *dlsym(void *handle, const char *symbol);
char *dlerror(void);









>
>
>







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#ifdef __cplusplus
extern "C" {
#endif


#if defined(_WIN32) || defined(WIN32)

#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#endif
#define HAVE_DLOPEN
void *dlopen(const char *path, int mode);
int dlclose(void *handle);
void *dlsym(void *handle, const char *symbol);
char *dlerror(void);


1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
"				-bl* {\n"
"					$f ndelay $(!$v)\n"
"				}\n"
"				-bu* {\n"
"					$f buffering $v\n"
"				}\n"
"				-tr* {\n"
"\n"
"				}\n"
"				default {\n"
"					return -code error \"fconfigure: unknown option $n\"\n"
"				}\n"
"			}\n"
"		}\n"
"	}\n"







|







1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
"				-bl* {\n"
"					$f ndelay $(!$v)\n"
"				}\n"
"				-bu* {\n"
"					$f buffering $v\n"
"				}\n"
"				-tr* {\n"
"					$f translation $v\n"
"				}\n"
"				default {\n"
"					return -code error \"fconfigure: unknown option $n\"\n"
"				}\n"
"			}\n"
"		}\n"
"	}\n"
2931
2932
2933
2934
2935
2936
2937






















2938
2939
2940
2941
2942
2943
2944
    if (af->wbuft == WBUF_OPT_FULL) {
        Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, af->wbuf_limit));
    }
    Jim_SetResult(interp, resultObj);

    return JIM_OK;
}























static int aio_cmd_readsize(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    AioFile *af = Jim_CmdPrivData(interp);

    if (argc) {
        long l;







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







2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
    if (af->wbuft == WBUF_OPT_FULL) {
        Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, af->wbuf_limit));
    }
    Jim_SetResult(interp, resultObj);

    return JIM_OK;
}

static int aio_cmd_translation(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
	enum {OPT_BINARY, OPT_TEXT};
    static const char * const options[] = {
        "binary",
        "text",
        NULL
    };
	int opt;

	if (Jim_GetEnum(interp, argv[0], options, &opt, NULL, JIM_ERRMSG) != JIM_OK) {
		return JIM_ERR;
	}
#if defined(_setmode) && defined(O_BINARY)
	else {
		AioFile *af = Jim_CmdPrivData(interp);
		_setmode(af->fh, opt == OPT_BINARY ? O_BINARY : O_TEXT);
	}
#endif
    return JIM_OK;
}

static int aio_cmd_readsize(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    AioFile *af = Jim_CmdPrivData(interp);

    if (argc) {
        long l;
3141
3142
3143
3144
3145
3146
3147







3148
3149
3150
3151
3152
3153
3154
#endif
    {   "buffering",
        "?none|line|full? ?size?",
        aio_cmd_buffering,
        0,
        2,








    },
    {   "readsize",
        "?size?",
        aio_cmd_readsize,
        0,
        1,








>
>
>
>
>
>
>







3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
#endif
    {   "buffering",
        "?none|line|full? ?size?",
        aio_cmd_buffering,
        0,
        2,

    },
    {   "translation",
        "binary|text",
        aio_cmd_translation,
        1,
        1,

    },
    {   "readsize",
        "?size?",
        aio_cmd_readsize,
        0,
        1,

24338
24339
24340
24341
24342
24343
24344




24345
24346
24347
24348
24349
24350
24351
}

#include <stdio.h>
#include <stdlib.h>
#include <string.h>







extern int Jim_initjimshInit(Jim_Interp *interp);

static void JimSetArgv(Jim_Interp *interp, int argc, char *const argv[])
{
    int n;
    Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);







>
>
>
>







24370
24371
24372
24373
24374
24375
24376
24377
24378
24379
24380
24381
24382
24383
24384
24385
24386
24387
}

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif


extern int Jim_initjimshInit(Jim_Interp *interp);

static void JimSetArgv(Jim_Interp *interp, int argc, char *const argv[])
{
    int n;
    Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
24421
24422
24423
24424
24425
24426
24427




24428
24429
24430
24431
24432
24433
24434
    if (argc == 1) {

        if (retcode == JIM_ERR) {
            JimPrintErrorMessage(interp);
        }
        if (retcode != JIM_EXIT) {
            JimSetArgv(interp, 0, NULL);




            retcode = Jim_InteractivePrompt(interp);
        }
    }
    else {

        if (argc > 2 && strcmp(argv[1], "-e") == 0) {








>
>
>
>







24457
24458
24459
24460
24461
24462
24463
24464
24465
24466
24467
24468
24469
24470
24471
24472
24473
24474
    if (argc == 1) {

        if (retcode == JIM_ERR) {
            JimPrintErrorMessage(interp);
        }
        if (retcode != JIM_EXIT) {
            JimSetArgv(interp, 0, NULL);
            if (!isatty(STDIN_FILENO)) {

                goto eval_stdin;
            }
            retcode = Jim_InteractivePrompt(interp);
        }
    }
    else {

        if (argc > 2 && strcmp(argv[1], "-e") == 0) {

24443
24444
24445
24446
24447
24448
24449

24450
24451
24452
24453
24454
24455
24456
                putchar('\n');
            }
        }
        else {
            Jim_SetVariableStr(interp, "argv0", Jim_NewStringObj(interp, argv[1], -1));
            JimSetArgv(interp, argc - 2, argv + 2);
            if (strcmp(argv[1], "-") == 0) {

                retcode = Jim_Eval(interp, "eval [info source [stdin read] stdin 1]");
            } else {
                retcode = Jim_EvalFile(interp, argv[1]);
            }
        }
        if (retcode == JIM_ERR) {
            JimPrintErrorMessage(interp);







>







24483
24484
24485
24486
24487
24488
24489
24490
24491
24492
24493
24494
24495
24496
24497
                putchar('\n');
            }
        }
        else {
            Jim_SetVariableStr(interp, "argv0", Jim_NewStringObj(interp, argv[1], -1));
            JimSetArgv(interp, argc - 2, argv + 2);
            if (strcmp(argv[1], "-") == 0) {
eval_stdin:
                retcode = Jim_Eval(interp, "eval [info source [stdin read] stdin 1]");
            } else {
                retcode = Jim_EvalFile(interp, argv[1]);
            }
        }
        if (retcode == JIM_ERR) {
            JimPrintErrorMessage(interp);
Changes to ext/fts5/fts5_index.c.
774
775
776
777
778
779
780
781
782

783
784
785

786
787
788
789
790
791
792
  fts5GetVarint32(&pLeaf->p[pLeaf->szLeaf], ret);
  return ret;
}

/*
** Close the read-only blob handle, if it is open.
*/
void sqlite3Fts5IndexCloseReader(Fts5Index *p){
  if( p->pReader ){

    sqlite3_blob *pReader = p->pReader;
    p->pReader = 0;
    sqlite3_blob_close(pReader);

  }
}

/*
** Retrieve a record from the %_data table.
**
** If an error occurs, NULL is returned and an error left in the 







|

>


|
>







774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
  fts5GetVarint32(&pLeaf->p[pLeaf->szLeaf], ret);
  return ret;
}

/*
** Close the read-only blob handle, if it is open.
*/
static void fts5IndexCloseReader(Fts5Index *p){
  if( p->pReader ){
    int rc;
    sqlite3_blob *pReader = p->pReader;
    p->pReader = 0;
    rc = sqlite3_blob_close(pReader);
    if( p->rc==SQLITE_OK ) p->rc = rc;
  }
}

/*
** Retrieve a record from the %_data table.
**
** If an error occurs, NULL is returned and an error left in the 
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
      ** is required.  */
      sqlite3_blob *pBlob = p->pReader;
      p->pReader = 0;
      rc = sqlite3_blob_reopen(pBlob, iRowid);
      assert( p->pReader==0 );
      p->pReader = pBlob;
      if( rc!=SQLITE_OK ){
        sqlite3Fts5IndexCloseReader(p);
      }
      if( rc==SQLITE_ABORT ) rc = SQLITE_OK;
    }

    /* If the blob handle is not open at this point, open it and seek 
    ** to the requested entry.  */
    if( p->pReader==0 && rc==SQLITE_OK ){







|







805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
      ** is required.  */
      sqlite3_blob *pBlob = p->pReader;
      p->pReader = 0;
      rc = sqlite3_blob_reopen(pBlob, iRowid);
      assert( p->pReader==0 );
      p->pReader = pBlob;
      if( rc!=SQLITE_OK ){
        fts5IndexCloseReader(p);
      }
      if( rc==SQLITE_ABORT ) rc = SQLITE_OK;
    }

    /* If the blob handle is not open at this point, open it and seek 
    ** to the requested entry.  */
    if( p->pReader==0 && rc==SQLITE_OK ){
5004
5005
5006
5007
5008
5009
5010








5011
5012
5013
5014
5015
5016
5017
}

static int fts5IndexReturn(Fts5Index *p){
  int rc = p->rc;
  p->rc = SQLITE_OK;
  return rc;
}









typedef struct Fts5FlushCtx Fts5FlushCtx;
struct Fts5FlushCtx {
  Fts5Index *pIdx;
  Fts5SegWriter writer; 
};








>
>
>
>
>
>
>
>







5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
}

static int fts5IndexReturn(Fts5Index *p){
  int rc = p->rc;
  p->rc = SQLITE_OK;
  return rc;
}

/*
** Close the read-only blob handle, if it is open.
*/
void sqlite3Fts5IndexCloseReader(Fts5Index *p){
  fts5IndexCloseReader(p);
  fts5IndexReturn(p);
}

typedef struct Fts5FlushCtx Fts5FlushCtx;
struct Fts5FlushCtx {
  Fts5Index *pIdx;
  Fts5SegWriter writer; 
};

6726
6727
6728
6729
6730
6731
6732
6733
6734
6735
6736
6737
6738
6739
6740
6741
6742
6743
6744
6745
6746
6747
6748
6749
6750
6751
6752
6753
6754
6755

/*
** Commit data to disk.
*/
int sqlite3Fts5IndexSync(Fts5Index *p){
  assert( p->rc==SQLITE_OK );
  fts5IndexFlush(p);
  sqlite3Fts5IndexCloseReader(p);
  return fts5IndexReturn(p);
}

/*
** Discard any data stored in the in-memory hash tables. Do not write it
** to the database. Additionally, assume that the contents of the %_data
** table may have changed on disk. So any in-memory caches of %_data 
** records must be invalidated.
*/
int sqlite3Fts5IndexRollback(Fts5Index *p){
  sqlite3Fts5IndexCloseReader(p);
  fts5IndexDiscardData(p);
  fts5StructureInvalidate(p);
  /* assert( p->rc==SQLITE_OK ); */
  return SQLITE_OK;
}

/*
** The %_data table is completely empty when this function is called. This
** function populates it with the initial structure objects for each index,
** and the initial version of the "averages" record (a zero-byte blob).
*/







|










|


<
|







6736
6737
6738
6739
6740
6741
6742
6743
6744
6745
6746
6747
6748
6749
6750
6751
6752
6753
6754
6755
6756

6757
6758
6759
6760
6761
6762
6763
6764

/*
** Commit data to disk.
*/
int sqlite3Fts5IndexSync(Fts5Index *p){
  assert( p->rc==SQLITE_OK );
  fts5IndexFlush(p);
  fts5IndexCloseReader(p);
  return fts5IndexReturn(p);
}

/*
** Discard any data stored in the in-memory hash tables. Do not write it
** to the database. Additionally, assume that the contents of the %_data
** table may have changed on disk. So any in-memory caches of %_data 
** records must be invalidated.
*/
int sqlite3Fts5IndexRollback(Fts5Index *p){
  fts5IndexCloseReader(p);
  fts5IndexDiscardData(p);
  fts5StructureInvalidate(p);

  return fts5IndexReturn(p);
}

/*
** The %_data table is completely empty when this function is called. This
** function populates it with the initial structure objects for each index,
** and the initial version of the "averages" record (a zero-byte blob).
*/
6941
6942
6943
6944
6945
6946
6947










6948
6949
6950
6951
6952
6953
6954
/*
** Ensure the segment-iterator passed as the only argument points to EOF.
*/
static void fts5SegIterSetEOF(Fts5SegIter *pSeg){
  fts5DataRelease(pSeg->pLeaf);
  pSeg->pLeaf = 0;
}











/*
** This function appends iterator pAppend to Fts5TokenDataIter pIn and 
** returns the result.
*/
static Fts5TokenDataIter *fts5AppendTokendataIter(
  Fts5Index *p,                   /* Index object (for error code) */







>
>
>
>
>
>
>
>
>
>







6950
6951
6952
6953
6954
6955
6956
6957
6958
6959
6960
6961
6962
6963
6964
6965
6966
6967
6968
6969
6970
6971
6972
6973
/*
** Ensure the segment-iterator passed as the only argument points to EOF.
*/
static void fts5SegIterSetEOF(Fts5SegIter *pSeg){
  fts5DataRelease(pSeg->pLeaf);
  pSeg->pLeaf = 0;
}

static void fts5IterClose(Fts5IndexIter *pIndexIter){
  if( pIndexIter ){
    Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
    Fts5Index *pIndex = pIter->pIndex;
    fts5TokendataIterDelete(pIter->pTokenDataIter);
    fts5MultiIterFree(pIter);
    fts5IndexCloseReader(pIndex);
  }
}

/*
** This function appends iterator pAppend to Fts5TokenDataIter pIn and 
** returns the result.
*/
static Fts5TokenDataIter *fts5AppendTokendataIter(
  Fts5Index *p,                   /* Index object (for error code) */
6969
6970
6971
6972
6973
6974
6975
6976
6977
6978
6979
6980
6981
6982
6983
        if( pIn==0 ) memset(pNew, 0, nByte);
        pRet = pNew;
        pNew->nIterAlloc = nAlloc;
      }
    }
  }
  if( p->rc ){
    sqlite3Fts5IterClose((Fts5IndexIter*)pAppend);
  }else{
    pRet->apIter[pRet->nIter++] = pAppend;
  }
  assert( pRet==0 || pRet->nIter<=pRet->nIterAlloc );

  return pRet;
}







|







6988
6989
6990
6991
6992
6993
6994
6995
6996
6997
6998
6999
7000
7001
7002
        if( pIn==0 ) memset(pNew, 0, nByte);
        pRet = pNew;
        pNew->nIterAlloc = nAlloc;
      }
    }
  }
  if( p->rc ){
    fts5IterClose((Fts5IndexIter*)pAppend);
  }else{
    pRet->apIter[pRet->nIter++] = pAppend;
  }
  assert( pRet==0 || pRet->nIter<=pRet->nIterAlloc );

  return pRet;
}
7182
7183
7184
7185
7186
7187
7188
7189
7190
7191
7192
7193
7194
7195
7196
    if( pSmall ){
      fts5BufferSet(&p->rc, &bSeek, pSmall->n, pSmall->p);
      fts5BufferAppendBlob(&p->rc, &bSeek, 1, (const u8*)"\0");
    }else{
      fts5BufferSet(&p->rc, &bSeek, nToken, pToken);
    }
    if( p->rc ){
      sqlite3Fts5IterClose((Fts5IndexIter*)pNew);
      break;
    }

    pNewIter = &pNew->aSeg[0];
    pPrevIter = (pPrev ? &pPrev->aSeg[0] : 0);
    for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
      for(iSeg=pStruct->aLevel[iLvl].nSeg-1; iSeg>=0; iSeg--){







|







7201
7202
7203
7204
7205
7206
7207
7208
7209
7210
7211
7212
7213
7214
7215
    if( pSmall ){
      fts5BufferSet(&p->rc, &bSeek, pSmall->n, pSmall->p);
      fts5BufferAppendBlob(&p->rc, &bSeek, 1, (const u8*)"\0");
    }else{
      fts5BufferSet(&p->rc, &bSeek, nToken, pToken);
    }
    if( p->rc ){
      fts5IterClose((Fts5IndexIter*)pNew);
      break;
    }

    pNewIter = &pNew->aSeg[0];
    pPrevIter = (pPrev ? &pPrev->aSeg[0] : 0);
    for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
      for(iSeg=pStruct->aLevel[iLvl].nSeg-1; iSeg>=0; iSeg--){
7247
7248
7249
7250
7251
7252
7253
7254
7255
7256
7257
7258
7259
7260
7261
      }
    }

    /* If pSmall is still NULL at this point, then the new iterator does
    ** not point to any terms that match the query. So delete it and break
    ** out of the loop - all required iterators have been collected.  */
    if( pSmall==0 ){
      sqlite3Fts5IterClose((Fts5IndexIter*)pNew);
      break;
    }

    /* Append this iterator to the set and continue. */
    pSet = fts5AppendTokendataIter(p, pSet, pNew);
  }








|







7266
7267
7268
7269
7270
7271
7272
7273
7274
7275
7276
7277
7278
7279
7280
      }
    }

    /* If pSmall is still NULL at this point, then the new iterator does
    ** not point to any terms that match the query. So delete it and break
    ** out of the loop - all required iterators have been collected.  */
    if( pSmall==0 ){
      fts5IterClose((Fts5IndexIter*)pNew);
      break;
    }

    /* Append this iterator to the set and continue. */
    pSet = fts5AppendTokendataIter(p, pSet, pNew);
  }

7376
7377
7378
7379
7380
7381
7382
7383
7384
7385
7386
7387
7388
7389
7390
7391
7392
          Fts5SegIter *pSeg = &pRet->aSeg[pRet->aFirst[1].iFirst];
          if( pSeg->pLeaf ) pRet->xSetOutputs(pRet, pSeg);
        }
      }
    }

    if( p->rc ){
      sqlite3Fts5IterClose((Fts5IndexIter*)pRet);
      pRet = 0;
      sqlite3Fts5IndexCloseReader(p);
    }

    *ppIter = (Fts5IndexIter*)pRet;
    sqlite3Fts5BufferFree(&buf);
  }
  return fts5IndexReturn(p);
}







|

|







7395
7396
7397
7398
7399
7400
7401
7402
7403
7404
7405
7406
7407
7408
7409
7410
7411
          Fts5SegIter *pSeg = &pRet->aSeg[pRet->aFirst[1].iFirst];
          if( pSeg->pLeaf ) pRet->xSetOutputs(pRet, pSeg);
        }
      }
    }

    if( p->rc ){
      fts5IterClose((Fts5IndexIter*)pRet);
      pRet = 0;
      fts5IndexCloseReader(p);
    }

    *ppIter = (Fts5IndexIter*)pRet;
    sqlite3Fts5BufferFree(&buf);
  }
  return fts5IndexReturn(p);
}
7628
7629
7630
7631
7632
7633
7634
7635
7636
7637
7638
7639
7640
7641
7642
7643
7644
7645
7646
}

/*
** Close an iterator opened by an earlier call to sqlite3Fts5IndexQuery().
*/
void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){
  if( pIndexIter ){
    Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
    Fts5Index *pIndex = pIter->pIndex;
    fts5TokendataIterDelete(pIter->pTokenDataIter);
    fts5MultiIterFree(pIter);
    sqlite3Fts5IndexCloseReader(pIndex);
  }
}

/*
** Read and decode the "averages" record from the database. 
**
** Parameter anSize must point to an array of size nCol, where nCol is







<
|
<
|
|







7647
7648
7649
7650
7651
7652
7653

7654

7655
7656
7657
7658
7659
7660
7661
7662
7663
}

/*
** Close an iterator opened by an earlier call to sqlite3Fts5IndexQuery().
*/
void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){
  if( pIndexIter ){

    Fts5Index *pIndex = ((Fts5Iter*)pIndexIter)->pIndex;

    fts5IterClose(pIndexIter);
    fts5IndexReturn(pIndex);
  }
}

/*
** Read and decode the "averages" record from the database. 
**
** Parameter anSize must point to an array of size nCol, where nCol is
8162
8163
8164
8165
8166
8167
8168
8169
8170
8171
8172
8173
8174
8175
8176
        cksum ^= sqlite3Fts5IndexEntryCksum(rowid, iCol, iOff, iIdx, z, n);
      }
    }
    if( rc==SQLITE_OK ){
      rc = sqlite3Fts5IterNext(pIter);
    }
  }
  sqlite3Fts5IterClose(pIter);

  *pCksum = cksum;
  return rc;
}

/*
** Check if buffer z[], size n bytes, contains as series of valid utf-8







|







8179
8180
8181
8182
8183
8184
8185
8186
8187
8188
8189
8190
8191
8192
8193
        cksum ^= sqlite3Fts5IndexEntryCksum(rowid, iCol, iOff, iIdx, z, n);
      }
    }
    if( rc==SQLITE_OK ){
      rc = sqlite3Fts5IterNext(pIter);
    }
  }
  fts5IterClose(pIter);

  *pCksum = cksum;
  return rc;
}

/*
** Check if buffer z[], size n bytes, contains as series of valid utf-8
Changes to ext/fts5/test/fts5faultI.test.
285
286
287
288
289
290
291



































292
293
294
} -body {
  execsql {
    INSERT INTO f1(rowid, content) SELECT id, content FROM g1;
  }
} -test {
  faultsim_test_result {0 {}}
}




































finish_test








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



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
} -body {
  execsql {
    INSERT INTO f1(rowid, content) SELECT id, content FROM g1;
  }
} -test {
  faultsim_test_result {0 {}}
}

#-------------------------------------------------------------------------
reset_db

ifcapable foreignkey {
  do_execsql_test 12.0 {
    CREATE VIRTUAL TABLE f1 USING fts5(content);
    CREATE TABLE p1(a INTEGER PRIMARY KEY);
    CREATE TABLE c1(b REFERENCES p1 DEFERRABLE INITIALLY DEFERRED);
  }

  faultsim_save_and_close

  do_faultsim_test 11 -faults oom* -prep {
    faultsim_restore_and_reopen
    execsql {
      PRAGMA foreign_keys = 1;
      BEGIN;
        INSERT INTO c1 VALUES(123);
        SAVEPOINT xyz;
    }
  } -body {
    execsql {
          INSERT INTO f1 VALUES('a b c');
        ROLLBACK TO xyz;
      COMMIT;
    }
  } -test {
    execsql { SELECT 123 }
    faultsim_test_result \
      {1 {FOREIGN KEY constraint failed}} \
      {1 {out of memory}} \
      {1 {constraint failed}}
  }
}

finish_test

Changes to ext/fts5/test/fts5misc.test.
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
  UPDATE t1 SET y='TWO' WHERE ii=2;
}

do_execsql_test 21.2 {
  PRAGMA integrity_check
} {ok}

breakpoint
sqlite3_db_config db DEFENSIVE 1
do_execsql_test 21.3 {
  CREATE TABLE xyz_notashadow(x, y);
  DROP TABLE xyz_notashadow;
}
sqlite3_db_config db DEFENSIVE 0








<







587
588
589
590
591
592
593

594
595
596
597
598
599
600
  UPDATE t1 SET y='TWO' WHERE ii=2;
}

do_execsql_test 21.2 {
  PRAGMA integrity_check
} {ok}


sqlite3_db_config db DEFENSIVE 1
do_execsql_test 21.3 {
  CREATE TABLE xyz_notashadow(x, y);
  DROP TABLE xyz_notashadow;
}
sqlite3_db_config db DEFENSIVE 0

660
661
662
663
664
665
666





















667
668
669
  CREATE VIRTUAL TABLE t1 USING fts5(a, detail='none', content='');
  INSERT INTO t1(a) VALUES('a b c');
}

do_execsql_test 25.0 {
  SELECT fts5_test_poslist(t1) FROM t1('b') ORDER BY rank;
} {{}}






















finish_test








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



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
  CREATE VIRTUAL TABLE t1 USING fts5(a, detail='none', content='');
  INSERT INTO t1(a) VALUES('a b c');
}

do_execsql_test 25.0 {
  SELECT fts5_test_poslist(t1) FROM t1('b') ORDER BY rank;
} {{}}

#-------------------------------------------------------------------------
reset_db

do_execsql_test 26.0 {
  PRAGMA foreign_keys = ON;
  CREATE TABLE t1(x INTEGER PRIMARY KEY);
  CREATE TABLE t2(y INTEGER PRIMARY KEY,
      z INTEGER REFERENCES t1(x) DEFERRABLE INITIALLY DEFERRED
  );
  CREATE VIRTUAL TABLE t3 USING fts5(a, b, content='', tokendata=1);
}

do_execsql_test 26.1 {
  BEGIN;
    INSERT INTO t2 VALUES(1,111);
    INSERT INTO t3 VALUES(3,3);
    PRAGMA defer_foreign_keys=ON;
    DELETE FROM t2 WHERE y+1;
  COMMIT;
}

finish_test

Changes to ext/misc/sqlite3_stdio.c.
42
43
44
45
46
47
48





49
50
51
52
53
54
55
** in the CLI, or other context clues in other applications) for all
** other output channels.
**
** The default behavior, if neither of the above is defined is to
** use O_U8TEXT when writing to the Windows console (or anything
** else for which _isatty() returns true) and to use O_BINARY or O_TEXT
** for all other output channels.





*/
#if defined(SQLITE_U8TEXT_ONLY)
# define UseWtextForOutput(fd) 1
# define UseWtextForInput(fd)  1
# define IsConsole(fd)         _isatty(_fileno(fd))
#elif defined(SQLITE_U8TEXT_STDIO)
# define UseWtextForOutput(fd) ((fd)==stdout || (fd)==stderr)







>
>
>
>
>







42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
** in the CLI, or other context clues in other applications) for all
** other output channels.
**
** The default behavior, if neither of the above is defined is to
** use O_U8TEXT when writing to the Windows console (or anything
** else for which _isatty() returns true) and to use O_BINARY or O_TEXT
** for all other output channels.
**
** The SQLITE_USE_W32_FOR_CONSOLE_IO macro is also available.  If
** defined, it forces the use of Win32 APIs for all console I/O, both
** input and output.  This is necessary for some non-Microsoft run-times
** that implement stdio differently from Microsoft/Visual-Studio.
*/
#if defined(SQLITE_U8TEXT_ONLY)
# define UseWtextForOutput(fd) 1
# define UseWtextForInput(fd)  1
# define IsConsole(fd)         _isatty(_fileno(fd))
#elif defined(SQLITE_U8TEXT_STDIO)
# define UseWtextForOutput(fd) ((fd)==stdout || (fd)==stderr)
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
    /* When reading from the command-prompt in Windows, it is necessary
    ** to use _O_WTEXT input mode to read UTF-16 characters, then translate
    ** that into UTF-8.  Otherwise, non-ASCII characters all get translated
    ** into '?'.
    */
    wchar_t *b1 = sqlite3_malloc( sz*sizeof(wchar_t) );
    if( b1==0 ) return 0;
#ifndef SQLITE_USE_STDIO_FOR_CONSOLE
    DWORD nRead = 0;
    if( IsConsole(in)
     && ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), b1, sz, &nRead, 0)
    ){
      b1[nRead] = 0;
    }else
#endif
    {
      _setmode(_fileno(in), IsConsole(in) ? _O_WTEXT : _O_U8TEXT);
      if( fgetws(b1, sz/4, in)==0 ){







|


|







149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
    /* When reading from the command-prompt in Windows, it is necessary
    ** to use _O_WTEXT input mode to read UTF-16 characters, then translate
    ** that into UTF-8.  Otherwise, non-ASCII characters all get translated
    ** into '?'.
    */
    wchar_t *b1 = sqlite3_malloc( sz*sizeof(wchar_t) );
    if( b1==0 ) return 0;
#ifdef SQLITE_USE_W32_FOR_CONSOLE_IO
    DWORD nRead = 0;
    if( IsConsole(in)
     && ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), b1, sz-1, &nRead, 0)
    ){
      b1[nRead] = 0;
    }else
#endif
    {
      _setmode(_fileno(in), IsConsole(in) ? _O_WTEXT : _O_U8TEXT);
      if( fgetws(b1, sz/4, in)==0 ){
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
    */
    int sz = (int)strlen(z);
    wchar_t *b1 = sqlite3_malloc( (sz+1)*sizeof(wchar_t) );
    if( b1==0 ) return 0;
    sz = MultiByteToWideChar(CP_UTF8, 0, z, sz, b1, sz);
    b1[sz] = 0;

#ifndef SQLITE_STDIO_FOR_CONSOLE
    DWORD nWr = 0;
    if( IsConsole(out)
      && WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),b1,sz,&nWr,0)
    ){
      /* If writing to the console, then the WriteConsoleW() is all we
      ** need to do. */
    }else
#endif
    {

      /* For non-console I/O, or if SQLITE_USE_STDIO_FOR_CONSOLE is defined
      ** then write using the standard library. */
      _setmode(_fileno(out), _O_U8TEXT);
      if( UseBinaryWText(out) ){
        piecemealOutput(b1, sz, out);
      }else{
        fputws(b1, out);
      }
    }







|









>
|
|







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
    */
    int sz = (int)strlen(z);
    wchar_t *b1 = sqlite3_malloc( (sz+1)*sizeof(wchar_t) );
    if( b1==0 ) return 0;
    sz = MultiByteToWideChar(CP_UTF8, 0, z, sz, b1, sz);
    b1[sz] = 0;

#ifdef SQLITE_USE_W32_FOR_CONSOLE_IO
    DWORD nWr = 0;
    if( IsConsole(out)
      && WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),b1,sz,&nWr,0)
    ){
      /* If writing to the console, then the WriteConsoleW() is all we
      ** need to do. */
    }else
#endif
    {
      /* As long as SQLITE_USE_W32_FOR_CONSOLE_IO is not defined, or for
      ** non-console I/O even if that macro is defined, write using the
      ** standard library. */
      _setmode(_fileno(out), _O_U8TEXT);
      if( UseBinaryWText(out) ){
        piecemealOutput(b1, sz, out);
      }else{
        fputws(b1, out);
      }
    }
Changes to ext/misc/vfstrace.c.
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
/*
** Close the dynamic library handle pHandle.
*/
static void vfstraceDlClose(sqlite3_vfs *pVfs, void *pHandle){
  vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
  sqlite3_vfs *pRoot = pInfo->pRootVfs;
  vfstraceOnOff(pInfo, VTR_DLCLOSE);
  vfstrace_printf(pInfo, "%s.xDlOpen()\n", pInfo->zVfsName);
  pRoot->xDlClose(pRoot, pHandle);
}

/*
** Populate the buffer pointed to by zBufOut with nByte bytes of 
** random data.
*/







|







1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
/*
** Close the dynamic library handle pHandle.
*/
static void vfstraceDlClose(sqlite3_vfs *pVfs, void *pHandle){
  vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
  sqlite3_vfs *pRoot = pInfo->pRootVfs;
  vfstraceOnOff(pInfo, VTR_DLCLOSE);
  vfstrace_printf(pInfo, "%s.xDlClose()\n", pInfo->zVfsName);
  pRoot->xDlClose(pRoot, pHandle);
}

/*
** Populate the buffer pointed to by zBufOut with nByte bytes of 
** random data.
*/
Changes to ext/session/session1.test.
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
  DELETE FROM t2 WHERE a = 4;
} -conflicts {
  {DELETE t2 NOTFOUND {i 3 t three}}
  {DELETE t2 DATA {i 4 t four} {i 4 t five}}
  {FOREIGN_KEY 1}
}
do_execsql_test $tn.3.2.4 "SELECT * FROM t2" {}
do_db2_test $tn.3.2.5 "SELECT * FROM t2" {1 one 2 two 4 five}

# Test UPDATE changesets.
#
do_execsql_test $tn.3.3.1 {
  CREATE TABLE t4(a, b, c, PRIMARY KEY(b, c))%WR%;
  INSERT INTO t4 VALUES(1, 2, 3);
  INSERT INTO t4 VALUES(4, 5, 6);







|







281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
  DELETE FROM t2 WHERE a = 4;
} -conflicts {
  {DELETE t2 NOTFOUND {i 3 t three}}
  {DELETE t2 DATA {i 4 t four} {i 4 t five}}
  {FOREIGN_KEY 1}
}
do_execsql_test $tn.3.2.4 "SELECT * FROM t2" {}
do_db2_test $tn.3.2.5 "SELECT * FROM t2" {4 five}

# Test UPDATE changesets.
#
do_execsql_test $tn.3.3.1 {
  CREATE TABLE t4(a, b, c, PRIMARY KEY(b, c))%WR%;
  INSERT INTO t4 VALUES(1, 2, 3);
  INSERT INTO t4 VALUES(4, 5, 6);
Changes to ext/session/session9.test.
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
  4   3 1 {FOREIGN_KEY 1} OMIT
  5   2 0 {FOREIGN_KEY 1} ABORT
  6   3 0 {FOREIGN_KEY 1} ABORT
  7   2 1 {FOREIGN_KEY 1} ABORT
  8   3 1 {FOREIGN_KEY 1} ABORT
} {

  set A(OMIT,0)  {1 SQLITE_CONSTRAINT}
  set A(OMIT,1)  {0 {}}
  set A(ABORT,0) {1 SQLITE_CONSTRAINT}
  set A(ABORT,1) {1 SQLITE_CONSTRAINT}
  do_test 1.2.$tn.1 {
    populate_db
    execsql { DELETE FROM p1 WHERE a=($delrow+0) }
    if {$trans} { execsql BEGIN }

    set ::xConflict [list]
    list [catch {sqlite3changeset_apply db $::cc xConflict} msg] $msg
  } $A($conflictret,$trans)

  do_test 1.2.$tn.2 { set ::xConflict } $conflictargs

  set A(OMIT,0)  {0 0}
  set A(OMIT,1)  {1 1}
  set A(ABORT,0) {0 0}
  set A(ABORT,1) {0 0}

  do_test 1.2.$tn.3 {
    execsql { SELECT count(*) FROM c1 UNION ALL SELECT count(*) FROM c2 }
  } $A($conflictret,$trans)







|














|







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
  4   3 1 {FOREIGN_KEY 1} OMIT
  5   2 0 {FOREIGN_KEY 1} ABORT
  6   3 0 {FOREIGN_KEY 1} ABORT
  7   2 1 {FOREIGN_KEY 1} ABORT
  8   3 1 {FOREIGN_KEY 1} ABORT
} {

  set A(OMIT,0)  {0 {}}
  set A(OMIT,1)  {0 {}}
  set A(ABORT,0) {1 SQLITE_CONSTRAINT}
  set A(ABORT,1) {1 SQLITE_CONSTRAINT}
  do_test 1.2.$tn.1 {
    populate_db
    execsql { DELETE FROM p1 WHERE a=($delrow+0) }
    if {$trans} { execsql BEGIN }

    set ::xConflict [list]
    list [catch {sqlite3changeset_apply db $::cc xConflict} msg] $msg
  } $A($conflictret,$trans)

  do_test 1.2.$tn.2 { set ::xConflict } $conflictargs

  set A(OMIT,0)  {1 1}
  set A(OMIT,1)  {1 1}
  set A(ABORT,0) {0 0}
  set A(ABORT,1) {0 0}

  do_test 1.2.$tn.3 {
    execsql { SELECT count(*) FROM c1 UNION ALL SELECT count(*) FROM c2 }
  } $A($conflictret,$trans)
Changes to ext/session/sessionnoact.test.
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
do_execsql_test 1.2 {
  PRAGMA foreign_keys = 1;
}

set ::nConflict 0
proc conflict {args} {
  incr ::nConflict
  return "OMIT"
}

sqlite3changeset_apply_v2 db $C conflict

do_execsql_test 1.3 {
  SELECT * FROM c1
} {







|







55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
do_execsql_test 1.2 {
  PRAGMA foreign_keys = 1;
}

set ::nConflict 0
proc conflict {args} {
  incr ::nConflict
  return "ABORT"
}

sqlite3changeset_apply_v2 db $C conflict

do_execsql_test 1.3 {
  SELECT * FROM c1
} {
107
108
109
110
111
112
113



114
115
116
117
118
119
120
  PRAGMA foreign_key_check
}

#-------------------------------------------------------------------------
# Check that a changeset that causes an FK violation may not be applied,
# even if SQLITE_CHANGESETAPPLY_FKNOACTION is specified.
#



reset_db
do_execsql_test 2.0 {
  CREATE TABLE p1(a INTEGER PRIMARY KEY, b, c UNIQUE);
  INSERT INTO p1 VALUES(1, 1, 'one');
  INSERT INTO p1 VALUES(2, 2, 'two');

  CREATE TABLE c1(x REFERENCES p1(c) ON DELETE CASCADE);







>
>
>







107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  PRAGMA foreign_key_check
}

#-------------------------------------------------------------------------
# Check that a changeset that causes an FK violation may not be applied,
# even if SQLITE_CHANGESETAPPLY_FKNOACTION is specified.
#
# UPDATE: Unless the conflict-handler returns OMIT. In that case it can
# be committed. See test cases 3.* in this file.
#
reset_db
do_execsql_test 2.0 {
  CREATE TABLE p1(a INTEGER PRIMARY KEY, b, c UNIQUE);
  INSERT INTO p1 VALUES(1, 1, 'one');
  INSERT INTO p1 VALUES(2, 2, 'two');

  CREATE TABLE c1(x REFERENCES p1(c) ON DELETE CASCADE);
159
160
161
162
163
164
165
166





























































167
168
} {1 SQLITE_CONSTRAINT}
do_execsql_test 2.7 {
  SELECT * FROM p1;
} {1 1 one 2 2 two}
do_execsql_test 2.8 {
  SELECT * FROM c1;
} {two}






























































finish_test









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


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
} {1 SQLITE_CONSTRAINT}
do_execsql_test 2.7 {
  SELECT * FROM p1;
} {1 1 one 2 2 two}
do_execsql_test 2.8 {
  SELECT * FROM c1;
} {two}

#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 3.0 {
  CREATE TABLE p1(a INTEGER PRIMARY KEY, b, c UNIQUE);
  INSERT INTO p1 VALUES(1, 1, 'one');
  INSERT INTO p1 VALUES(2, 2, 'two');

  CREATE TABLE c1(x REFERENCES p1(c) ON DELETE CASCADE);
  INSERT INTO c1 VALUES('two');
}

set ::nConflict 0
proc conflict {args} {
  incr ::nConflict
  return "OMIT"
}

db_save

set C [changeset_from_sql {
  DELETE FROM p1 WHERE a=2;
}]

db_restore_and_reopen

do_test 3.1 {
  sqlite3changeset_apply_v2 -noaction db $C conflict
} {}
do_execsql_test 3.2 {
  SELECT * FROM p1
} {1 1 one}

db_restore_and_reopen
db eval { PRAGMA foreign_keys = 1 }

do_test 3.3 {
  list [catch { sqlite3changeset_apply_v2 -noaction db $C conflict } msg] $msg
} {0 {}}
do_execsql_test 3.4 {
  SELECT * FROM p1;
} {1 1 one}
do_execsql_test 3.5 {
  SELECT * FROM c1;
} {two}

db_restore_and_reopen
db eval { PRAGMA foreign_keys = 1 }

do_test 3.6 {
  list [catch { 
    sqlite3changeset_apply_v2 -ignorenoop -noaction db $C conflict 
  } msg] $msg
} {0 {}}
do_execsql_test 3.7 {
  SELECT * FROM p1;
} {1 1 one}
do_execsql_test 3.8 {
  SELECT * FROM c1;
} {two}

finish_test

Changes to ext/session/sqlite3session.c.
5279
5280
5281
5282
5283
5284
5285





5286
5287
5288
5289
5290
5291
5292
      sIter.nCol = nFk;
      res = xConflict(pCtx, SQLITE_CHANGESET_FOREIGN_KEY, &sIter);
      if( res!=SQLITE_CHANGESET_OMIT ){
        rc = SQLITE_CONSTRAINT;
      }
    }
  }






  if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
    if( rc==SQLITE_OK ){
      rc = sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
    }
    if( rc!=SQLITE_OK ){
      sqlite3_exec(db, "ROLLBACK TO changeset_apply", 0, 0, 0);







>
>
>
>
>







5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
      sIter.nCol = nFk;
      res = xConflict(pCtx, SQLITE_CHANGESET_FOREIGN_KEY, &sIter);
      if( res!=SQLITE_CHANGESET_OMIT ){
        rc = SQLITE_CONSTRAINT;
      }
    }
  }

  {
    int rc2 = sqlite3_exec(db, "PRAGMA defer_foreign_keys = 0", 0, 0, 0);
    if( rc==SQLITE_OK ) rc = rc2;
  }

  if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
    if( rc==SQLITE_OK ){
      rc = sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
    }
    if( rc!=SQLITE_OK ){
      sqlite3_exec(db, "ROLLBACK TO changeset_apply", 0, 0, 0);
Changes to ext/wasm/api/extern-post-js.c-pp.js.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
   most of the associated JS code, runs outside of the
   Emscripten-generated module init scope, in the current
   global scope. */
//#if target=es6-module
const toExportForESM =
//#endif
(function(){

  /**
     In order to hide the sqlite3InitModule()'s resulting
     Emscripten module from downstream clients (and simplify our
     documentation by being able to elide those details), we hide that
     function and expose a hand-written sqlite3InitModule() to return
     the sqlite3 object (most of the time).








>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   most of the associated JS code, runs outside of the
   Emscripten-generated module init scope, in the current
   global scope. */
//#if target=es6-module
const toExportForESM =
//#endif
(function(){
  //console.warn("this is extern-post-js");
  /**
     In order to hide the sqlite3InitModule()'s resulting
     Emscripten module from downstream clients (and simplify our
     documentation by being able to elide those details), we hide that
     function and expose a hand-written sqlite3InitModule() to return
     the sqlite3 object (most of the time).

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
    li.pop();
    initModuleState.sqlite3Dir = li.join('/') + '/';
  }

  globalThis.sqlite3InitModule = function ff(...args){
    //console.warn("Using replaced sqlite3InitModule()",globalThis.location);
    return originalInit(...args).then((EmscriptenModule)=>{











//#if wasmfs
      if('undefined'!==typeof WorkerGlobalScope &&
         EmscriptenModule['ENVIRONMENT_IS_PTHREAD']){
        /** Workaround for wasmfs-generated worker, which calls this
            routine from each individual thread and requires that its
            argument be returned. The conditional criteria above are
            fragile, based solely on inspection of the offending code,
            not public Emscripten details. */
        //console.warn("sqlite3InitModule() returning E-module.",EmscriptenModule);
        return EmscriptenModule;
      }
//#endif
      //console.warn("sqlite3InitModule() returning sqlite3 object.");
      const s = EmscriptenModule.sqlite3;
      s.scriptInfo = initModuleState;
      //console.warn("sqlite3.scriptInfo =",s.scriptInfo);
      if(ff.__isUnderTest) s.__isUnderTest = true;
      const f = s.asyncPostInit;
      delete s.asyncPostInit;
      return f();







>
>
>
>
>
>
>
>
>
>
>












<







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
    li.pop();
    initModuleState.sqlite3Dir = li.join('/') + '/';
  }

  globalThis.sqlite3InitModule = function ff(...args){
    //console.warn("Using replaced sqlite3InitModule()",globalThis.location);
    return originalInit(...args).then((EmscriptenModule)=>{
      //console.warn("originalInit() then() arg =",EmscriptenModule);
      //console.warn("initModuleState =",initModuleState);
      if( EmscriptenModule.postRun && EmscriptenModule.postRun.length ){
        /* Emscripten 4.0.0 changes the order in which our Module.postRun handler
           runs. In 3.x postRun would have run by now, and our code relies
           heavily on that order, so we'll work around that difference here.

           https://github.com/emscripten-core/emscripten/issues/23420 */
        //console.warn("Emscripten did not run postRun: running them now!");
        EmscriptenModule.postRun.shift()(EmscriptenModule);
      }
//#if wasmfs
      if('undefined'!==typeof WorkerGlobalScope &&
         EmscriptenModule['ENVIRONMENT_IS_PTHREAD']){
        /** Workaround for wasmfs-generated worker, which calls this
            routine from each individual thread and requires that its
            argument be returned. The conditional criteria above are
            fragile, based solely on inspection of the offending code,
            not public Emscripten details. */
        //console.warn("sqlite3InitModule() returning E-module.",EmscriptenModule);
        return EmscriptenModule;
      }
//#endif

      const s = EmscriptenModule.sqlite3;
      s.scriptInfo = initModuleState;
      //console.warn("sqlite3.scriptInfo =",s.scriptInfo);
      if(ff.__isUnderTest) s.__isUnderTest = true;
      const f = s.asyncPostInit;
      delete s.asyncPostInit;
      return f();
Changes to ext/wasm/api/post-js-footer.js.
1
2
3

4

/* The current function scope was opened via post-js-header.js, which
   gets prepended to this at build-time. This file closes that
   scope. */

})/*postRun.push(...)*/;




>

>
1
2
3
4
5
6
/* The current function scope was opened via post-js-header.js, which
   gets prepended to this at build-time. This file closes that
   scope. */
//console.warn("This is the end of the Module.postRun handler.");
})/*postRun.push(...)*/;
//console.warn("This is the end of the setup of the (pending) Module.postRun");
Changes to ext/wasm/api/post-js-header.js.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
/**
   post-js-header.js is to be prepended to other code to create
   post-js.js for use with Emscripten's --post-js flag. This code
   requires that it be running in that context. The Emscripten
   environment must have been set up already but it will not have
   loaded its WASM when the code in this file is run. The function it
   installs will be run after the WASM module is loaded, at which
   point the sqlite3 JS API bits will get set up.
*/
if(!Module.postRun) Module.postRun = [];
Module.postRun.push(function(Module/*the Emscripten-style module object*/){
  'use strict';

  /* This function will contain at least the following:

     - post-js-header.js (this file)
     - sqlite3-api-prologue.js  => Bootstrapping bits to attach the rest to
     - common/whwasmutil.js     => Replacements for much of Emscripten's glue
     - jaccwaby/jaccwabyt.js    => Jaccwabyt (C/JS struct binding)
     - sqlite3-api-glue.js      => glues previous parts together












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
   post-js-header.js is to be prepended to other code to create
   post-js.js for use with Emscripten's --post-js flag. This code
   requires that it be running in that context. The Emscripten
   environment must have been set up already but it will not have
   loaded its WASM when the code in this file is run. The function it
   installs will be run after the WASM module is loaded, at which
   point the sqlite3 JS API bits will get set up.
*/
if(!Module.postRun) Module.postRun = [];
Module.postRun.push(function(Module/*the Emscripten-style module object*/){
  'use strict';
  //console.warn("This is the start of the Module.postRun handler.");
  /* This function will contain at least the following:

     - post-js-header.js (this file)
     - sqlite3-api-prologue.js  => Bootstrapping bits to attach the rest to
     - common/whwasmutil.js     => Replacements for much of Emscripten's glue
     - jaccwaby/jaccwabyt.js    => Jaccwabyt (C/JS struct binding)
     - sqlite3-api-glue.js      => glues previous parts together
Changes to ext/wasm/api/sqlite3-api-cleanup.js.
10
11
12
13
14
15
16



17
18
19
20
21
22
23

  ***********************************************************************

  This file is the tail end of the sqlite3-api.js constellation,
  intended to be appended after all other sqlite3-api-*.js files so
  that it can finalize any setup and clean up any global symbols
  temporarily used for setting up the API's various subsystems.



*/
'use strict';
if('undefined' !== typeof Module){ // presumably an Emscripten build
  /**
     Install a suitable default configuration for sqlite3ApiBootstrap().
  */
  const SABC = Object.assign(







>
>
>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

  ***********************************************************************

  This file is the tail end of the sqlite3-api.js constellation,
  intended to be appended after all other sqlite3-api-*.js files so
  that it can finalize any setup and clean up any global symbols
  temporarily used for setting up the API's various subsystems.

  In Emscripten builds it's run in the context of a Module.postRun
  handler.
*/
'use strict';
if('undefined' !== typeof Module){ // presumably an Emscripten build
  /**
     Install a suitable default configuration for sqlite3ApiBootstrap().
  */
  const SABC = Object.assign(
Changes to ext/wasm/api/sqlite3-api-glue.c-pp.js.
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
      }),
      '*'
    ]],
    ["sqlite3_set_auxdata", undefined, [
      "sqlite3_context*", "int", "*",
      new wasm.xWrap.FuncPtrAdapter({
        name: 'xDestroyAuxData',
        signature: 'v(*)',
        contextKey: (argv, argIndex)=>argv[0/* sqlite3_context* */]
      })
    ]],
    ["sqlite3_shutdown", undefined],
    ["sqlite3_sourceid", "string"],
    ["sqlite3_sql", "string", "sqlite3_stmt*"],
    ["sqlite3_status", "int", "int", "*", "*", "int"],







|







228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
      }),
      '*'
    ]],
    ["sqlite3_set_auxdata", undefined, [
      "sqlite3_context*", "int", "*",
      new wasm.xWrap.FuncPtrAdapter({
        name: 'xDestroyAuxData',
        signature: 'v(p)',
        contextKey: (argv, argIndex)=>argv[0/* sqlite3_context* */]
      })
    ]],
    ["sqlite3_shutdown", undefined],
    ["sqlite3_sourceid", "string"],
    ["sqlite3_sql", "string", "sqlite3_stmt*"],
    ["sqlite3_status", "int", "int", "*", "*", "int"],
Changes to ext/wasm/dist.make.
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
# 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) \
    $(dist.build) $(STRIP_K1.js) $(STRIP_K2.js) \
    $(dist.jswasm.extras) $(dist.common.extras) \
    $(MAKEFILE) $(MAKEFILE.dist)
	@echo "Making end-user deliverables..."
	@rm -fr $(dist-dir.top)
	@mkdir -p $(dist-dir.jswasm) $(dist-dir.common)
	@cp -p $(dist.top.extras) $(dist-dir.top)
	@cp -p README-dist.txt $(dist-dir.top)/README.txt
	@cp -p index-dist.html $(dist-dir.top)/index.html
	@cp -p $(dist.jswasm.extras) $(dist-dir.jswasm)
	@$(foreach JS,$(STRIP_K1.js),$(call DIST_STRIP_COMMENTS,$(JS),-k))
	@$(foreach JS,$(STRIP_K2.js),$(call DIST_STRIP_COMMENTS,$(JS),-k -k))
	@cp -p $(dist.common.extras) $(dist-dir.common)
	@set -e; \
		vnum=$$($(bin.version-info) --download-version); \
		vdir=$(dist-name-prefix)-$$vnum; \
		arczip=$$vdir.zip; \
		echo "Making $$arczip ..."; \
		rm -fr $$arczip $$vdir; \







>
>
>
>
>
>
>
>
>
>












|
|







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
# 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.
#
# 2025-01-15: Emsdk 4.0.0 introduces, in its generated code, a regex
# which contains the pattern /*. That, of course, confuses any C-style
# comment-stripper which is not specifically JS-aware and smart enough
# to know that it's in a regex or string literal. Because of that,
# comment-stripping is currently disabled, which means the builds will
# be significantly larger than before.
#apply_comment_stripper := false
apply_comment_stripper := true
# ^^^ shell command true or false
dist: \
    $(bin.stripccomments) $(bin.version-info) \
    $(dist.build) $(STRIP_K1.js) $(STRIP_K2.js) \
    $(dist.jswasm.extras) $(dist.common.extras) \
    $(MAKEFILE) $(MAKEFILE.dist)
	@echo "Making end-user deliverables..."
	@rm -fr $(dist-dir.top)
	@mkdir -p $(dist-dir.jswasm) $(dist-dir.common)
	@cp -p $(dist.top.extras) $(dist-dir.top)
	@cp -p README-dist.txt $(dist-dir.top)/README.txt
	@cp -p index-dist.html $(dist-dir.top)/index.html
	@cp -p $(dist.jswasm.extras) $(dist-dir.jswasm)
	@if $(apply_comment_stripper); then $(foreach JS,$(STRIP_K1.js),$(call DIST_STRIP_COMMENTS,$(JS),-k)) fi
	@if $(apply_comment_stripper); then $(foreach JS,$(STRIP_K2.js),$(call DIST_STRIP_COMMENTS,$(JS),-k -k)) fi
	@cp -p $(dist.common.extras) $(dist-dir.common)
	@set -e; \
		vnum=$$($(bin.version-info) --download-version); \
		vdir=$(dist-name-prefix)-$$vnum; \
		arczip=$$vdir.zip; \
		echo "Making $$arczip ..."; \
		rm -fr $$arczip $$vdir; \
Changes to main.mk.
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
#
mksourceid$(B.exe): $(MAKE_SANITY_CHECK) $(TOP)/tool/mksourceid.c
	$(B.cc) -o $@ $(TOP)/tool/mksourceid.c

sqlite3.h: $(MAKE_SANITY_CHECK) $(TOP)/src/sqlite.h.in \
    $(TOP)/manifest mksourceid$(B.exe) \
		$(TOP)/VERSION $(B.tclsh)
	$(B.tclsh) $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h

sqlite3.c:	.target_source sqlite3.h $(TOP)/tool/mksqlite3c.tcl src-verify$(B.exe) \
		$(B.tclsh)
	$(B.tclsh) $(TOP)/tool/mksqlite3c.tcl $(AMALGAMATION_GEN_FLAGS) $(EXTRA_SRC)
	cp tsrc/sqlite3ext.h .
	cp $(TOP)/ext/session/sqlite3session.h .

sqlite3r.h: sqlite3.h $(B.tclsh)
	$(B.tclsh) $(TOP)/tool/mksqlite3h.tcl $(TOP) --enable-recover >sqlite3r.h

sqlite3r.c: sqlite3.c sqlite3r.h $(B.tclsh)
	cp $(TOP)/ext/recover/sqlite3recover.c tsrc/
	cp $(TOP)/ext/recover/sqlite3recover.h tsrc/
	cp $(TOP)/ext/recover/dbdata.c tsrc/
	$(B.tclsh) $(TOP)/tool/mksqlite3c.tcl --enable-recover $(AMALGAMATION_GEN_FLAGS) $(EXTRA_SRC)








|








|







1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
#
mksourceid$(B.exe): $(MAKE_SANITY_CHECK) $(TOP)/tool/mksourceid.c
	$(B.cc) -o $@ $(TOP)/tool/mksourceid.c

sqlite3.h: $(MAKE_SANITY_CHECK) $(TOP)/src/sqlite.h.in \
    $(TOP)/manifest mksourceid$(B.exe) \
		$(TOP)/VERSION $(B.tclsh)
	$(B.tclsh) $(TOP)/tool/mksqlite3h.tcl $(TOP) -o sqlite3.h

sqlite3.c:	.target_source sqlite3.h $(TOP)/tool/mksqlite3c.tcl src-verify$(B.exe) \
		$(B.tclsh)
	$(B.tclsh) $(TOP)/tool/mksqlite3c.tcl $(AMALGAMATION_GEN_FLAGS) $(EXTRA_SRC)
	cp tsrc/sqlite3ext.h .
	cp $(TOP)/ext/session/sqlite3session.h .

sqlite3r.h: sqlite3.h $(B.tclsh)
	$(B.tclsh) $(TOP)/tool/mksqlite3h.tcl $(TOP) --enable-recover -o sqlite3r.h

sqlite3r.c: sqlite3.c sqlite3r.h $(B.tclsh)
	cp $(TOP)/ext/recover/sqlite3recover.c tsrc/
	cp $(TOP)/ext/recover/sqlite3recover.h tsrc/
	cp $(TOP)/ext/recover/dbdata.c tsrc/
	$(B.tclsh) $(TOP)/tool/mksqlite3c.tcl --enable-recover $(AMALGAMATION_GEN_FLAGS) $(EXTRA_SRC)

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
sqlite3d$(T.exe):	shell.c $(LIBOBJS0)
	$(T.link) -o $@ \
		shell.c $(LIBOBJS0) \
		$(CFLAGS.readline) $(SHELL_OPT) \
		$(LDFLAGS.libsqlite3) $(LDFLAGS.readline)

install-shell-0: sqlite3$(T.exe) $(install-dir.bin)
	$(INSTALL) -s sqlite3$(T.exe) "$(install-dir.bin)"
install-shell-1:
install: install-shell-$(HAVE_WASI_SDK)

# How to build sqldiff$(T.exe) depends on $(LINK_TOOLS_DYNAMICALLY)
#
sqldiff.0.deps = $(TOP)/tool/sqldiff.c $(TOP)/ext/misc/sqlite3_stdio.h sqlite3.o sqlite3.h
sqldiff.0.rules = $(T.link) -o $@ $(TOP)/tool/sqldiff.c sqlite3.o $(LDFLAGS.libsqlite3)
sqldiff.1.deps = $(TOP)/tool/sqldiff.c $(TOP)/ext/misc/sqlite3_stdio.h $(libsqlite3.SO)
sqldiff.1.rules = $(T.link) -o $@ $(TOP)/tool/sqldiff.c -L. -lsqlite3 $(LDFLAGS.configure)
sqldiff$(T.exe): $(sqldiff.$(LINK_TOOLS_DYNAMICALLY).deps)
	$(sqldiff.$(LINK_TOOLS_DYNAMICALLY).rules)

install-diff: sqldiff$(T.exe) $(install-dir.bin)
	$(INSTALL) -s sqldiff$(T.exe) "$(install-dir.bin)"
#install: install-diff

dbhash$(T.exe):	$(TOP)/tool/dbhash.c sqlite3.o sqlite3.h
	$(T.link) -o $@ $(TOP)/tool/dbhash.c sqlite3.o $(LDFLAGS.libsqlite3)
xbin: dbhash$(T.exe)

RSYNC_SRC = \







|













|







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
sqlite3d$(T.exe):	shell.c $(LIBOBJS0)
	$(T.link) -o $@ \
		shell.c $(LIBOBJS0) \
		$(CFLAGS.readline) $(SHELL_OPT) \
		$(LDFLAGS.libsqlite3) $(LDFLAGS.readline)

install-shell-0: sqlite3$(T.exe) $(install-dir.bin)
	$(INSTALL) sqlite3$(T.exe) "$(install-dir.bin)"
install-shell-1:
install: install-shell-$(HAVE_WASI_SDK)

# How to build sqldiff$(T.exe) depends on $(LINK_TOOLS_DYNAMICALLY)
#
sqldiff.0.deps = $(TOP)/tool/sqldiff.c $(TOP)/ext/misc/sqlite3_stdio.h sqlite3.o sqlite3.h
sqldiff.0.rules = $(T.link) -o $@ $(TOP)/tool/sqldiff.c sqlite3.o $(LDFLAGS.libsqlite3)
sqldiff.1.deps = $(TOP)/tool/sqldiff.c $(TOP)/ext/misc/sqlite3_stdio.h $(libsqlite3.SO)
sqldiff.1.rules = $(T.link) -o $@ $(TOP)/tool/sqldiff.c -L. -lsqlite3 $(LDFLAGS.configure)
sqldiff$(T.exe): $(sqldiff.$(LINK_TOOLS_DYNAMICALLY).deps)
	$(sqldiff.$(LINK_TOOLS_DYNAMICALLY).rules)

install-diff: sqldiff$(T.exe) $(install-dir.bin)
	$(INSTALL) sqldiff$(T.exe) "$(install-dir.bin)"
#install: install-diff

dbhash$(T.exe):	$(TOP)/tool/dbhash.c sqlite3.o sqlite3.h
	$(T.link) -o $@ $(TOP)/tool/dbhash.c sqlite3.o $(LDFLAGS.libsqlite3)
xbin: dbhash$(T.exe)

RSYNC_SRC = \
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
    $(TOP)/ext/recover/dbdata.c \
    $(TOP)/ext/recover/sqlite3recover.c \
    $(TOP)/ext/recover/sqlite3recover.h \
    $(TOP)/src/test_windirent.c \
    $(TOP)/src/test_windirent.h

shell.c:	$(SHELL_DEP) $(TOP)/tool/mkshellc.tcl $(B.tclsh)
	$(B.tclsh) $(TOP)/tool/mkshellc.tcl >shell.c

#
# Rules to build the extension objects.
#
DEPS_EXT_COMMON = $(DEPS_OBJ_COMMON) $(EXTHDR)
icu.o:	$(TOP)/ext/icu/icu.c $(DEPS_EXT_COMMON)
	$(T.cc.extension) -c $(TOP)/ext/icu/icu.c $(CFLAGS.icu)







|







2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
    $(TOP)/ext/recover/dbdata.c \
    $(TOP)/ext/recover/sqlite3recover.c \
    $(TOP)/ext/recover/sqlite3recover.h \
    $(TOP)/src/test_windirent.c \
    $(TOP)/src/test_windirent.h

shell.c:	$(SHELL_DEP) $(TOP)/tool/mkshellc.tcl $(B.tclsh)
	$(B.tclsh) $(TOP)/tool/mkshellc.tcl shell.c

#
# Rules to build the extension objects.
#
DEPS_EXT_COMMON = $(DEPS_OBJ_COMMON) $(EXTHDR)
icu.o:	$(TOP)/ext/icu/icu.c $(DEPS_EXT_COMMON)
	$(T.cc.extension) -c $(TOP)/ext/icu/icu.c $(CFLAGS.icu)
Changes to src/date.c.
218
219
220
221
222
223
224



225
226
227
228
229
230
231
      zDate++;
      while( sqlite3Isdigit(*zDate) ){
        ms = ms*10.0 + *zDate - '0';
        rScale *= 10.0;
        zDate++;
      }
      ms /= rScale;



    }
  }else{
    s = 0;
  }
  p->validJD = 0;
  p->rawS = 0;
  p->validHMS = 1;







>
>
>







218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
      zDate++;
      while( sqlite3Isdigit(*zDate) ){
        ms = ms*10.0 + *zDate - '0';
        rScale *= 10.0;
        zDate++;
      }
      ms /= rScale;
      /* Truncate to avoid problems with sub-milliseconds
      ** rounding. https://sqlite.org/forum/forumpost/766a2c9231 */
      if( ms>0.999 ) ms = 0.999;
    }
  }else{
    s = 0;
  }
  p->validJD = 0;
  p->rawS = 0;
  p->validHMS = 1;
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
      case 'd':  /* Fall thru */
      case 'e': {
        sqlite3_str_appendf(&sRes, cf=='d' ? "%02d" : "%2d", x.D);
        break;
      }
      case 'f': {  /* Fractional seconds.  (Non-standard) */
        double s = x.s;
        if( s>59.999 ) s = 59.999;
        sqlite3_str_appendf(&sRes, "%06.3f", s);
        break;
      }
      case 'F': {
        sqlite3_str_appendf(&sRes, "%04d-%02d-%02d", x.Y, x.M, x.D);
        break;
      }







|







1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
      case 'd':  /* Fall thru */
      case 'e': {
        sqlite3_str_appendf(&sRes, cf=='d' ? "%02d" : "%2d", x.D);
        break;
      }
      case 'f': {  /* Fractional seconds.  (Non-standard) */
        double s = x.s;
        if( NEVER(s>59.999) ) s = 59.999;
        sqlite3_str_appendf(&sRes, "%06.3f", s);
        break;
      }
      case 'F': {
        sqlite3_str_appendf(&sRes, "%04d-%02d-%02d", x.Y, x.M, x.D);
        break;
      }
Changes to src/dbpage.c.
420
421
422
423
424
425
426

427
428
429
430
431
432
433
  }else{
    pTab->pgnoTrunc = 0;
  }
  sqlite3PagerUnref(pDbPage);
  return rc;

update_fail:

  sqlite3_free(pVtab->zErrMsg);
  pVtab->zErrMsg = sqlite3_mprintf("%s", zErr);
  return SQLITE_ERROR;
}

static int dbpageBegin(sqlite3_vtab *pVtab){
  DbpageTable *pTab = (DbpageTable *)pVtab;







>







420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
  }else{
    pTab->pgnoTrunc = 0;
  }
  sqlite3PagerUnref(pDbPage);
  return rc;

update_fail:
  pTab->pgnoTrunc = 0;
  sqlite3_free(pVtab->zErrMsg);
  pVtab->zErrMsg = sqlite3_mprintf("%s", zErr);
  return SQLITE_ERROR;
}

static int dbpageBegin(sqlite3_vtab *pVtab){
  DbpageTable *pTab = (DbpageTable *)pVtab;
Changes to src/expr.c.
3461
3462
3463
3464
3465
3466
3467

3468
3469
3470
3471
3472
3473
3474
  pOp = sqlite3VdbeGetOp(v, 1);
  pEnd = sqlite3VdbeGetLastOp(v);
  for(; pOp<pEnd; pOp++){
    if( pOp->p4type!=P4_SUBRTNSIG ) continue;
    assert( pOp->opcode==OP_BeginSubrtn );
    pSig = pOp->p4.pSubrtnSig;
    assert( pSig!=0 );

    if( pNewSig->selId!=pSig->selId ) continue;
    if( strcmp(pNewSig->zAff,pSig->zAff)!=0 ) continue;
    pExpr->y.sub.iAddr = pSig->iAddr;
    pExpr->y.sub.regReturn = pSig->regReturn;
    pExpr->iTable = pSig->iTable;
    ExprSetProperty(pExpr, EP_Subrtn);
    return 1;







>







3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
  pOp = sqlite3VdbeGetOp(v, 1);
  pEnd = sqlite3VdbeGetLastOp(v);
  for(; pOp<pEnd; pOp++){
    if( pOp->p4type!=P4_SUBRTNSIG ) continue;
    assert( pOp->opcode==OP_BeginSubrtn );
    pSig = pOp->p4.pSubrtnSig;
    assert( pSig!=0 );
    if( !pSig->bComplete ) continue;
    if( pNewSig->selId!=pSig->selId ) continue;
    if( strcmp(pNewSig->zAff,pSig->zAff)!=0 ) continue;
    pExpr->y.sub.iAddr = pSig->iAddr;
    pExpr->y.sub.regReturn = pSig->regReturn;
    pExpr->iTable = pSig->iTable;
    ExprSetProperty(pExpr, EP_Subrtn);
    return 1;
3507
3508
3509
3510
3511
3512
3513

3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
){
  int addrOnce = 0;           /* Address of the OP_Once instruction at top */
  int addr;                   /* Address of OP_OpenEphemeral instruction */
  Expr *pLeft;                /* the LHS of the IN operator */
  KeyInfo *pKeyInfo = 0;      /* Key information */
  int nVal;                   /* Size of vector pLeft */
  Vdbe *v;                    /* The prepared statement under construction */


  v = pParse->pVdbe;
  assert( v!=0 );

  /* The evaluation of the IN must be repeated every time it
  ** is encountered if any of the following is true:
  **
  **    *  The right-hand side is a correlated subquery
  **    *  The right-hand side is an expression list containing variables
  **    *  We are inside a trigger
  **
  ** If all of the above are false, then we can compute the RHS just once
  ** and reuse it many names.
  */
  if( !ExprHasProperty(pExpr, EP_VarSelect) && pParse->iSelfTab==0 ){
    /* Reuse of the RHS is allowed
    **
    ** Compute a signature for the RHS of the IN operator to facility
    ** finding and reusing prior instances of the same IN operator.
    */
    SubrtnSig *pSig = 0;
    assert( !ExprUseXSelect(pExpr) || pExpr->x.pSelect!=0 );
    if( ExprUseXSelect(pExpr) && (pExpr->x.pSelect->selFlags & SF_All)==0 ){
      pSig = sqlite3DbMallocRawNN(pParse->db, sizeof(pSig[0]));
      if( pSig ){
        pSig->selId = pExpr->x.pSelect->selId;
        pSig->zAff = exprINAffinity(pParse, pExpr);
      }







>




















<







3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535

3536
3537
3538
3539
3540
3541
3542
){
  int addrOnce = 0;           /* Address of the OP_Once instruction at top */
  int addr;                   /* Address of OP_OpenEphemeral instruction */
  Expr *pLeft;                /* the LHS of the IN operator */
  KeyInfo *pKeyInfo = 0;      /* Key information */
  int nVal;                   /* Size of vector pLeft */
  Vdbe *v;                    /* The prepared statement under construction */
  SubrtnSig *pSig = 0;        /* Signature for this subroutine */

  v = pParse->pVdbe;
  assert( v!=0 );

  /* The evaluation of the IN must be repeated every time it
  ** is encountered if any of the following is true:
  **
  **    *  The right-hand side is a correlated subquery
  **    *  The right-hand side is an expression list containing variables
  **    *  We are inside a trigger
  **
  ** If all of the above are false, then we can compute the RHS just once
  ** and reuse it many names.
  */
  if( !ExprHasProperty(pExpr, EP_VarSelect) && pParse->iSelfTab==0 ){
    /* Reuse of the RHS is allowed
    **
    ** Compute a signature for the RHS of the IN operator to facility
    ** finding and reusing prior instances of the same IN operator.
    */

    assert( !ExprUseXSelect(pExpr) || pExpr->x.pSelect!=0 );
    if( ExprUseXSelect(pExpr) && (pExpr->x.pSelect->selFlags & SF_All)==0 ){
      pSig = sqlite3DbMallocRawNN(pParse->db, sizeof(pSig[0]));
      if( pSig ){
        pSig->selId = pExpr->x.pSelect->selId;
        pSig->zAff = exprINAffinity(pParse, pExpr);
      }
3570
3571
3572
3573
3574
3575
3576

3577
3578
3579
3580
3581
3582
3583
    assert( !ExprUseYWin(pExpr) );
    ExprSetProperty(pExpr, EP_Subrtn);
    assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
    pExpr->y.sub.regReturn = ++pParse->nMem;
    pExpr->y.sub.iAddr =
      sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pExpr->y.sub.regReturn) + 1;
    if( pSig ){

      pSig->iAddr = pExpr->y.sub.iAddr;
      pSig->regReturn = pExpr->y.sub.regReturn;
      pSig->iTable = iTab;
      pParse->mSubrtnSig = 1 << (pSig->selId&7);
      sqlite3VdbeChangeP4(v, -1, (const char*)pSig, P4_SUBRTNSIG);
    }
    addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);







>







3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
    assert( !ExprUseYWin(pExpr) );
    ExprSetProperty(pExpr, EP_Subrtn);
    assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
    pExpr->y.sub.regReturn = ++pParse->nMem;
    pExpr->y.sub.iAddr =
      sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pExpr->y.sub.regReturn) + 1;
    if( pSig ){
      pSig->bComplete = 0;
      pSig->iAddr = pExpr->y.sub.iAddr;
      pSig->regReturn = pExpr->y.sub.regReturn;
      pSig->iTable = iTab;
      pParse->mSubrtnSig = 1 << (pSig->selId&7);
      sqlite3VdbeChangeP4(v, -1, (const char*)pSig, P4_SUBRTNSIG);
    }
    addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
3705
3706
3707
3708
3709
3710
3711

3712
3713
3714
3715
3716
3717
3718
      sqlite3ExprCode(pParse, pE2, r1);
      sqlite3VdbeAddOp4(v, OP_MakeRecord, r1, 1, r2, &affinity, 1);
      sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r2, r1, 1);
    }
    sqlite3ReleaseTempReg(pParse, r1);
    sqlite3ReleaseTempReg(pParse, r2);
  }

  if( pKeyInfo ){
    sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO);
  }
  if( addrOnce ){
    sqlite3VdbeAddOp1(v, OP_NullRow, iTab);
    sqlite3VdbeJumpHere(v, addrOnce);
    /* Subroutine return */







>







3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
      sqlite3ExprCode(pParse, pE2, r1);
      sqlite3VdbeAddOp4(v, OP_MakeRecord, r1, 1, r2, &affinity, 1);
      sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r2, r1, 1);
    }
    sqlite3ReleaseTempReg(pParse, r1);
    sqlite3ReleaseTempReg(pParse, r2);
  }
  if( pSig ) pSig->bComplete = 1;
  if( pKeyInfo ){
    sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO);
  }
  if( addrOnce ){
    sqlite3VdbeAddOp1(v, OP_NullRow, iTab);
    sqlite3VdbeJumpHere(v, addrOnce);
    /* Subroutine return */
Changes to src/os_unix.c.
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
  int rc;
  unixInodeInfo *pInode = pFile->pInode;
  assert( pInode!=0 );
  assert( sqlite3_mutex_held(pInode->pLockMutex) );
  if( (pFile->ctrlFlags & (UNIXFILE_EXCL|UNIXFILE_RDONLY))==UNIXFILE_EXCL ){
    if( pInode->bProcessLock==0 ){
      struct flock lock;
      assert( pInode->nLock==0 );
      lock.l_whence = SEEK_SET;
      lock.l_start = SHARED_FIRST;
      lock.l_len = SHARED_SIZE;
      lock.l_type = F_WRLCK;
      rc = osSetPosixAdvisoryLock(pFile->h, &lock, pFile);
      if( rc<0 ) return rc;
      pInode->bProcessLock = 1;







|







1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
  int rc;
  unixInodeInfo *pInode = pFile->pInode;
  assert( pInode!=0 );
  assert( sqlite3_mutex_held(pInode->pLockMutex) );
  if( (pFile->ctrlFlags & (UNIXFILE_EXCL|UNIXFILE_RDONLY))==UNIXFILE_EXCL ){
    if( pInode->bProcessLock==0 ){
      struct flock lock;
      /* assert( pInode->nLock==0 ); <-- Not true if unix-excl READONLY used */
      lock.l_whence = SEEK_SET;
      lock.l_start = SHARED_FIRST;
      lock.l_len = SHARED_SIZE;
      lock.l_type = F_WRLCK;
      rc = osSetPosixAdvisoryLock(pFile->h, &lock, pFile);
      if( rc<0 ) return rc;
      pInode->bProcessLock = 1;
Changes to src/pager.c.
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
  assert( pPager->fd!=0 );
  if( pPager->fd->pMethods==0 ) return 0;  /* Case (1) */
  if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; /* Failed (3) */
#ifndef SQLITE_OMIT_WAL
  if( pPager->pWal ){
    u32 iRead = 0;
    (void)sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
    return iRead==0; /* Condition (4) */
  }
#endif
  assert( pPager->fd->pMethods->xDeviceCharacteristics!=0 );
  if( (pPager->fd->pMethods->xDeviceCharacteristics(pPager->fd)
        & SQLITE_IOCAP_SUBPAGE_READ)==0 ){
    return 0; /* Case (2) */
  }







|







804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
  assert( pPager->fd!=0 );
  if( pPager->fd->pMethods==0 ) return 0;  /* Case (1) */
  if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; /* Failed (3) */
#ifndef SQLITE_OMIT_WAL
  if( pPager->pWal ){
    u32 iRead = 0;
    (void)sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
    if( iRead ) return 0;  /* Case (4) */
  }
#endif
  assert( pPager->fd->pMethods->xDeviceCharacteristics!=0 );
  if( (pPager->fd->pMethods->xDeviceCharacteristics(pPager->fd)
        & SQLITE_IOCAP_SUBPAGE_READ)==0 ){
    return 0; /* Case (2) */
  }
Changes to src/vdbe.h.
36
37
38
39
40
41
42

43
44
45
46
47
48
49

/*
** A signature for a reusable subroutine that materializes the RHS of
** an IN operator.
*/
struct SubrtnSig {
  int selId;          /* SELECT-id for the SELECT statement on the RHS */

  char *zAff;         /* Affinity of the overall IN expression */
  int iTable;         /* Ephemeral table generated by the subroutine */
  int iAddr;          /* Subroutine entry address */
  int regReturn;      /* Register used to hold return address */
};

/*







>







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

/*
** A signature for a reusable subroutine that materializes the RHS of
** an IN operator.
*/
struct SubrtnSig {
  int selId;          /* SELECT-id for the SELECT statement on the RHS */
  u8 bComplete;       /* True if fully coded and available for reusable */
  char *zAff;         /* Affinity of the overall IN expression */
  int iTable;         /* Ephemeral table generated by the subroutine */
  int iAddr;          /* Subroutine entry address */
  int regReturn;      /* Register used to hold return address */
};

/*
Changes to src/vdbeapi.c.
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
** Invoke the profile callback.  This routine is only called if we already
** know that the profile callback is defined and needs to be invoked.
*/
static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){
  sqlite3_int64 iNow;
  sqlite3_int64 iElapse;
  assert( p->startTime>0 );
  assert( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0 );
  assert( db->init.busy==0 );
  assert( p->zSql!=0 );
  sqlite3OsCurrentTimeInt64(db->pVfs, &iNow);
  iElapse = (iNow - p->startTime)*1000000;
#ifndef SQLITE_OMIT_DEPRECATED
  if( db->xProfile ){
    db->xProfile(db->pProfileArg, p->zSql, iElapse);







<







59
60
61
62
63
64
65

66
67
68
69
70
71
72
** Invoke the profile callback.  This routine is only called if we already
** know that the profile callback is defined and needs to be invoked.
*/
static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){
  sqlite3_int64 iNow;
  sqlite3_int64 iElapse;
  assert( p->startTime>0 );

  assert( db->init.busy==0 );
  assert( p->zSql!=0 );
  sqlite3OsCurrentTimeInt64(db->pVfs, &iNow);
  iElapse = (iNow - p->startTime)*1000000;
#ifndef SQLITE_OMIT_DEPRECATED
  if( db->xProfile ){
    db->xProfile(db->pProfileArg, p->zSql, iElapse);
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
      ** from interrupting a statement that has not yet started.
      */
      if( db->nVdbeActive==0 ){
        AtomicStore(&db->u1.isInterrupted, 0);
      }

      assert( db->nVdbeWrite>0 || db->autoCommit==0
          || (db->nDeferredCons==0 && db->nDeferredImmCons==0)
      );

#ifndef SQLITE_OMIT_TRACE
      if( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0
          && !db->init.busy && p->zSql ){
        sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
      }else{







|







778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
      ** from interrupting a statement that has not yet started.
      */
      if( db->nVdbeActive==0 ){
        AtomicStore(&db->u1.isInterrupted, 0);
      }

      assert( db->nVdbeWrite>0 || db->autoCommit==0
          || ((db->nDeferredCons + db->nDeferredImmCons)==0)
      );

#ifndef SQLITE_OMIT_TRACE
      if( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0
          && !db->init.busy && p->zSql ){
        sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
      }else{
Changes to src/whereexpr.c.
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
    sqlite3VdbeSetVarmask(pParse->pVdbe, iCol);
    assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER );
  }else if( op==TK_STRING ){
    assert( !ExprHasProperty(pRight, EP_IntValue) );
     z = (u8*)pRight->u.zToken;
  }
  if( z ){
    /* Count the number of prefix bytes prior to the first wildcard.
    ** or U+fffd character.  If the underlying database has a UTF16LE
    ** encoding, then only consider ASCII characters.  Note that the
    ** encoding of z[] is UTF8 - we are dealing with only UTF8 here in
    ** this code, but the database engine itself might be processing
    ** content using a different encoding. */
    cnt = 0;
    while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
      cnt++;
      if( c==wc[3] && z[cnt]>0 && z[cnt]<0x80 ){
        cnt++;
      }else if( c>=0x80 ){
        const u8 *z2 = z+cnt-1;
        if( sqlite3Utf8Read(&z2)==0xfffd || ENC(db)==SQLITE_UTF16LE ){


          cnt--;
          break;
        }else{
          cnt = (int)(z2-z);
        }
      }
    }







|
|
|
|
|
|







|
>
>







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
    sqlite3VdbeSetVarmask(pParse->pVdbe, iCol);
    assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER );
  }else if( op==TK_STRING ){
    assert( !ExprHasProperty(pRight, EP_IntValue) );
     z = (u8*)pRight->u.zToken;
  }
  if( z ){
    /* Count the number of prefix bytes prior to the first wildcard,
    ** U+fffd character, or malformed utf-8. If the underlying database
    ** has a UTF16LE encoding, then only consider ASCII characters.  Note that
    ** the encoding of z[] is UTF8 - we are dealing with only UTF8 here in this
    ** code, but the database engine itself might be processing content using a
    ** different encoding. */
    cnt = 0;
    while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
      cnt++;
      if( c==wc[3] && z[cnt]>0 && z[cnt]<0x80 ){
        cnt++;
      }else if( c>=0x80 ){
        const u8 *z2 = z+cnt-1;
        if( sqlite3Utf8Read(&z2)==0xfffd || c==0xFF   /* bad utf-8 */
         || ENC(db)==SQLITE_UTF16LE 
        ){
          cnt--;
          break;
        }else{
          cnt = (int)(z2-z);
        }
      }
    }
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
      for(i=0; (c = pStr1->u.zToken[i])!=0; i++){
        pStr1->u.zToken[i] = sqlite3Toupper(c);
        pStr2->u.zToken[i] = sqlite3Tolower(c);
      }
    }

    if( !db->mallocFailed ){
      u8 c, *pC;       /* Last character before the first wildcard */
      pC = (u8*)&pStr2->u.zToken[sqlite3Strlen30(pStr2->u.zToken)-1];
      c = *pC;
      if( noCase ){
        /* The point is to increment the last character before the first
        ** wildcard.  But if we increment '@', that will push it into the
        ** alphabetic range where case conversions will mess up the
        ** inequality.  To avoid this, make sure to also run the full
        ** LIKE on all candidate expressions by clearing the isComplete flag
        */
        if( c=='A'-1 ) isComplete = 0;
        c = sqlite3UpperToLower[c];
      }



      *pC = c + 1;




    }
    zCollSeqName = noCase ? "NOCASE" : sqlite3StrBINARY;
    pNewExpr1 = sqlite3ExprDup(db, pLeft, 0);
    pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
           sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName),
           pStr1);
    transferJoinMarkings(pNewExpr1, pExpr);







|

<







|
|

>
>
>
|
>
>
>
>







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
      for(i=0; (c = pStr1->u.zToken[i])!=0; i++){
        pStr1->u.zToken[i] = sqlite3Toupper(c);
        pStr2->u.zToken[i] = sqlite3Tolower(c);
      }
    }

    if( !db->mallocFailed ){
      u8 *pC;       /* Last character before the first wildcard */
      pC = (u8*)&pStr2->u.zToken[sqlite3Strlen30(pStr2->u.zToken)-1];

      if( noCase ){
        /* The point is to increment the last character before the first
        ** wildcard.  But if we increment '@', that will push it into the
        ** alphabetic range where case conversions will mess up the
        ** inequality.  To avoid this, make sure to also run the full
        ** LIKE on all candidate expressions by clearing the isComplete flag
        */
        if( *pC=='A'-1 ) isComplete = 0;
        *pC = sqlite3UpperToLower[*pC];
      }

      /* Increment the value of the last utf8 character in the prefix. */
      while( *pC==0xBF && pC>(u8*)pStr2->u.zToken ){
        *pC = 0x80;
        pC--;
      }
      assert( *pC!=0xFF );        /* isLikeOrGlob() guarantees this */
      (*pC)++;
    }
    zCollSeqName = noCase ? "NOCASE" : sqlite3StrBINARY;
    pNewExpr1 = sqlite3ExprDup(db, pLeft, 0);
    pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
           sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName),
           pStr1);
    transferJoinMarkings(pNewExpr1, pExpr);
Changes to test/date.test.
647
648
649
650
651
652
653








654
655
datetest 19.48 {date('2024-02-29','-0110-00-00','floor')} {1914-02-28}
datetest 19.49 {date('2024-02-29','-0110-00-00','ceiling')} {1914-03-01}
datetest 19.50 {date('2000-08-31','+0023-06-00','floor')} {2024-02-29}
datetest 19.51 {date('2000-08-31','+0022-06-00','floor')} {2023-02-28}
datetest 19.52 {date('2000-08-31','+0023-06-00','ceiling')} {2024-03-02}
datetest 19.53 {date('2000-08-31','+0022-06-00','ceiling')} {2023-03-03}










finish_test







>
>
>
>
>
>
>
>


647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
datetest 19.48 {date('2024-02-29','-0110-00-00','floor')} {1914-02-28}
datetest 19.49 {date('2024-02-29','-0110-00-00','ceiling')} {1914-03-01}
datetest 19.50 {date('2000-08-31','+0023-06-00','floor')} {2024-02-29}
datetest 19.51 {date('2000-08-31','+0022-06-00','floor')} {2023-02-28}
datetest 19.52 {date('2000-08-31','+0023-06-00','ceiling')} {2024-03-02}
datetest 19.53 {date('2000-08-31','+0022-06-00','ceiling')} {2023-03-03}

# 2025-01-21
# https://sqlite.org/forum/forumpost/766a2c9231
#
datetest 20.1 {datetime('2024-12-31 23:59:59.9990')} {2024-12-31 23:59:59}
datetest 20.2 {datetime('2024-12-31 23:59:59.9999999999999')} \
                 {2024-12-31 23:59:59}
datetest 20.3 {datetime('2024-12-31 23:59:59.9995')} {2024-12-31 23:59:59}
datetest 20.4 {datetime('2024-12-31 23:59:58.9995')} {2024-12-31 23:59:58}

finish_test
Changes to test/fkey6.test.
246
247
248
249
250
251
252

253














254
255
256
    DELETE FROM p1 WHERE a=2;
}

do_catchsql_test 4.2 {
  COMMIT;
} {1 {FOREIGN KEY constraint failed}}



















finish_test







>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>



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
    DELETE FROM p1 WHERE a=2;
}

do_catchsql_test 4.2 {
  COMMIT;
} {1 {FOREIGN KEY constraint failed}}

#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 5.0 {
  PRAGMA foreign_keys = 1;
  CREATE TABLE p1(a INTEGER PRIMARY KEY, b);
  CREATE TABLE c1(x REFERENCES p1 DEFERRABLE INITIALLY DEFERRED);
}

do_execsql_test 5.1 {
  BEGIN;
    INSERT INTO c1 VALUES(123);
    PRAGMA defer_foreign_keys = 1;
    INSERT INTO p1 VALUES(123, 'one two three');
  COMMIT;
}


finish_test
Changes to test/in7.test.
214
215
216
217
218
219
220





























221
222
} {1 1}
do_execsql_test 3.7 {
  SELECT t1.a, t2.b FROM t1, t2 WHERE (t1.a, t2.b) = (1, 2);
} {1 2}
do_execsql_test 3.8 {
  SELECT t1.a, t2.b FROM t1, t2 WHERE (t1.a, t2.b) IN ((1, 2));
} {1 2}






























finish_test







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


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
} {1 1}
do_execsql_test 3.7 {
  SELECT t1.a, t2.b FROM t1, t2 WHERE (t1.a, t2.b) = (1, 2);
} {1 2}
do_execsql_test 3.8 {
  SELECT t1.a, t2.b FROM t1, t2 WHERE (t1.a, t2.b) IN ((1, 2));
} {1 2}

# 2025-01-30 Inifinite loop in byte-code discovered by dbsqlfuzz
# having to do with SubrtnSig logic.  The code was using a Subroutine
# from within itself resulting in infinite recursion.
#
# This test will spin forever if the bug has not been fixed, or if
# it reappears.
#
reset_db
do_execsql_test 4.0 {
  CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
  INSERT INTO t1 VALUES(1,x'1111');
  CREATE TABLE t2(c);
  CREATE TABLE t3(d);
  CREATE TRIGGER t1tr UPDATE ON t1 BEGIN
    UPDATE t1 SET b=x'2222' FROM t2;
    UPDATE t1
       SET b = (SELECT a IN (SELECT a
                               FROM t1
                              WHERE (b,a) IN (SELECT rowid, d
                                                FROM t3
                                             )
                            )
                  FROM t1 NATURAL RIGHT JOIN t1
               );
  END;
  UPDATE t1 SET b=x'3333';
  SELECT quote(b) FROM t1;
} {X'3333'}

finish_test
Changes to test/like3.test.
270
271
272
273
274
275
276
277















































































278

do_eqp_test like3-6.240 {
  SELECT * FROM t2 WHERE path LIKE 'a%' ESCAPE '\';
} {
  QUERY PLAN
  `--SEARCH t2 USING INDEX t2path2 (path>? AND path<?)
}
}
















































































finish_test









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

>
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
do_eqp_test like3-6.240 {
  SELECT * FROM t2 WHERE path LIKE 'a%' ESCAPE '\';
} {
  QUERY PLAN
  `--SEARCH t2 USING INDEX t2path2 (path>? AND path<?)
}
}

#-------------------------------------------------------------------------

ifcapable utf16 {
  reset_db
  do_execsql_test like3-7.0 {
    PRAGMA encoding = 'UTF-16be';
  
    CREATE TABLE Example(word TEXT NOT NULL);
    CREATE INDEX Example_word on Example(word);
  
    INSERT INTO Example VALUES(char(0x307F));
  }
  
  do_execsql_test like3-7.1 {
    SELECT char(0x307F)=='み';
  } {1}
  
  do_execsql_test like3-7.1 {
    SELECT * FROM Example WHERE word GLOB 'み*'
  } {み}
  
  do_execsql_test like3-7.2 {
    SELECT * FROM Example WHERE word >= char(0x307F) AND word < char(0x3080);
  } {み}
}

#-------------------------------------------------------------------------
reset_db

foreach enc {
  UTF-8
  UTF-16le 
  UTF-16be
} {
  foreach {tn expr} {
    1 "CAST (X'FF' AS TEXT)"
    2 "CAST (X'FFBF' AS TEXT)"
    3 "CAST (X'FFBFBF' AS TEXT)"
    4 "CAST (X'FFBFBFBF' AS TEXT)"

    5 "'abc' || CAST (X'FF' AS TEXT)"
    6 "'def' || CAST (X'FFBF' AS TEXT)"
    7 "'ghi' || CAST (X'FFBFBF' AS TEXT)"
    8 "'jkl' || CAST (X'FFBFBFBF' AS TEXT)"
  } {
    reset_db
    execsql "PRAGMA encoding = '$enc'"
    do_execsql_test like3-8.$tn.0 {
      CREATE TABLE t1(x);
    }
  
    do_execsql_test like3-8.$tn.1 {
      PRAGMA encoding
    } $enc
  
    do_execsql_test like3-8.$tn.1 "
      INSERT INTO t1 VALUES( $expr )
    "
  
    do_execsql_test like3-8.$tn.2 {
      SELECT typeof(x) FROM t1
    } {text}
  
    set x [db one {SELECT x || '%' FROM t1}]
  
    do_execsql_test like3-8.$tn.3 {
      SELECT rowid FROM t1 WHERE x LIKE $x
    } 1
  
    do_execsql_test like3-8.$tn.4 {
      CREATE INDEX i1 ON t1(x);
    }
  
    do_execsql_test like3-8.$tn.5 {
      SELECT rowid FROM t1 WHERE x LIKE $x
    } 1
  }
}

finish_test

Changes to test/trace3.test.
338
339
340
341
342
343
344
















345
346
    HAVING (1.0 - ((distance / 100.0) / CAST( length('A') - 1 AS REAL ))) >= 'F'
  }

do_test 12.1.2 {
  sqlite3_finalize $STMT
} {SQLITE_OK}


















finish_test







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


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
    HAVING (1.0 - ((distance / 100.0) / CAST( length('A') - 1 AS REAL ))) >= 'F'
  }

do_test 12.1.2 {
  sqlite3_finalize $STMT
} {SQLITE_OK}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 13.0 {
  CREATE TABLE T1(a, b);
  INSERT INTO t1 VALUES(1, 2), (3, 4);
}

proc trace_callback {args} {}
db trace_v2 trace_callback profile

do_test 13.1 {
  db eval { SELECT * FROM t1 } {
    db trace_v2 "" ""
  }
  set {} {}
} {}

finish_test
Changes to tool/emcc.sh.in.
59
60
61
62
63
64
65
66
  emcc=`which emcc 2>/dev/null`
  if [ x = "x${emcc}" ]; then
    echo "emcc not found in PATH. Normally that's set up by ${EMSDK_ENV_SH}." 1>&2
    exit 4
  fi
fi

exec emcc "$@"







|
59
60
61
62
63
64
65
66
  emcc=`which emcc 2>/dev/null`
  if [ x = "x${emcc}" ]; then
    echo "emcc not found in PATH. Normally that's set up by ${EMSDK_ENV_SH}." 1>&2
    exit 4
  fi
fi

exec $emcc "$@"
Changes to tool/mkshellc.tcl.
8
9
10
11
12
13
14



15
16
17
18
19
20
21
# This script should be tool/mkshellc.tcl.  If the directory holding
# the script is $DIR, then the component parts are located in $DIR/../src
# and $DIR/../ext/misc.
#
set topdir [file dir [file dir [file normal $argv0]]]
set out stdout
fconfigure stdout -translation binary



puts $out {/* DO NOT EDIT!
** This file is automatically generated by the script in the canonical
** SQLite source tree at tool/mkshellc.tcl.  That script combines source
** code from various constituent source files of SQLite into this single
** "shell.c" file used to implement the SQLite command-line shell.
**
** Most of the code found below comes from the "src/shell.c.in" file in







>
>
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# This script should be tool/mkshellc.tcl.  If the directory holding
# the script is $DIR, then the component parts are located in $DIR/../src
# and $DIR/../ext/misc.
#
set topdir [file dir [file dir [file normal $argv0]]]
set out stdout
fconfigure stdout -translation binary
if {[lindex $argv 0]!=""} {
  set out [open [lindex $argv 0] wb]
}
puts $out {/* DO NOT EDIT!
** This file is automatically generated by the script in the canonical
** SQLite source tree at tool/mkshellc.tcl.  That script combines source
** code from various constituent source files of SQLite into this single
** "shell.c" file used to implement the SQLite command-line shell.
**
** Most of the code found below comes from the "src/shell.c.in" file in
Changes to tool/mksqlite3c-noext.tcl.
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
close $in

# Open the output file and write a header comment at the beginning
# of the file.
#
set out [open sqlite3.c w]
# Force the output to use unix line endings, even on Windows.
fconfigure $out -translation lf
set today [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S UTC" -gmt 1]
puts $out [subst \
{/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
** version $VERSION.  By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit.  This allows many compilers to do optimizations that would not be







|







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
close $in

# Open the output file and write a header comment at the beginning
# of the file.
#
set out [open sqlite3.c w]
# Force the output to use unix line endings, even on Windows.
fconfigure $out -translation binary
set today [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S UTC" -gmt 1]
puts $out [subst \
{/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
** version $VERSION.  By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit.  This allows many compilers to do optimizations that would not be
Changes to tool/mksqlite3c.tcl.
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# Open the output file and write a header comment at the beginning
# of the file.
#
set fname sqlite3.c
if {$enable_recover} { set fname sqlite3r.c }
set out [open $fname wb]
# Force the output to use unix line endings, even on Windows.
fconfigure $out -translation lf
set today [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S UTC" -gmt 1]
puts $out [subst \
{/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
** version $VERSION.  By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit.  This allows many compilers to do optimizations that would not be







|







84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# Open the output file and write a header comment at the beginning
# of the file.
#
set fname sqlite3.c
if {$enable_recover} { set fname sqlite3r.c }
set out [open $fname wb]
# Force the output to use unix line endings, even on Windows.
fconfigure $out -translation binary
set today [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S UTC" -gmt 1]
puts $out [subst \
{/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
** version $VERSION.  By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit.  This allows many compilers to do optimizations that would not be
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
  puts $out "** The content in this amalgamation comes from Fossil check-in"
  puts -nonewline $out "** [string range [lindex $res 0] 0 35]"
  if {[llength $res]==1} {
    puts $out "."
  } else {
    puts $out " with changes in files:\n**"
    foreach f [lrange $res 1 end] {
       puts $out "**    $f"
    }
  }
} else {
  puts $out "** The origin of the sources used to build this amalgamation"
  puts $out "** is unknown."
}
puts $out [subst {*/







|







126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
  puts $out "** The content in this amalgamation comes from Fossil check-in"
  puts -nonewline $out "** [string range [lindex $res 0] 0 35]"
  if {[llength $res]==1} {
    puts $out "."
  } else {
    puts $out " with changes in files:\n**"
    foreach f [lrange $res 1 end] {
       puts $out "**    [string trim $f]"
    }
  }
} else {
  puts $out "** The origin of the sources used to build this amalgamation"
  puts $out "** is unknown."
}
puts $out [subst {*/
Changes to tool/mksqlite3h.tcl.
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
#   4) Replaces the string --VERSION-NUMBER-- with current library version,
#      formatted as an integer (e.g. "3006017").
#   5) Replaces the string --SOURCE-ID-- with the date and time and sha1
#      hash of the fossil-scm manifest for the source tree.
#   6) Adds the SQLITE_CALLBACK calling convention macro in front of all
#      callback declarations.
#
# This script outputs to stdout.
#
# Example usage:
#
#   tclsh mksqlite3h.tcl ../sqlite >sqlite3.h


#










# Get the source tree root directory from the command-line
#
set TOP [lindex $argv 0]









# Enable use of SQLITE_APICALL macros at the right points?
#
set useapicall 0

# Include sqlite3recover.h?
#
set enable_recover 0


if {[lsearch -regexp [lrange $argv 1 end] {^-+useapicall}] != -1} {
  set useapicall 1
}
if {[lsearch -regexp [lrange $argv 1 end] {^-+enable-recover}] != -1} {
  set enable_recover 1
}








|



|
>
>

>
|
>
>
>
>
>
>
>




>
>
>
>
>
>
>
>









>







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
#   4) Replaces the string --VERSION-NUMBER-- with current library version,
#      formatted as an integer (e.g. "3006017").
#   5) Replaces the string --SOURCE-ID-- with the date and time and sha1
#      hash of the fossil-scm manifest for the source tree.
#   6) Adds the SQLITE_CALLBACK calling convention macro in front of all
#      callback declarations.
#
# This script outputs to stdout unless the -o FILENAME option is used.
#
# Example usage:
#
#   tclsh mksqlite3h.tcl ../sqlite [OPTIONS]
#                        ^^^^^^^^^
#                        Root of source tree
#
# Where options are:
#
#   --enable-recover          Include the sqlite3recover extension
#   -o FILENAME               Write results to FILENAME instead of stdout
#   --useapicall              SQLITE_APICALL instead of SQLITE_CDECL
#

# Default output stream
set out stdout

# Get the source tree root directory from the command-line
#
set TOP [lindex $argv 0]

# If the -o FILENAME option is present, use FILENAME for output.
#
set x [lsearch $argv -o]
if {$x>0} {
  incr x
  set out [open [lindex $argv $x] wb]
}

# Enable use of SQLITE_APICALL macros at the right points?
#
set useapicall 0

# Include sqlite3recover.h?
#
set enable_recover 0

# Process command-line arguments
if {[lsearch -regexp [lrange $argv 1 end] {^-+useapicall}] != -1} {
  set useapicall 1
}
if {[lsearch -regexp [lrange $argv 1 end] {^-+enable-recover}] != -1} {
  set enable_recover 1
}

84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
set declpattern4 \
    {^ *([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3changegroup_[_a-zA-Z0-9]+)(\(.*)$}

set declpattern5 \
    {^ *([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3rebaser_[_a-zA-Z0-9]+)(\(.*)$}

# Force the output to use unix line endings, even on Windows.
fconfigure stdout -translation lf

set filelist [subst {
  $TOP/src/sqlite.h.in
  $TOP/ext/rtree/sqlite3rtree.h
  $TOP/ext/session/sqlite3session.h
  $TOP/ext/fts5/fts5.h
}]







|







103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
set declpattern4 \
    {^ *([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3changegroup_[_a-zA-Z0-9]+)(\(.*)$}

set declpattern5 \
    {^ *([a-zA-Z][a-zA-Z_0-9 ]+ \**)(sqlite3rebaser_[_a-zA-Z0-9]+)(\(.*)$}

# Force the output to use unix line endings, even on Windows.
fconfigure stdout -translation binary

set filelist [subst {
  $TOP/src/sqlite.h.in
  $TOP/ext/rtree/sqlite3rtree.h
  $TOP/ext/session/sqlite3session.h
  $TOP/ext/fts5/fts5.h
}]
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
}

# Process the source files.
#
foreach file $filelist {
  set in [open $file rb]
  if {![regexp {sqlite\.h\.in} $file]} {
    puts "/******** Begin file [file tail $file] *********/"
  }
  while {![eof $in]} {

    set line [string trimright [gets $in]]

    # File sqlite3rtree.h contains a line "#include <sqlite3.h>". Omit this
    # line when copying sqlite3rtree.h into sqlite3.h.







|







133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
}

# Process the source files.
#
foreach file $filelist {
  set in [open $file rb]
  if {![regexp {sqlite\.h\.in} $file]} {
    puts $out "/******** Begin file [file tail $file] *********/"
  }
  while {![eof $in]} {

    set line [string trimright [gets $in]]

    # File sqlite3rtree.h contains a line "#include <sqlite3.h>". Omit this
    # line when copying sqlite3rtree.h into sqlite3.h.
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
      }
    }
    if {$useapicall} {
      set line [string map [list (*sqlite3_syscall_ptr) \
          "(SQLITE_SYSAPI *sqlite3_syscall_ptr)"] $line]
      regsub {\(\*} $line {(SQLITE_CALLBACK *} line
    }
    puts $line
  }
  close $in
  if {![regexp {sqlite\.h\.in} $file]} {
    puts "/******** End of [file tail $file] *********/"
  }
}
puts "#endif /* SQLITE3_H */"







|



|


|
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
      }
    }
    if {$useapicall} {
      set line [string map [list (*sqlite3_syscall_ptr) \
          "(SQLITE_SYSAPI *sqlite3_syscall_ptr)"] $line]
      regsub {\(\*} $line {(SQLITE_CALLBACK *} line
    }
    puts $out $line
  }
  close $in
  if {![regexp {sqlite\.h\.in} $file]} {
    puts $out "/******** End of [file tail $file] *********/"
  }
}
puts $out "#endif /* SQLITE3_H */"
Changes to tool/split-sqlite3c.tcl.
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
set MAX 32768    ;# Maximum number of lines per file.

set BEGIN {^/\*+ Begin file ([a-zA-Z0-9_.]+) \*+/}
set END   {^/\*+ End of %s \*+/}

set in [open sqlite3.c]
set out1 [open sqlite3-all.c w]
fconfigure $out1 -translation lf

# Copy the header from sqlite3.c into sqlite3-all.c
#
while {[gets $in line]} {
  if {[regexp $BEGIN $line]} break
  puts $out1 $line
}







|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
set MAX 32768    ;# Maximum number of lines per file.

set BEGIN {^/\*+ Begin file ([a-zA-Z0-9_.]+) \*+/}
set END   {^/\*+ End of %s \*+/}

set in [open sqlite3.c]
set out1 [open sqlite3-all.c w]
fconfigure $out1 -translation binary

# Copy the header from sqlite3.c into sqlite3-all.c
#
while {[gets $in line]} {
  if {[regexp $BEGIN $line]} break
  puts $out1 $line
}
Changes to tool/stripccomments.c.
107
108
109
110
111
112
113
















114

115
116
117
118
119
120
121
            App.rc = 1;
            return;
          }
          break;
        }
        else if(slash == ch){
          /* MARKER(("state 0 ==> 1 @ %d:%d\n", line, col)); */
















          state = S_SLASH1;

          break;
        }
        fputc(ch, out);
        break;
      case S_SLASH1: /* 1 slash */
        /* MARKER(("SLASH1 @ %d:%d App.keepFirst=%d\n",
           line, col, App.keepFirst)); */







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>







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
            App.rc = 1;
            return;
          }
          break;
        }
        else if(slash == ch){
          /* MARKER(("state 0 ==> 1 @ %d:%d\n", line, col)); */
          if( '\\'==prev ){
            /**
               JS regexes may contain slash-asterisks, as happened at:

               https://github.com/emscripten-core/emscripten/issues/23412

               Such regexes will always necessarily be preceeded by a
               backslash, though.

               It is hypothetically possible for a legitimate comment
               slash-asterisk to appear immediately before a
               backslash, but that seems like an even rarer corner
               case than the JS regex case.
            */
            fputc(ch, out);
          }else{
            state = S_SLASH1;
          }
          break;
        }
        fputc(ch, out);
        break;
      case S_SLASH1: /* 1 slash */
        /* MARKER(("SLASH1 @ %d:%d App.keepFirst=%d\n",
           line, col, App.keepFirst)); */