SQLite

Check-in Differences
Login

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

Difference From 1bd9de719b0944fd To 301df5c2beb08e8e

2024-12-01
14:02
Export a clipped copy of sqlite370.eps as sqlite370.svg, based on discussion in forum post 1bbd6d17ca. (check-in: dd3a13c120 user: stephan tags: trunk)
2024-11-30
17:48
At the end of the configure script ensure that none of the files which are filtered for @VARS@ contain any unresolved @VAR@ placeholders, failing fatally if any do. (check-in: 301df5c2be user: stephan tags: trunk)
14:13
In sqlite_dbpage, cancel any pending truncate operation if there an error occurs later in the transaction. (check-in: 1abab10f85 user: drh tags: trunk)
2024-11-08
14:34
Remove one dep from .tclenv.sh which is only valid for configure-driven builds, not static makefiles. (check-in: 22986767da user: stephan tags: trunk)
13:37
Add 'tcl' makefile target which builds all but tclextension (which does not have a well-defined name and dependencies). Improve the deps for .tclenv.sh to avoid getting a stale tclsh when re-configuring with a different --with-tcl(sh). (check-in: 1bd9de719b user: stephan tags: trunk)
08:01
Add missing CFLAGS.intree_includes to T.compile.tcl to fix build of tclsqlite3. (check-in: bb3c6dc126 user: stephan tags: trunk)

Changes to Makefile.in.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18











-







#!/usr/bin/make
# ^^^^ help out editors which guess this file's type.
#
# Makefile for SQLITE
#
# This makefile is intended to be configured automatically using the
# configure script.
#
# The docs for many of its variables are in the primary static
# makefile, main.mk (which this one includes at runtime).
#
.POSIX: #maintenance reminder: X:=Y is not POSIX-portable
all:
########################################################################
#
# Known TODOs/FIXMEs/TOIMPROVEs for the autosetup port, in no
# particular order...
#
# - TEA pieces.
38
39
40
41
42
43
44
45

46
47
48
49
50
51
52
53
54
55
56

57
58
59
60
61
62
63
64



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
37
38
39
40
41
42
43

44






45


46

47








48
49
50



















51
52
53
54
55
56
57







-
+
-
-
-
-
-
-

-
-

-
+
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







#

#
# The top-most directory of the source tree.  This is the directory
# that contains this "Makefile.in" and the "configure" script.
#
TOP = @abs_top_srcdir@
#

# Just testing some default dir expansions...
# srcdir = @srcdir@
# builddir = @builddir@
# top_srcdir = @top_srcdir@
# abs_top_srcdir = @abs_top_srcdir@
# abs_top_builddir = @abs_top_builddir@
#

#
# Autotools-conventional vars which are used by package installation
# rules in main.mk.
# rules in main.mk. To get sane handling when a user overrides only
#
# Autosetup allows the various XYZdir vars to be overridden at
# configure-time with, e.g. --libdir=X and --mandir=Y. However,
# defining them at configure-time, instead of at make-time, leads to
# later awkwardness:
#
# $ ./configure --prefix=/usr
# $ make prefix=/bar
# a subset of these, we perform some acrobatics with these vars
# in the configure script: see [proj-remap-autoconf-dir-vars] for
# full details.
#
# In that invocation, libdir will be /usr/foo, not /bar/foo as it
# normally should, unless the user _also_ passes libdir=... to make.
#
# In 99%+ of use cases, setting prefix=X has the desired effect of
# calculating conventional defaults for various other dirs, like
# $prefix/lib, $prefix/include, etc. If, however, we export those at
# configure-time, the passing prefix=... to make will update only
# $prefix and none of its derived dirs.
#
# Because it is more important (for our use cases) that these vars be
# overridable via a make invocation than a configure invocation, and
# they conventionally derive from $(prefix) in all but the most exotic
# of use cases, we do not export the configure-defined overrides of
# those vars to this makefile.  Instead, we export only $prefix and
# its derived vars are set to their conventional default values in
# main.mk, which users can then override at make-time as needed.
# Overriding $prefix via make will also calculate any derived vars, as
# one would expect, unless each is specifically overridden.
#
# For completeness's sake, the aforementioned conventional vars which
# are relevant to our installation rules are:
#
# datadir     = $(prefix)/share
# mandir      = $(datadir)/man
# includedir  = $(prefix)/include
125
126
127
128
129
130
131
132

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

148
149
150
151
152
153
154
155

156


157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
92
93
94
95
96
97
98

99


100
101
102
103
104
105
106
107
108
109
110
111

112
113
114
115
116
117
118
119
120
121

122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137





138
139
140
141
142
143
144
145
146
147
148
149
150
151
152





153
154
155
156
157
158
159







-
+
-
-












-
+








+
-
+
+














-
-
-
-
-















-
-
-
-
-







# details.
#
# Historical note: the pre-3.48 build only honored CPPFLAGS at
# configure-time, and expanded them into the generated Makefile. There
# are, in that build, no uses of CPPFLAGS in the configure-expanded
# Makefile. Ergo: if a client configures with CPPFLAGS=... and then
# explicitly passes CFLAGS=... to make, the CPPFLAGS will be
# lost. That behavior is retained in 3.48+ because also honoring
# lost. That behavior is retained in 3.48+.
# CPPFLAGS at make-time may have undesired side effects on any number
# of builds.
#
CFLAGS = @CFLAGS@ @CPPFLAGS@
#
# $(LDFLAGS.configure) represents any LDFLAGS=... the client passes to
# configure. See main.mk.
#
LDFLAGS.configure = @LDFLAGS@

#
# CFLAGS.core is documented in main.mk.
#
CFLAGS.core = @SH_CFLAGS@
LDFLAGS.shobj = @SHOBJ_LDFLAGS@
LDFLAGS.shlib = @SH_LDFLAGS@
LDFLAGS.zlib = @LDFLAGS_ZLIB@
LDFLAGS.math = @LDFLAGS_MATH@
LDFLAGS.rpath = @LDFLAGS_RPATH@
LDFLAGS.pthread = @LDFLAGS_PTHREAD@
LDFLAGS.dlopen = @LDFLAGS_DLOPEN@
LDFLAGS.readline = @LDFLAGS_READLINE@
CFLAGS.readline = @CFLAGS_READLINE@
LDFLAGS.icu = @LDFLAGS_ICU@
CFLAGS.icu = @CFLAGS_ICU@
LDFLAGS.soname.libsqlite3 = @LDFLAGS_SONAME_LIBSQLITE3@
LDFLAGS.libsqlite3.soname = @LDFLAGS_LIBSQLITE3_SONAME@
# soname: see https://sqlite.org/src/forumpost/5a3b44f510df8ded
ENABLE_SHARED = @ENABLE_SHARED@
ENABLE_STATIC = @ENABLE_STATIC@
HAVE_WASI_SDK = @HAVE_WASI_SDK@

T.cc.sqlite = $(T.cc) @TARGET_DEBUG@

#
# Define -D_HAVE_SQLITE_CONFIG_H so that the code knows it
# can include the generated sqlite_cfg.h.
#
# main.mk will fill out T.cc.sqlite with additional flags common to
# all builds.
#
T.cc.sqlite += -D_HAVE_SQLITE_CONFIG_H -DBUILD_sqlite
#
# -I$(prefix)/include is primarily so that the ICU
# headers can be found.
#
T.cc.sqlite += -I$(prefix)/include

#
# $(JIMSH) and $(CFLAGS.jimsh) are documented in main.mk.  $(JIMSH)
# must start with a path component so that it can be invoked as a
# shell command.
#
CFLAGS.jimsh = @CFLAGS_JIMSH@
JIMSH = ./jimsh$(TEXE)

#
# $(B.tclsh) is documented in main.mk.
#
B.tclsh = @BTCLSH@
$(B.tclsh):

#
# $(CFLAGS.libsqlite3) is documented in main.mk.
#
CFLAGS.libsqlite3 = -DSQLITE_TEMP_STORE=@TEMP_STORE@

#
# $(OPT_FEATURE_FLAGS) is documented in main.mk.
#
# The appending of $(OPTIONS) to $(OPT_FEATURE_FLAGS) is historical
# and somewhat confusing because there's another var, $(OPTS), which
# has a similar (but not identical) role.
#
253
254
255
256
257
258
259
260

261
262
263
264
265
266
267
210
211
212
213
214
215
216

217
218
219
220
221
222
223
224







-
+







# clients are not required to pass it at make-time, or set it in their
# environment, to override it.
#
TCLLIBDIR = @TCLLIBDIR@

#
# Additional options when running tests using testrunner.tcl
# This is usually either blank, or else --status
# This is usually either blank or --status.
#
TSTRNNR_OPTS = @TSTRNNR_OPTS@

#
# If gcov support was enabled by the configure script, add the appropriate
# flags here.  It's not always as easy as just having the user add the right
# CFLAGS / LDFLAGS, because libtool wants to use CFLAGS when linking, which
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
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268

269
270
271
272
273
274
275
276







+
















-
+







#
# Shell commands to re-run $(TOP)/configure with the same args it was
# invoked with to produce this makefile.
#
AS_AUTORECONFIG = @SQLITE_AUTORECONFIG@

USE_AMALGAMATION ?= @USE_AMALGAMATION@
LINK_TOOLS_DYNAMICALLY ?= @LINK_TOOLS_DYNAMICALLY@
AMALGAMATION_GEN_FLAGS ?= --linemacros=@AMALGAMATION_LINE_MACROS@

#
# CFLAGS for sqlite3$(T.exe)
#
SHELL_OPT ?= @OPT_SHELL@

Makefile: $(TOP)/Makefile.in $(AS_AUTO_DEF)
	$(AS_AUTORECONFIG)
	@touch $@

sqlite3.pc: $(TOP)/sqlite3.pc.in $(AS_AUTO_DEF)
	$(AS_AUTORECONFIG)
	@touch $@
install: install-pc # defined in main.mk

sqlite_cfg.h: $(TOP)/sqlite_cfg.h.in $(AS_AUTO_DEF)
sqlite_cfg.h: $(AS_AUTO_DEF)
	$(AS_AUTORECONFIG)
	@touch $@

#
# Fiddle app
#
# EMCC_WRAPPER must refer to the genuine emcc binary, or a
Changes to auto.def.
32
33
34
35
36
37
38
39


40
41
42
43
44
45


46
47
48
49
50
51
52
32
33
34
35
36
37
38

39
40
41
42
43
44
45

46
47
48
49
50
51
52
53
54







-
+
+





-
+
+







# A very long story made short, autosetup's --flag handling has
# some behaviors which make it impossible to implement 100% identical
# flags compared to the historical autotools build. The differences
# are documented here:
#
# 1) --debug is used by autosetup itself, so we have to rename it to
# --with-debug. We cannot use --enable-debug because that is, for
# autosetup, and alias for --debug=1.
# autosetup, an alias for --debug=1. Alternately, we can patch
# autosetup to use --autosetup-debug for its own purposes instead.
#
# 2) In autosetup, all flags starting with (--enable, --disable) are
# forced to be booleans and receive special handling in how they're
# resolved. Because of that we have to rename:
#
#   2.1) --enable-tempstore[=no] to --with-tempstore[=no].
#   2.1) --enable-tempstore[=no] to --with-tempstore[=no], noting that
#        it has four legal values, not two.
#
########################################################################
# A gentle introduction to flags handling in autosetup
#
# Reference: https://msteveb.github.io/autosetup/developer/
#
# All configure flags must be described in an 'options' call, which
60
61
62
63
64
65
66
67

68
69
70


71
72
73
74
75
76
77



78
79
80
81
82
83
84
85

86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121

122
123
124






125
126
127
128
129
130
131
132
133
62
63
64
65
66
67
68

69



70
71
72
73
74
75



76
77
78
79
80
81
82
83
84
85

86
87
88
89
90
91
92
93
94
95








96








97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118

119
120
121
122
123
124
125







-
+
-
-
-
+
+




-
-
-
+
+
+







-
+









-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-











+



+
+
+
+
+
+

-







#   boolopt2=1         => "a boolean option which defaults to enabled"
#   stringopt:         => "an option which takes an argument, e.g. --stringopt=value"
#   stringopt2:=value  => "an option where the argument is optional and defaults to 'value'"
#   optalias booltopt3 => "a boolean with a hidden alias. --optalias is not shown in --help"
#
# Autosetup does no small amount of specialized handling for flags,
# especially booleans. Each bool-type --FLAG implicitly gets
# --enable-FLAG and --disable-FLAG forms, and explicitly adding flags
# --enable-FLAG and --disable-FLAG forms. e.g. we define a flag
# with those prefixes will force them to be boolean flags. e.g. we
# define a flag "readline", which will be interpreted in one of two
# ways, depending on how it's invoked and how its default is defined:
# "readline", which will be interpreted in one of two ways, depending
# on how it's invoked and how its default is defined:
#
#   --enable-readline ==> boolean true
#   --disable-readline ==> boolean false
#
# Trying to pass --readline or --readline=1 or --readline=0 will
# result in an "unrecognized option" error, despite the the [options]
# call listing the flag as "readline".
# Passing --readline or --readline=1 is equivalent to passing
# --enable-readline, and --readline=0 is equivalent to
# --disable-readline.
#
# The behavior described above can lead lead to some confusion when
# writing help text. For example:
#
#   options { json=1 {Disable JSON functions} }
#
# The reason the help text says "disable" is because a boolean option
# defaulting to true is, in the --help text, rendered as:
# which defaults to true is, in the --help text, rendered as:
#
#   --disable-json          Disable JSON functions
#
# Whereas a bool flag which defaults to false will instead render as:
#
#   --enable-FLAG
#
# Non-boolean flags, in contrast, use the names specifically given to
# them in the [options] invocation. e.g. "with-tcl" is the --with-tcl
# flag. Autosetup may, however, choose to automatically alter the help
# text, as demonstrated here:
#
#   options {
#    readline=1           => {Disable readline support}
#    with-readline-lib:   => {Readline library}
#    with-readline-inc:   => {Readline include paths}
#   }
# flag.
#
#   $ ./configure --help | grep readline
#   --disable-readline      disable readline support
#   --with-readline-lib     specify readline library
#   --with-readline-inc     specify readline include paths
#
# Note that it prefixed and lower-case the help message. Whether
# that's a feature or a bug can be debated.
#
# Fetching values for flags:
#
#   booleans: use one of:
#     - [opt-bool FLAG] is autosetup's built-in command for this, but we
#       have some convenience variants:
#     - [proj-opt-truthy FLAG]
#     - [proj-opt-if-truthy FLAG {THEN} {ELSE}]
#
#   Non-boolean (i.e. string) flags:
#     - [opt-val FLAG ?default?]
#     - [opt-str ...] - see the docs in ./autosetup/autosetup
#
########################################################################
set flags {
  # When writing {help text blocks}, be aware that autosetup formats
  # them differently (left-aligned, directly under the --flag) if the
  # block starts with a newline. It does NOT expand vars and commands,
  # but we use a [subst] call below which will replace (only) var
  # refs.

  # <build-modes>
  with-debug:=1        => {Enable debug build flags}
  shared=1             => {Disable build of shared libary}
  static=1             => {Disable build of static library (mostly)}
  amalgamation=1       => {Disable the amalgamation and instead build all files separately.}
  # </build-modes>
  # <lib-feature>
  threadsafe=1         => {Disable mutexing}
  with-tempstore:=no   => {Use an in-RAM database for temporary tables: never,no,yes,always}
143
144
145
146
147
148
149

150
151


152
153
154
155
156
157
158
159
160
161
162












163
164
165
166
167
168
169
170
135
136
137
138
139
140
141
142


143
144











145
146
147
148
149
150
151
152
153
154
155
156

157
158
159
160
161
162
163







+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-







  update-limit         => {Enable the UPDATE/DELETE LIMIT clause}
  geopoly              => {Enable the GEOPOLY extension}
  rtree                => {Enable the RTREE extension}
  session              => {Enable the SESSION extension}
  all                  => {Enable FTS4, FTS5, Geopoly, RTree, Sessions}
  # </lib-feature>
  # <tcl>
  with-tcl:DIR         =>
  # --with-tcl=DIR may be either a dir containing tclConfig.sh or a
  # dir one level up from that from which we can derive a dir
    {Directory containing tclConfig.sh or a directory one level up from
     that, from which we can derive a directory containing tclConfig.sh.
  # containing tclConfig.sh.
  with-tcl:            => {Root of path containing tclConfig.sh}
  # If --with-tclsh=X given, it is used for (A) trying to find
  # tclConfig.sh and (B) all TCL-based code generation.  Warning: if
  # its containing dir has multiple tclsh versions, it may select the
  # wrong tclConfig.sh!
  with-tclsh:PATH      => {Full pathname of tclsh to use}
  # --disable-tcl disables building of components which require TCL,
  # including tests. This tree requires TCL for code generation but
  # can use the in-tree copy of autosetup/jimsh0.c for that. The
  # SQLite TCL extension and the test code require a canonical tclsh.
     A dir name of "prefix" is equivalent to the directory specified by
     the --prefix flag.}
  with-tclsh:PATH      =>
    {Full pathname of tclsh to use.  It is used for (A) trying to find
     tclConfig.sh and (B) all TCL-based code generation.  Warning: if
     its containing dir has multiple tclsh versions, it may select the
     wrong tclConfig.sh!}
  tcl=1                =>
    {Disable components which require TCL, including all tests.
     This tree requires TCL for code generation but can use the in-tree
     copy of autosetup/jimsh0.c for that. The SQLite TCL extension and the
     test code require a canonical tclsh.}
  tcl=1                => {Disable components which require TCL}
  # <tcl>
  # <line-editing>
  readline=1           => {Disable readline support}
  # --with-readline-lib is a backwards-compatible alias for
  # --with-readline-ldflags
  with-readline-lib:
  with-readline-ldflags:=auto
178
179
180
181
182
183
184


185

186
187
188
189
190
191
192
193










194
195
196
197


198

199
200




201
202
203



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221

222
223
224
225
226
227
228
229
230
231
232
233
234
235

236
237
238
239
240
241
242
243
244
245
246
247
248

249
250
251
252
253
254

255
256
257
258
259
260
261
171
172
173
174
175
176
177
178
179

180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204

205


206
207
208
209



210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244

245
246
247
248
249
250
251
252
253
254
255
256
257

258
259
260
261
262
263

264
265
266
267
268
269
270
271







+
+
-
+








+
+
+
+
+
+
+
+
+
+




+
+
-
+
-
-
+
+
+
+
-
-
-
+
+
+


















+













-
+












-
+





-
+







                       => {Full path to readline.h, from which --with-readline-cflags will be derived}
  with-linenoise:DIR   => {Source directory for linenoise.c and linenoise.h}
  editline=0           => {Enable BSD editline support}
  # </line-editing>
  # <icu>
  with-icu-ldflags:LDFLAGS
                        => {Enable SQLITE_ENABLE_ICU and add the given linker flags for the ICU libraries}
  with-icu-cflags:CFLAGS
                        => {Apply extra CFLAGS/CPPFLAGS necessary for building with ICU. e.g. -I/usr/local/include}
  with-icu-config:=auto => {Enable SQLITE_ENABLE_ICU and fetch linker flags from the given icu-config binary}
  with-icu-config:=auto => {Enable SQLITE_ENABLE_ICU. Value must be one of: auto, pkg-config, /path/to/icu-config}
  icu-collations=0      => {Enable SQLITE_ENABLE_ICU_COLLATIONS. Requires --with-icu-ldflags=... or --with-icu-config}
  # </icu>
  # <alternative-builds>
  with-wasi-sdk:=/opt/wasi-sdk
                       => {Top-most dir of the wasi-sdk for a WASI build}
  with-emsdk:=auto     => {Top-most dir of the Emscripten SDK installation. Default = EMSDK env var.}
  # </alternative-builds>
  # <developer>
  # Note that using the --debug/--enable-debug flag here requires patching
  # autosetup/autosetup to rename the --debug to --autosetup-debug.
  with-debug=0
  debug=0              =>
    {Enable debug build flags. This option will impact performance by
     as much as 4x, as it includes large numbers of assert()s in
     performance-critical loops.  Never use --debug for production
     builds.}
  scanstatus           => {Enable the SQLITE_ENABLE_STMT_SCANSTATUS feature flag}
  dev                  => {Enable dev-mode build: automatically enables certain other flags}
  test-status          => {Enable status of tests}
  gcov=0               => {Enable coverage testing using gcov}
  linemacros           => {Enable #line macros in the amalgamation}
  dump-defines=0       => {Dump autosetup defines to $DUMP_DEFINES_TXT (for build debugging)}
  dynlink-tools        => {Dynamically link libsqlite3 to certain tools which normally statically embed it.}
  soname:=legacy       =>
  #soname:=none         => {SONAME for libsqlite3.so}
    {SONAME for libsqlite3.so. "none", or not using this flag, sets no
  #^^^ we "could", but arguably shouldn't, support clients passing a
  # value of libsqlite3.so.0 for compatibility with clients which
     soname. "legacy" sets it to its historical value of
     libsqlite3.so.0.  A value matching the glob "libsqlite3.*" sets
     it to that literal value. Any other value is assumed to be a
     suffix which gets applied to "libsqlite3.so.",
  # linked against a pre-3.48 build.
  # Maybe we should support values of --soname=(none,auto,legacy), where auto means
  # to use the 3.48+ value of libsqlite3.so.3..
     e.g. --soname=9.10 equates to "libsqlite3.so.9.10".
    }
  # --soname has a long story behind it: https://sqlite.org/src/forumpost/5a3b44f510df8ded
  # </developer>
}
if {"" ne $DUMP_DEFINES_JSON} {
  lappend flags \
    defines-json-include-lowercase=0 \
    => {Include lower-case defines (primarily system paths) in $DUMP_DEFINES_JSON}
}

options [subst -nobackslashes -nocommands $flags]
unset flags

#
# Carry values from hidden --flag aliases over to their canonical flag
# forms.
#
proj-xfer-options-aliases {
  with-readline-inc => with-readline-cflags
  with-readline-lib => with-readline-ldflags
  with-debug => debug
}

set srcdir $::autosetup(srcdir)
set PACKAGE_VERSION [proj-file-content -trim $srcdir/VERSION]
define PACKAGE_NAME "sqlite"
define PACKAGE_URL {https://sqlite.org}
define PACKAGE_VERSION $PACKAGE_VERSION
define PACKAGE_STRING "[get-define PACKAGE_NAME] $PACKAGE_VERSION"
define PACKAGE_BUGREPORT [get-define PACKAGE_URL]/forum
msg-result "Source dir = $srcdir"
msg-result "Build dir  = $::autosetup(builddir)"
msg-result "Configuring SQLite version $PACKAGE_VERSION"

if {1} {
apply {{} {
  #
  # SQLITE_AUTORECONFIG contains make target rules for re-running the
  # configure script with the same arguments it was initially invoked
  # with. This can be used to automatically reconfigure
  #
  proc squote {arg} {
    # Wrap $arg in single-quotes if it looks like it might need that
    # to avoid mis-handling as a shell argument. We assume that $arg
    # will never contain any single-quote characters.
    if {[string match {*[ &;$*"]*} $arg]} { return '$arg' }
    return $arg
  }
  define-append SQLITE_AUTORECONFIG cd [squote $::autosetup(builddir)] && [squote $srcdir/configure]
  define-append SQLITE_AUTORECONFIG cd [squote $::autosetup(builddir)] && [squote $::srcdir/configure]
  #{*}$::autosetup(argv) breaks with --flag='val with spaces', so...
  foreach arg $::autosetup(argv) {
    define-append SQLITE_AUTORECONFIG [squote $arg]
  }
  rename squote ""
}
}}

# Are we cross-compiling?
set isCrossCompiling [proj-is-cross-compiling]

define OPT_FEATURE_FLAGS {} ; # -DSQLITE_OMIT/ENABLE flags.
define OPT_SHELL {}         ; # Feature-related CFLAGS for the sqlite3 CLI app
########################################################################
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307

308
309

310
311
312
313
314
315
316
317
318
319
320









321
322
323
324
325
326


327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343

344

345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363

364
365
366
367
368
369
370
301
302
303
304
305
306
307

308
309
310

311
312
313
314

315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342


343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360

361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390







-



-




-
+


+











+
+
+
+
+
+
+
+
+




-
-
+
+
















-
+

+



















+







  }
}

proj-file-extensions
if {".exe" eq [get-define TARGET_EXEEXT]} {
  define SQLITE_OS_UNIX 0
  define SQLITE_OS_WIN 1
  # todo? add -DSQLITE_OS_WIN=1 to CFLAGS or CFLAGS_sqlite3_os?
} else {
  define SQLITE_OS_UNIX 1
  define SQLITE_OS_WIN 0
  # todo? add -DSQLITE_OS_UNIX=1 to CFLAGS or CFLAGS_sqlite3_os
}

#########
# Programs needed
cc-check-tools ld ar ; # must come before sqlite-check-wasi-sdk
cc-check-tools ld ar ; # must come before [sqlite-check-wasi-sdk]
if {"" eq [proj-bin-define install]} {
  proj-warn "Cannot find install binary, so 'make install' will not work."
  define BIN_INSTALL false
}

########################################################################
# 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 early on because it may change the toolchain and
# disable a number of config options.
# This must be run relatively early on because it may change the
# toolchain and disable a number of config options.
proc sqlite-check-wasi-sdk {} {
  set wasiSdkDir [opt-val with-wasi-sdk] ; # ??? [lindex [opt-val with-wasi-sdk] end]
  define HAVE_WASI_SDK 0
  if {$wasiSdkDir eq ""} {
    return 0
  } elseif {$::isCrossCompiling} {
    proj-fatal "Cannot combine --with-wasi-sdk with cross-compilation"
  }
  msg-result "Checking WASI SDK directory \[$wasiSdkDir]... "
  #puts "prefix = [prefix $wasiSdkDir/bin {clang ld}]"
  proj-affirm-files-exist -v {*}[prefix "$wasiSdkDir/bin/" {clang wasm-ld ar}]
  define HAVE_WASI_SDK 1
  define WASI_SDK_DIR $wasiSdkDir
  # Disable numerous options which we know either can't work or are
  # not useful in this build...
  msg-result "Using wasi-sdk clang. Disabling CLI shell modifying config flags:"
  # Boolean flags which must be switched off:
  # Boolean (--enable-/--disable-) flags which must be switched off:
  foreach opt {
    dynlink-tools
    editline
    gcov
    icu-collations
    load-extension
    readline
    shared
    tcl
    threadsafe
  } {
    if {[opt-bool $opt]} {
      msg-result "  --disable-$opt"
      proj-opt-set $opt 0
    }
  }
  # Non-boolean flags which need to be cleared:
  foreach opt {
    with-emsdk
    with-icu-config
    with-icu-ldflags
    with-icu-cflags
    with-linenoise
    with-tcl
  } {
    if {[proj-opt-was-provided $opt]} {
      msg-result "  removing --$opt"
      proj-opt-set $opt ""
    }
387
388
389
390
391
392
393





394
395
396
397
398
399
400
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425







+
+
+
+
+







  define CC "${wasiSdkDir}/bin/clang"
  define LD "${wasiSdkDir}/bin/wasm-ld"
  define AR "${wasiSdkDir}/bin/ar"
  #define STRIP "${wasiSdkDir}/bin/strip"
  return 1
}; # sqlite-check-wasi-sdk
sqlite-check-wasi-sdk

########################################################################
# --dynlink-tools tells the build to dynamically link certain binaries
# to libsqlite3.so instead of embedding a copy of the amalgamation.
define LINK_TOOLS_DYNAMICALLY [proj-opt-was-provided dynlink-tools]

#
# Enable large file support (if special flags are necessary)
define HAVE_LFS 0
if {[opt-bool largefile]} {
  cc-check-lfs
}
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447




448
449

450




451

452
453
454
455
456



457


458




459
460
461
462
463
464





465

466

467
468
469

470
471
472

473
474

475
476
477
478
479

480
481

482
483

484
485
486

487
488
489
490

491
492
493
494
495
496
497
456
457
458
459
460
461
462










463
464
465
466
467

468
469
470
471
472
473

474
475
476



477
478
479
480
481
482

483
484
485
486
487
488
489
490


491
492
493
494
495
496
497

498
499


500

501

502
503

504
505
506
507
508

509
510

511
512

513
514
515

516
517
518
519

520
521
522
523
524
525
526
527







-
-
-
-
-
-
-
-
-
-
+
+
+
+

-
+

+
+
+
+
-
+


-
-
-
+
+
+

+
+
-
+
+
+
+




-
-
+
+
+
+
+

+
-
+

-
-
+
-

-
+

-
+




-
+

-
+

-
+


-
+



-
+







  define HAVE_ZLIB 0
  define LDFLAGS_ZLIB ""
}

proj-check-rpath  ; # Determine proper rpath-handling flag

########################################################################
# It's not yet clear whether we gain anything from setting -soname,
# but not having it has been a source of anxiety for some users.
# Setting it to any value other than its historical value of
# libsqlite3.so.0 may (this is not certain) break dynamic linking of
# clients which initially linked against a legacy build.
#
# See discussion in/around:
# https://sqlite.org/forum/forumpost/0c6fc6f46b2cb3
proc sqlite-check-soname {} {
  define LDFLAGS_SONAME_LIBSQLITE3 ""
# "soname" for libsqlite3.so. See discussion at:
# https://sqlite.org/src/forumpost/5a3b44f510df8ded
apply {{} {
  define LDFLAGS_LIBSQLITE3_SONAME ""
  if {[proj-opt-was-provided soname]} {
    set soname [opt-val soname]
    set soname [join [opt-val soname] ""]
  } else {
    # Enabling soname breaks linking for the --dynlink-tools feature,
    # and this project has no direct use for soname, so default to
    # none. Package maintainers, on the other hand, like to have an
    # soname.
    return 0
    set soname none
  }
  switch -exact -- $soname {
    none       { return 0 }
    auto   - 3 { set soname libsqlite3.so.3 }
    legacy - 0 { set soname libsqlite3.so.0 }
    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
      proj-fatal "Invalid value for --soname. Use one of (none, auto, legacy)."
      } else {
        # Assume it's a suffix
        set soname "libsqlite3.so.${soname}"
      }
    }
  }
  msg-debug "soname=$soname"
  if {[proj-check-soname $soname]} {
    define LDFLAGS_SONAME_LIBSQLITE3 [get-define LDFLAGS_SONAME_PREFIX]$soname
    msg-result "Setting SONAME: [get-define LDFLAGS_SONAME_LIBSQLITE3]"
    define LDFLAGS_LIBSQLITE3_SONAME [get-define LDFLAGS_SONAME_PREFIX]$soname
    msg-result "Setting SONAME using: [get-define LDFLAGS_LIBSQLITE3_SONAME]"
  } elseif {[proj-opt-was-provided soname]} {
    # --soname was explicitly requested but not available, so fail fatally
    proj-fatal "This environment does not support SONAME."
  } else {
    # --soname was not explicitly requested but not available, so just warn
    proj-fatal "This environment does not support SONAME."
    msg-result "This environment does not support SONAME."
  }
  return sqlite-check-soname ""
}
}}
sqlite-check-soname

proj-define-if-opt-truthy shared ENABLE_SHARED "Build shared library?"
proj-define-for-opt shared ENABLE_SHARED "Build shared library?"

if {![proj-define-if-opt-truthy static ENABLE_STATIC \
if {![proj-define-for-opt static ENABLE_STATIC \
        "Build static library?"]} {
  proj-warn "Static lib build may be implicitly re-activated by other components, e.g. some test apps."
}

proj-define-if-opt-truthy amalgamation USE_AMALGAMATION "Use amalgamation for builds?"
proj-define-for-opt amalgamation USE_AMALGAMATION "Use amalgamation for builds?"

proj-define-if-opt-truthy gcov USE_GCOV "Use gcov?"
proj-define-for-opt gcov USE_GCOV "Use gcov?"

proj-define-if-opt-truthy test-status TSTRNNR_OPTS \
proj-define-for-opt test-status TSTRNNR_OPTS \
  "test-runner flags:" {--status} {}

proj-define-if-opt-truthy linemacros AMALGAMATION_LINE_MACROS \
proj-define-for-opt linemacros AMALGAMATION_LINE_MACROS \
  "Use #line macros in the amalgamation:"

msg-checking "SQLITE_DEBUG build? "
proj-if-opt-truthy with-debug {
proj-if-opt-truthy debug {
  define SQLITE_DEBUG 1
  define TARGET_DEBUG {-g -DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0 -Wall}
  msg-result yes
} {
  define TARGET_DEBUG {-DNDEBUG}
  msg-result no
}
523
524
525
526
527
528
529

530
531
532
533
534
535
536
537
538
539


540
541
542
543
544
545
546

547
548
549
550
551
552
553
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568


569
570
571
572
573
574
575
576

577
578
579
580
581
582
583
584







+








-
-
+
+






-
+







#    components.
#
# If --tcl or --with-tcl are provided but no TCL is found, this
# function fails fatally. If they are not explicitly provided then
# failure to find TCL is not fatal but a loud warning will be emitted.
#
proc sqlite-check-tcl {} {
  rename sqlite-check-tcl ""
  define TCLSH_CMD false ; # Significant is that it exits with non-0
  define HAVE_TCL 0      ; # Will be enabled via --tcl or a successful search
  define TCLLIBDIR ""    ; # Installation dir for TCL extension lib
  define TCL_CONFIG_SH ""; # full path to tclConfig.sh
  file delete -force ".tclenv.sh"; # ensure no stale state from previous configures.
  if {![opt-bool tcl]} {
    proj-indented-notice {
      NOTE: TCL is disabled via --disable-tcl. This means that none
      of the TCL-based components, including tests and sqlite3_analyzer,
      will be built.
      of the TCL-based components will be built, including tests
      and sqlite3_analyzer.
    }
    return
  }
  # TODO: document the steps this is taking.
  global srcdir
  msg-result "Checking for a suitable tcl... "
  proj-assert {proj-opt-truthy tcl}
  proj-assert [proj-opt-truthy tcl]
  set use_tcl 1
  set with_tclsh [opt-val with-tclsh]
  set with_tcl [opt-val with-tcl]
  if {"prefix" eq $with_tcl} {
    set with_tcl [get-define prefix]
  }
  msg-debug "sqlite-check-tcl: use_tcl ${use_tcl}"
626
627
628
629
630
631
632
633

634
635
636
637
638

639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658


659
660
661
662
663
664
665
657
658
659
660
661
662
663

664
665
666
667
668

669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687


688
689
690
691
692
693
694
695
696







-
+




-
+


















-
-
+
+







    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/tclConfigShToTcl.sh" "$cfg"]
  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 {expr {"" ne [get-define TCL_EXEC_PREFIX]}}
    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]} {
      set with_tclsh2 [get-define TCL_EXEC_PREFIX]/bin/tclsh
      if {![file-isexec $with_tclsh2]} {
        proj-warn "Cannot find a usable tclsh (tried: $with_tclsh $with_tclsh2)"
      } else {
        set with_tclsh $with_tclsh2
      }
    }
  }
  define TCLSH_CMD $with_tclsh
  if {$use_tcl} {
    # Set up the TCLLIBDIR
    #
    # 2024-10-28: calculation of TCLLIBDIR is now done via the shell
    # in main.mk (search it for T.tcl.env.sh) so that
    # static/hand-written makefiles which import main.mk do not have
    # to define that before importing main.mk. Even so, we export
    # TCLLIBDIR from here, which will cause the makefile to use this
    # one rather than to re-calculate it at make-time.
    # TCLLIBDIR from here, which will cause the canonical makefile to
    # use this one rather than to re-calculate it at make-time.
    set tcllibdir [get-env TCLLIBDIR ""]
    if {"" eq $tcllibdir} {
      # Attempt to extract TCLLIBDIR from TCL's $auto_path
      if {"" ne $with_tclsh &&
          [catch {exec echo "puts stdout \$auto_path" | "$with_tclsh"} result] == 0} {
        foreach i $result {
          if {[file isdir $i]} {
682
683
684
685
686
687
688




689
690
691
692
693
694

695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710

711
712
713
714
715
716
717
718
719
720
721

722
723
724
725

726
727
728






729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790












































791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811


812
813
814
815
816
817
818
819
820
821

822
823
824
825

826
827
828
829
830
831
832
833
834
835

836
837

838
839
840
841
842
843
844
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728

729
730
731
732
733
734
735
736
737

738
739
740
741
742
743

744
745
746
747
748
749
750
751
752
753
754

755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782

















































783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826

827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857

858
859
860
861

862
863
864
865
866
867
868
869
870
871

872


873
874
875
876
877
878
879
880







+
+
+
+





-
+








-






-
+










-
+




+



+
+
+
+
+
+













-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-




















+
+









-
+



-
+









-
+
-
-
+







    if {$cfg ne ""} {
      define HAVE_TCL 1
    } else {
      proj-warn "Found tclsh but no tclConfig.sh."
    }
  }
  show-notices
  # If TCL is not found: if it was explicitly requested then fail
  # fatally, else just emit a warning. If we can find the APIs needed
  # to generate a working JimTCL then that will suffice for build-time
  # TCL purposes (see: proc sqlite-determine-codegen-tcl).
  if {![get-define HAVE_TCL] &&
      ([proj-opt-was-provided tcl] || [proj-opt-was-provided with-tcl])} {
    proj-fatal "TCL support was requested but no tclConfig.sh could be found."
  }
  if {"" eq $cfg} {
    proj-assert {expr {0 == [get-define HAVE_TCL]}}
    proj-assert {0 == [get-define HAVE_TCL]}
    proj-indented-notice {
      WARNING: Cannot find a usable tclConfig.sh file.  Use
      --with-tcl=DIR to specify a directory where tclConfig.sh can be
      found.  SQLite does not use TCL internally, but some optional
      components require TCL, including tests and sqlite3_analyzer.
    }
  }
}; # sqlite-check-tcl

sqlite-check-tcl

########################################################################
# sqlite-determine-codegen-tcl checks which TCL to use as a code
# generator.  By default, prefer jimsh simply because we have it
# in-tree (it's part of autosetup) unless --with-tclsh=X is used, in
# which case prefix X.
# which case prefer X.
#
# Returns the human-readable name of the TCL it selects. Fails fatally
# if it cannot detect a TCL appropriate for code generation.
#
# Defines:
#
#   - BTCLSH = the TCL shell used for code generation. It may set this
#     to an unexpanded makefile var name.
#
#   - CFLAGS_JIMSH = any flags needed for buildng a BTCLSH-compatible
#     jimsh. The defaults may be pass on to configure as
#     jimsh. The defaults may be passed on to configure as
#     CFLAGS_JIMSH=...
set useJimForCodeGen 0 ; # Set to 1 when using jimsh for code generation.
                         # May affect later decisions.
proc sqlite-determine-codegen-tcl {} {
  rename sqlite-determine-codegen-tcl ""
  msg-result "Checking for TCL to use for code generation... "
  define CFLAGS_JIMSH [proj-get-env CFLAGS_JIMSH {-O1}]
  set cgtcl [opt-val with-tclsh jimsh]
  if {"jimsh" ne $cgtcl} {
    # When --with-tclsh=X is used, use that for all TCL purposes,
    # including in-tree code generation, per developer request.
    define BTCLSH "\$(TCLSH_CMD)"
    return $cgtcl
  }
  set flagsToRestore {CC CFLAGS AS_CFLAGS CPPFLAGS AS_CPPFLAGS LDFLAGS LINKFLAGS LIBS CROSS}
  define-push $flagsToRestore {
    # We have to swap CC to CC_FOR_BUILD for purposes of the various
    # [cc-...] tests below. Recall that --with-wasi-sdk may have
    # swapped out CC with one which is not appropriate for this block.
    # Per consulation with autosetup's creator, doing this properly
    # requires us to [define-push] the whole $flagsToRestore list
    # (plus a few others which are not relevant in this tree).
    #
    # These will get set to their previous values at the end of this
    # block.
    foreach flag $flagsToRestore {define $flag ""}
    define CC [get-define CC_FOR_BUILD]
    if {"jimsh" ne $cgtcl} {
      # When --with-tclsh=X is used, use that for all TCL purposes,
      # including in-tree code generation, per developer request.
      define BTCLSH "\$(TCLSH_CMD)"
    } else {
      # These headers are technically optional for JimTCL but necessary if
      # we want to use it for code generation:
      set sysh [cc-check-includes dirent.h sys/time.h]
      # jimsh0.c hard-codes #define's for HAVE_DIRENT_H and
      # HAVE_SYS_TIME_H on the platforms it supports, so we do not
      # need to add -D... flags for those. We check for them here only
      # so that we can avoid the situation that we later, at
      # make-time, try to compile jimsh but it then fails due to
      # missing headers (i.e. fail earlier rather than later).
      if {$sysh && [cc-check-functions realpath]} {
        define-append CFLAGS_JIMSH -DHAVE_REALPATH
        define BTCLSH "\$(JIMSH)"
        set ::useJimForCodeGen 1
      } elseif {$sysh && [cc-check-functions _fullpath]} {
        # _fullpath() is a Windows API. It's not entirely clear
        # whether we need to add {-DHAVE_SYS_TIME_H -DHAVE_DIRENT_H}
        # to CFLAGS_JIMSH in this case. On MinGW32 we definitely do
        # not want to because it already hard-codes them. On _MSC_VER
        # builds it does not.
        define-append CFLAGS_JIMSH -DHAVE__FULLPATH
        define BTCLSH "\$(JIMSH)"
        set ::useJimForCodeGen 1
      } elseif {[file-isexec [get-define TCLSH_CMD]]} {
        set cgtcl [get-define TCLSH_CMD]
        define BTCLSH "\$(TCLSH_CMD)"
      } else {
        # One last-ditch effort to find TCLSH_CMD: use info from
        # tclConfig.sh to try to find a tclsh
        if {"" eq [get-define TCLSH_CMD]} {
          set tpre [get-define TCL_EXEC_PREFIX]
          if {"" ne $tpre} {
            set tv [get-define TCL_VERSION]
            if {[file-isexec "${tpre}/bin/tclsh${tv}"]} {
              define TCLSH_CMD "${tpre}/bin/tclsh${tv}"
            } elseif {[file-isexec "${tpre}/bin/tclsh"]} {
              define TCLSH_CMD "${tpre}/bin/tclsh"
            }
          }
        }
        set cgtcl [get-define TCLSH_CMD]
        if {![file-isexec $cgtcl]} {
          proj-fatal "Cannot find a tclsh to use for code generation."
        }
        define BTCLSH "\$(TCLSH_CMD)"
    # These headers are technically optional for JimTCL but necessary if
    # we want to use it for code generation:
    set sysh [cc-check-includes dirent.h sys/time.h]
    # jimsh0.c hard-codes #define's for HAVE_DIRENT_H and
    # HAVE_SYS_TIME_H on the platforms it supports, so we do not
    # need to add -D... flags for those. We check for them here only
    # so that we can avoid the situation that we later, at
    # make-time, try to compile jimsh but it then fails due to
    # missing headers (i.e. fail earlier rather than later).
    if {$sysh && [cc-check-functions realpath]} {
      define-append CFLAGS_JIMSH -DHAVE_REALPATH
      define BTCLSH "\$(JIMSH)"
      set ::useJimForCodeGen 1
    } elseif {$sysh && [cc-check-functions _fullpath]} {
      # _fullpath() is a Windows API. It's not entirely clear
      # whether we need to add {-DHAVE_SYS_TIME_H -DHAVE_DIRENT_H}
      # to CFLAGS_JIMSH in this case. On MinGW32 we definitely do
      # not want to because it already hard-codes them. On _MSC_VER
      # builds it does not.
      define-append CFLAGS_JIMSH -DHAVE__FULLPATH
      define BTCLSH "\$(JIMSH)"
      set ::useJimForCodeGen 1
    } elseif {[file-isexec [get-define TCLSH_CMD]]} {
      set cgtcl [get-define TCLSH_CMD]
      define BTCLSH "\$(TCLSH_CMD)"
    } else {
      # One last-ditch effort to find TCLSH_CMD: use info from
      # tclConfig.sh to try to find a tclsh
      if {"" eq [get-define TCLSH_CMD]} {
        set tpre [get-define TCL_EXEC_PREFIX]
        if {"" ne $tpre} {
          set tv [get-define TCL_VERSION]
          if {[file-isexec "${tpre}/bin/tclsh${tv}"]} {
            define TCLSH_CMD "${tpre}/bin/tclsh${tv}"
          } elseif {[file-isexec "${tpre}/bin/tclsh"]} {
            define TCLSH_CMD "${tpre}/bin/tclsh"
          }
        }
      }
      set cgtcl [get-define TCLSH_CMD]
      if {![file-isexec $cgtcl]} {
        proj-fatal "Cannot find a tclsh to use for code generation."
      }
      define BTCLSH "\$(TCLSH_CMD)"
      }
    }
  }; # CC swap-out
  return $cgtcl
}; # sqlite-determine-codegen-tcl
msg-result "TCL for code generation: [sqlite-determine-codegen-tcl]"
# /TCL
########################################################################

########################################################################
# Thread safety?
msg-checking "Support threadsafe operation? "
proj-if-opt-truthy threadsafe {
  msg-result yes
  sqlite-add-feature-flag -DSQLITE_THREADSAFE=1
  if {![proj-check-function-in-lib pthread_create pthread]
      || ![proj-check-function-in-lib pthread_mutexattr_init pthread]} {
    user-error "Missing required pthread bits"
  }
  define LDFLAGS_PTHREAD [get-define lib_pthread_create]
  undefine lib_pthread_create
  # Recall that LDFLAGS_PTHREAD might be empty even if pthreads if
  # found because it's in -lc on some platforms.
} {
  msg-result no
  sqlite-add-feature-flag -DSQLITE_THREADSAFE=0
  define LDFLAGS_PTHREAD ""
}

########################################################################
# Do we want temporary databases in memory?
#
if {1} {
apply {{} {
  set ts [opt-val with-tempstore no]
  set tsn 1
  msg-checking "Use an in-RAM database for temporary tables? "
  switch -- $ts {
  switch -exact -- $ts {
    never  { set tsn 0 }
    no     { set tsn 1 }
    yes    { set tsn 2 }
    always { set tsn 3 }
    default {
      user-error "Invalid --with-tempstore value '$ts'. Use one of: never, no, yes, always"
    }
  }
  msg-result $ts
  define TEMP_STORE $tsn
  sqlite-add-feature-flag -DSQLITE_TEMP_STORE=$tsn
  unset ts tsn
}
}}

########################################################################
# sqlite-check-line-editing jumps through proverbial hoops to try to
# find a working line-editing library, setting:
#
#   - HAVE_READLINE to 0 or 1
#   - HAVE_LINENOISE to 0, 1, or 2
869
870
871
872
873
874
875

876
877
878
879
880
881
882
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919







+







#
#  4) Default to automatic search for optional readline
#
#  5) Try to find readline or editline. If it's not found AND the
#     corresponding --FEATURE flag was explicitly given, fail fatally,
#     else fail silently.
proc sqlite-check-line-editing {} {
  rename sqlite-check-line-editing ""
  msg-result "Checking for line-editing capability..."
  define HAVE_READLINE 0
  define HAVE_LINENOISE 0
  define HAVE_EDITLINE 0
  define LDFLAGS_READLINE ""
  define CFLAGS_READLINE ""
  set failIfNotFound 0 ; # Gets set to 1 for explicit --FEATURE requests
1038
1039
1040
1041
1042
1043
1044
1045
1046


1047
1048
1049
1050
1051
1052
1053
1075
1076
1077
1078
1079
1080
1081


1082
1083
1084
1085
1086
1087
1088
1089
1090







-
-
+
+







        libedit.
      }
    }
    set rlLib [join $rlLib]
    set rlInc [join $rlInc]
    define LDFLAGS_READLINE $rlLib
    define CFLAGS_READLINE $rlInc
    proj-assert {expr {$editLibDef in {HAVE_READLINE HAVE_EDITLINE}}}
    proj-assert {expr {$editLibName in {readline editline}}}
    proj-assert {$editLibDef in {HAVE_READLINE HAVE_EDITLINE}}
    proj-assert {$editLibName in {readline editline}}
    sqlite-add-shell-opt -D${editLibDef}=1
    msg-result "Using $editLibName flags: $rlInc $rlLib"
    # Check whether rl_completion_matches() has a signature we can use
    # and disable that sub-feature if it doesn't.
    if {![cctest \
            -cflags "$rlInc -D${editLibDef}" -libs $rlLib -nooutput 1 -source {
             #include <stdio.h>
1104
1105
1106
1107
1108
1109
1110
1111


1112
1113










1114
1115
1116



1117
1118
1119
1120



1121

1122
1123

1124
1125
1126
1127
1128
1129
1130
1131











1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149































1150
1151

1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168













1169
1170
1171
1172
1173
1174
1175
1176
1177
1178

1179
1180
1181
1182
1183
1184
1185
1186
1187

1188
1189
1190
1191
1192






1193
1194
1195
1196
1197
1198
1199

1200
1201
1202
1203
1204
1205
1206
1141
1142
1143
1144
1145
1146
1147

1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161



1162
1163
1164
1165



1166
1167
1168
1169
1170
1171

1172



1173




1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184


















1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216

1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231



1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253

1254

1255
1256
1257
1258
1259
1260
1261
1262
1263





1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284







-
+
+


+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+

-
-
-
+
+
+

+

-
+
-
-
-

-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+














-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+









-
+
-








+
-
-
-
-
-
+
+
+
+
+
+







+








########################################################################
# ICU - International Components for Unicode
#
# Handles these flags:
#
#  --with-icu-ldflags=LDFLAGS
#  --with-icu-config[=/path/to/icu-config]
#  --with-icu-cflags=CFLAGS
#  --with-icu-config[=auto | pkg-config | /path/to/icu-config]
#  --enable-icu-collations
#
# --with-icu-config values:
#
#   - auto: use the first one of (pkg-config, icu-config) found on the
#     system.
#   - pkg-config: use only pkg-config to determine flags
#   - /path/to/icu-config: use that to determine flags
#
# If --with-icu-config is used as neither pkg-config nor icu-config
# are found, fail fatally.
#
# If both icu-ldflags and icu-config are provided, they are
# cumulative.  If neither are provided, icu-collations is not honored
# and a warning is emitted if it is provided.
# If both --with-icu-ldflags and --with-icu-config are provided, they
# are cumulative.  If neither are provided, icu-collations is not
# honored and a warning is emitted if it is provided.
#
# Design note: though we can automatically enable ICU if the
# icu-config binary is found, we specifically do not. ICU is always an
# opt-in feature.
# Design note: though we could automatically enable ICU if the
# icu-config binary or (pkg-config icu-io) are found, we specifically
# do not. ICU is always an opt-in feature.
proc sqlite-check-icu {} {
  rename sqlite-check-icu ""
  define LDFLAGS_ICU [join [opt-val with-icu-ldflags ""]]
  # Flags sets seen in the wild for ICU:
  define CFLAGS_ICU [join [opt-val with-icu-cflags ""]]
  # - -licui18n -licuuc -licudata
  # - -licui18n -licuuc
  # - /usr/local/bin/icu-config --ldflags
  if {[proj-opt-was-provided with-icu-config]} {
    set bin [opt-val with-icu-config]
    if {"auto" eq $bin} {
      set bin [proj-first-bin-of \
                 [get-define prefix]/bin/icu-config \
    set icuConfigBin [opt-val with-icu-config]
    set tryIcuConfigBin 1; # set to 0 if we end up using pkg-config
    if {"auto" eq $icuConfigBin || "pkg-config" eq $icuConfigBin} {
      if {[pkg-config-init 0] && [pkg-config icu-io]} {
        # Maintenance reminder: historical docs say to use both of
        # (icu-io, icu-uc). icu-uc lacks a required lib and icu-io has
        # all of them on tested OSes.
        set tryIcuConfigBin 0
        define LDFLAGS_ICU [get-define PKG_ICU_IO_LDFLAGS]
        define-append LDFLAGS_ICU [get-define PKG_ICU_IO_LIBS]
        define CFLAGS_ICU [get-define PKG_ICU_IO_CFLAGS]
                 /usr/local/bin/icu-config \
                 /usr/bin/icu-config]
      if {"" eq $bin} {
        proj-fatal "--with-icu-config=auto cannot find icu-config binary"
      }
    }
    if {[file-isexec $bin]} {
      set x [exec $bin --ldflags]
      if {"" eq $x} {
        proj-fatal "$bin --ldflags returned no data"
      }
      define-append LDFLAGS_ICU $x
    } else {
      proj-fatal "--with-icu-config=$bin does not refer to an executable"
    }
  }
  set flags [define LDFLAGS_ICU [string trim [get-define LDFLAGS_ICU]]]
  if {"" ne $flags} {
      } elseif {"pkg-config" eq $icuConfigBin} {
        proj-fatal "pkg-config cannot find package icu-io"
      } else {
        proj-assert {"auto" eq $icuConfigBin}
      }
    }
    if {$tryIcuConfigBin} {
      if {"auto" eq $icuConfigBin} {
        set icuConfigBin [proj-first-bin-of \
                            /usr/local/bin/icu-config \
                            /usr/bin/icu-config]
        if {"" eq $icuConfigBin} {
          proj-fatal "--with-icu-config=auto cannot find (pkg-config icu-io) or icu-config binary"
        }
      }
      if {[file-isexec $icuConfigBin]} {
        set x [exec $icuConfigBin --ldflags]
        if {"" eq $x} {
          proj-fatal "$icuConfigBin --ldflags returned no data"
        }
        define-append LDFLAGS_ICU $x
        set x [exec $icuConfigBin --cppflags]
        define-append CFLAGS_ICU $x
      } else {
        proj-fatal "--with-icu-config=$bin does not refer to an executable"
      }
    }
  }
  set ldflags [define LDFLAGS_ICU [string trim [get-define LDFLAGS_ICU]]]
  set cflags [define CFLAGS_ICU [string trim [get-define CFLAGS_ICU]]]
  if {"" ne $ldflags} {
    sqlite-add-feature-flag -shell -DSQLITE_ENABLE_ICU
    msg-result "Enabling ICU support with libs: $flags"
    msg-result "Enabling ICU support with flags: $ldflags $cflags"
    if {[opt-bool icu-collations]} {
      msg-result "Enabling ICU collations."
      sqlite-add-feature-flag -shell -DSQLITE_ENABLE_ICU_COLLATIONS
      # Recall that shell.c builds with sqlite3.c
    }
  } elseif {[opt-bool icu-collations]} {
    proj-warn "ignoring --enable-icu-collations because neither --with-icu-ldflags nor --with-icu-config provided any linker flags"
  } else {
    msg-result "ICU support is disabled."
  }
}; # sqlite-check-icu
sqlite-check-icu

########################################################################
# Emscripten SDK for building the web-based wasm components.
#
proc sqlite-check-emsdk {} {
# Check for the Emscripten SDK for building the web-based wasm
# components.  The core lib and tools do not require this but ext/wasm
# does.
apply {{} {
  if {$::autosetup(srcdir) ne $::autosetup(builddir)} {
    # The EMSDK pieces require writing to the original source tree
    # even when doing an out-of-tree build. The ext/wasm pieces do not
    # support an out-of-tree build so we catch that case and treat it
    # as if EMSDK were not found.
    msg-result "Out-of tree build: not checking for EMSDK."
    define EMCC_WRAPPER ""
    return
  }
  set emccsh $::srcdir/tool/emcc.sh
  if {![get-define HAVE_WASI_SDK] && [proj-check-emsdk]} {
    define EMCC_WRAPPER $emccsh
    proj-make-from-dot-in $emccsh
    catch {exec chmod u+x $emccsh}
  } else {
    define EMCC_WRAPPER ""
    file delete -force $emccsh
  }
}
}}
sqlite-check-emsdk

########################################################################
# Check for log(3) in libm and die with an error if it is not
# found. $featureName should be the feature name which requires that
# function (it's used only in error messages). defines LDFLAGS_MATH to
# the required linker flags (which may be empty even if the math APIs
# are found, depending on the OS).
proc affirm-have-math {featureName} {
  if {"" eq [get-define LDFLAGS_MATH ""]} {
  if {![msg-quiet proj-check-function-in-lib log m]} {
    user-error "Missing math APIs for $featureName"
  }
  define LDFLAGS_MATH [get-define lib_log ""]
  undefine lib_log
    if {![msg-quiet proj-check-function-in-lib log m]} {
      user-error "Missing math APIs for $featureName"
    }
    define LDFLAGS_MATH [get-define lib_log ""]
    undefine lib_log
  }
}

########################################################################
# Handle various SQLITE_ENABLE_... feature flags.
msg-result "Feature flags..."
foreach {boolFlag featureFlag ifSetEvalThis} {
  all         {} {
    # The 'all' option must be first in this list.
    proj-opt-set fts4
    proj-opt-set fts5
    proj-opt-set geopoly
    proj-opt-set rtree
    proj-opt-set session
  }
  fts4         -DSQLITE_ENABLE_FTS4    {affirm-have-math fts4}
1214
1215
1216
1217
1218
1219
1220

1221
1222
1223
1224
1225
1226
1227
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306







+







    if {[opt-bool memsys5]} {
      proj-warn "not enabling memsys3 because memsys5 is enabled."
      expr 0
    } else {
      sqlite-add-feature-flag -DSQLITE_ENABLE_MEMSYS3
    }
  }
  scanstatus     -DSQLITE_ENABLE_STMT_SCANSTATUS {}
} {
  proj-if-opt-truthy $boolFlag {
    sqlite-add-feature-flag $featureFlag
    if {0 != [eval $ifSetEvalThis] && "all" ne $boolFlag} {
      msg-result "  + $boolFlag"
    }
  } {
1245
1246
1247
1248
1249
1250
1251
1252

1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264

1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295







1296
1297
1298
1299
1300
1301
1302
1303
1324
1325
1326
1327
1328
1329
1330

1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342

1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361













1362
1363
1364
1365
1366
1367
1368

1369
1370
1371
1372
1373
1374
1375







-
+











-
+


















-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-







    sqlite-add-feature-flag $featureFlag
    msg-result "  - $boolFlag"
  }
}

#########################################################################
# Show the final feature flag sets:
if {1} {
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
# the Makefile and other generated files, so that configure tests
# which may make use of the autotools-conventional flags
# (e.g. [proj-check-rpath]) may do so before we "mangle" them here.
proj-remap-autoconf-dir-vars

########################################################################
# Generate the output files.
#
# Potential TODO (unclear): in sqlite3.pc.in, do we need to include
# any CFLAGS_READLINE, CFLAGS_ZLIB, etc in its "Cflags:" section?
proj-make-from-dot-in -touch Makefile sqlite3.pc
if {0} {
  # Requires a hand-written sqlite_cfg.h.in...
  proj-make-from-dot-in sqlite_cfg.h
  # vs...
} else {
  # Requires no input template...
  make-config-header sqlite_cfg.h \
    -bare {SIZEOF_* HAVE_DECL_*} \
    -none {HAVE_CFLAG_* LDFLAGS_* SH_* SQLITE_AUTORECONFIG
      TARGET_* USE_GCOV TCL_*} \
    -auto {HAVE_* PACKAGE_*} \
    -none *
  proj-touch sqlite_cfg.h ; # help avoid frequent unnecessary @SQLITE_AUTORECONFIG@
make-config-header sqlite_cfg.h \
  -bare {SIZEOF_* HAVE_DECL_*} \
  -none {HAVE_CFLAG_* LDFLAGS_* SH_* SQLITE_AUTORECONFIG
    TARGET_* USE_GCOV TCL_*} \
  -auto {HAVE_* PACKAGE_*} \
  -none *
proj-touch sqlite_cfg.h ; # help avoid frequent unnecessary @SQLITE_AUTORECONFIG@
}

########################################################################
# Some build-dev/debug-only output
proj-if-opt-truthy dump-defines {
  make-config-header $::DUMP_DEFINES_TXT \
    -bare {SQLITE_OS* SQLITE_DEBUG USE_*} \
    -str {BIN_* CC LD AR LDFLAG* OPT_*} \
1324
1325
1326
1327
1328
1329
1330























1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    }
    lappend dumpDefsOpt -none *
    proj-dump-defs-json $DUMP_DEFINES_JSON {*}$dumpDefsOpt
    undefine OPT_FEATURE_FLAGS.list
    undefine OPT_SHELL.list
  }
}

########################################################################
# Perform some high-level validation on the generated files...
#
# 1) Ensure that no unresolved @VAR@ placeholders are in files which
#    use those.
#
# 2) TBD
apply {{} {
  # Check #1: ensure that files which get filtered for @VAR@ do not
  # contain any unresolved @VAR@ refs. That may indicate an
  # unexported/unused var or a typo.
  foreach f "Makefile sqlite3.pc $::srcdir/tool/emcc.sh" {
    if {![file exists $f]} continue
    set lnno 1
    foreach line [proj-file-content-list $f] {
      if {[regexp {(@[A-Za-z_]+@)} $line match]} {
        error "Unresolved reference to $match at line $lnno of $f"
      }
      incr lnno
    }
  }
}}
Changes to autosetup/README.md.
10
11
12
13
14
15
16

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







+







- [Autosetup API Reference](#apiref)
- [API Tips](#apitips)
- [Ensuring TCL Compatibility](#tclcompat)
- [Design Conventions](#conventions)
  - Symbolic Names of Feature Flags
  - Do Not Update Global Shared State
- [Updating Autosetup](#updating)
  - [Patching Autosetup for Project-local changes](#patching)

------------------------------------------------------------------------

<a name="apiref"></a>
Autosetup API Reference
========================================================================

51
52
53
54
55
56
57
58

59
60
61
62
63
64




65
66
67
68
69
70
71
72

73
74
75
76


77
78
79
80
81
82
83
52
53
54
55
56
57
58

59
60
61




62
63
64
65

66
67
68
69
70
71

72
73
74


75
76
77
78
79
80
81
82
83







-
+


-
-
-
-
+
+
+
+
-






-
+


-
-
+
+







scattered around [the TCL files in ./autosetup](/dir/autosetup).

In (mostly) alphabetical order:

- **`file-isexec filename`**\  
  Should be used in place of `[file executable]`, as it will also
  check for `${filename}.exe` on Windows platforms. However, on such
  platforms is also assumes that _any_ existing file is executable.
  platforms it also assumes that _any_ existing file is executable.

- **`get-env VAR ?default?`**\  
  Will fetch an "environment variable"
  from the first of either: (1) a KEY=VALUE passed to the configure
  script or (2) the system's environment variables. Not to be confused
  with `getenv`, which only does the latter and is rarely, if ever,
  Will fetch an "environment variable" from the first of either: (1) a
  KEY=VALUE passed to the configure script or (2) the system's
  environment variables. Not to be confused with `getenv`, which only
  does the latter and is rarely, if ever, useful in this tree.
  useful in this tree.
  - **`proj-get-env VAR ?default?`**\  
    Works like `get-env` but will, if that function finds no match,
    look for a file named `./.env-$VAR` and, if found, return its
    trimmed contents. This can be used, e.g., to set a developer's
    local preferences for the default `CFLAGS`.

- **`proj-define-if-opt-truthy flag defineName ?checkingMsg? ?yesVal=1? ?noVal=0?`**\  
- **`define-for-opt flag defineName ?checkingMsg? ?yesVal=1? ?noVal=0?`**\  
  `[define $defineName]` to either `$yesVal` or `$noVal`, depending on
  whether `--$flag` is truthy or not. `$checkingMsg` is a
  human-readable description of the check being made, e.g. "enable foo
  bar baz?" If no `checkingMsg` is provided, the operation is silent.\  
  human-readable description of the check being made, e.g. "enable foo?"
  If no `checkingMsg` is provided, the operation is silent.\  
  Potential TODO: change the final two args to `-yes` and `-no`
  flags. They're rarely needed, though: search [auto.def][] for
  `TSTRNNR_OPTS` for an example of where they are used.

- **`proj-fatal msg`**\  
  Emits `$msg` to stderr and exits with non-zero.

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
108
109
110
111
112
113
114





115
116
117
118
119
120
121
122

123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140







-
-
-
-
-
+
+
+
+
+
+


-
+
+








+







  of "truthy."

- **`proj-warn msg`**\  
  Emits `$msg` to stderr. Closely-related is autosetup's `user-notice`
  (described below).

- **`sqlite-add-feature-flag ?-shell? FLAG...`**\  
  Adds the given feature flag to the CFLAGS which are specific to building
  the library. It's intended to be passed one or more `-DSQLITE_ENABLE_...`,
  or similar, flags. If the `-shell` flag is used then it also passes
  its arguments to `sqlite-add-shell-opt`. This is a no-op if `FLAG`
  is not provided or is empty.
  Adds the given feature flag to the CFLAGS which are specific to
  building libsqlite3. It's intended to be passed one or more
  `-DSQLITE_ENABLE_...`, or similar, flags. If the `-shell` flag is
  used then it also passes its arguments to
  `sqlite-add-shell-opt`. This is a no-op if `FLAG` is not provided or
  is empty.

- **`sqlite-add-shell-opt FLAG...`**\  
  The shell-specific counterpart of `sqlite-add-feature-flag`.
  The shell-specific counterpart of `sqlite-add-feature-flag` which
  only adds the given flag(s) to the CLI-shell-specific CFLAGS.

- **`user-notice msg`**\  
  Queues `$msg` to be sent to stderr, but does not emit it until
  either `show-notices` is called or the next time autosetup would
  output something (it internally calls `show-notices`). This can be
  used to generate warnings between a "checking for..." message and
  its resulting "yes/no/whatever" message in such a way as to not
  spoil the layout of such messages.


<a name="tclcompat"></a>
Ensuring TCL Compatibility
========================================================================

It is important that any TCL files used by the configure process
remain compatible with both [JimTCL][] and the canonical TCL. Though
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
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







-
-
+
+



-
-
-
+
+
+
















-
+








2. Manually build `./jimsh0` in the top of the checkout with:\  
   `cc -o jimsh0 autosetup/jimsh0.c`\  
   With that in place, the configure script will prefer to use that
   before looking for a system-level `tclsh`. Be aware, though, that
   `make distclean` will remove that file.

**Note that `jimsh0` is distinctly different** from the `jimsh` which
gets built for code-generation purposes. The latter requires
**Note that `jimsh0` is distinctly different from the `jimsh`** which
gets built for code-generation purposes.  The latter requires
non-default build flags to enable features which are
platform-dependent, most notably to make its `[file normalize]` work.
This means, for example, that the configure script and its utility
APIs must not use `[file normalize]`, but autosetup provides a TCL
implementation of `[file-normalize]` (note the dash) for portable use
in the configure script.
APIs must not use `[file normalize]`, but autosetup provides a
TCL-only implementation of `[file-normalize]` (note the dash) for
portable use in the configure script.


<a name="conventions"></a>
Design Conventions
========================================================================

This section describes the motivations for the most glaring of the
build's design decisions, in particular how they deviate from
historical, or even widely-conventional, practices.

Symbolic Names of Feature Flags
------------------------------------------------------------------------

Historically, the project's makefile has exclusively used
`UPPER_UNDERSCORE` form for makefile variables. This build, however,
primarily uses `X.y` format, where `X` is often a category label,
e.g. `CFLAGS` and `y` is the specific instance of that category,
e.g. `CFLAGS`, and `y` is the specific instance of that category,
e.g. `CFLAGS.readline`.

When the configure script exports flags for consumption by filtered
files, e.g. [Makefile.in][] and the generated
`sqlite_cfg.h`, it does so in the more conventional `X_Y` form because
those flags get exported as as C `#define`s to `sqlite_cfg.h`, where
dots are not permitted.
239
240
241
242
243
244
245
246

247
248
249
250
251
252
253
242
243
244
245
246
247
248

249
250
251
252
253
254
255
256







-
+







  in a specific order so that the resulting flags get applied at
  the correct time and/or in the correct order.\  
  (A real-life example: before the approach described below was taken
  to collecting build-time flags, the test for `-rpath` had to come
  _after_ the test for zlib because the results of the `-rpath` test
  implicitly modified global state which broke the zlib feature
  test. Because the feature tests no longer (intentionally) modify
  global state, that is not an issue.)
  shared global state, that is not an issue.)

In this build, cases where feature tests modify global state in such a
way that it may impact later feature tests are either (A) very
intentionally defined to do so (e.g. the `--with-wasi-sdk` flag has
invasive side-effects) or (B) are oversights (i.e. bugs).

This tree's [configure script][auto.def], [utility APIs][proj.tcl],
300
301
302
303
304
305
306
307


308
309
















310
311
312
313
314
315
316
317
318
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







-
+
+


+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+









>
```
$ /path/to/autosetup-checkout/autosetup --install .
$ fossil status # show the modified files
```

Unless the upgrade made any incompatible changes (which is exceedingly
rare), that's all there is to it. Check over the diff, test the
rare), that's all there is to it.  After that's done, **apply a patch
for the change described in the following section**, test the
configure process, and check it in.

<a name="patching"></a>
Patching Autosetup for Project-local Changes
------------------------------------------------------------------------

Autosetup reserves the flag name **`--debug`** for its own purposes,
and its own special handling of `--enable-...` flags makes `--debug`
an alias for `--enable-debug`. As we have a long history of using
`--enable-debug` for this project's own purposes, we patch autosetup
to use the name `--autosetup-debug` in place of `--debug`. That
requires (as of this writing) four small edits in
[](/file/autosetup/autosetup), as demonstrated in [check-in
3296c8d3](/info/3296c8d3).

If autosetup is upgraded and this patch is _not_ applied the invoking
`./configure` will fail loudly because of the declaration of the
`debug` flag in `auto.def` - duplicated flags are not permitted.


[Autosetup]: https://msteveb.github.io/autosetup/
[auto.def]: /file/auto.def
[autosetup-git]: https://github.com/msteveb/autosetup
[proj.tcl]: /file/autosetup/proj.tcl
[Makefile.in]: /file/Makefile.in
[main.mk]: /file/main.mk
[JimTCL]: https://jim.tcl.tk
Changes to autosetup/autosetup.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
19











-
+







#!/bin/sh
# Copyright (c) 2006-2011 WorkWare Systems http://www.workware.net.au/
# All rights reserved
# vim:se syntax=tcl:
# \
dir=`dirname "$0"`; exec "`$dir/autosetup-find-tclsh`" "$0" "$@"

# Note that the version has a trailing + on unreleased versions
set autosetup(version) 0.7.2

# Can be set to 1 to debug early-init problems
set autosetup(debug) [expr {"--debug" in $argv}]
set autosetup(debug) [expr {"--autosetup-debug" in $argv}]

##################################################################
#
# Main flow of control, option handling
#
proc main {argv} {
	global autosetup define
94
95
96
97
98
99
100
101

102
103
104
105
106
107
108
94
95
96
97
98
99
100

101
102
103
104
105
106
107
108







-
+







	#"=Core Options:"
	options-add {
		help:=all       => "display help and options. Optional: module name, such as --help=system"
		licence license => "display the autosetup license"
		version         => "display the version of autosetup"
		ref:=text manual:=text
		reference:=text => "display the autosetup command reference. 'text', 'wiki', 'asciidoc' or 'markdown'"
		debug           => "display debugging output as autosetup runs"
		autosetup-debug => "display debugging output as autosetup runs"
		install:=.      => "install autosetup to the current or given directory"
	}
	if {$autosetup(installed)} {
		# hidden options so we can produce a nice error
		options-add {
			sysinstall:path
		}
128
129
130
131
132
133
134
135

136
137
138
139
140
141
142
128
129
130
131
132
133
134

135
136
137
138
139
140
141
142







-
+








	# autosetup --conf=alternate-auto.def
	if {[opt-str conf o]} {
		set autosetup(autodef) $o
	}

	# Debugging output (set this early)
	incr autosetup(debug) [opt-bool debug]
	incr autosetup(debug) [opt-bool autosetup-debug]
	incr autosetup(force) [opt-bool force]
	incr autosetup(msg-quiet) [opt-bool quiet]
	incr autosetup(msg-timing) [opt-bool timing]

	# If the local module exists, source it now to allow for
	# project-local customisations
	if {[file exists $autosetup(libdir)/local.tcl]} {
2526
2527
2528
2529
2530
2531
2532
2533

2534
2535
2536
2526
2527
2528
2529
2530
2531
2532

2533
2534
2535
2536







-
+



if {$autosetup(debug)} {
	main $argv
}
if {[catch {main $argv} msg opts] == 1} {
	show-notices
	autosetup-full-error [error-dump $msg $opts $autosetup(debug)]
	if {!$autosetup(debug)} {
		puts stderr "Try: '[file tail $autosetup(exe)] --debug' for a full stack trace"
		puts stderr "Try: '[file tail $autosetup(exe)] --autosetup-debug' for a full stack trace"
	}
	exit 1
}
Deleted autosetup/default.auto.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

























-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
# Copyright (c) 2012 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Auto-load module for 'make' build system integration

use init

autosetup_add_init_type make {Simple "make" build system} {
	autosetup_check_create auto.def \
{# Initial auto.def created by 'autosetup --init=make'

use cc

# Add any user options here
options {
}

make-config-header config.h
make-template Makefile.in
}

	if {![file exists Makefile.in]} {
		puts "Note: I don't see Makefile.in. You will probably need to create one."
	}
}
Changes to autosetup/proj.tcl.
73
74
75
76
77
78
79
80
81
82





83
84

85

86
87





88
89
90
91
92
93
94
73
74
75
76
77
78
79



80
81
82
83
84
85

86
87
88


89
90
91
92
93
94
95
96
97
98
99
100







-
-
-
+
+
+
+
+

-
+

+
-
-
+
+
+
+
+







  puts stderr "ERROR: $msg"
  exit 1
}

########################################################################
# @proj-assert script
#
# Kind of like a C assert if uplevel (eval) of $script is false,
# triggers a fatal error.
proc proj-assert {script} {
# Kind of like a C assert: if uplevel (eval) of [expr {$script}] is
# false, a fatal error is triggered. The error message, by default,
# includes the body of the failed assertion, but if $descr is set then
# that is used instead.
proc proj-assert {script {descr ""}} {
  if {1 == [get-env proj-assert 0]} {
    msg-result [proj-bold "asserting: [string trim $script]"]
    msg-result [proj-bold "asserting: $script"]
  }
  set x "expr \{ $script \}"
  if {![uplevel 1 $script]} {
    proj-fatal "Assertion failed: $script"
  if {![uplevel 1 $x]} {
    if {"" eq $descr} {
      set descr $script
    }
    proj-fatal "Assertion failed: $descr"
  }
}

########################################################################
# @proj-bold str
#
# If this function believes that the current console might support
128
129
130
131
132
133
134




135


136
137
138
139
140
141
142
134
135
136
137
138
139
140
141
142
143
144

145
146
147
148
149
150
151
152
153







+
+
+
+
-
+
+







      default {
        break
      }
    }
  }
  set lines [split [join $args] \n]
  foreach line $lines {
    set line [string trimleft $line]
    if {"" eq $line} {
      $outFunc $line
    } else {
    $outFunc "      [string trimleft $line]"
      $outFunc "    $line"
    }
  }
  if {"" ne $fErr} {
    show-notices
    exit 1
  }
}

301
302
303
304
305
306
307
308
309
310
311





312
313
314
315
316
317
318
319
312
313
314
315
316
317
318




319
320
321
322
323

324
325
326
327
328
329
330







-
-
-
-
+
+
+
+
+
-







  }
  return $rc
}

########################################################################
# @proj-opt-was-provided key
#
# Returns 1 if the user specifically provided the given configure
# flag, else 0. This can be used to distinguish between options which
# have a default value and those which were explicitly provided by the
# user, even if the latter is done in a way which uses the default
# Returns 1 if the user specifically provided the given configure flag
# or if it was specifically set using proj-opt-set, else 0. This can
# be used to distinguish between options which have a default value
# and those which were explicitly provided by the user, even if the
# latter is done in a way which uses the default value.
# value.
#
# For example, with a configure flag defined like:
#
#   { foo-bar:=baz => {its help text} }
#
# This function will, when passed foo-bar, return 1 only if the user
# passes --foo-bar to configure, even if that invocation would resolve
382
383
384
385
386
387
388
389

390
391
392
393
394
395

396
397
398
399
400
401
402
393
394
395
396
397
398
399

400
401
402
403
404
405

406
407
408
409
410
411
412
413







-
+





-
+







    uplevel 1 $thenScript
  } else {
    uplevel 1 $elseScript
  }
}

########################################################################
# @proj-define-if-opt-truthy flag def ?msg? ?iftrue? ?iffalse?
# @proj-define-for-opt flag def ?msg? ?iftrue? ?iffalse?
#
# If [proj-opt-truthy $flag] then [define $def $iftrue] else [define
# $def $iffalse]. If $msg is not empty, output [msg-checking $msg] and
# a [msg-results ...] which corresponds to the result. Returns 1 if
# the opt-truthy check passes, else 0.
proc proj-define-if-opt-truthy {flag def {msg ""} {iftrue 1} {iffalse 0}} {
proc proj-define-for-opt {flag def {msg ""} {iftrue 1} {iffalse 0}} {
  if {"" ne $msg} {
    msg-checking "$msg "
  }
  set rcMsg ""
  set rc 0
  if {[proj-opt-truthy $flag]} {
    define $def $iftrue
936
937
938
939
940
941
942
943

944
945
946
947
948
949
950
947
948
949
950
951
952
953

954
955
956
957
958
959
960
961







-
+







}

########################################################################
# @proj-check-soname ?libname?
#
# Checks whether CC supports the -Wl,soname,lib... flag. If so, it
# returns 1 and defines LDFLAGS_SONAME_PREFIX to the flag's prefix, to
# which the client would need to append "libwhatever.N". If not, it
# which the client would need to append "libwhatever.N".  If not, it
# returns 0 and defines LDFLAGS_SONAME_PREFIX to an empty string.
#
# The libname argument is only for purposes of running the flag
# compatibility test, and is not included in the resulting
# LDFLAGS_SONAME_PREFIX. It is provided so that clients may
# potentially avoid some end-user confusion by using their own lib's
# name here (which shows up in the "checking..." output).
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206



1207
1208
1209
1210
1211
1212
1213
1207
1208
1209
1210
1211
1212
1213




1214
1215
1216
1217
1218
1219
1220
1221
1222
1223







-
-
-
-
+
+
+







# use FOO if exec_prefix is not overridden at make-time.  Without this
# post-processing, libdir would be cemented in as FOO/lib at
# configure-time, so could be tedious to override properly via a make
# invocation.
proc proj-remap-autoconf-dir-vars {} {
  set prefix [get-define prefix]
  set exec_prefix [get-define exec_prefix $prefix]
  # Note that the ${...} here refers to make-side var derefs, not
  # TCL-side vars. They must be formulated such that they are legal
  # for use in (A) makefiles, (B) pkgconfig files, and (C) TCL's
  # [subst] command. i.e. they must use the form ${X}.
  # The following var derefs must be formulated such that they are
  # legal for use in (A) makefiles, (B) pkgconfig files, and (C) TCL's
  # [subst] command.  i.e. they must use the form ${X}.
  foreach {flag makeVar makeDeref} {
    exec-prefix     exec_prefix    ${prefix}
    datadir         datadir        ${prefix}/share
    mandir          mandir         ${datadir}/man
    includedir      includedir     ${prefix}/include
    bindir          bindir         ${exec_prefix}/bin
    libdir          libdir         ${exec_prefix}/lib
Deleted autosetup/tmake.auto.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73









































































-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
# Copyright (c) 2016 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Auto-load module for 'tmake' build system integration

use init

autosetup_add_init_type tmake "Tcl-based tmake build system" {
	autosetup_check_create auto.def \
{# Initial auto.def created by 'autosetup --init=tmake'
# vim:set syntax=tcl:

use cc cc-lib cc-db cc-shared
use tmake

# Add any user options here
# Really want a --configure that takes over the rest of the command line
options {
}

cc-check-tools ar ranlib

set objdir [get-env BUILDDIR objdir]

make-config-header $objdir/include/autoconf.h
make-tmake-settings $objdir/settings.conf {[A-Z]*} *dir lib_*
}

	autosetup_check_create project.spec \
{# Initial project.spec created by 'autosetup --init=tmake'

tmake-require-version 0.7.3

# vim:set syntax=tcl:
define? DESTDIR _install

# XXX If configure creates additional/different files than include/autoconf.h
#     that should be reflected here
Autosetup include/autoconf.h

# e.g. for autoconf.h
IncludePaths include

ifconfig !CONFIGURED {
	# Not configured, so don't process subdirs
	AutoSubDirs off
	# And don't process this file any further
	ifconfig false
}
}

	set configure [readfile configure]
	# XXX Do we need also need to support a system install of tmake?
	if {[string first {#@TMAKEUPDATED@} $configure] < 0} {
		if {[regsub {#@@INITCHECK@@#} $configure \
			{test -z "$TMAKE" -a -x "$dir/tmake" \&\& exec "$dir/tmake" --force --configure "$@"; #@TMAKEUPDATED@} configure]} {
			writefile configure $configure\n
			exec chmod +x configure
			puts "Updated configure to invoke local tmake."
			if {![file exec autosetup/tmake]} {
				puts "Warning: autosetup/tmake is missing."
				puts "   Install it with: tmake --install=autosetup"
			}
		} else {
			puts "Warning: configure isn't created by a recent autosetup, not updating."
		}
	} else {
		puts "I see configure for tmake already exists."
	}
	if {![file exists build.spec]} {
		puts "Note: I don't see build.spec. Try running: tmake --genie"
	}
}
Deleted autosetup/tmake.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52




















































-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
# Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# @synopsis:
#
# The 'tmake' module makes it easy to support the tmake build system.
#
# The following variables are set:
#
## CONFIGURED  - to indicate that the project is configured

use system

options {}

define CONFIGURED

# @make-tmake-settings outfile patterns ...
#
# Examines all defined variables which match the given patterns (defaults to '*')
# and writes a tmake-compatible .conf file defining those variables.
# For example, if 'ABC' is '"3 monkeys"' and 'ABC' matches a pattern, then the file will include:
#
## define ABC {3 monkeys}
#
# If the file would be unchanged, it is not written.
#
# Typical usage is:
#
## make-tmake-settings [get-env BUILDDIR objdir]/settings.conf {[A-Z]*}
proc make-tmake-settings {file args} {
	file mkdir [file dirname $file]
	set lines {}

	if {[llength $args] == 0} {
		set args *
	}

	foreach n [lsort [dict keys [all-defines]]] {
		foreach p $args {
			if {[string match $p $n]} {
				set value [get-define $n]
				lappend lines "define $n [list $value]"
				break
			}
		}
	}
	set buf [join $lines \n]
	write-if-changed $file $buf {
		msg-result "Created $file"
	}
}
Changes to ext/expert/sqlite3expert.c.
1487
1488
1489
1490
1491
1492
1493
1494

1495
1496
1497
1498
1499
1500
1501
1487
1488
1489
1490
1491
1492
1493

1494
1495
1496
1497
1498
1499
1500
1501







-
+








    if( zType[0]=='v' || zType[1]=='r' || bVirtual ){
      /* A view. Or a trigger on a view. */
      if( zSql ) rc = expertSchemaSql(p->dbv, zSql, pzErrmsg);
    }else{
      IdxTable *pTab;
      rc = idxGetTableInfo(p->db, zName, &pTab, pzErrmsg);
      if( rc==SQLITE_OK ){
      if( rc==SQLITE_OK && ALWAYS(pTab!=0) ){
        int i;
        char *zInner = 0;
        char *zOuter = 0;
        pTab->pNext = p->pTable;
        p->pTable = pTab;

        /* The statement the vtab will pass to sqlite3_declare_vtab() */
Changes to ext/fts3/fts3.c.
2340
2341
2342
2343
2344
2345
2346



2347
2348
2349
2350


2351
2352
2353
2354
2355
2356
2357
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362







+
+
+




+
+







  /* Never set both isSaveLeft and isExact for the same invocation. */
  assert( isSaveLeft==0 || isExact==0 );

  assert_fts3_nc( p!=0 && *p1!=0 && *p2!=0 );
  if( *p1==POS_COLUMN ){ 
    p1++;
    p1 += fts3GetVarint32(p1, &iCol1);
    /* iCol1==0 indicates corruption. Column 0 does not have a POS_COLUMN
    ** entry, so this is actually end-of-doclist. */
    if( iCol1==0 ) return 0;
  }
  if( *p2==POS_COLUMN ){ 
    p2++;
    p2 += fts3GetVarint32(p2, &iCol2);
    /* As above, iCol2==0 indicates corruption. */
    if( iCol2==0 ) return 0;
  }

  while( 1 ){
    if( iCol1==iCol2 ){
      char *pSave = p;
      sqlite3_int64 iPrev = 0;
      sqlite3_int64 iPos1 = 0;
Changes to ext/fts3/fts3_expr.c.
315
316
317
318
319
320
321
322
323
324
325




326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350




351
352
353
354
355
356
357

358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375

376
377
378
379

380
381
382





383
384
385
386
387
388
389
315
316
317
318
319
320
321


322

323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340



341
342
343
344
345
346
347

348
349
350
351
352
353
354
355
356
357
358
359
360
361



362
363
364
365
366
367
368
369
370




371
372
373
374
375
376



377
378
379
380
381
382
383
384
385
386
387
388







-
-

-
+
+
+
+














-
-
-







-
+
+
+
+







+


-
-
-









-
-
-
-
+




+
-
-
-
+
+
+
+
+







      const char *zByte;
      int nByte = 0, iBegin = 0, iEnd = 0, iPos = 0;
      rc = pModule->xNext(pCursor, &zByte, &nByte, &iBegin, &iEnd, &iPos);
      if( rc==SQLITE_OK ){
        Fts3PhraseToken *pToken;

        p = fts3ReallocOrFree(p, nSpace + ii*sizeof(Fts3PhraseToken));
        if( !p ) goto no_mem;

        zTemp = fts3ReallocOrFree(zTemp, nTemp + nByte);
        if( !zTemp ) goto no_mem;
        if( !zTemp || !p ){
          rc = SQLITE_NOMEM;
          goto getnextstring_out;
        }

        assert( nToken==ii );
        pToken = &((Fts3Phrase *)(&p[1]))->aToken[ii];
        memset(pToken, 0, sizeof(Fts3PhraseToken));

        memcpy(&zTemp[nTemp], zByte, nByte);
        nTemp += nByte;

        pToken->n = nByte;
        pToken->isPrefix = (iEnd<nInput && zInput[iEnd]=='*');
        pToken->bFirst = (iBegin>0 && zInput[iBegin-1]=='^');
        nToken = ii+1;
      }
    }

    pModule->xClose(pCursor);
    pCursor = 0;
  }

  if( rc==SQLITE_DONE ){
    int jj;
    char *zBuf = 0;

    p = fts3ReallocOrFree(p, nSpace + nToken*sizeof(Fts3PhraseToken) + nTemp);
    if( !p ) goto no_mem;
    if( !p ){
      rc = SQLITE_NOMEM;
      goto getnextstring_out;
    }
    memset(p, 0, (char *)&(((Fts3Phrase *)&p[1])->aToken[0])-(char *)p);
    p->eType = FTSQUERY_PHRASE;
    p->pPhrase = (Fts3Phrase *)&p[1];
    p->pPhrase->iColumn = pParse->iDefaultCol;
    p->pPhrase->nToken = nToken;

    zBuf = (char *)&p->pPhrase->aToken[nToken];
    assert( nTemp==0 || zTemp );
    if( zTemp ){
      memcpy(zBuf, zTemp, nTemp);
      sqlite3_free(zTemp);
    }else{
      assert( nTemp==0 );
    }

    for(jj=0; jj<p->pPhrase->nToken; jj++){
      p->pPhrase->aToken[jj].z = zBuf;
      zBuf += p->pPhrase->aToken[jj].n;
    }
    rc = SQLITE_OK;
  }

  *ppExpr = p;
  return rc;
no_mem:

 getnextstring_out:
  if( pCursor ){
    pModule->xClose(pCursor);
  }
  sqlite3_free(zTemp);
  if( rc!=SQLITE_OK ){
  sqlite3_free(p);
  *ppExpr = 0;
  return SQLITE_NOMEM;
    sqlite3_free(p);
    p = 0;
  }
  *ppExpr = p;
  return rc;
}

/*
** The output variable *ppExpr is populated with an allocated Fts3Expr 
** structure, or set to 0 if the end of the input buffer is reached.
**
** Returns an SQLite error code. SQLITE_OK if everything works, SQLITE_NOMEM
Changes to ext/fts5/fts5.h.
294
295
296
297
298
299
300
301
302
303

304
305
306
307
308

















309
310

311
312
313
314
315
316
317
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







-
-
-
+





+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+







**
** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken)
**   This is used to access token iToken of phrase hit iIdx within the
**   current row. If iIdx is less than zero or greater than or equal to the
**   value returned by xInstCount(), SQLITE_RANGE is returned.  Otherwise,
**   output variable (*ppToken) is set to point to a buffer containing the
**   matching document token, and (*pnToken) to the size of that buffer in 
**   bytes. This API is not available if the specified token matches a 
**   prefix query term. In that case both output variables are always set 
**   to 0.
**   bytes. 
**
**   The output text is not a copy of the document text that was tokenized.
**   It is the output of the tokenizer module. For tokendata=1 tables, this 
**   includes any embedded 0x00 and trailing data.
**
**   This API may be slow in some cases if the token identified by parameters 
**   iIdx and iToken matched a prefix token in the query. In most cases, the
**   first call to this API for each prefix token in the query is forced
**   to scan the portion of the full-text index that matches the prefix
**   token to collect the extra data required by this API. If the prefix
**   token matches a large number of token instances in the document set,
**   this may be a performance problem. 
**
**   If the user knows in advance that a query may use this API for a
**   prefix token, FTS5 may be configured to collect all required data as part
**   of the initial querying of the full-text index, avoiding the second scan
**   entirely. This also causes prefix queries that do not use this API to 
**   run more slowly and use more memory. FTS5 may be configured in this way
**   either on a per-table basis using the [FTS5 insttoken | 'insttoken'] 
**   option, or on a per-query basis using the 
**   [fts5_insttoken | fts5_insttoken()] user function.
**
**   This API can be quite slow if used with an FTS5 table created with the
**   "detail=none" or "detail=column" option.
**   "detail=none" or "detail=column" option. 
**
** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
**   If parameter iCol is less than zero, or greater than or equal to the
**   number of columns in the table, SQLITE_RANGE is returned.
**
**   Otherwise, this function attempts to retrieve the locale associated
**   with column iCol of the current row. Usually, there is no associated
Changes to ext/fts5/fts5Int.h.
243
244
245
246
247
248
249
250


251
252
253
254
255
256
257
243
244
245
246
247
248
249

250
251
252
253
254
255
256
257
258







-
+
+







  int nAutomerge;                 /* 'automerge' setting */
  int nCrisisMerge;               /* Maximum allowed segments per level */
  int nUsermerge;                 /* 'usermerge' setting */
  int nHashSize;                  /* Bytes of memory for in-memory hash */
  char *zRank;                    /* Name of rank function */
  char *zRankArgs;                /* Arguments to rank function */
  int bSecureDelete;              /* 'secure-delete' */
  int nDeleteMerge;           /* 'deletemerge' */
  int nDeleteMerge;               /* 'deletemerge' */
  int bPrefixInsttoken;           /* 'prefix-insttoken' */

  /* If non-NULL, points to sqlite3_vtab.base.zErrmsg. Often NULL. */
  char **pzErrmsg;

#ifdef SQLITE_DEBUG
  int bPrefixIndex;               /* True to use prefix-indexes */
#endif
500
501
502
503
504
505
506
507








508
509
510
511
512
513
514
501
502
503
504
505
506
507

508
509
510
511
512
513
514
515
516
517
518
519
520
521
522







-
+
+
+
+
+
+
+
+







void *sqlite3Fts5StructureRef(Fts5Index*);
void sqlite3Fts5StructureRelease(void*);
int sqlite3Fts5StructureTest(Fts5Index*, void*);

/*
** Used by xInstToken():
*/
int sqlite3Fts5IterToken(Fts5IndexIter*, i64, int, int, const char**, int*);
int sqlite3Fts5IterToken(
  Fts5IndexIter *pIndexIter, 
  const char *pToken, int nToken,
  i64 iRowid,
  int iCol, 
  int iOff, 
  const char **ppOut, int *pnOut
);

/*
** Insert or remove data to or from the index. Each time a document is 
** added to or removed from the index, this function is called one or more
** times.
**
** For an insert, it must be called once for each token in the new document.
Changes to ext/fts5/fts5_config.c.
1022
1023
1024
1025
1026
1027
1028













1029
1030
1031
1032
1033
1034
1035
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048







+
+
+
+
+
+
+
+
+
+
+
+
+







      bVal = sqlite3_value_int(pVal);
    }
    if( bVal<0 ){
      *pbBadkey = 1;
    }else{
      pConfig->bSecureDelete = (bVal ? 1 : 0);
    }
  }

  else if( 0==sqlite3_stricmp(zKey, "insttoken") ){
    int bVal = -1;
    if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
      bVal = sqlite3_value_int(pVal);
    }
    if( bVal<0 ){
      *pbBadkey = 1;
    }else{
      pConfig->bPrefixInsttoken = (bVal ? 1 : 0);
    }

  }else{
    *pbBadkey = 1;
  }
  return rc;
}

/*
Changes to ext/fts5/fts5_expr.c.
3042
3043
3044
3045
3046
3047
3048
3049

3050
3051
3052
3053
3054
3055
3056
3042
3043
3044
3045
3046
3047
3048

3049
3050
3051
3052
3053
3054
3055
3056







-
+







    for(pT=&pExpr->apExprPhrase[i]->aTerm[0]; pT; pT=pT->pSynonym){
      if( (pT->nQueryTerm==nQuery || (pT->nQueryTerm<nQuery && pT->bPrefix))
       && memcmp(pT->pTerm, pToken, pT->nQueryTerm)==0
      ){
        int rc = sqlite3Fts5PoslistWriterAppend(
            &pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff
        );
        if( rc==SQLITE_OK && pExpr->pConfig->bTokendata && !pT->bPrefix ){
        if( rc==SQLITE_OK && (pExpr->pConfig->bTokendata || pT->bPrefix) ){
          int iCol = p->iOff>>32;
          int iTokOff = p->iOff & 0x7FFFFFFF;
          rc = sqlite3Fts5IndexIterWriteTokendata(
              pT->pIter, pToken, nToken, iRowid, iCol, iTokOff
          );
        }
        if( rc ) return rc;
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249








3250
3251
3252
3253
3254
3255
3256
3257
3235
3236
3237
3238
3239
3240
3241








3242
3243
3244
3245
3246
3247
3248
3249

3250
3251
3252
3253
3254
3255
3256







-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-







    return SQLITE_RANGE;
  }
  pPhrase = pExpr->apExprPhrase[iPhrase];
  if( iToken<0 || iToken>=pPhrase->nTerm ){
    return SQLITE_RANGE;
  }
  pTerm = &pPhrase->aTerm[iToken];
  if( pTerm->bPrefix==0 ){
    if( pExpr->pConfig->bTokendata ){
      rc = sqlite3Fts5IterToken(
          pTerm->pIter, iRowid, iCol, iOff+iToken, ppOut, pnOut
      );
    }else{
      *ppOut = pTerm->pTerm;
      *pnOut = pTerm->nFullTerm;
  if( pExpr->pConfig->bTokendata || pTerm->bPrefix ){
    rc = sqlite3Fts5IterToken(
        pTerm->pIter, pTerm->pTerm, pTerm->nQueryTerm, 
        iRowid, iCol, iOff+iToken, ppOut, pnOut
    );
  }else{
    *ppOut = pTerm->pTerm;
    *pnOut = pTerm->nFullTerm;
    }
  }
  return rc;
}

/*
** Clear the token mappings for all Fts5IndexIter objects mannaged by 
** the expression passed as the only argument.
Changes to ext/fts5/fts5_index.c.
6199
6200
6201
6202
6203
6204
6205

























































































































































































































































































































































































6206
6207
6208
6209
6210
6211
6212
6213
6214
6215


6216
6217
6218
6219
6220















6221
6222
6223
6224


6225
6226
6227
6228
6229




6230
6231
6232

6233
6234

6235
6236
6237

6238
6239
6240
6241
6242
6243
6244
6245
6246
6247
6248
6249
6250
6251
6252
6253
6254
6255
6256
6257
6258

6259
6260
6261
6262
6263
6264
6265
6266
6267
6268
6269
6270


6271
6272
6273
6274
6275

6276
6277
6278
6279
6280
6281
6282
6283
6284
6285
6286
6287
6288
6289
6290
6291
6292
6293
6294
6295
6296
6297
6298
6299
6300
6301
6302
6303
6304
6305
6306
6307
6308
6309
6310
6311
6312
6313
6314
6315
6316
6317
6318
6319
6320


6321
6322
6323

6324
6325
6326


6327
6328
6329
6330
6331

6332
6333
6334
6335


6336
6337
6338
6339
6340










6341
6342

6343
6344
6345
6346
6347
6348
6349
6199
6200
6201
6202
6203
6204
6205
6206
6207
6208
6209
6210
6211
6212
6213
6214
6215
6216
6217
6218
6219
6220
6221
6222
6223
6224
6225
6226
6227
6228
6229
6230
6231
6232
6233
6234
6235
6236
6237
6238
6239
6240
6241
6242
6243
6244
6245
6246
6247
6248
6249
6250
6251
6252
6253
6254
6255
6256
6257
6258
6259
6260
6261
6262
6263
6264
6265
6266
6267
6268
6269
6270
6271
6272
6273
6274
6275
6276
6277
6278
6279
6280
6281
6282
6283
6284
6285
6286
6287
6288
6289
6290
6291
6292
6293
6294
6295
6296
6297
6298
6299
6300
6301
6302
6303
6304
6305
6306
6307
6308
6309
6310
6311
6312
6313
6314
6315
6316
6317
6318
6319
6320
6321
6322
6323
6324
6325
6326
6327
6328
6329
6330
6331
6332
6333
6334
6335
6336
6337
6338
6339
6340
6341
6342
6343
6344
6345
6346
6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360
6361
6362
6363
6364
6365
6366
6367
6368
6369
6370
6371
6372
6373
6374
6375
6376
6377
6378
6379
6380
6381
6382
6383
6384
6385
6386
6387
6388
6389
6390
6391
6392
6393
6394
6395
6396
6397
6398
6399
6400
6401
6402
6403
6404
6405
6406
6407
6408
6409
6410
6411
6412
6413
6414
6415
6416
6417
6418
6419
6420
6421
6422
6423
6424
6425
6426
6427
6428
6429
6430
6431
6432
6433
6434
6435
6436
6437
6438
6439
6440
6441
6442
6443
6444
6445
6446
6447
6448
6449
6450
6451
6452
6453
6454
6455
6456
6457
6458
6459
6460
6461
6462
6463
6464
6465
6466
6467
6468
6469
6470
6471
6472
6473
6474
6475
6476
6477
6478
6479
6480
6481
6482
6483
6484
6485
6486
6487
6488
6489
6490
6491
6492
6493
6494
6495
6496
6497
6498
6499
6500
6501
6502
6503
6504
6505
6506
6507
6508
6509
6510
6511
6512
6513
6514
6515
6516
6517
6518
6519
6520
6521
6522
6523
6524
6525
6526
6527
6528
6529
6530
6531
6532
6533
6534
6535
6536
6537
6538
6539
6540
6541
6542
6543
6544
6545
6546
6547
6548
6549
6550
6551
6552
6553
6554
6555
6556
6557
6558
6559
6560
6561
6562
6563
6564
6565
6566
6567
6568
6569
6570
6571
6572
6573
6574
6575
6576
6577
6578
6579
6580
6581
6582
6583
6584
6585
6586
6587
6588
6589
6590
6591
6592
6593
6594





6595
6596
6597
6598
6599
6600
6601
6602
6603
6604
6605
6606
6607
6608
6609

6610


6611
6612
6613




6614
6615
6616
6617
6618
6619

6620
6621

6622
6623
6624

6625


6626


6627




6628
6629
6630
6631
6632
6633
6634


6635

6636












6637
6638



6639

6640

6641











































6642
6643
6644
6645

6646
6647


6648
6649
6650
6651

6652

6653
6654
6655


6656
6657
6658
6659



6660
6661
6662
6663
6664
6665
6666
6667
6668
6669
6670

6671
6672
6673
6674
6675
6676
6677
6678







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+










+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-

-
-
+
+

-
-
-
-
+
+
+
+


-
+

-
+


-
+
-
-

-
-

-
-
-
-







-
-

-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-

-
+
-

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+


-
+

-
-
+
+


-

-
+


-
-
+
+


-
-
-
+
+
+
+
+
+
+
+
+
+

-
+








  fts5BufferFree(p1);
  fts5BufferFree(&tmp);
  memset(&out.p[out.n], 0, FTS5_DATA_ZERO_PADDING);
  *p1 = out;
}


/*
** Iterate through a range of entries in the FTS index, invoking the xVisit
** callback for each of them.
**
** Parameter pToken points to an nToken buffer containing an FTS index term
** (i.e. a document term with the preceding 1 byte index identifier -
** FTS5_MAIN_PREFIX or similar). If bPrefix is true, then the call visits
** all entries for terms that have pToken/nToken as a prefix. If bPrefix
** is false, then only entries with pToken/nToken as the entire key are
** visited. 
**
** If the current table is a tokendata=1 table, then if bPrefix is true then
** each index term is treated separately. However, if bPrefix is false, then
** all index terms corresponding to pToken/nToken are collapsed into a single
** term before the callback is invoked.
**
** The callback invoked for each entry visited is specified by paramter xVisit.
** Each time it is invoked, it is passed a pointer to the Fts5Index object,
** a copy of the 7th paramter to this function (pCtx) and a pointer to the
** iterator that indicates the current entry. If the current entry is the
** first with a new term (i.e. different from that of the previous entry,
** including the very first term), then the final two parameters are passed
** a pointer to the term and its size in bytes, respectively. If the current
** entry is not the first associated with its term, these two parameters
** are passed 0.
**
** If parameter pColset is not NULL, then it is used to filter entries before
** the callback is invoked.
*/
static int fts5VisitEntries(
  Fts5Index *p,                   /* Fts5 index object */
  Fts5Colset *pColset,            /* Columns filter to apply, or NULL */
  u8 *pToken,                     /* Buffer containing token */
  int nToken,                     /* Size of buffer pToken in bytes */
  int bPrefix,                    /* True for a prefix scan */
  void (*xVisit)(Fts5Index*, void *pCtx, Fts5Iter *pIter, const u8*, int),
  void *pCtx                      /* Passed as second argument to xVisit() */
){
  const int flags = (bPrefix ? FTS5INDEX_QUERY_SCAN : 0)
                  | FTS5INDEX_QUERY_SKIPEMPTY 
                  | FTS5INDEX_QUERY_NOOUTPUT;
  Fts5Iter *p1 = 0;     /* Iterator used to gather data from index */
  int bNewTerm = 1;
  Fts5Structure *pStruct = fts5StructureRead(p);

  fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1);
  fts5IterSetOutputCb(&p->rc, p1);
  for( /* no-op */ ;
      fts5MultiIterEof(p, p1)==0;
      fts5MultiIterNext2(p, p1, &bNewTerm)
  ){
    Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
    int nNew = 0;
    const u8 *pNew = 0;

    p1->xSetOutputs(p1, pSeg);
    if( p->rc ) break;

    if( bNewTerm ){
      nNew = pSeg->term.n;
      pNew = pSeg->term.p;
      if( nNew<nToken || memcmp(pToken, pNew, nToken) ) break;
    }

    xVisit(p, pCtx, p1, pNew, nNew);
  }
  fts5MultiIterFree(p1);

  fts5StructureRelease(pStruct);
  return p->rc;
}


/*
** Usually, a tokendata=1 iterator (struct Fts5TokenDataIter) accumulates an
** array of these for each row it visits (so all iRowid fields are the same).
** Or, for an iterator used by an "ORDER BY rank" query, it accumulates an
** array of these for the entire query (in which case iRowid fields may take
** a variety of values).
**
** Each instance in the array indicates the iterator (and therefore term)
** associated with position iPos of rowid iRowid. This is used by the
** xInstToken() API.
**
** iRowid:
**   Rowid for the current entry.
**
** iPos:
**   Position of current entry within row. In the usual ((iCol<<32)+iOff)
**   format (e.g. see macros FTS5_POS2COLUMN() and FTS5_POS2OFFSET()).
**
** iIter:
**   If the Fts5TokenDataIter iterator that the entry is part of is
**   actually an iterator (i.e. with nIter>0, not just a container for
**   Fts5TokenDataMap structures), then this variable is an index into
**   the apIter[] array. The corresponding term is that which the iterator
**   at apIter[iIter] currently points to.
**
**   Or, if the Fts5TokenDataIter iterator is just a container object
**   (nIter==0), then iIter is an index into the term.p[] buffer where
**   the term is stored.
**
** nByte:
**   In the case where iIter is an index into term.p[], this variable
**   is the size of the term in bytes. If iIter is an index into apIter[],
**   this variable is unused.
*/
struct Fts5TokenDataMap {
  i64 iRowid;                     /* Row this token is located in */
  i64 iPos;                       /* Position of token */
  int iIter;                      /* Iterator token was read from */
  int nByte;                      /* Length of token in bytes (or 0) */
};

/*
** An object used to supplement Fts5Iter for tokendata=1 iterators.
**
** This object serves two purposes. The first is as a container for an array
** of Fts5TokenDataMap structures, which are used to find the token required
** when the xInstToken() API is used. This is done by the nMapAlloc, nMap and
** aMap[] variables.
*/
struct Fts5TokenDataIter {
  int nMapAlloc;                  /* Allocated size of aMap[] in entries */
  int nMap;                       /* Number of valid entries in aMap[] */
  Fts5TokenDataMap *aMap;         /* Array of (rowid+pos -> token) mappings */

  /* The following are used for prefix-queries only. */
  Fts5Buffer terms;

  /* The following are used for other full-token tokendata queries only. */
  int nIter;
  int nIterAlloc;
  Fts5PoslistReader *aPoslistReader;
  int *aPoslistToIter;
  Fts5Iter *apIter[1];
};

/*
** The two input arrays - a1[] and a2[] - are in sorted order. This function
** merges the two arrays together and writes the result to output array 
** aOut[]. aOut[] is guaranteed to be large enough to hold the result.
**
** Duplicate entries are copied into the output. So the size of the output
** array is always (n1+n2) entries.
*/
static void fts5TokendataMerge(
  Fts5TokenDataMap *a1, int n1,   /* Input array 1 */
  Fts5TokenDataMap *a2, int n2,   /* Input array 2 */
  Fts5TokenDataMap *aOut          /* Output array */
){
  int i1 = 0;
  int i2 = 0;

  assert( n1>=0 && n2>=0 );
  while( i1<n1 || i2<n2 ){
    Fts5TokenDataMap *pOut = &aOut[i1+i2];
    if( i2>=n2 || (i1<n1 && (
        a1[i1].iRowid<a2[i2].iRowid
     || (a1[i1].iRowid==a2[i2].iRowid && a1[i1].iPos<=a2[i2].iPos)
    ))){
      memcpy(pOut, &a1[i1], sizeof(Fts5TokenDataMap));
      i1++;
    }else{
      memcpy(pOut, &a2[i2], sizeof(Fts5TokenDataMap));
      i2++;
    }
  }
}


/*
** Append a mapping to the token-map belonging to object pT.
*/
static void fts5TokendataIterAppendMap(
  Fts5Index *p, 
  Fts5TokenDataIter *pT, 
  int iIter,
  int nByte,
  i64 iRowid, 
  i64 iPos
){
  if( p->rc==SQLITE_OK ){
    if( pT->nMap==pT->nMapAlloc ){
      int nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64;
      int nAlloc = nNew * sizeof(Fts5TokenDataMap);
      Fts5TokenDataMap *aNew;

      aNew = (Fts5TokenDataMap*)sqlite3_realloc(pT->aMap, nAlloc);
      if( aNew==0 ){
        p->rc = SQLITE_NOMEM;
        return;
      }

      pT->aMap = aNew;
      pT->nMapAlloc = nNew;
    }

    pT->aMap[pT->nMap].iRowid = iRowid;
    pT->aMap[pT->nMap].iPos = iPos;
    pT->aMap[pT->nMap].iIter = iIter;
    pT->aMap[pT->nMap].nByte = nByte;
    pT->nMap++;
  }
}

/*
** Sort the contents of the pT->aMap[] array.
**
** The sorting algorithm requries a malloc(). If this fails, an error code
** is left in Fts5Index.rc before returning.
*/
static void fts5TokendataIterSortMap(Fts5Index *p, Fts5TokenDataIter *pT){
  Fts5TokenDataMap *aTmp = 0;
  int nByte = pT->nMap * sizeof(Fts5TokenDataMap);

  aTmp = (Fts5TokenDataMap*)sqlite3Fts5MallocZero(&p->rc, nByte);
  if( aTmp ){
    Fts5TokenDataMap *a1 = pT->aMap;
    Fts5TokenDataMap *a2 = aTmp;
    i64 nHalf;

    for(nHalf=1; nHalf<pT->nMap; nHalf=nHalf*2){
      int i1;
      for(i1=0; i1<pT->nMap; i1+=(nHalf*2)){
        int n1 = MIN(nHalf, pT->nMap-i1);
        int n2 = MIN(nHalf, pT->nMap-i1-n1);
        fts5TokendataMerge(&a1[i1], n1, &a1[i1+n1], n2, &a2[i1]);
      }
      SWAPVAL(Fts5TokenDataMap*, a1, a2);
    }

    if( a1!=pT->aMap ){
      memcpy(pT->aMap, a1, pT->nMap*sizeof(Fts5TokenDataMap));
    }
    sqlite3_free(aTmp);

#ifdef SQLITE_DEBUG
    {
      int ii;
      for(ii=1; ii<pT->nMap; ii++){
        Fts5TokenDataMap *p1 = &pT->aMap[ii-1];
        Fts5TokenDataMap *p2 = &pT->aMap[ii];
        assert( p1->iRowid<p2->iRowid 
             || (p1->iRowid==p2->iRowid && p1->iPos<=p2->iPos)
        );
      }
    }
#endif
  }
}

/*
** Delete an Fts5TokenDataIter structure and its contents.
*/
static void fts5TokendataIterDelete(Fts5TokenDataIter *pSet){
  if( pSet ){
    int ii;
    for(ii=0; ii<pSet->nIter; ii++){
      fts5MultiIterFree(pSet->apIter[ii]);
    }
    fts5BufferFree(&pSet->terms);
    sqlite3_free(pSet->aPoslistReader);
    sqlite3_free(pSet->aMap);
    sqlite3_free(pSet);
  }
}


/*
** fts5VisitEntries() context object used by fts5SetupPrefixIterTokendata()
** to pass data to prefixIterSetupTokendataCb().
*/
typedef struct TokendataSetupCtx TokendataSetupCtx;
struct TokendataSetupCtx {
  Fts5TokenDataIter *pT;          /* Object being populated with mappings */
  int iTermOff;                   /* Offset of current term in terms.p[] */
  int nTermByte;                  /* Size of current term in bytes */
};

/*
** fts5VisitEntries() callback used by fts5SetupPrefixIterTokendata(). This
** callback adds an entry to the Fts5TokenDataIter.aMap[] array for each
** position in the current position-list. It doesn't matter that some of
** these may be out of order - they will be sorted later.
*/
static void prefixIterSetupTokendataCb(
  Fts5Index *p, 
  void *pCtx, 
  Fts5Iter *p1, 
  const u8 *pNew,
  int nNew
){
  TokendataSetupCtx *pSetup = (TokendataSetupCtx*)pCtx;
  int iPosOff = 0;
  i64 iPos = 0;

  if( pNew ){
    pSetup->nTermByte = nNew-1;
    pSetup->iTermOff = pSetup->pT->terms.n;
    fts5BufferAppendBlob(&p->rc, &pSetup->pT->terms, nNew-1, pNew+1);
  }

  while( 0==sqlite3Fts5PoslistNext64(
     p1->base.pData, p1->base.nData, &iPosOff, &iPos
  ) ){
    fts5TokendataIterAppendMap(p, 
        pSetup->pT, pSetup->iTermOff, pSetup->nTermByte, p1->base.iRowid, iPos
    );
  }
}


/*
** Context object passed by fts5SetupPrefixIter() to fts5VisitEntries().
*/
typedef struct PrefixSetupCtx PrefixSetupCtx;
struct PrefixSetupCtx {
  void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*);
  void (*xAppend)(Fts5Index*, u64, Fts5Iter*, Fts5Buffer*);
  i64 iLastRowid;
  int nMerge;
  Fts5Buffer *aBuf;
  int nBuf;
  Fts5Buffer doclist;
  TokendataSetupCtx *pTokendata;
};

/*
** fts5VisitEntries() callback used by fts5SetupPrefixIter()
*/
static void prefixIterSetupCb(
  Fts5Index *p, 
  void *pCtx, 
  Fts5Iter *p1, 
  const u8 *pNew,
  int nNew
){
  PrefixSetupCtx *pSetup = (PrefixSetupCtx*)pCtx;
  const int nMerge = pSetup->nMerge;

  if( p1->base.nData>0 ){
    if( p1->base.iRowid<=pSetup->iLastRowid && pSetup->doclist.n>0 ){
      int i;
      for(i=0; p->rc==SQLITE_OK && pSetup->doclist.n; i++){
        int i1 = i*nMerge;
        int iStore;
        assert( i1+nMerge<=pSetup->nBuf );
        for(iStore=i1; iStore<i1+nMerge; iStore++){
          if( pSetup->aBuf[iStore].n==0 ){
            fts5BufferSwap(&pSetup->doclist, &pSetup->aBuf[iStore]);
            fts5BufferZero(&pSetup->doclist);
            break;
          }
        }
        if( iStore==i1+nMerge ){
          pSetup->xMerge(p, &pSetup->doclist, nMerge, &pSetup->aBuf[i1]);
          for(iStore=i1; iStore<i1+nMerge; iStore++){
            fts5BufferZero(&pSetup->aBuf[iStore]);
          }
        }
      }
      pSetup->iLastRowid = 0;
    }

    pSetup->xAppend(
        p, (u64)p1->base.iRowid-(u64)pSetup->iLastRowid, p1, &pSetup->doclist
    );
    pSetup->iLastRowid = p1->base.iRowid;
  }

  if( pSetup->pTokendata ){
    prefixIterSetupTokendataCb(p, (void*)pSetup->pTokendata, p1, pNew, nNew);
  }
}

static void fts5SetupPrefixIter(
  Fts5Index *p,                   /* Index to read from */
  int bDesc,                      /* True for "ORDER BY rowid DESC" */
  int iIdx,                       /* Index to scan for data */
  u8 *pToken,                     /* Buffer containing prefix to match */
  int nToken,                     /* Size of buffer pToken in bytes */
  Fts5Colset *pColset,            /* Restrict matches to these columns */
  Fts5Iter **ppIter               /* OUT: New iterator */
){
  Fts5Structure *pStruct;
  PrefixSetupCtx s;
  TokendataSetupCtx s2;
  Fts5Buffer *aBuf;
  int nBuf = 32;
  int nMerge = 1;

  void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*);

  memset(&s, 0, sizeof(s));
  memset(&s2, 0, sizeof(s2));

  s.nMerge = 1;
  s.iLastRowid = 0;
  s.nBuf = 32;
  if( iIdx==0 
   && p->pConfig->eDetail==FTS5_DETAIL_FULL 
   && p->pConfig->bPrefixInsttoken 
  ){
    s.pTokendata = &s2;
    s2.pT = (Fts5TokenDataIter*)fts5IdxMalloc(p, sizeof(*s2.pT));
  }

  void (*xAppend)(Fts5Index*, u64, Fts5Iter*, Fts5Buffer*);
  if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
    xMerge = fts5MergeRowidLists;
    xAppend = fts5AppendRowid;
    s.xMerge = fts5MergeRowidLists;
    s.xAppend = fts5AppendRowid;
  }else{
    nMerge = FTS5_MERGE_NLIST-1;
    nBuf = nMerge*8;   /* Sufficient to merge (16^8)==(2^32) lists */
    xMerge = fts5MergePrefixLists;
    xAppend = fts5AppendPoslist;
    s.nMerge = FTS5_MERGE_NLIST-1;
    s.nBuf = s.nMerge*8;   /* Sufficient to merge (16^8)==(2^32) lists */
    s.xMerge = fts5MergePrefixLists;
    s.xAppend = fts5AppendPoslist;
  }

  aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf);
  s.aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*s.nBuf);
  pStruct = fts5StructureRead(p);
  assert( p->rc!=SQLITE_OK || (aBuf && pStruct) );
  assert( p->rc!=SQLITE_OK || (s.aBuf && pStruct) );

  if( p->rc==SQLITE_OK ){
    const int flags = FTS5INDEX_QUERY_SCAN 
    void *pCtx = (void*)&s;
                    | FTS5INDEX_QUERY_SKIPEMPTY 
                    | FTS5INDEX_QUERY_NOOUTPUT;
    int i;
    i64 iLastRowid = 0;
    Fts5Iter *p1 = 0;     /* Iterator used to gather data from index */
    Fts5Data *pData;
    Fts5Buffer doclist;
    int bNewTerm = 1;

    memset(&doclist, 0, sizeof(doclist));

    /* If iIdx is non-zero, then it is the number of a prefix-index for
    ** prefixes 1 character longer than the prefix being queried for. That
    ** index contains all the doclists required, except for the one
    ** corresponding to the prefix itself. That one is extracted from the
    ** main term index here.  */
    if( iIdx!=0 ){
      int dummy = 0;
      const int f2 = FTS5INDEX_QUERY_SKIPEMPTY|FTS5INDEX_QUERY_NOOUTPUT;
      pToken[0] = FTS5_MAIN_PREFIX;
      fts5MultiIterNew(p, pStruct, f2, pColset, pToken, nToken, -1, 0, &p1);
      fts5VisitEntries(p, pColset, pToken, nToken, 0, prefixIterSetupCb, pCtx);
      fts5IterSetOutputCb(&p->rc, p1);
      for(;
        fts5MultiIterEof(p, p1)==0;
        fts5MultiIterNext2(p, p1, &dummy)
      ){
        Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
        p1->xSetOutputs(p1, pSeg);
        if( p1->base.nData ){
          xAppend(p, (u64)p1->base.iRowid-(u64)iLastRowid, p1, &doclist);
          iLastRowid = p1->base.iRowid;
        }
      }
    }

      fts5MultiIterFree(p1);
    }

    pToken[0] = FTS5_MAIN_PREFIX + iIdx;
    fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1);
    fts5VisitEntries(p, pColset, pToken, nToken, 1, prefixIterSetupCb, pCtx);
    fts5IterSetOutputCb(&p->rc, p1);

    for( /* no-op */ ;
        fts5MultiIterEof(p, p1)==0;
        fts5MultiIterNext2(p, p1, &bNewTerm)
    ){
      Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
      int nTerm = pSeg->term.n;
      const u8 *pTerm = pSeg->term.p;
      p1->xSetOutputs(p1, pSeg);

      assert_nc( memcmp(pToken, pTerm, MIN(nToken, nTerm))<=0 );
      if( bNewTerm ){
        if( nTerm<nToken || memcmp(pToken, pTerm, nToken) ) break;
      }

      if( p1->base.nData==0 ) continue;
      if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){
        for(i=0; p->rc==SQLITE_OK && doclist.n; i++){
          int i1 = i*nMerge;
          int iStore;
          assert( i1+nMerge<=nBuf );
          for(iStore=i1; iStore<i1+nMerge; iStore++){
            if( aBuf[iStore].n==0 ){
              fts5BufferSwap(&doclist, &aBuf[iStore]);
              fts5BufferZero(&doclist);
              break;
            }
          }
          if( iStore==i1+nMerge ){
            xMerge(p, &doclist, nMerge, &aBuf[i1]);
            for(iStore=i1; iStore<i1+nMerge; iStore++){
              fts5BufferZero(&aBuf[iStore]);
            }
          }
        }
        iLastRowid = 0;
      }

      xAppend(p, (u64)p1->base.iRowid-(u64)iLastRowid, p1, &doclist);
      iLastRowid = p1->base.iRowid;
    }

    assert( (nBuf%nMerge)==0 );
    for(i=0; i<nBuf; i+=nMerge){
    assert( (s.nBuf%s.nMerge)==0 );
    for(i=0; i<s.nBuf; i+=s.nMerge){
      int iFree;
      if( p->rc==SQLITE_OK ){
        xMerge(p, &doclist, nMerge, &aBuf[i]);
        s.xMerge(p, &s.doclist, s.nMerge, &s.aBuf[i]);
      }
      for(iFree=i; iFree<i+nMerge; iFree++){
        fts5BufferFree(&aBuf[iFree]);
      for(iFree=i; iFree<i+s.nMerge; iFree++){
        fts5BufferFree(&s.aBuf[iFree]);
      }
    }
    fts5MultiIterFree(p1);

    pData = fts5IdxMalloc(p, sizeof(*pData)+doclist.n+FTS5_DATA_ZERO_PADDING);
    pData = fts5IdxMalloc(p, sizeof(*pData)+s.doclist.n+FTS5_DATA_ZERO_PADDING);
    if( pData ){
      pData->p = (u8*)&pData[1];
      pData->nn = pData->szLeaf = doclist.n;
      if( doclist.n ) memcpy(pData->p, doclist.p, doclist.n);
      pData->nn = pData->szLeaf = s.doclist.n;
      if( s.doclist.n ) memcpy(pData->p, s.doclist.p, s.doclist.n);
      fts5MultiIterNew2(p, pData, bDesc, ppIter);
    }
    fts5BufferFree(&doclist);
  }


    if( p->rc==SQLITE_OK && s.pTokendata ){
      fts5TokendataIterSortMap(p, s2.pT);
      (*ppIter)->pTokenDataIter = s2.pT;
      s2.pT = 0;
    }
  }

  fts5TokendataIterDelete(s2.pT);
  fts5BufferFree(&s.doclist);
  fts5StructureRelease(pStruct);
  sqlite3_free(aBuf);
  sqlite3_free(s.aBuf);
}


/*
** Indicate that all subsequent calls to sqlite3Fts5IndexWrite() pertain
** to the document with rowid iRowid.
*/
6589
6590
6591
6592
6593
6594
6595
6596
6597
6598
6599
6600
6601
6602
6603
6604
6605
6606
6607
6608
6609
6610
6611
6612
6613
6614
6615
6616
6617
6618
6619
6620
6621
6622
6623
6624
6625
6626
6627
6628
6629
6630
6631
6632
6633
6634
6918
6919
6920
6921
6922
6923
6924
































6925
6926
6927
6928
6929
6930
6931







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







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

/*
** Usually, a tokendata=1 iterator (struct Fts5TokenDataIter) accumulates an
** array of these for each row it visits. Or, for an iterator used by an
** "ORDER BY rank" query, it accumulates an array of these for the entire
** query.
**
** Each instance in the array indicates the iterator (and therefore term)
** associated with position iPos of rowid iRowid. This is used by the
** xInstToken() API.
*/
struct Fts5TokenDataMap {
  i64 iRowid;                     /* Row this token is located in */
  i64 iPos;                       /* Position of token */
  int iIter;                      /* Iterator token was read from */
};

/*
** An object used to supplement Fts5Iter for tokendata=1 iterators.
*/
struct Fts5TokenDataIter {
  int nIter;
  int nIterAlloc;

  int nMap;
  int nMapAlloc;
  Fts5TokenDataMap *aMap;

  Fts5PoslistReader *aPoslistReader;
  int *aPoslistToIter;
  Fts5Iter *apIter[1];
};

/*
** This function appends iterator pAppend to Fts5TokenDataIter pIn and 
** returns the result.
*/
static Fts5TokenDataIter *fts5AppendTokendataIter(
  Fts5Index *p,                   /* Index object (for error code) */
  Fts5TokenDataIter *pIn,         /* Current Fts5TokenDataIter struct */
6657
6658
6659
6660
6661
6662
6663
6664
6665
6666
6667
6668
6669
6670
6671
6672
6673
6674
6675
6676
6677
6678
6679
6680
6681
6682
6683
6684
6685
6686
6687
6688
6689
6690
6691
6692
6693
6694
6695
6696
6697
6698
6699
6700
6701
6702
6703
6704
6705
6706
6707
6708
6709
6710
6711
6712
6713
6714
6715
6716
6717
6718
6954
6955
6956
6957
6958
6959
6960
















































6961
6962
6963
6964
6965
6966
6967







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







    pRet->apIter[pRet->nIter++] = pAppend;
  }
  assert( pRet==0 || pRet->nIter<=pRet->nIterAlloc );

  return pRet;
}

/*
** Delete an Fts5TokenDataIter structure and its contents.
*/
static void fts5TokendataIterDelete(Fts5TokenDataIter *pSet){
  if( pSet ){
    int ii;
    for(ii=0; ii<pSet->nIter; ii++){
      fts5MultiIterFree(pSet->apIter[ii]);
    }
    sqlite3_free(pSet->aPoslistReader);
    sqlite3_free(pSet->aMap);
    sqlite3_free(pSet);
  }
}

/*
** Append a mapping to the token-map belonging to object pT.
*/
static void fts5TokendataIterAppendMap(
  Fts5Index *p, 
  Fts5TokenDataIter *pT, 
  int iIter,
  i64 iRowid, 
  i64 iPos
){
  if( p->rc==SQLITE_OK ){
    if( pT->nMap==pT->nMapAlloc ){
      int nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64;
      int nByte = nNew * sizeof(Fts5TokenDataMap);
      Fts5TokenDataMap *aNew;

      aNew = (Fts5TokenDataMap*)sqlite3_realloc(pT->aMap, nByte);
      if( aNew==0 ){
        p->rc = SQLITE_NOMEM;
        return;
      }

      pT->aMap = aNew;
      pT->nMapAlloc = nNew;
    }

    pT->aMap[pT->nMap].iRowid = iRowid;
    pT->aMap[pT->nMap].iPos = iPos;
    pT->aMap[pT->nMap].iIter = iIter;
    pT->nMap++;
  }
}

/*
** The iterator passed as the only argument must be a tokendata=1 iterator
** (pIter->pTokenDataIter!=0). This function sets the iterator output
** variables (pIter->base.*) according to the contents of the current
** row.
*/
static void fts5IterSetOutputsTokendata(Fts5Iter *pIter){
6745
6746
6747
6748
6749
6750
6751
6752

6753
6754
6755
6756
6757
6758
6759
6994
6995
6996
6997
6998
6999
7000

7001
7002
7003
7004
7005
7006
7007
7008







-
+







    pIter->base.bEof = 1;
  }else{
    int eDetail = pIter->pIndex->pConfig->eDetail;
    pIter->base.bEof = 0;
    pIter->base.iRowid = iRowid;

    if( nHit==1 && eDetail==FTS5_DETAIL_FULL ){
      fts5TokendataIterAppendMap(pIter->pIndex, pT, iMin, iRowid, -1);
      fts5TokendataIterAppendMap(pIter->pIndex, pT, iMin, 0, iRowid, -1);
    }else
    if( nHit>1 && eDetail!=FTS5_DETAIL_NONE ){
      int nReader = 0;
      int nByte = 0;
      i64 iPrev = 0;

      /* Allocate array of iterators if they are not already allocated. */
6998
6999
7000
7001
7002
7003
7004

7005
7006
7007
7008
7009
7010
7011
7012
7013
7014
7015
7016
7017
7018
7019
7020
7021
7022
7023
7024
7025
7026
7247
7248
7249
7250
7251
7252
7253
7254
7255
7256
7257
7258
7259
7260
7261
7262
7263
7264
7265
7266
7267
7268

7269
7270
7271
7272
7273
7274
7275







+














-







    }
  }
    
  if( p->rc==SQLITE_OK ){
    pRet = fts5MultiIterAlloc(p, 0);
  }
  if( pRet ){
    pRet->nSeg = 0;
    pRet->pTokenDataIter = pSet;
    if( pSet ){
      fts5IterSetOutputsTokendata(pRet);
    }else{
      pRet->base.bEof = 1;
    }
  }else{
    fts5TokendataIterDelete(pSet);
  }

  fts5StructureRelease(pStruct);
  fts5BufferFree(&bSeek);
  return pRet;
}


/*
** Open a new iterator to iterate though all rowid that match the 
** specified token or token prefix.
*/
int sqlite3Fts5IndexQuery(
  Fts5Index *p,                   /* FTS index to query */
7038
7039
7040
7041
7042
7043
7044





7045
7046
7047
7048
7049
7050
7051
7287
7288
7289
7290
7291
7292
7293
7294
7295
7296
7297
7298
7299
7300
7301
7302
7303
7304
7305







+
+
+
+
+








  if( sqlite3Fts5BufferSize(&p->rc, &buf, nToken+1)==0 ){
    int iIdx = 0;                 /* Index to search */
    int iPrefixIdx = 0;           /* +1 prefix index */
    int bTokendata = pConfig->bTokendata;
    if( nToken>0 ) memcpy(&buf.p[1], pToken, nToken);

    /* The NOTOKENDATA flag is set when each token in a tokendata=1 table
    ** should be treated individually, instead of merging all those with
    ** a common prefix into a single entry. This is used, for example, by
    ** queries performed as part of an integrity-check, or by the fts5vocab
    ** module.  */
    if( flags & (FTS5INDEX_QUERY_NOTOKENDATA|FTS5INDEX_QUERY_SCAN) ){
      bTokendata = 0;
    }

    /* Figure out which index to search and set iIdx accordingly. If this
    ** is a prefix query for which there is no prefix index, set iIdx to
    ** greater than pConfig->nPrefix to indicate that the query will be
7068
7069
7070
7071
7072
7073
7074
7075

7076
7077
7078
7079
7080
7081
7082
7083
7084
7085
7086
7087
7088

7089
7090
7091
7092
7093
7094
7095
7322
7323
7324
7325
7326
7327
7328

7329
7330
7331
7332
7333
7334
7335
7336
7337
7338
7339
7340
7341

7342
7343
7344
7345
7346
7347
7348
7349







-
+












-
+







        int nIdxChar = pConfig->aPrefix[iIdx-1];
        if( nIdxChar==nChar ) break;
        if( nIdxChar==nChar+1 ) iPrefixIdx = iIdx;
      }
    }

    if( bTokendata && iIdx==0 ){
      buf.p[0] = '0';
      buf.p[0] = FTS5_MAIN_PREFIX;
      pRet = fts5SetupTokendataIter(p, buf.p, nToken+1, pColset);
    }else if( iIdx<=pConfig->nPrefix ){
      /* Straight index lookup */
      Fts5Structure *pStruct = fts5StructureRead(p);
      buf.p[0] = (u8)(FTS5_MAIN_PREFIX + iIdx);
      if( pStruct ){
        fts5MultiIterNew(p, pStruct, flags | FTS5INDEX_QUERY_SKIPEMPTY, 
            pColset, buf.p, nToken+1, -1, 0, &pRet
        );
        fts5StructureRelease(pStruct);
      }
    }else{
      /* Scan multiple terms in the main index */
      /* Scan multiple terms in the main index for a prefix query. */
      int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0;
      fts5SetupPrefixIter(p, bDesc, iPrefixIdx, buf.p, nToken+1, pColset,&pRet);
      if( pRet==0 ){
        assert( p->rc!=SQLITE_OK );
      }else{
        assert( pRet->pColset==0 );
        fts5IterSetOutputCb(&p->rc, pRet);
7117
7118
7119
7120
7121
7122
7123

7124

7125
7126
7127
7128
7129
7130
7131
7371
7372
7373
7374
7375
7376
7377
7378

7379
7380
7381
7382
7383
7384
7385
7386







+
-
+







*/
/*
** Move to the next matching rowid. 
*/
int sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){
  Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
  assert( pIter->pIndex->rc==SQLITE_OK );
  if( pIter->nSeg==0 ){
  if( pIter->pTokenDataIter ){
    assert( pIter->pTokenDataIter );
    fts5TokendataIterNext(pIter, 0, 0);
  }else{
    fts5MultiIterNext(pIter->pIndex, pIter, 0, 0);
  }
  return fts5IndexReturn(pIter->pIndex);
}

7154
7155
7156
7157
7158
7159
7160

7161

7162
7163
7164
7165
7166
7167
7168
7169
7170
7171
7172
7173
7174
7175
7176
7177
7178











































7179
7180
7181
7182
7183
7184


7185
7186
7187

7188
7189
7190
7191
7192
7193
7194
7195
7196
7197

7198
7199

7200










7201
7202
7203
7204
7205
7206
7207
7409
7410
7411
7412
7413
7414
7415
7416

7417
7418
7419
7420
7421
7422
7423
7424
7425
7426
7427
7428
7429
7430
7431
7432
7433
7434
7435
7436
7437
7438
7439
7440
7441
7442
7443
7444
7445
7446
7447
7448
7449
7450
7451
7452
7453
7454
7455
7456
7457
7458
7459
7460
7461
7462
7463
7464
7465
7466
7467
7468
7469
7470
7471
7472
7473
7474
7475
7476
7477
7478
7479
7480
7481
7482
7483
7484
7485
7486
7487
7488
7489
7490
7491
7492
7493
7494
7495
7496

7497

7498
7499

7500
7501
7502
7503
7504
7505
7506
7507
7508
7509
7510
7511
7512
7513
7514
7515
7516
7517
7518







+
-
+

















+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+






+
+



+







-

-
+

-
+

+
+
+
+
+
+
+
+
+
+







/*
** Move to the next matching rowid that occurs at or after iMatch. The
** definition of "at or after" depends on whether this iterator iterates
** in ascending or descending rowid order.
*/
int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){
  Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
  if( pIter->nSeg==0 ){
  if( pIter->pTokenDataIter ){
    assert( pIter->pTokenDataIter );
    fts5TokendataIterNext(pIter, 1, iMatch);
  }else{
    fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch);
  }
  return fts5IndexReturn(pIter->pIndex);
}

/*
** Return the current term.
*/
const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIndexIter, int *pn){
  int n;
  const char *z = (const char*)fts5MultiIterTerm((Fts5Iter*)pIndexIter, &n);
  assert_nc( z || n<=1 );
  *pn = n-1;
  return (z ? &z[1] : 0);
}

/*
** pIter is a prefix query. This function populates pIter->pTokenDataIter
** with an Fts5TokenDataIter object containing mappings for all rows
** matched by the query.
*/
static int fts5SetupPrefixIterTokendata(
  Fts5Iter *pIter,
  const char *pToken,             /* Token prefix to search for */
  int nToken                      /* Size of pToken in bytes */
){
  Fts5Index *p = pIter->pIndex;
  Fts5Buffer token = {0, 0, 0};
  TokendataSetupCtx ctx;

  memset(&ctx, 0, sizeof(ctx));

  fts5BufferGrow(&p->rc, &token, nToken+1);
  ctx.pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, sizeof(*ctx.pT));

  if( p->rc==SQLITE_OK ){

    /* Fill in the token prefix to search for */
    token.p[0] = FTS5_MAIN_PREFIX;
    memcpy(&token.p[1], pToken, nToken);
    token.n = nToken+1;

    fts5VisitEntries(
        p, 0, token.p, token.n, 1, prefixIterSetupTokendataCb, (void*)&ctx
    );

    fts5TokendataIterSortMap(p, ctx.pT);
  }

  if( p->rc==SQLITE_OK ){
    pIter->pTokenDataIter = ctx.pT;
  }else{
    fts5TokendataIterDelete(ctx.pT);
  }
  fts5BufferFree(&token);

  return fts5IndexReturn(p);
}

/*
** This is used by xInstToken() to access the token at offset iOff, column
** iCol of row iRowid. The token is returned via output variables *ppOut
** and *pnOut. The iterator passed as the first argument must be a tokendata=1
** iterator (pIter->pTokenDataIter!=0).
**
** pToken/nToken:
*/
int sqlite3Fts5IterToken(
  Fts5IndexIter *pIndexIter, 
  const char *pToken, int nToken,
  i64 iRowid,
  int iCol, 
  int iOff, 
  const char **ppOut, int *pnOut
){
  Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
  Fts5TokenDataIter *pT = pIter->pTokenDataIter;
  Fts5TokenDataMap *aMap = pT->aMap;
  i64 iPos = (((i64)iCol)<<32) + iOff;

  Fts5TokenDataMap *aMap = 0;
  int i1 = 0;
  int i2 = pT->nMap;
  int i2 = 0;
  int iTest = 0;

  assert( pT || (pToken && pIter->nSeg>0) );
  if( pT==0 ){
    int rc = fts5SetupPrefixIterTokendata(pIter, pToken, nToken);
    if( rc!=SQLITE_OK ) return rc;
    pT = pIter->pTokenDataIter;
  }

  i2 = pT->nMap;
  aMap = pT->aMap;

  while( i2>i1 ){
    iTest = (i1 + i2) / 2;

    if( aMap[iTest].iRowid<iRowid ){
      i1 = iTest+1;
    }else if( aMap[iTest].iRowid>iRowid ){
7217
7218
7219
7220
7221
7222
7223

7224
7225
7226








7227
7228
7229
7230
7231
7232
7233
7234
7235
7236
7237
7238



7239
7240
7241
7242
7243
7244
7245
7246
7247
7248
7249
7250
7251
7252
7253
7254
7255
7256
7257
7258

7259
7260
7261
7262
7263
7264
7265
7266
7267
7268




















7269
7270
7271
7272
7273
7274
7275
7528
7529
7530
7531
7532
7533
7534
7535



7536
7537
7538
7539
7540
7541
7542
7543
7544
7545
7546
7547
7548
7549
7550
7551
7552
7553
7554

7555
7556
7557
7558
7559
7560
7561
7562
7563
7564
7565
7566
7567
7568
7569
7570
7571
7572
7573
7574
7575
7576

7577
7578
7579








7580
7581
7582
7583
7584
7585
7586
7587
7588
7589
7590
7591
7592
7593
7594
7595
7596
7597
7598
7599
7600
7601
7602
7603
7604
7605
7606







+
-
-
-
+
+
+
+
+
+
+
+











-
+
+
+



















-
+


-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







      }else{
        break;
      }
    }
  }

  if( i2>i1 ){
    if( pIter->nSeg==0 ){
    Fts5Iter *pMap = pT->apIter[aMap[iTest].iIter];
    *ppOut = (const char*)pMap->aSeg[0].term.p+1;
    *pnOut = pMap->aSeg[0].term.n-1;
      Fts5Iter *pMap = pT->apIter[aMap[iTest].iIter];
      *ppOut = (const char*)pMap->aSeg[0].term.p+1;
      *pnOut = pMap->aSeg[0].term.n-1;
    }else{
      Fts5TokenDataMap *p = &aMap[iTest];
      *ppOut = (const char*)&pT->terms.p[p->iIter];
      *pnOut = aMap[iTest].nByte;
    }
  }

  return SQLITE_OK;
}

/*
** Clear any existing entries from the token-map associated with the
** iterator passed as the only argument. 
*/
void sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter *pIndexIter){
  Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
  if( pIter && pIter->pTokenDataIter ){
  if( pIter && pIter->pTokenDataIter 
   && (pIter->nSeg==0 || pIter->pIndex->pConfig->eDetail!=FTS5_DETAIL_FULL)
  ){
    pIter->pTokenDataIter->nMap = 0;
  }
}

/*
** Set a token-mapping for the iterator passed as the first argument. This
** is used in detail=column or detail=none mode when a token is requested
** using the xInstToken() API. In this case the caller tokenizers the
** current row and configures the token-mapping via multiple calls to this
** function.
*/
int sqlite3Fts5IndexIterWriteTokendata(
  Fts5IndexIter *pIndexIter, 
  const char *pToken, int nToken, 
  i64 iRowid, int iCol, int iOff
){
  Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
  Fts5TokenDataIter *pT = pIter->pTokenDataIter;
  Fts5Index *p = pIter->pIndex;
  int ii;
  i64 iPos = (((i64)iCol)<<32) + iOff;

  assert( p->pConfig->eDetail!=FTS5_DETAIL_FULL );
  assert( pIter->pTokenDataIter );

  for(ii=0; ii<pT->nIter; ii++){
    Fts5Buffer *pTerm = &pT->apIter[ii]->aSeg[0].term;
    if( nToken==pTerm->n-1 && memcmp(pToken, pTerm->p+1, nToken)==0 ) break;
  }
  if( ii<pT->nIter ){
    fts5TokendataIterAppendMap(p, pT, ii, iRowid, (((i64)iCol)<<32) + iOff);
  assert( pIter->pTokenDataIter || pIter->nSeg>0 );
  if( pIter->nSeg>0 ){
    /* This is a prefix term iterator. */
    if( pT==0 ){
      pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, sizeof(*pT));
      pIter->pTokenDataIter = pT;
    }
    if( pT ){
      fts5TokendataIterAppendMap(p, pT, pT->terms.n, nToken, iRowid, iPos);
      fts5BufferAppendBlob(&p->rc, &pT->terms, nToken, (const u8*)pToken);
    }
  }else{
    int ii;
    for(ii=0; ii<pT->nIter; ii++){
      Fts5Buffer *pTerm = &pT->apIter[ii]->aSeg[0].term;
      if( nToken==pTerm->n-1 && memcmp(pToken, pTerm->p+1, nToken)==0 ) break;
    }
    if( ii<pT->nIter ){
      fts5TokendataIterAppendMap(p, pT, ii, 0, iRowid, iPos);
    }
  }
  return fts5IndexReturn(p);
}

/*
** Close an iterator opened by an earlier call to sqlite3Fts5IndexQuery().
*/
Changes to ext/fts5/fts5_main.c.
89
90
91
92
93
94
95

96
97
98
99
100
101
102
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103







+







/*
** Size of header on fts5_locale() values. And macro to access a buffer
** containing a copy of the header from an Fts5Config pointer.
*/
#define FTS5_LOCALE_HDR_SIZE ((int)sizeof( ((Fts5Global*)0)->aLocaleHdr ))
#define FTS5_LOCALE_HDR(pConfig) ((const u8*)(pConfig->pGlobal->aLocaleHdr))

#define FTS5_INSTTOKEN_SUBTYPE 73

/*
** Each auxiliary function registered with the FTS5 module is represented
** by an object of the following type. All such objects are stored as part
** of the Fts5Global.pAux list.
*/
struct Fts5Auxiliary {
628
629
630
631
632
633
634

635
636
637
638
639
640
641
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643







+







    if( p->op==SQLITE_INDEX_CONSTRAINT_MATCH
     || (p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol>=nCol)
    ){
      /* A MATCH operator or equivalent */
      if( p->usable==0 || iCol<0 ){
        /* As there exists an unusable MATCH constraint this is an 
        ** unusable plan. Return SQLITE_CONSTRAINT. */
        idxStr[iIdxStr] = 0;
        return SQLITE_CONSTRAINT;
      }else{
        if( iCol==nCol+1 ){
          if( bSeenRank ) continue;
          idxStr[iIdxStr++] = 'r';
          bSeenRank = 1;
        }else{
1413
1414
1415
1416
1417
1418
1419

1420
1421
1422
1423
1424
1425
1426
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429







+







  int bOrderByRank;               /* True if ORDER BY rank */
  sqlite3_value *pRank = 0;       /* rank MATCH ? expression (or NULL) */
  sqlite3_value *pRowidEq = 0;    /* rowid = ? expression (or NULL) */
  sqlite3_value *pRowidLe = 0;    /* rowid <= ? expression (or NULL) */
  sqlite3_value *pRowidGe = 0;    /* rowid >= ? expression (or NULL) */
  int iCol;                       /* Column on LHS of MATCH operator */
  char **pzErrmsg = pConfig->pzErrmsg;
  int bPrefixInsttoken = pConfig->bPrefixInsttoken;
  int i;
  int iIdxStr = 0;
  Fts5Expr *pExpr = 0;

  assert( pConfig->bLock==0 );
  if( pCsr->ePlan ){
    fts5FreeCursorComponents(pCsr);
1448
1449
1450
1451
1452
1453
1454



1455
1456
1457
1458
1459
1460
1461
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467







+
+
+







        char *zText = 0;
        int bFreeAndReset = 0;
        int bInternal = 0;

        rc = fts5ExtractExprText(pConfig, apVal[i], &zText, &bFreeAndReset);
        if( rc!=SQLITE_OK ) goto filter_out;
        if( zText==0 ) zText = "";
        if( sqlite3_value_subtype(apVal[i])==FTS5_INSTTOKEN_SUBTYPE ){
          pConfig->bPrefixInsttoken = 1;
        }

        iCol = 0;
        do{
          iCol = iCol*10 + (idxStr[iIdxStr]-'0');
          iIdxStr++;
        }while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' );

1588
1589
1590
1591
1592
1593
1594

1595
1596
1597
1598
1599
1600
1601
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608







+







      rc = fts5NextMethod(pCursor);
    }
  }

 filter_out:
  sqlite3Fts5ExprFree(pExpr);
  pConfig->pzErrmsg = pzErrmsg;
  pConfig->bPrefixInsttoken = bPrefixInsttoken;
  return rc;
}

/* 
** This is the xEof method of the virtual table. SQLite calls this 
** routine to find out if it has reached the end of a result set.
*/
3646
3647
3648
3649
3650
3651
3652













3653
3654
3655
3656
3657
3658
3659
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679







+
+
+
+
+
+
+
+
+
+
+
+
+







    (*pCsr++) = 0x00;
    if( zText ) memcpy(pCsr, zText, nText);
    assert( &pCsr[nText]==&pBlob[nBlob] );

    sqlite3_result_blob(pCtx, pBlob, nBlob, sqlite3_free);
  }
}

/*
** Implementation of fts5_insttoken() function.
*/
static void fts5InsttokenFunc(
  sqlite3_context *pCtx,          /* Function call context */
  int nArg,                       /* Number of args */
  sqlite3_value **apArg           /* Function arguments */
){
  assert( nArg==1 );
  sqlite3_result_value(pCtx, apArg[0]);
  sqlite3_result_subtype(pCtx, FTS5_INSTTOKEN_SUBTYPE);
}

/*
** Return true if zName is the extension on one of the shadow tables used
** by this module.
*/
static int fts5ShadowName(const char *zName){
  static const char *azName[] = {
3776
3777
3778
3779
3780
3781
3782
3783

3784
3785







3786
3787
3788
3789
3790
3791
3792
3796
3797
3798
3799
3800
3801
3802

3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819







-
+


+
+
+
+
+
+
+







          SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS,
          p, fts5SourceIdFunc, 0, 0
      );
    }
    if( rc==SQLITE_OK ){
      rc = sqlite3_create_function(
          db, "fts5_locale", 2, 
          SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE,
          SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE|SQLITE_SUBTYPE,
          p, fts5LocaleFunc, 0, 0
      );
    }
    if( rc==SQLITE_OK ){
      rc = sqlite3_create_function(
          db, "fts5_insttoken", 1, 
          SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE,
          p, fts5InsttokenFunc, 0, 0
      );
    }
  }

  /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
  ** fts5_test_mi.c is compiled and linked into the executable. And call
  ** its entry point to enable the matchinfo() demo.  */
#ifdef SQLITE_FTS5_ENABLE_TEST_MI
Changes to ext/fts5/fts5_tcl.c.
726
727
728
729
730
731
732

733
734


735
736
737
738
739
740
741
726
727
728
729
730
731
732
733


734
735
736
737
738
739
740
741
742







+
-
-
+
+







*/
static int SQLITE_TCLAPI f5tTokenize(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  char *pCopy = 0;
  char *zText;
  Tcl_Size nText;
  char *zText = 0;
  Tcl_Size nText = 0;
  sqlite3 *db = 0;
  fts5_api *pApi = 0;
  Fts5Tokenizer *pTok = 0;
  fts5_tokenizer tokenizer;
  Tcl_Obj *pRet = 0;
  void *pUserdata;
  int rc;
773
774
775
776
777
778
779











780
781
782
783
784
785

786
787

788
789

790
791
792
793
794
795
796
797
798
799
800
801
802
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796

797
798

799
800
801
802
803
804
805
806
807

808
809
810
811
812
813
814







+
+
+
+
+
+
+
+
+
+
+





-
+

-
+


+





-







  }

  rc = tokenizer.xCreate(pUserdata, &azArg[1], (int)(nArg-1), &pTok);
  if( rc!=SQLITE_OK ){
    Tcl_AppendResult(interp, "error in tokenizer.xCreate()", (char*)0);
    return TCL_ERROR;
  }

  if( nText>0 ){
    pCopy = sqlite3_malloc(nText);
    if( pCopy==0 ){
      tokenizer.xDelete(pTok);
      Tcl_AppendResult(interp, "error in sqlite3_malloc()", (char*)0);
      return TCL_ERROR;
    }else{
      memcpy(pCopy, zText, nText);
    }
  }

  pRet = Tcl_NewObj();
  Tcl_IncrRefCount(pRet);
  ctx.bSubst = (objc==5);
  ctx.pRet = pRet;
  ctx.zInput = zText;
  ctx.zInput = pCopy;
  rc = tokenizer.xTokenize(
      pTok, (void*)&ctx, FTS5_TOKENIZE_DOCUMENT, zText,(int)nText, xTokenizeCb2
      pTok, (void*)&ctx, FTS5_TOKENIZE_DOCUMENT, pCopy,(int)nText, xTokenizeCb2
  );
  tokenizer.xDelete(pTok);
  sqlite3_free(pCopy);
  if( rc!=SQLITE_OK ){
    Tcl_AppendResult(interp, "error in tokenizer.xTokenize()", (char*)0);
    Tcl_DecrRefCount(pRet);
    return TCL_ERROR;
  }


  Tcl_Free((void*)azArg);
  Tcl_SetObjResult(interp, pRet);
  Tcl_DecrRefCount(pRet);
  return TCL_OK;
}

Changes to ext/fts5/fts5_tokenize.c.
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
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







-
-
+
+








+

-




















+
+
+
+

-







){
  TrigramTokenizer *p = (TrigramTokenizer*)pTok;
  int rc = SQLITE_OK;
  char aBuf[32];
  char *zOut = aBuf;
  int ii;
  const unsigned char *zIn = (const unsigned char*)pText;
  const unsigned char *zEof = &zIn[nText];
  u32 iCode;
  const unsigned char *zEof = (zIn ? &zIn[nText] : 0);
  u32 iCode = 0;
  int aStart[3];                  /* Input offset of each character in aBuf[] */

  UNUSED_PARAM(unusedFlags);

  /* Populate aBuf[] with the characters for the first trigram. */
  for(ii=0; ii<3; ii++){
    do {
      aStart[ii] = zIn - (const unsigned char*)pText;
      if( zIn>=zEof ) return SQLITE_OK;
      READ_UTF8(zIn, zEof, iCode);
      if( iCode==0 ) return SQLITE_OK;
      if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
    }while( iCode==0 );
    WRITE_UTF8(zOut, iCode);
  }

  /* At the start of each iteration of this loop:
  **
  **  aBuf:      Contains 3 characters. The 3 characters of the next trigram.
  **  zOut:      Points to the byte following the last character in aBuf.
  **  aStart[3]: Contains the byte offset in the input text corresponding
  **             to the start of each of the three characters in the buffer.
  */
  assert( zIn<=zEof );
  while( 1 ){
    int iNext;                    /* Start of character following current tri */
    const char *z1;

    /* Read characters from the input up until the first non-diacritic */
    do {
      iNext = zIn - (const unsigned char*)pText;
      if( zIn>=zEof ){
        iCode = 0;
        break;
      }
      READ_UTF8(zIn, zEof, iCode);
      if( iCode==0 ) break;
      if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
    }while( iCode==0 );

    /* Pass the current trigram back to fts5 */
    rc = xToken(pCtx, 0, aBuf, zOut-aBuf, aStart[0], iNext);
    if( iCode==0 || rc!=SQLITE_OK ) break;

Changes to ext/fts5/test/fts5origintext.test.
18
19
20
21
22
23
24





25
26
27

28
29
30

31
32
33
34

35
36
37
38

39
40
41
42
43
44
45

46
47
48
49
50
51
52

53
54
55
56
57
58
59
18
19
20
21
22
23
24
25
26
27
28
29
30
31

32
33
34
35
36
37
38
39

40
41
42
43

44
45
46
47
48
49
50

51
52
53
54
55
56
57

58
59
60
61
62
63
64
65







+
+
+
+
+


-
+



+



-
+



-
+






-
+






-
+







# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
  finish_test
  return
}

foreach_detail_mode $testprefix {
foreach {tn insttoken} {
  1 0
  2 1
} {
reset_db

sqlite3_fts5_register_origintext db
do_execsql_test 1.0 {
do_execsql_test $tn.1.0 {
  CREATE VIRTUAL TABLE ft USING fts5(
      x, tokenize="origintext unicode61", detail=%DETAIL%
  );
  INSERT INTO ft(ft, rank) VALUES('insttoken', $insttoken);
  CREATE VIRTUAL TABLE vocab USING fts5vocab(ft, instance);
}

do_execsql_test 1.1 {
do_execsql_test $tn.1.1 {
  INSERT INTO ft VALUES('Hello world');
}

do_execsql_test 1.2 {
do_execsql_test $tn.1.2 {
  INSERT INTO ft(ft) VALUES('integrity-check');
}

proc b {x} { string map [list "\0" "."] $x }
db func b b

do_execsql_test 1.3 {
do_execsql_test $tn.1.3 {
  select b(term) from vocab;
} {
  hello.Hello
  world
}

do_execsql_test 1.4 {
do_execsql_test $tn.1.4 {
  SELECT rowid FROM ft('Hello');
} {1}

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

# Return a random integer between 0 and n-1.
84
85
86
87
88
89
90
91

92
93
94

95
96
97
98
99

100
101
102
103
104
105

106
107
108
109

110
111
112
113

114
115
116
117

118
119
120
121
122
123
124
125

126
127
128

129
130
131
132
133
134
135
136
137
138
139
140
141
142



143
144

145
146
147
148
149

150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165



166
167








168
169
170
171
172
173
174
175
176
177
178
179

180
181
182

183
184
185
186

187
188
189

190
191
192

193
194
195
196
197
198
199

200
201
202

203
204
205

206
207
208

209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224

225
226
227

228
229
230
231

232
233
234
235
236
237
238
239
240
241
242
243

























244
245
246
247
248
249

250
251
252
253
254
255
256
257
258
259
260
261
262
263

264
265
266

267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282

283
284
285
286

287
288

289
290

291
292

293
294
295

296
297
298
299

300
301
302
303

304
305
306

307
308
309

310
311
312
313
90
91
92
93
94
95
96

97
98
99
100
101
102
103
104
105

106
107
108
109
110
111

112
113
114
115

116
117
118
119

120
121
122
123

124
125
126
127
128
129
130
131

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



148
149
150
151

152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171



172
173
174
175

176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194

195
196
197
198
199
200
201
202

203
204
205

206
207
208

209
210
211
212
213
214
215

216
217
218

219
220
221

222
223
224

225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240

241
242
243
244
245
246
247
248

249
250
251
252
253
254
255
256
257
258
259
260

261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290

291
292
293
294
295
296
297
298
299
300
301
302
303
304

305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324

325
326
327
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







-
+



+




-
+





-
+



-
+



-
+



-
+







-
+



+











-
-
-
+
+
+

-
+





+













-
-
-
+
+
+

-
+
+
+
+
+
+
+
+











-
+



+



-
+


-
+


-
+






-
+


-
+


-
+


-
+















-
+



+



-
+











-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+





-
+













-
+



+















-
+



-
+

-
+

-
+

-
+


-
+



-
+



-
+


-
+



+




    lappend doc [term]
  }
  set doc
}
db func document document

sqlite3_fts5_register_origintext db
do_execsql_test 2.0 {
do_execsql_test $tn.2.0 {
  CREATE VIRTUAL TABLE ft USING fts5(
      x, tokenize="origintext unicode61", detail=%DETAIL%
  );
  INSERT INTO ft(ft, rank) VALUES('insttoken', $insttoken);
  INSERT INTO ft(ft, rank) VALUES('pgsz', 128);
  CREATE VIRTUAL TABLE vocab USING fts5vocab(ft, instance);
}

do_test 2.1 {
do_test $tn.2.1 {
  for {set ii 0} {$ii < 500} {incr ii} {
    execsql { INSERT INTO ft VALUES( document() ) }
  }
} {}

do_execsql_test 2.2 {
do_execsql_test $tn.2.2 {
  INSERT INTO ft(ft) VALUES('integrity-check');
}

do_execsql_test 2.3 {
do_execsql_test $tn.2.3 {
  INSERT INTO ft(ft, rank) VALUES('merge', 16);
}

do_execsql_test 2.4 {
do_execsql_test $tn.2.4 {
  INSERT INTO ft(ft) VALUES('integrity-check');
}

do_execsql_test 2.5 {
do_execsql_test $tn.2.5 {
  INSERT INTO ft(ft) VALUES('optimize');
}

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

sqlite3_fts5_register_origintext db
do_execsql_test 3.0 {
do_execsql_test $tn.3.0 {
  CREATE VIRTUAL TABLE ft USING fts5(
      x, tokenize="origintext unicode61", detail=%DETAIL%
  );
  INSERT INTO ft(ft, rank) VALUES('insttoken', $insttoken);
  CREATE VIRTUAL TABLE vocab USING fts5vocab(ft, instance);

  INSERT INTO ft(rowid, x) VALUES(1, 'hello');
  INSERT INTO ft(rowid, x) VALUES(2, 'Hello');
  INSERT INTO ft(rowid, x) VALUES(3, 'HELLO');
}

#proc b {x} { string map [list "\0" "."] $x }
#db func b b
#execsql_pp { SELECT b(term) FROM vocab }

do_execsql_test 3.1.1 { SELECT rowid FROM ft('hello') } 1
do_execsql_test 3.1.2 { SELECT rowid FROM ft('Hello') } 2
do_execsql_test 3.1.3 { SELECT rowid FROM ft('HELLO') } 3
do_execsql_test $tn.3.1.1 { SELECT rowid FROM ft('hello') } 1
do_execsql_test $tn.3.1.2 { SELECT rowid FROM ft('Hello') } 2
do_execsql_test $tn.3.1.3 { SELECT rowid FROM ft('HELLO') } 3

do_execsql_test 3.2 {
do_execsql_test $tn.3.2 {
  CREATE VIRTUAL TABLE ft2 USING fts5(x, 
      tokenize="origintext unicode61", 
      tokendata=1,
      detail=%DETAIL%
  );
  INSERT INTO ft2(ft2, rank) VALUES('insttoken', $insttoken);
  CREATE VIRTUAL TABLE vocab2 USING fts5vocab(ft2, instance);

  INSERT INTO ft2(rowid, x) VALUES(1, 'hello');
  INSERT INTO ft2(rowid, x) VALUES(2, 'Hello');
  INSERT INTO ft2(rowid, x) VALUES(3, 'HELLO');

  INSERT INTO ft2(rowid, x) VALUES(10, 'helloooo');
}

#proc b {x} { string map [list "\0" "."] $x }
#db func b b
#execsql_pp { SELECT b(term) FROM vocab }

do_execsql_test 3.3.1 { SELECT rowid FROM ft2('hello') } {1 2 3}
do_execsql_test 3.3.2 { SELECT rowid FROM ft2('Hello') } {1 2 3}
do_execsql_test 3.3.3 { SELECT rowid FROM ft2('HELLO') } {1 2 3}
do_execsql_test $tn.3.3.1 { SELECT rowid FROM ft2('hello') } {1 2 3}
do_execsql_test $tn.3.3.2 { SELECT rowid FROM ft2('Hello') } {1 2 3}
do_execsql_test $tn.3.3.3 { SELECT rowid FROM ft2('HELLO') } {1 2 3}

do_execsql_test 3.3.4 { SELECT rowid FROM ft2('hello*') } {1 2 3 10}
do_execsql_test $tn.3.3.4 { SELECT rowid FROM ft2('hello*') } {1 2 3 10}

do_execsql_test $tn.3.3.5.1 { SELECT rowid FROM ft2('HELLO') ORDER BY rowid DESC} {
  3 2 1
}
do_execsql_test $tn.3.3.5.2 { SELECT rowid FROM ft2('HELLO') ORDER BY +rowid DESC} {
  3 2 1
}

#-------------------------------------------------------------------------
#
reset_db
sqlite3_fts5_register_origintext db
proc querytoken {cmd iPhrase iToken} { 
  set txt [$cmd xQueryToken $iPhrase $iToken]
  string map [list "\0" "."] $txt
}
sqlite3_fts5_create_function db querytoken querytoken

do_execsql_test 4.0 {
do_execsql_test $tn.4.0 {
  CREATE VIRTUAL TABLE ft USING fts5(
      x, tokenize='origintext unicode61', tokendata=1, detail=%DETAIL%
  );
  INSERT INTO ft(ft, rank) VALUES('insttoken', $insttoken);
  INSERT INTO ft VALUES('one two three four');
}

do_execsql_test 4.1 {
do_execsql_test $tn.4.1 {
  SELECT rowid, querytoken(ft, 0, 0) FROM ft('TwO')
} {1 two.TwO}
do_execsql_test 4.2 {
do_execsql_test $tn.4.2 {
  SELECT rowid, querytoken(ft, 0, 0) FROM ft('one TWO ThreE')
} {1 one}
do_execsql_test 4.3 {
do_execsql_test $tn.4.3 {
  SELECT rowid, querytoken(ft, 1, 0) FROM ft('one TWO ThreE')
} {1 two.TWO}

if {"%DETAIL%"=="full"} {
  # Phrase queries are only supported for detail=full.
  #
  do_execsql_test 4.4 {
  do_execsql_test $tn.4.4 {
    SELECT rowid, querytoken(ft, 0, 2) FROM ft('"one TWO ThreE"')
  } {1 three.ThreE}
  do_catchsql_test 4.5 {
  do_catchsql_test $tn.4.5 {
    SELECT rowid, querytoken(ft, 0, 3) FROM ft('"one TWO ThreE"')
  } {1 SQLITE_RANGE}
  do_catchsql_test 4.6 {
  do_catchsql_test $tn.4.6 {
    SELECT rowid, querytoken(ft, 1, 0) FROM ft('"one TWO ThreE"')
  } {1 SQLITE_RANGE}
  do_catchsql_test 4.7 {
  do_catchsql_test $tn.4.7 {
    SELECT rowid, querytoken(ft, -1, 0) FROM ft('"one TWO ThreE"')
  } {1 SQLITE_RANGE}
}

#-------------------------------------------------------------------------
#
reset_db
sqlite3_fts5_register_origintext db
proc insttoken {cmd iIdx iToken} { 
  set txt [$cmd xInstToken $iIdx $iToken]
  string map [list "\0" "."] $txt
}
sqlite3_fts5_create_function db insttoken insttoken
fts5_aux_test_functions db

do_execsql_test 5.0 {
do_execsql_test $tn.5.0 {
  CREATE VIRTUAL TABLE ft USING fts5(
      x, tokenize='origintext unicode61', tokendata=1, detail=%DETAIL%
  );
  INSERT INTO ft(ft, rank) VALUES('insttoken', $insttoken);
  INSERT INTO ft VALUES('one ONE One oNe oNE one');
}

do_execsql_test 5.1 {
do_execsql_test $tn.5.1 {
  SELECT insttoken(ft, 0, 0), 
         insttoken(ft, 1, 0),
         insttoken(ft, 2, 0),
         insttoken(ft, 3, 0),
         insttoken(ft, 4, 0),
         insttoken(ft, 5, 0)
  FROM ft('one');
} {
  one one.ONE one.One one.oNe one.oNE one
}

do_execsql_test 5.2 {
do_execsql_test $tn.5.2 {
  SELECT insttoken(ft, 0, 0), 
         insttoken(ft, 1, 0),
         insttoken(ft, 2, 0),
         insttoken(ft, 3, 0),
         insttoken(ft, 4, 0),
         insttoken(ft, 5, 0)
  FROM ft('on*');
} {
  one one.ONE one.One one.oNe one.oNE one
}

do_execsql_test $tn.5.3 {
  SELECT insttoken(ft, 0, 0), 
         insttoken(ft, 1, 0),
         insttoken(ft, 2, 0),
         insttoken(ft, 3, 0),
         insttoken(ft, 4, 0),
         insttoken(ft, 5, 0)
  FROM ft(fts5_insttoken('on*'));
} {
  one one.ONE one.One one.oNe one.oNE one
}

do_execsql_test $tn.5.4 {
  SELECT insttoken(ft, 1, 0) FROM ft('one');
} {
  one.ONE
}

do_execsql_test 5.3 {
do_execsql_test $tn.5.5 {
  SELECT fts5_test_poslist(ft) FROM ft('one');
} {
  {0.0.0 0.0.1 0.0.2 0.0.3 0.0.4 0.0.5}
}

#-------------------------------------------------------------------------
# Test the xInstToken() API with:
#
#   * a non tokendata=1 table.
#   * prefix queries.
#
reset_db
sqlite3_fts5_register_origintext db
do_execsql_test 6.0 {
do_execsql_test $tn.6.0 {
  CREATE VIRTUAL TABLE ft USING fts5( 
      x, y, tokenize='origintext unicode61', detail=%DETAIL%, tokendata=0
  );
  INSERT INTO ft(ft, rank) VALUES('insttoken', $insttoken);

  INSERT INTO ft VALUES('One Two', 'Three two');
  INSERT INTO ft VALUES('three Three', 'one One');
}
proc tokens {cmd} { 
  set ret [list]
  for {set iTok 0} {$iTok < [$cmd xInstCount]} {incr iTok} {
    set txt [$cmd xInstToken $iTok 0]
    set txt [string map [list "\0" "."] $txt]
    lappend ret $txt
  }
  set ret
}
sqlite3_fts5_create_function db tokens tokens

do_execsql_test 6.1 {
do_execsql_test $tn.6.1 {
  SELECT rowid, tokens(ft) FROM ft('One');
} {1 one.One 2 one.One}

do_execsql_test 6.2 {
do_execsql_test $tn.6.2 {
  SELECT rowid, tokens(ft) FROM ft('on*');
} {1 {{}} 2 {{} {}}}
} {1 one.One 2 {one one.One}}

do_execsql_test 6.3 {
do_execsql_test $tn.6.3 {
  SELECT rowid, tokens(ft) FROM ft('Three*');
} {1 {{}} 2 {{}}}
} {1 three.Three 2 three.Three}

fts5_aux_test_functions db
do_catchsql_test 6.4 {
do_catchsql_test $tn.6.4 {
  SELECT fts5_test_insttoken(ft, -1, 0) FROM ft('one');
} {1 SQLITE_RANGE}

do_catchsql_test 6.5 {
do_catchsql_test $tn.6.5 {
  SELECT fts5_test_insttoken(ft, 1, 0) FROM ft('one');
} {1 SQLITE_RANGE}

do_catchsql_test 6.6 {
do_catchsql_test $tn.6.6 {
  CREATE VIRTUAL TABLE ft2 USING fts5(x, tokendata=2);
} {1 {malformed tokendata=... directive}}
do_catchsql_test 6.7 {
do_catchsql_test $tn.6.7 {
  CREATE VIRTUAL TABLE ft2 USING fts5(x, content='', tokendata=11);
} {1 {malformed tokendata=... directive}}

}
}

finish_test

Changes to ext/fts5/test/fts5origintext3.test.
18
19
20
21
22
23
24





25
26
27
28
29
30
31
32
33
34
35

36
37
38
39
40
41






42
43
44
45

46
47
48








49

50
51
52
53
54

55
56
57

58
59
60
61
62
63
64
65

66
67
68
69
70
71
72
73
74

75
76
77
78

79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96


97























98
99
100
101
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

40
41
42
43
44


45
46
47
48
49
50
51
52
53

54
55
56
57
58
59
60
61
62
63
64
65

66
67
68
69
70

71
72
73

74
75
76
77
78
79
80
81

82
83
84
85
86
87
88
89
90

91
92
93
94

95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111


112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141







+
+
+
+
+










-
+




-
-
+
+
+
+
+
+



-
+



+
+
+
+
+
+
+
+
-
+




-
+


-
+







-
+








-
+



-
+
















-
-
+
+

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+




# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
  finish_test
  return
}

foreach_detail_mode $testprefix {
  foreach {tn insttoken} {
    1 0
    2 1
  } {

  reset_db

  sqlite3_fts5_register_origintext db
  fts5_aux_test_functions db
  proc insttoken {cmd iIdx iToken} { 
    set txt [$cmd xInstToken $iIdx $iToken]
    string map [list "\0" "."] $txt
  }
  sqlite3_fts5_create_function db insttoken insttoken
  
  do_execsql_test 1.0 {
  do_execsql_test $tn.1.0 {
    CREATE VIRTUAL TABLE ft USING fts5(
        x, tokenize="origintext unicode61", tokendata=1, detail=%DETAIL%
    );
  }
  
  do_execsql_test 1.1 {

  do_execsql_test $tn.1.0.1 {
    INSERT INTO ft(ft, rank) VALUES('insttoken', 1);
  }
  
  do_execsql_test $tn.1.1 {
    INSERT INTO ft VALUES('Hello world HELLO WORLD hello');
  }
  
  do_execsql_test 1.2 {
  do_execsql_test $tn.1.2 {
    SELECT fts5_test_poslist(ft) FROM ft('hello');
  } {{0.0.0 0.0.2 0.0.4}}

  do_execsql_test $tn.1.3 {
    SELECT 
      insttoken(ft, 0, 0),
      insttoken(ft, 1, 0),
      insttoken(ft, 2, 0)
    FROM ft('hello');
  } {hello.Hello hello.HELLO hello}

  do_execsql_test 1.3 {
  do_execsql_test $tn.1.3.1 {
    SELECT 
      insttoken(ft, 0, 0),
      insttoken(ft, 1, 0),
      insttoken(ft, 2, 0)
    FROM ft('hello');
    FROM ft('hel*');
  } {hello.Hello hello.HELLO hello}

  do_execsql_test 1.4 {
  do_execsql_test $tn.1.4 {
    SELECT 
      insttoken(ft, 0, 0),
      insttoken(ft, 1, 0),
      insttoken(ft, 2, 0)
    FROM ft('hello') ORDER BY rank;
  } {hello.Hello hello.HELLO hello}

  do_execsql_test 1.5 {
  do_execsql_test $tn.1.5 {
    CREATE VIRTUAL TABLE ft2 USING fts5(
        x, tokenize="origintext unicode61", tokendata=1, detail=%DETAIL%
    );
    INSERT INTO ft2(rowid, x) VALUES(1, 'ONE one two three ONE');
    INSERT INTO ft2(rowid, x) VALUES(2, 'TWO one two three TWO');
    INSERT INTO ft2(rowid, x) VALUES(3, 'THREE one two three THREE');
  }

  do_execsql_test 1.6 {
  do_execsql_test $tn.1.6 {
    SELECT insttoken(ft2, 0, 0), rowid FROM ft2('three') ORDER BY rank;
  } {three.THREE 3 three 1 three 2}

  do_execsql_test 1.7 {
  do_execsql_test $tn.1.7 {
    INSERT INTO ft2(rowid, x) VALUES(10, 'aaa bbb BBB');
    INSERT INTO ft2(rowid, x) VALUES(12, 'bbb bbb bbb');
    INSERT INTO ft2(rowid, x) VALUES(13, 'bbb bbb bbb');
    INSERT INTO ft2(rowid, x) VALUES(14, 'bbb BBB bbb');
    INSERT INTO ft2(rowid, x) VALUES(15, 'bbb bbb bbb');
    INSERT INTO ft2(rowid, x) VALUES(16, 'bbb bbb bbb');
    INSERT INTO ft2(rowid, x) VALUES(17, 'bbb bbb bbb');
    INSERT INTO ft2(rowid, x) VALUES(18, 'bbb bbb bbb');
    INSERT INTO ft2(rowid, x) VALUES(19, 'bbb bbb bbb');
    INSERT INTO ft2(rowid, x) VALUES(20, 'bbb bbb bbb');
    INSERT INTO ft2(rowid, x) VALUES(21, 'bbb bbb bbb');
    INSERT INTO ft2(rowid, x) VALUES(22, 'bbb bbb bbb');
    INSERT INTO ft2(rowid, x) VALUES(23, 'bbb bbb bbb');
    INSERT INTO ft2(rowid, x) VALUES(24, 'aaa bbb BBB');
  }

  do_execsql_test 1.8 { SELECT rowid FROM ft2('aaa AND bbb'); } {10 24}
  do_execsql_test 1.9 { SELECT rowid FROM ft2('bbb AND aaa'); } {10 24}
  do_execsql_test $tn.1.8 { SELECT rowid FROM ft2('aaa AND bbb'); } {10 24}
  do_execsql_test $tn.1.9 { SELECT rowid FROM ft2('bbb AND aaa'); } {10 24}

  do_execsql_test $tn.2.0 {
    CREATE VIRTUAL TABLE ft3 USING fts5(
        x, tokenize="origintext unicode61", tokendata=1, detail=%DETAIL%,
        prefix=2
    );
  }
  do_execsql_test $tn.2.1 {
    INSERT INTO ft3(rowid, x) VALUES(1, 'one');
    INSERT INTO ft3(rowid, x) VALUES(2, 'ONE');
    INSERT INTO ft3(rowid, x) VALUES(3, 'ONT');
    INSERT INTO ft3(rowid, x) VALUES(4, 'on');
    INSERT INTO ft3(rowid, x) VALUES(5, 'On');
  }

  do_execsql_test $tn.2.2 {
    SELECT rowid FROM ft3('on*');
  } {1 2 3 4 5}

  do_execsql_test $tn.2.3 {
    SELECT rowid, insttoken(ft3, 0, 0) FROM ft3('on*');
  } {1 one 2 one.ONE 3 ont.ONT 4 on 5 on.On}

  }
}

finish_test

Added ext/fts5/test/fts5origintext6.test.

















































































































































































































1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2014 Jan 08
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# Tests focused on phrase queries.
#

source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5origintext6

# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
  finish_test
  return
}

proc insert_data {tbl} {
  db eval "
  INSERT INTO $tbl (rowid, x, y) VALUES
    (1, 'ChH BDd HhG efc BjJ BGi GBG FdD','ciJ AFf ADf fBJ fhC GFI JEH fcA'),
    (2, 'deg AIG Fie jII cCd Hbf igF fEE','GeA Ija gJg EDc HFi DDI dCf aDd'),
    (3, 'IJC hga deC Jfa Aeg hfh CcH dfb','ajD hgC Jaf IfH CHe jIG AjD adF'),
    (4, 'FiH GJH IDA AiG bBc CGG Eih bIH','hHg JaH aii IHE Ggd gcH gji CGc'),
    (5, 'ceg CAd jFI GAB BGg EeC IdH acG','bBC eIG ifH eDE Adj bjb GCj ebA'),
    (6, 'Eac Fbh aFF Eea jeG EIj HCc JJH','hbd giE Gfe eiI dEF abE cJf cAb'),
    (7, 'dic hAc jEC AiG FEF jHc HiD HBI','aEd ebE Gfi AJG EBA faj GiG jjE'),
    (8, 'Fca iEe EgE jjJ gce ijf EGc EBi','gaI dhH bFg CFc HeC CjI Jfg ccH'),
    (9, 'cfd iaa HCf iHJ HjG ffh ABb ibi','CfG bia Dai eii Ejg Jeg fCg hDb'),
    (10, 'Jjf hJC IID HJj bGB EbJ cgg eBj','jci jhi JAF jIg Bei Bcd cAC AJd'),
    (11, 'egG Cdi bFf fEB hfH jDH jia Efd','FAd eCg fAi aiC baC eJG acF iGE'),
    (12, 'Ada Gde CJI ADG gJA Cbb ccF iAB','eAE ajC FBB ccd Jgh fJg ieg hGE'),
    (13, 'gBb fDG Jdd HdD fiJ Bed Cig iGg','heC FeI iaj gdg ebB giC HaD FIe'),
    (14, 'FiI iDd Ffe igI bgB EJf FHG hDF','cjC AeI abf Fah cbJ ffH jEb aib'),
    (15, 'jaF hBI jIH Gdh FEc Fij hgj jFh','dGA ADH feh AAI AfJ DbC gBi hGH'),
    (16, 'gjH BGg iGj aFE CAH edI idf HEH','hIf DDg fjB hGi cHF BCH FjG Bgd'),
    (17, 'iaI JGH hji gcj Dda eeG jDd CBi','cHg jeh caG gIc feF ihG hgJ Abj'),
    (18, 'jHI iDB eFf AiH EFB CDb IAj GbC','Ghe dEI gdI jai gib dAG BIa djb'),
    (19, 'abI fHG Ccf aAc FDa fiC agF bdB','afi hde IgE bGF cfg DHD diE aca'),
    (20, 'IFh eDJ jfh cDg dde JGJ GAf fIJ','IBa EfH faE aeI FIF baJ FGj EIH'),
    (21, 'Dee bFC bBA dEI CEj aJI ghA dCH','hBA ddA HJh dfj egI Dij dFE bGE'),
    (22, 'JFE BCj FgA afc Jda FGD iHJ HDh','eAI jHe BHD Gah bbD Bgj gbh eGB'),
    (23, 'edE CJE FjG aFI edA Cea FId iFe','ABG jcA ddj EEc Dcg hAI agA biA'),
    (24, 'AgE cfc eef cGh aFB DcH efJ hcH','eGF HaB diG fgi bdc iGJ FGJ fFB'),
    (25, 'aCa AgI GhC DDI hGJ Hgc Gcg bbG','iID Fga jHa jIj idj DFD bAC AFJ'),
    (26, 'gjC JGh Fge faa eCA iGG gHE Gai','bDi hFE BbI DHD Adb Fgi hCa Hij'),
    (27, 'Eji jEI jhF DFC afH cDh AGc dHA','IDe GcA ChF DIb Bif HfH agD DGh'),
    (28, 'gDD AEE Dfg ICf Cbi JdE jgH eEi','eEb dBG FDE jgf cAI FaJ jaA cDd'),
    (29, 'cbe Gec hgB Egi bca dHg bAJ jBf','EFB DgD GJc fDb EeE bBA GFC Hbe'),
    (30, 'Adc eHB afI hDc Bhh baE hcJ BBd','JAH deg bcF Dab Bgj Gbb JHi FIB'),
    (31, 'agF dIj AJJ Hfg cCG hED Igc fHC','JEf eia dHf Ggc Agj geD bEE Gei'),
    (32, 'DAd cCe cbJ FjG gJe gba dJA GCf','eAf hFc bGE ABI hHA IcE abF CCE'),
    (33, 'fFh jJe DhJ cDJ EBi AfD eFI IhG','fEG GCc Bjd EFF ggg CFe EHd ciB'),
    (34, 'Ejb BjI eAF HaD eEJ FaG Eda AHC','Iah hgD EJG fdD cIE Daj IFf eJh'),
    (35, 'aHG eCe FjA djJ dAJ jiJ IaE GGB','Acg iEF JfB FIC Eei ggj dic Iii'),
    (36, 'Fdb EDF GaF JjB ehH IgC hgi DCG','cag DHI Fah hAJ bbh egG Hia hgJ'),
    (37, 'HGg icC JEC AFJ Ddh dhi hfC Ich','fEg bED Bff hCJ EiA cIf bfG cGA'),
    (38, 'aEJ jGI BCi FaA ebA BHj cIJ GcC','dCH ADd bGB cFE AgF geD cbG jIc'),
    (39, 'JFB bBi heA BFA hgB Ahj EIE CgI','EIJ JFG FJE GeA Hdg HeH ACh GiA'),
    (40, 'agB DDC CED igC Dfc DhI eiC fHi','dAB dcg iJF cej Fcc cAc AfB Fdd'),
    (41, 'BdF DHj Ege hcG DEd eFa dCf gBb','FBG ChB cej iGd Hbh fCc Ibe Abh'),
    (42, 'Bgc DjI cbC jGD bdb hHB IJA IJH','heg cii abb IGf eDe hJc dii fcE'),
    (43, 'fhf ECa FiA aDh Jbf CiB Jhe ajD','GFE bIF aeD gDE BIE Jea DfC BEc'),
    (44, 'GjE dBj DbJ ICF aDh EEH Ejb jFb','dJj aEc IBg bEG Faf fjA hjf FAF'),
    (45, 'BfA efd IIJ AHG dDF eGg dIJ Gcb','Bfj jeb Ahc dAE ACH Dfb ieb dhC'),
    (46, 'Ibj ege geC dJh CIi hbD EAG fGA','DEb BFe Bjg FId Fhg HeF JAc BbE'),
    (47, 'dhB afC hgG bEJ aIe Cbe iEE JCD','bdg Ajc FGA jbh Jge iAj fIA jbE'),
    (48, 'egH iDi bfH iiI hGC jFF Hfd AHB','bjE Beb iCc haB gIH Dea bga dfd'),
    (49, 'jgf chc jGc Baj HBb jdE hgh heI','FFB aBd iEB EIG HGf Bbj EIi JbI'),
    (50, 'jhe EGi ajA fbH geh EHe FdC bij','jDE bBC gbH HeE dcH iBH IFE AHi'),
    (51, 'aCb JiD cgJ Bjj iAI Hbe IAF FhH','ijf bhE Jdf FED dCH bbG HcJ ebH');
  "
}

foreach_detail_mode $testprefix {
foreach external {0 1 2} {
  reset_db

  proc tokens {cmd} { 
    set ret [list]
    for {set iTok 0} {$iTok < [$cmd xInstCount]} {incr iTok} {
      set txt [$cmd xInstToken $iTok 0]
      set txt [string map [list "\0" "."] $txt]
      lappend ret $txt
    }
    set ret
  }
  sqlite3_fts5_create_function db tokens tokens
  sqlite3_fts5_register_origintext db

  set E(0) internal
  set E(1) external
  set E(2) contentless
  set e $E($external)

  db eval { CREATE TABLE ex(x, y) }
  switch -- $external {
    0 {
      do_execsql_test 1.$e.0 {
        CREATE VIRTUAL TABLE ft USING fts5(
            x, y, tokenize="origintext unicode61", tokendata=1, detail=%DETAIL%
        );
      }
    }

    1 {
      do_execsql_test 1.$e.0 {
        CREATE VIRTUAL TABLE ft USING fts5(
            x, y, tokenize="origintext unicode61", tokendata=1, detail=%DETAIL%,
            content=ex
        );
      }
    }

    2 {
      do_execsql_test 1.$e.0 {
        CREATE VIRTUAL TABLE ft USING fts5(
            x, y, tokenize="origintext unicode61", tokendata=1, detail=%DETAIL%,
            content=
        );
      }
    }
  }
  insert_data ex
  insert_data ft
  
  proc prefixquery {prefix bInst bYOnly} {
    set ret [list]
    db eval { SELECT rowid, x, y FROM ex ORDER BY rowid } {
      set row [list]
      set bSeen 0

      set T [concat $x $y]
      if {$bYOnly} { set T $y }

      foreach w $T {
        if {[string match -nocase $prefix $w]} {
          set bSeen 1
          if {$bInst} {
            set v [string tolower $w]
            if {$w != $v} { append v ".$w" }
            lappend row $v
          }
        }
      }
  
      if {$bSeen} {
        lappend ret $rowid
        lappend ret $row
      }
    }
  
    set ret
  }
  
  proc do_prefixquery_test {tn prefix} {
    set bInst [expr {$::e!="contentless" || "%DETAIL%"=="full"}]
    set expect [prefixquery $prefix $bInst 0]
    set expect2 [prefixquery $prefix $bInst 1]

    uplevel [list do_execsql_test $tn.1 "
        SELECT rowid, tokens(ft) FROM ft('$prefix')
    " $expect]
    uplevel [list do_execsql_test $tn.2 "
        SELECT rowid, tokens(ft) FROM ft(fts5_insttoken('$prefix'))
    " $expect]
    db eval { INSERT INTO ft(ft, rank) VALUES('insttoken', 1) }
    uplevel [list do_execsql_test $tn.3 "
        SELECT rowid, tokens(ft) FROM ft('$prefix')
    " $expect]
    db eval { INSERT INTO ft(ft, rank) VALUES('insttoken', 0) }

    if {"%DETAIL%"!="none"} {
      uplevel [list do_execsql_test $tn.4 "
          SELECT rowid, tokens(ft) FROM ft('y: $prefix')
      " $expect2]
      uplevel [list do_execsql_test $tn.5 "
          SELECT rowid, tokens(ft) FROM ft(fts5_insttoken('y: $prefix'))
      " $expect2]
      db eval { INSERT INTO ft(ft, rank) VALUES('insttoken', 1) }
      uplevel [list do_execsql_test $tn.6 "
          SELECT rowid, tokens(ft) FROM ft('y: $prefix')
      " $expect2]
      db eval { INSERT INTO ft(ft, rank) VALUES('insttoken', 0) }
    }
  }
  
  do_prefixquery_test 1.$e.1 a*
  do_prefixquery_test 1.$e.2 b*
  do_prefixquery_test 1.$e.3 c*
  do_prefixquery_test 1.$e.4 d*
  do_prefixquery_test 1.$e.5 e*
  do_prefixquery_test 1.$e.6 f*
  do_prefixquery_test 1.$e.7 g*
  do_prefixquery_test 1.$e.8 h*
  do_prefixquery_test 1.$e.9 i*
  do_prefixquery_test 1.$e.10 j*
}}



finish_test

Added ext/fts5/test/fts5tokendata.test.









































































































1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2014 Jan 08
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# Tests focused on phrase queries.
#

source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5tokendata

# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
  finish_test
  return
}

foreach_detail_mode $testprefix {

  sqlite3_fts5_register_origintext db
  fts5_aux_test_functions db
  proc b {x} { string map [list "\0" "."] $x }
  db func b b

  do_execsql_test 1.0 {
    CREATE VIRTUAL TABLE ft USING fts5(a, b, tokendata=1,
      tokenize="origintext unicode61", detail=%DETAIL%
    );
    CREATE VIRTUAL TABLE vocab USING fts5vocab(ft, instance);
  }

  do_execsql_test 1.1 {
    INSERT INTO ft(rowid, a, b) VALUES
      (1, 'Pedagog Pedal Pedant', 'Peculier Day Today'),
      (2, 'Pedant pedantic pecked', 'Peck Penalize Pen');

    INSERT INTO ft(rowid, a, b) VALUES
      (3, 'Penalty Pence Penciled', 'One Two Three'),
      (4, 'Pedant Pedal Pedant', 'Peculier Day Today');
  }

  do_execsql_test 1.2 {
    SELECT DISTINCT b(term) FROM vocab
  } {
    day.Day one.One peck.Peck pecked peculier.Peculier pedagog.Pedagog
    pedal.Pedal pedant.Pedant pedantic pen.Pen penalize.Penalize 
    penalty.Penalty pence.Pence penciled.Penciled three.Three 
    today.Today two.Two
  }

  do_execsql_test 1.3.1 {
    SELECT rowid FROM ft('pe*')
  } {
    1 2 3 4
  }

  do_execsql_test 1.3.2 {
    SELECT rowid FROM ft('pe*') ORDER BY rowid DESC
  } {
    4 3 2 1
  }
  
  if {"%DETAIL%"!="none"} {
    do_execsql_test 1.3.3 {
      SELECT rowid FROM ft WHERE a MATCH 'pe*' ORDER BY rowid DESC
    } {
      4 3 2 1
    }
  }

  do_execsql_test 1.4 {
    SELECT rowid, b( fts5_test_insttoken(ft, 0, 0) ) FROM ft('pedant')
  } {
    1 pedant.Pedant
    2 pedant.Pedant
    4 pedant.Pedant
  }

  do_execsql_test 1.5 {
    SELECT rowid, b( fts5_test_insttoken(ft, 0, 0) ) FROM ft('pe*')
  } {
    1 pedagog.Pedagog
    2 pedant.Pedant
    3 penalty.Penalty
    4 pedant.Pedant
  }

  do_execsql_test 1.6 {
    SELECT rowid, fts5_test_poslist(ft) FROM ft('pe*')
  } {
    1 {0.0.0 0.0.1 0.0.2 0.1.0} 
    2 {0.0.0 0.0.1 0.0.2 0.1.0 0.1.1 0.1.2}
    3 {0.0.0 0.0.1 0.0.2}
    4 {0.0.0 0.0.1 0.0.2 0.1.0}
  }
}

finish_test

Changes to ext/fts5/test/fts5trigram.test.
345
346
347
348
349
350
351












352
353
354
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366







+
+
+
+
+
+
+
+
+
+
+
+



do_execsql_test 11.0 {
  CREATE VIRTUAL TABLE t4 USING fts5(y, tokenize=trigram);
}
sqlite3_fts5_register_str db
do_execsql_test 11.1 {
  INSERT INTO t4 VALUES( str('') );
}

do_test 12.0 {
  sqlite3_fts5_tokenize db trigram "abcd"
} {abc 0 3 bcd 1 4}

do_test 12.1 {
  sqlite3_fts5_tokenize db trigram "a"
} {}

do_test 12.2 {
  sqlite3_fts5_tokenize db trigram ""
} {}

finish_test

Changes to ext/icu/README.txt.
1
2
3
4
5
6
7

8
9
10
11
12

13
14

15
16

17
18
19
20
21
22
23
24
25
26

27
28
29

30
31
32
33
34
35
36
37
38
39

40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

61
62
63
64
65
66
67
68
69

70
71

72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

91
92
93
94
95
96
97

1
2
3
4
5

6
7
8
9
10

11
12

13
14

15
16
17
18
19
20
21
22
23
24

25
26
27

28
29
30
31
32
33
34
35
36
37

38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

59
60
61
62
63
64
65
66
67

68
69

70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

89
90
91
92
93
94
95
96
-





-
+




-
+

-
+

-
+









-
+


-
+









-
+




















-
+








-
+

-
+


















-
+








This directory contains source code for the SQLite "ICU" extension, an
integration of the "International Components for Unicode" library with
SQLite. Documentation follows.

    1. Features
    

        1.1  SQL Scalars upper() and lower()
        1.2  Unicode Aware LIKE Operator
        1.3  ICU Collation Sequences
        1.4  SQL REGEXP Operator
    

    2. Compilation and Usage
    

    3. Bugs, Problems and Security Issues
    

        3.1  The "case_sensitive_like" Pragma
        3.2  The SQLITE_MAX_LIKE_PATTERN_LENGTH Macro
        3.3  Collation Sequence Security Issue


1. FEATURES

  1.1  SQL Scalars upper() and lower()

    SQLite's built-in implementations of these two functions only 
    SQLite's built-in implementations of these two functions only
    provide case mapping for the 26 letters used in the English
    language. The ICU based functions provided by this extension
    provide case mapping, where defined, for the full range of 
    provide case mapping, where defined, for the full range of
    unicode characters.

    ICU provides two types of case mapping, "general" case mapping and
    "language specific". Refer to ICU documentation for the differences
    between the two. Specifically:

       http://www.icu-project.org/userguide/caseMappings.html
       http://www.icu-project.org/userguide/posix.html#case_mappings

    To utilise "general" case mapping, the upper() or lower() scalar 
    To utilise "general" case mapping, the upper() or lower() scalar
    functions are invoked with one argument:

        upper('abc') -> 'ABC'
        lower('ABC') -> 'abc'

    To access ICU "language specific" case mapping, upper() or lower()
    should be invoked with two arguments. The second argument is the name
    of the locale to use. Passing an empty string ("") or SQL NULL value
    as the second argument is the same as invoking the 1 argument version
    of upper() or lower():

        lower('I', 'en_us') -> 'i'
        lower('I', 'tr_tr') -> 'ı' (small dotless i)

  1.2  Unicode Aware LIKE Operator

    Similarly to the upper() and lower() functions, the built-in SQLite LIKE
    operator understands case equivalence for the 26 letters of the English
    language alphabet. The implementation of LIKE included in this
    extension uses the ICU function u_foldCase() to provide case
    independent comparisons for the full range of unicode characters.  
    independent comparisons for the full range of unicode characters.

    The U_FOLD_CASE_DEFAULT flag is passed to u_foldCase(), meaning the
    dotless 'I' character used in the Turkish language is considered
    to be in the same equivalence class as the dotted 'I' character
    used by many languages (including English).

  1.3  ICU Collation Sequences

    A special SQL scalar function, icu_load_collation() is provided that 
    A special SQL scalar function, icu_load_collation() is provided that
    may be used to register ICU collation sequences with SQLite. It
    is always called with exactly two arguments, the ICU locale 
    is always called with exactly two arguments, the ICU locale
    identifying the collation sequence to ICU, and the name of the
    SQLite collation sequence to create. For example, to create an
    SQLite collation sequence named "turkish" using Turkish language
    sorting rules, the SQL statement:

        SELECT icu_load_collation('tr_TR', 'turkish');

    Or, for Australian English:

        SELECT icu_load_collation('en_AU', 'australian');

    The identifiers "turkish" and "australian" may then be used
    as collation sequence identifiers in SQL statements:

        CREATE TABLE aust_turkish_penpals(
          australian_penpal_name TEXT COLLATE australian,
          turkish_penpal_name    TEXT COLLATE turkish
        );
  

  1.4 SQL REGEXP Operator

    This extension provides an implementation of the SQL binary
    comparision operator "REGEXP", based on the regular expression functions
    provided by the ICU library. The syntax of the operator is as described
    in SQLite documentation:

112
113
114
115
116
117
118
119

120
121
122
123
124
125





126
127
128
129
130
131
132
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







-
+






+
+
+
+
+








2  COMPILATION AND USAGE

  The easiest way to compile and use the ICU extension is to build
  and use it as a dynamically loadable SQLite extension. To do this
  using gcc on *nix:

    gcc -fPIC -shared icu.c `pkg-config --libs --cflags icu-uc icu-io` \
    gcc -fPIC -shared icu.c `pkg-config --libs --cflags icu-io` \
        -o libSqliteIcu.so

  You may need to add "-I" flags so that gcc can find sqlite3ext.h
  and sqlite3.h. The resulting shared lib, libSqliteIcu.so, may be
  loaded into sqlite in the same way as any other dynamically loadable
  extension.

  As of version 3.48, it can be enabled in the canonical build process
  by passing one of --with-icu-config or --with-icu-ldflags to the
  configure script, optionally together with --enable-icu-collations.
  See the configure --help for more details.


3 BUGS, PROBLEMS AND SECURITY ISSUES

  3.1 The "case_sensitive_like" Pragma

    This extension does not work well with the "case_sensitive_like"
140
141
142
143
144
145
146
147
148


149
150
151
152
153

154
155
156
157
158
159
160
161
162
163
164
144
145
146
147
148
149
150


151
152
153
154
155
156

157
158
159
160
161
162
163
164
165
166
167
168







-
-
+
+




-
+











  3.2 The SQLITE_MAX_LIKE_PATTERN_LENGTH Macro

    Passing very long patterns to the built-in SQLite LIKE operator can
    cause excessive CPU usage. To curb this problem, SQLite defines the
    SQLITE_MAX_LIKE_PATTERN_LENGTH macro as the maximum length of a
    pattern in bytes (irrespective of encoding). The default value is
    defined in internal header file "limits.h".
    
    The ICU extension LIKE implementation suffers from the same 

    The ICU extension LIKE implementation suffers from the same
    problem and uses the same solution. However, since the ICU extension
    code does not include the SQLite file "limits.h", modifying
    the default value therein does not affect the ICU extension.
    The default value of SQLITE_MAX_LIKE_PATTERN_LENGTH used by
    the ICU extension LIKE operator is 50000, defined in source 
    the ICU extension LIKE operator is 50000, defined in source
    file "icu.c".

  3.3 Collation Sequence Security

    Internally, SQLite assumes that indices stored in database files
    are sorted according to the collation sequence indicated by the
    SQL schema. Changing the definition of a collation sequence after
    an index has been built is therefore equivalent to database
    corruption. The SQLite library is well tested for robustness in
    the fact of database corruption.  Database corruption may well
    lead to incorrect answers, but should not cause memory errors.
Changes to ext/misc/sqlite3_stdio.c.
144
145
146
147
148
149
150









151
152
153
154





155
156
157
158
159
160
161
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159




160
161
162
163
164
165
166
167
168
169
170
171







+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+







    /* 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 ){
      sqlite3_free(b1);
      return 0;
      _setmode(_fileno(in), IsConsole(in) ? _O_WTEXT : _O_U8TEXT);
      if( fgetws(b1, sz/4, in)==0 ){
        sqlite3_free(b1);
        return 0;
      }
    }
    WideCharToMultiByte(CP_UTF8, 0, b1, -1, buf, sz, 0, 0);
    sqlite3_free(b1);
    return buf;
  }else{
    /* Reading from a file or other input source, just read bytes without
    ** any translation. */
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
213
214
215
216
217
218
219


220
221

222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240





241
242
243
244
245
246
247
248
249
250
251
252
253







-
-
+
+
-






+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+







*/
int sqlite3_fputs(const char *z, FILE *out){
  if( !UseWtextForOutput(out) ){
    /* Writing to a file or other destination, just write bytes without
    ** any translation. */
    return fputs(z, out);
  }else{
    /* When writing to the command-prompt in Windows, it is necessary
    ** to use O_U8TEXT to render Unicode U+0080 and greater.  Go ahead
    /* One must use UTF16 in order to get unicode support when writing
    ** to the console on Windows. 
    ** use O_U8TEXT for everything in text mode.
    */
    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);
      _setmode(_fileno(out), _O_U8TEXT);
      if( UseBinaryWText(out) ){
        piecemealOutput(b1, sz, out);
      }else{
        fputws(b1, out);
      }
    }
    sqlite3_free(b1);
    return 0;
  }
}


Changes to ext/misc/vfstrace.c.
101
102
103
104
105
106
107
108





















109
110
111
112
113
114
115
116
117
118
119
120
121


122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
































138
139
140
141
142
143
144
101
102
103
104
105
106
107

108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198







-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+













+
+
















+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







**         -DSQLITE_THREADSAFE=0 -DSQLITE_ENABLE_VFSTRACE \
**         shell.c test_vfstrace.c sqlite3.c
**
** Similar compiler commands will work on different systems.  The key
** invariants are (1) you must have -DSQLITE_ENABLE_VFSTRACE so that
** the shell.c source file will know to include the -vfstrace command-line
** option and (2) you must compile and link the three source files
** shell,c, test_vfstrace.c, and sqlite3.c.  
** shell,c, test_vfstrace.c, and sqlite3.c.
**
** RUNTIME CONTROL OF VFSTRACE OUTPUT
**
** The application can use the "vfstrace" pragma to control which VFS
** APIs are traced.  To disable all output:
**
**    PRAGMA vfstrace('-all');
**
** To enable all output (which is the default setting):
**
**    PRAGMA vfstrace('+all');
**
** Individual APIs can be enabled or disabled by name, with or without
** the initial "x" character.  For example, to set up for tracing lock
** primatives only:
**
**    PRAGMA vfstrace('-all, +Lock,Unlock,ShmLock');
**
** The argument to the vfstrace pragma ignores capitalization and any
** characters other than alphabetics, '+', and '-'.
*/
#include <stdlib.h>
#include <string.h>
#include "sqlite3.h"

/*
** An instance of this structure is attached to the each trace VFS to
** provide auxiliary information.
*/
typedef struct vfstrace_info vfstrace_info;
struct vfstrace_info {
  sqlite3_vfs *pRootVfs;              /* The underlying real VFS */
  int (*xOut)(const char*, void*);    /* Send output here */
  unsigned int mTrace;                /* Mask of interfaces to trace */
  u8 bOn;                             /* Tracing on/off */
  void *pOutArg;                      /* First argument to xOut */
  const char *zVfsName;               /* Name of this trace-VFS */
  sqlite3_vfs *pTraceVfs;             /* Pointer back to the trace VFS */
};

/*
** The sqlite3_file object for the trace VFS
*/
typedef struct vfstrace_file vfstrace_file;
struct vfstrace_file {
  sqlite3_file base;        /* Base class.  Must be first */
  vfstrace_info *pInfo;     /* The trace-VFS to which this file belongs */
  const char *zFName;       /* Base name of the file */
  sqlite3_file *pReal;      /* The real underlying file */
};

/*
** Bit values for vfstrace_info.mTrace.
*/
#define VTR_CLOSE           0x00000001
#define VTR_READ            0x00000002
#define VTR_WRITE           0x00000004
#define VTR_TRUNC           0x00000008
#define VTR_SYNC            0x00000010
#define VTR_FSIZE           0x00000020
#define VTR_LOCK            0x00000040
#define VTR_UNLOCK          0x00000080
#define VTR_CRL             0x00000100
#define VTR_FCTRL           0x00000200
#define VTR_SECSZ           0x00000400
#define VTR_DEVCHAR         0x00000800
#define VTR_SHMLOCK         0x00001000
#define VTR_SHMMAP          0x00002000
#define VTR_SHMBAR          0x00004000
#define VTR_SHMUNMAP        0x00008000
#define VTR_OPEN            0x00010000
#define VTR_DELETE          0x00020000
#define VTR_ACCESS          0x00040000
#define VTR_FULLPATH        0x00080000
#define VTR_DLOPEN          0x00100000
#define VTR_DLERR           0x00200000
#define VTR_DLSYM           0x00400000
#define VTR_DLCLOSE         0x00800000
#define VTR_RAND            0x01000000
#define VTR_SLEEP           0x02000000
#define VTR_CURTIME         0x04000000
#define VTR_LASTERR         0x08000000

/*
** Method declarations for vfstrace_file.
*/
static int vfstraceClose(sqlite3_file*);
static int vfstraceRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
static int vfstraceWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
static int vfstraceTruncate(sqlite3_file*, sqlite3_int64 size);
195
196
197
198
199
200
201

202
203
204
205
206






207
208
209
210
211
212
213
249
250
251
252
253
254
255
256





257
258
259
260
261
262
263
264
265
266
267
268
269







+
-
-
-
-
-
+
+
+
+
+
+







static void vfstrace_printf(
  vfstrace_info *pInfo,
  const char *zFormat,
  ...
){
  va_list ap;
  char *zMsg;
  if( pInfo->bOn ){
  va_start(ap, zFormat);
  zMsg = sqlite3_vmprintf(zFormat, ap);
  va_end(ap);
  pInfo->xOut(zMsg, pInfo->pOutArg);
  sqlite3_free(zMsg);
    va_start(ap, zFormat);
    zMsg = sqlite3_vmprintf(zFormat, ap);
    va_end(ap);
    pInfo->xOut(zMsg, pInfo->pOutArg);
    sqlite3_free(zMsg);
  }
}

/*
** Try to convert an error code into a symbolic name for that error code.
*/
static const char *vfstrace_errcode_name(int rc ){
  const char *zVal = 0;
297
298
299
300
301
302
303







304
305
306
307
308
309
310
311

312
313
314
315
316
317
318
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382







+
+
+
+
+
+
+








+







*/
static void strappend(char *z, int *pI, const char *zAppend){
  int i = *pI;
  while( zAppend[0] ){ z[i++] = *(zAppend++); }
  z[i] = 0;
  *pI = i;
}

/*
** Turn tracing output on or off according to mMask.
*/
static void vfstraceOnOff(vfstrace_info *pInfo, unsigned int mMask){
  pInfo->bOn = (pInfo->mTrace & mMask)!=0;
}

/*
** Close an vfstrace-file.
*/
static int vfstraceClose(sqlite3_file *pFile){
  vfstrace_file *p = (vfstrace_file *)pFile;
  vfstrace_info *pInfo = p->pInfo;
  int rc;
  vfstraceOnOff(pInfo, VTR_CLOSE);
  vfstrace_printf(pInfo, "%s.xClose(%s)", pInfo->zVfsName, p->zFName);
  rc = p->pReal->pMethods->xClose(p->pReal);
  vfstrace_print_errcode(pInfo, " -> %s\n", rc);
  if( rc==SQLITE_OK ){
    sqlite3_free((void*)p->base.pMethods);
    p->base.pMethods = 0;
  }
327
328
329
330
331
332
333

334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352

353
354
355
356
357
358
359
360
361
362
363
364
365
366

367
368
369
370
371
372
373
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440







+



















+














+







  void *zBuf, 
  int iAmt, 
  sqlite_int64 iOfst
){
  vfstrace_file *p = (vfstrace_file *)pFile;
  vfstrace_info *pInfo = p->pInfo;
  int rc;
  vfstraceOnOff(pInfo, VTR_READ);
  vfstrace_printf(pInfo, "%s.xRead(%s,n=%d,ofst=%lld)",
                  pInfo->zVfsName, p->zFName, iAmt, iOfst);
  rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
  vfstrace_print_errcode(pInfo, " -> %s\n", rc);
  return rc;
}

/*
** Write data to an vfstrace-file.
*/
static int vfstraceWrite(
  sqlite3_file *pFile, 
  const void *zBuf, 
  int iAmt, 
  sqlite_int64 iOfst
){
  vfstrace_file *p = (vfstrace_file *)pFile;
  vfstrace_info *pInfo = p->pInfo;
  int rc;
  vfstraceOnOff(pInfo, VTR_WRITE);
  vfstrace_printf(pInfo, "%s.xWrite(%s,n=%d,ofst=%lld)",
                  pInfo->zVfsName, p->zFName, iAmt, iOfst);
  rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
  vfstrace_print_errcode(pInfo, " -> %s\n", rc);
  return rc;
}

/*
** Truncate an vfstrace-file.
*/
static int vfstraceTruncate(sqlite3_file *pFile, sqlite_int64 size){
  vfstrace_file *p = (vfstrace_file *)pFile;
  vfstrace_info *pInfo = p->pInfo;
  int rc;
  vfstraceOnOff(pInfo, VTR_TRUNC);
  vfstrace_printf(pInfo, "%s.xTruncate(%s,%lld)", pInfo->zVfsName, p->zFName,
                  size);
  rc = p->pReal->pMethods->xTruncate(p->pReal, size);
  vfstrace_printf(pInfo, " -> %d\n", rc);
  return rc;
}

384
385
386
387
388
389
390

391
392
393
394
395
396
397
398
399
400
401
402
403
404

405
406
407
408
409
410
411
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480







+














+







  i = 0;
  if( flags & SQLITE_SYNC_FULL )        strappend(zBuf, &i, "|FULL");
  else if( flags & SQLITE_SYNC_NORMAL ) strappend(zBuf, &i, "|NORMAL");
  if( flags & SQLITE_SYNC_DATAONLY )    strappend(zBuf, &i, "|DATAONLY");
  if( flags & ~(SQLITE_SYNC_FULL|SQLITE_SYNC_DATAONLY) ){
    sqlite3_snprintf(sizeof(zBuf)-i, &zBuf[i], "|0x%x", flags);
  }
  vfstraceOnOff(pInfo, VTR_SYNC);
  vfstrace_printf(pInfo, "%s.xSync(%s,%s)", pInfo->zVfsName, p->zFName,
                  &zBuf[1]);
  rc = p->pReal->pMethods->xSync(p->pReal, flags);
  vfstrace_printf(pInfo, " -> %d\n", rc);
  return rc;
}

/*
** Return the current file-size of an vfstrace-file.
*/
static int vfstraceFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
  vfstrace_file *p = (vfstrace_file *)pFile;
  vfstrace_info *pInfo = p->pInfo;
  int rc;
  vfstraceOnOff(pInfo, VTR_FSIZE);
  vfstrace_printf(pInfo, "%s.xFileSize(%s)", pInfo->zVfsName, p->zFName);
  rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
  vfstrace_print_errcode(pInfo, " -> %s,", rc);
  vfstrace_printf(pInfo, " size=%lld\n", *pSize);
  return rc;
}

426
427
428
429
430
431
432

433
434
435
436
437
438
439
440
441
442
443
444
445
446

447
448
449
450
451
452
453
454
455
456
457
458
459
460

461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479

480
481
482
483
484
485
486
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559







+














+














+



















+







/*
** Lock an vfstrace-file.
*/
static int vfstraceLock(sqlite3_file *pFile, int eLock){
  vfstrace_file *p = (vfstrace_file *)pFile;
  vfstrace_info *pInfo = p->pInfo;
  int rc;
  vfstraceOnOff(pInfo, VTR_LOCK);
  vfstrace_printf(pInfo, "%s.xLock(%s,%s)", pInfo->zVfsName, p->zFName,
                  lockName(eLock));
  rc = p->pReal->pMethods->xLock(p->pReal, eLock);
  vfstrace_print_errcode(pInfo, " -> %s\n", rc);
  return rc;
}

/*
** Unlock an vfstrace-file.
*/
static int vfstraceUnlock(sqlite3_file *pFile, int eLock){
  vfstrace_file *p = (vfstrace_file *)pFile;
  vfstrace_info *pInfo = p->pInfo;
  int rc;
  vfstraceOnOff(pInfo, VTR_UNLOCK);
  vfstrace_printf(pInfo, "%s.xUnlock(%s,%s)", pInfo->zVfsName, p->zFName,
                  lockName(eLock));
  rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
  vfstrace_print_errcode(pInfo, " -> %s\n", rc);
  return rc;
}

/*
** Check if another file-handle holds a RESERVED lock on an vfstrace-file.
*/
static int vfstraceCheckReservedLock(sqlite3_file *pFile, int *pResOut){
  vfstrace_file *p = (vfstrace_file *)pFile;
  vfstrace_info *pInfo = p->pInfo;
  int rc;
  vfstraceOnOff(pInfo, VTR_CRL);
  vfstrace_printf(pInfo, "%s.xCheckReservedLock(%s,%d)", 
                  pInfo->zVfsName, p->zFName);
  rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
  vfstrace_print_errcode(pInfo, " -> %s", rc);
  vfstrace_printf(pInfo, ", out=%d\n", *pResOut);
  return rc;
}

/*
** File control method. For custom operations on an vfstrace-file.
*/
static int vfstraceFileControl(sqlite3_file *pFile, int op, void *pArg){
  vfstrace_file *p = (vfstrace_file *)pFile;
  vfstrace_info *pInfo = p->pInfo;
  int rc;
  char zBuf[100];
  char zBuf2[100];
  char *zOp;
  char *zRVal = 0;
  vfstraceOnOff(pInfo, VTR_FCTRL);
  switch( op ){
    case SQLITE_FCNTL_LOCKSTATE:           zOp = "LOCKSTATE";           break;
    case SQLITE_GET_LOCKPROXYFILE:         zOp = "GET_LOCKPROXYFILE";   break;
    case SQLITE_SET_LOCKPROXYFILE:         zOp = "SET_LOCKPROXYFILE";   break;
    case SQLITE_LAST_ERRNO:                zOp = "LAST_ERRNO";          break;
    case SQLITE_FCNTL_SIZE_HINT: {
      sqlite3_snprintf(sizeof(zBuf), zBuf, "SIZE_HINT,%lld",
501
502
503
504
505
506
507









































































508
509
510
511
512
513
514
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







       break;
    }
    case SQLITE_FCNTL_OVERWRITE:           zOp = "OVERWRITE";           break;
    case SQLITE_FCNTL_VFSNAME:             zOp = "VFSNAME";             break;
    case SQLITE_FCNTL_POWERSAFE_OVERWRITE: zOp = "POWERSAFE_OVERWRITE"; break;
    case SQLITE_FCNTL_PRAGMA: {
      const char *const* a = (const char*const*)pArg;
      if( a[1] && strcmp(a[1],"vfstrace")==0 && a[2] ){
        const u8 *zArg = (const u8*)a[2];
        if( zArg[0]>='0' && zArg[0]<=9 ){
          pInfo->mTrace = (sqlite3_uint64)strtoll(a[2], 0, 0);
        }else{
          static const struct {
            const char *z;
            unsigned int m;
          } aKw[] = {
            { "all",                   0xffffffff   },
            { "close",                 VTR_CLOSE    },
            { "read",                  VTR_READ     },
            { "write",                 VTR_WRITE    },
            { "truncate",              VTR_TRUNC    },
            { "sync",                  VTR_SYNC     },
            { "filesize",              VTR_FSIZE    },
            { "lock",                  VTR_LOCK     },
            { "unlock",                VTR_UNLOCK   },
            { "checkreservedlock",     VTR_CRL      },
            { "filecontrol",           VTR_FCTRL    },
            { "sectorsize",            VTR_SECSZ    },
            { "devicecharacteristics", VTR_DEVCHAR  },
            { "shmlock",               VTR_SHMLOCK  },
            { "shmmap",                VTR_SHMMAP   },
            { "shmummap",              VTR_SHMUNMAP },
            { "shmbarrier",            VTR_SHMBAR   },
            { "open",                  VTR_OPEN     },
            { "delete",                VTR_DELETE   },
            { "access",                VTR_ACCESS   },
            { "fullpathname",          VTR_FULLPATH },
            { "dlopen",                VTR_DLOPEN   },
            { "dlerror",               VTR_DLERR    },
            { "dlsym",                 VTR_DLSYM    },
            { "dlclose",               VTR_DLCLOSE  },
            { "randomness",            VTR_RAND     },
            { "sleep",                 VTR_SLEEP    },
            { "currenttime",           VTR_CURTIME  },
            { "currenttimeint64",      VTR_CURTIME  },
            { "getlasterror",          VTR_LASTERR  },
          };
          int onOff = 1;
          while( zArg[0] ){
            int jj, n;
            while( zArg[0]!=0 && zArg[0]!='-' && zArg[0]!='+'
                   && !isalpha(zArg[0]) ) zArg++;
            if( zArg[0]==0 ) break;
            if( zArg[0]=='-' ){
              onOff = 0;
              zArg++;
            }else if( zArg[0]=='+' ){
              onOff = 1;
              zArg++;
            }
            while( !isalpha(zArg[0]) ){
              if( zArg[0]==0 ) break;
              zArg++;
            }
            if( zArg[0]=='x' && isalpha(zArg[1]) ) zArg++;
            for(n=0; isalpha(zArg[n]); n++){}
            for(jj=0; jj<sizeof(aKw)/sizeof(aKw[0]); jj++){
              if( sqlite3_strnicmp(aKw[jj].z,(const char*)zArg,n)==0 ){
                if( onOff ){
                  pInfo->mTrace |= aKw[jj].m;
                }else{
                  pInfo->mTrace &= ~aKw[jj].m;
                }
                break;
              }
            }
            zArg += n;
          }
        }
      }
      sqlite3_snprintf(sizeof(zBuf), zBuf, "PRAGMA,[%s,%s]",a[1],a[2]);
      zOp = zBuf;
      break;
    }
    case SQLITE_FCNTL_BUSYHANDLER:         zOp = "BUSYHANDLER";         break;
    case SQLITE_FCNTL_TEMPFILENAME:        zOp = "TEMPFILENAME";        break;
    case SQLITE_FCNTL_MMAP_SIZE: {
596
597
598
599
600
601
602

603
604
605
606
607
608
609
610
611
612
613
614
615

616
617
618
619
620
621
622
623
624
625
626










627
628
629
630
631

632
633
634
635
636
637
638
639

640
641








642
643
644
645
646
647
648
649
650
651
652
653
654
655

656
657
658
659
660
661
662
663
664

665
666
667
668
669
670
671

672
673
674
675
676
677
678
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799


800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847







+













+











+
+
+
+
+
+
+
+
+
+





+








+
-
-
+
+
+
+
+
+
+
+














+









+







+







/*
** Return the sector-size in bytes for an vfstrace-file.
*/
static int vfstraceSectorSize(sqlite3_file *pFile){
  vfstrace_file *p = (vfstrace_file *)pFile;
  vfstrace_info *pInfo = p->pInfo;
  int rc;
  vfstraceOnOff(pInfo, VTR_SECSZ);
  vfstrace_printf(pInfo, "%s.xSectorSize(%s)", pInfo->zVfsName, p->zFName);
  rc = p->pReal->pMethods->xSectorSize(p->pReal);
  vfstrace_printf(pInfo, " -> %d\n", rc);
  return rc;
}

/*
** Return the device characteristic flags supported by an vfstrace-file.
*/
static int vfstraceDeviceCharacteristics(sqlite3_file *pFile){
  vfstrace_file *p = (vfstrace_file *)pFile;
  vfstrace_info *pInfo = p->pInfo;
  int rc;
  vfstraceOnOff(pInfo, VTR_DEVCHAR);
  vfstrace_printf(pInfo, "%s.xDeviceCharacteristics(%s)",
                  pInfo->zVfsName, p->zFName);
  rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
  vfstrace_printf(pInfo, " -> 0x%08x\n", rc);
  return rc;
}

/*
** Shared-memory operations.
*/
static int vfstraceShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
  static const char *azLockName[] = {
     "WRITE",
     "CKPT",
     "RECOVER",
     "READ0",
     "READ1",
     "READ2",
     "READ3",
     "READ4",
  };
  vfstrace_file *p = (vfstrace_file *)pFile;
  vfstrace_info *pInfo = p->pInfo;
  int rc;
  char zLck[100];
  int i = 0;
  vfstraceOnOff(pInfo, VTR_SHMLOCK);
  memcpy(zLck, "|0", 3);
  if( flags & SQLITE_SHM_UNLOCK )    strappend(zLck, &i, "|UNLOCK");
  if( flags & SQLITE_SHM_LOCK )      strappend(zLck, &i, "|LOCK");
  if( flags & SQLITE_SHM_SHARED )    strappend(zLck, &i, "|SHARED");
  if( flags & SQLITE_SHM_EXCLUSIVE ) strappend(zLck, &i, "|EXCLUSIVE");
  if( flags & ~(0xf) ){
     sqlite3_snprintf(sizeof(zLck)-i, &zLck[i], "|0x%x", flags);
  }
  if( ofst>=0 && ofst<sizeof(azLockName)/sizeof(azLockName[0]) ){
  vfstrace_printf(pInfo, "%s.xShmLock(%s,ofst=%d,n=%d,%s)",
                  pInfo->zVfsName, p->zFName, ofst, n, &zLck[1]);
    vfstrace_printf(pInfo, "%s.xShmLock(%s,ofst=%d(%s),n=%d,%s)",
                  pInfo->zVfsName, p->zFName, ofst, azLockName[ofst],
                  n, &zLck[1]);
  }else{
    vfstrace_printf(pInfo, "%s.xShmLock(%s,ofst=5d,n=%d,%s)",
                  pInfo->zVfsName, p->zFName, ofst,
                  n, &zLck[1]);
  }
  rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
  vfstrace_print_errcode(pInfo, " -> %s\n", rc);
  return rc;
}
static int vfstraceShmMap(
  sqlite3_file *pFile, 
  int iRegion, 
  int szRegion, 
  int isWrite, 
  void volatile **pp
){
  vfstrace_file *p = (vfstrace_file *)pFile;
  vfstrace_info *pInfo = p->pInfo;
  int rc;
  vfstraceOnOff(pInfo, VTR_SHMMAP);
  vfstrace_printf(pInfo, "%s.xShmMap(%s,iRegion=%d,szRegion=%d,isWrite=%d,*)",
                  pInfo->zVfsName, p->zFName, iRegion, szRegion, isWrite);
  rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
  vfstrace_print_errcode(pInfo, " -> %s\n", rc);
  return rc;
}
static void vfstraceShmBarrier(sqlite3_file *pFile){
  vfstrace_file *p = (vfstrace_file *)pFile;
  vfstrace_info *pInfo = p->pInfo;
  vfstraceOnOff(pInfo, VTR_SHMBAR);
  vfstrace_printf(pInfo, "%s.xShmBarrier(%s)\n", pInfo->zVfsName, p->zFName);
  p->pReal->pMethods->xShmBarrier(p->pReal);
}
static int vfstraceShmUnmap(sqlite3_file *pFile, int delFlag){
  vfstrace_file *p = (vfstrace_file *)pFile;
  vfstrace_info *pInfo = p->pInfo;
  int rc;
  vfstraceOnOff(pInfo, VTR_SHMUNMAP);
  vfstrace_printf(pInfo, "%s.xShmUnmap(%s,delFlag=%d)",
                  pInfo->zVfsName, p->zFName, delFlag);
  rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
  vfstrace_print_errcode(pInfo, " -> %s\n", rc);
  return rc;
}

692
693
694
695
696
697
698

699
700
701
702
703
704
705
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875







+







  vfstrace_file *p = (vfstrace_file *)pFile;
  vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
  sqlite3_vfs *pRoot = pInfo->pRootVfs;
  p->pInfo = pInfo;
  p->zFName = zName ? fileTail(zName) : "<temp>";
  p->pReal = (sqlite3_file *)&p[1];
  rc = pRoot->xOpen(pRoot, zName, p->pReal, flags, pOutFlags);
  vfstraceOnOff(pInfo, VTR_OPEN);
  vfstrace_printf(pInfo, "%s.xOpen(%s,flags=0x%x)",
                  pInfo->zVfsName, p->zFName, flags);
  if( p->pReal->pMethods ){
    sqlite3_io_methods *pNew = sqlite3_malloc( sizeof(*pNew) );
    const sqlite3_io_methods *pSub = p->pReal->pMethods;
    memset(pNew, 0, sizeof(*pNew));
    pNew->iVersion = pSub->iVersion;
737
738
739
740
741
742
743

744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763

764
765
766
767
768
769
770
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942







+




















+







** ensure the file-system modifications are synced to disk before
** returning.
*/
static int vfstraceDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
  vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
  sqlite3_vfs *pRoot = pInfo->pRootVfs;
  int rc;
  vfstraceOnOff(pInfo, VTR_DELETE);
  vfstrace_printf(pInfo, "%s.xDelete(\"%s\",%d)",
                  pInfo->zVfsName, zPath, dirSync);
  rc = pRoot->xDelete(pRoot, zPath, dirSync);
  vfstrace_print_errcode(pInfo, " -> %s\n", rc);
  return rc;
}

/*
** Test for access permissions. Return true if the requested permission
** is available, or false otherwise.
*/
static int vfstraceAccess(
  sqlite3_vfs *pVfs, 
  const char *zPath, 
  int flags, 
  int *pResOut
){
  vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
  sqlite3_vfs *pRoot = pInfo->pRootVfs;
  int rc;
  vfstraceOnOff(pInfo, VTR_ACCESS);
  vfstrace_printf(pInfo, "%s.xAccess(\"%s\",%d)",
                  pInfo->zVfsName, zPath, flags);
  rc = pRoot->xAccess(pRoot, zPath, flags, pResOut);
  vfstrace_print_errcode(pInfo, " -> %s", rc);
  vfstrace_printf(pInfo, ", out=%d\n", *pResOut);
  return rc;
}
779
780
781
782
783
784
785

786
787
788
789
790
791
792
793
794
795
796
797
798
799

800
801
802
803
804
805
806
807
808
809
810
811

812
813
814
815
816
817
818
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993







+














+












+







  const char *zPath, 
  int nOut, 
  char *zOut
){
  vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
  sqlite3_vfs *pRoot = pInfo->pRootVfs;
  int rc;
  vfstraceOnOff(pInfo, VTR_FULLPATH);
  vfstrace_printf(pInfo, "%s.xFullPathname(\"%s\")",
                  pInfo->zVfsName, zPath);
  rc = pRoot->xFullPathname(pRoot, zPath, nOut, zOut);
  vfstrace_print_errcode(pInfo, " -> %s", rc);
  vfstrace_printf(pInfo, ", out=\"%.*s\"\n", nOut, zOut);
  return rc;
}

/*
** Open the dynamic library located at zPath and return a handle.
*/
static void *vfstraceDlOpen(sqlite3_vfs *pVfs, const char *zPath){
  vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
  sqlite3_vfs *pRoot = pInfo->pRootVfs;
  vfstraceOnOff(pInfo, VTR_DLOPEN);
  vfstrace_printf(pInfo, "%s.xDlOpen(\"%s\")\n", pInfo->zVfsName, zPath);
  return pRoot->xDlOpen(pRoot, zPath);
}

/*
** Populate the buffer zErrMsg (size nByte bytes) with a human readable
** utf-8 string describing the most recent error encountered associated 
** with dynamic libraries.
*/
static void vfstraceDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
  vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
  sqlite3_vfs *pRoot = pInfo->pRootVfs;
  vfstraceOnOff(pInfo, VTR_DLERR);
  vfstrace_printf(pInfo, "%s.xDlError(%d)", pInfo->zVfsName, nByte);
  pRoot->xDlError(pRoot, nByte, zErrMsg);
  vfstrace_printf(pInfo, " -> \"%s\"", zErrMsg);
}

/*
** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
826
827
828
829
830
831
832

833
834
835
836
837
838
839
840
841
842
843

844
845
846
847
848
849
850
851
852
853
854


855
856
857
858
859
860
861
862
863



864



865
866
867
868



869



870
871
872
873

874
875

876
877




878



879
880
881
882
883
884
885
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045

1046
1047
1048
1049
1050
1051
1052
1053
1054
1055

1056
1057
1058
1059
1060
1061

1062
1063

1064
1065
1066
1067
1068
1069
1070

1071
1072
1073
1074
1075
1076
1077
1078
1079
1080







+











+











+
+









+
+
+
-
+
+
+




+
+
+
-
+
+
+



-
+

-
+


+
+
+
+
-
+
+
+








/*
** 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.
*/
static int vfstraceRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
  vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
  sqlite3_vfs *pRoot = pInfo->pRootVfs;
  vfstraceOnOff(pInfo, VTR_RAND);
  vfstrace_printf(pInfo, "%s.xRandomness(%d)\n", pInfo->zVfsName, nByte);
  return pRoot->xRandomness(pRoot, nByte, zBufOut);
}

/*
** Sleep for nMicro microseconds. Return the number of microseconds 
** actually slept.
*/
static int vfstraceSleep(sqlite3_vfs *pVfs, int nMicro){
  vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
  sqlite3_vfs *pRoot = pInfo->pRootVfs;
  vfstraceOnOff(pInfo, VTR_SLEEP);
  vfstrace_printf(pInfo, "%s.xSleep(%d)\n", pInfo->zVfsName, nMicro);
  return pRoot->xSleep(pRoot, nMicro);
}

/*
** Return the current time as a Julian Day number in *pTimeOut.
*/
static int vfstraceCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
  vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
  sqlite3_vfs *pRoot = pInfo->pRootVfs;
  int rc;
  vfstraceOnOff(pInfo, VTR_CURTIME);
  vfstrace_printf(pInfo, "%s.xCurrentTime()", pInfo->zVfsName);
  return pRoot->xCurrentTime(pRoot, pTimeOut);
  rc = pRoot->xCurrentTime(pRoot, pTimeOut);
  vfstrace_printf(pInfo, " -> %.17g\n", *pTimeOut);
  return rc;
}
static int vfstraceCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
  vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
  sqlite3_vfs *pRoot = pInfo->pRootVfs;
  int rc;
  vfstraceOnOff(pInfo, VTR_CURTIME);
  vfstrace_printf(pInfo, "%s.xCurrentTimeInt64()", pInfo->zVfsName);
  return pRoot->xCurrentTimeInt64(pRoot, pTimeOut);
  rc = pRoot->xCurrentTimeInt64(pRoot, pTimeOut);
  vfstrace_printf(pInfo, " -> %lld\n", *pTimeOut);
  return rc;
}

/*
** Return th3 most recent error code and message
** Return the most recent error code and message
*/
static int vfstraceGetLastError(sqlite3_vfs *pVfs, int iErr, char *zErr){
static int vfstraceGetLastError(sqlite3_vfs *pVfs, int nErr, char *zErr){
  vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
  sqlite3_vfs *pRoot = pInfo->pRootVfs;
  int rc;
  vfstraceOnOff(pInfo, VTR_LASTERR);
  vfstrace_printf(pInfo, "%s.xGetLastError(%d,zBuf)", pInfo->zVfsName, nErr);
  if( nErr ) zErr[0] = 0;
  return pRoot->xGetLastError(pRoot, iErr, zErr);
  rc = pRoot->xGetLastError(pRoot, nErr, zErr);
  vfstrace_printf(pInfo, " -> zBuf[] = \"%s\", rc = %d\n", nErr?zErr:"", rc);
  return rc;
}

/*
** Override system calls.
*/
static int vfstraceSetSystemCall(
  sqlite3_vfs *pVfs,
965
966
967
968
969
970
971


972
973
974
975
976
977
978
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175







+
+







    }
  }
  pInfo->pRootVfs = pRoot;
  pInfo->xOut = xOut;
  pInfo->pOutArg = pOutArg;
  pInfo->zVfsName = pNew->zName;
  pInfo->pTraceVfs = pNew;
  pInfo->mTrace = 0xffffffff;
  pInfo->bOn = 1;
  vfstrace_printf(pInfo, "%s.enabled_for(\"%s\")\n",
       pInfo->zVfsName, pRoot->zName);
  return sqlite3_vfs_register(pNew, makeDefault);
}

/*
** Look for the named VFS.  If it is a TRACEVFS, then unregister it
Changes to ext/recover/recovercorrupt2.test.
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
521
522
523
524
525
526
527

528
529
530
531
532
533
534







-







do_test 7.1 {
  set R [sqlite3_recover_init db main test.db2]
  catch { $R run }
  list [catch { $R finish } msg] $msg
} {1 {file is not a database}}

reset_db
breakpoint
do_test 8.0 {
  sqlite3 db {}
  db deserialize [decode_hexdb {
| size 8192 pagesize 4096 filename db.sqlite
| page 1 offset 0
|      0: ac ae b3 76 74 65 20 66 6f 72 6d 61 74 20 33 00   ...vte format 3.
|     16: 10 00 01 01 00 40 20 20 00 00 00 01 00 00 00 02   .....@  ........
547
548
549
550
551
552
553
554





















































555
556
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608








+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


}]} {}

do_test 8.1 {
  set R [sqlite3_recover_init db main test.db2]
  catch { $R run }
  list [catch { $R finish } msg] $msg
} {0 {}}

reset_db
do_test 9.0 {
  sqlite3 db {}
  db deserialize [decode_hexdb {
| size 16384 pagesize 4096t 0
|      0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00   
|     16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 06   ........
|     32: 00 00 00 0r 00 00 00 00 00 00 00 06 00 00 00 04 ..
|     48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00   ........
|     96: 00 00 00 00 0d 00 00 00 06 0d e2 00 0f c4 0f 6a   .......j
|    112: 0e fc 0e 9d 0e 3d 0d e2 00 00 00 00 00 00 00 00  .
|   3552: 00 00 59 06 06 17 21 21 01 7f 74 61 62 6c 65 74   ..tablet
|   3568: 74 74 5f 63 6f 6e 66 69 67 74 74 74 5f 63 6f 6econ
|   3584: 66 69 67 06 43 52 45 41 54 45 20 54 41 42 4c 45   
|   3616: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 20 ) 
|   3632: 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5e 05 07   WOWID^..
|   3648: 17 23 23 01 81 03 74 61 62 6c 65 74 74 74 5f 6tt_d
|   3664: 6f 63 73 69 7a 65 74 74 74 5f 64 6f 63 73 69 7a  z
|   3680: 65 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 27   e.ABLE '
|   3696: 74 74 74 5f 64 6f 63 73 69 7a 65 27 28 69 64 20id 
|   3712: 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20   
|   3728: 4b 45 59 2c 20 73 7a 20 42 4c 4f 42 29 5d 04 07   KEYB)]..
|   3744: 17 23 23 01 81 B1 74 61 62 6c 65 74 74 74 5f 63 _c
|   3760: 6f 6e 74 65 6e 74 74 74 74 5f 63 6f 6e 74 65 6e   o_conten
|   3776: 7 04 01 03 00 011 54 45 20 54 41 42 4c 45 20 27   t.CRLE '
|   3792: 74 74 74 5f 63 6f 6e 74 65 6e 74 27 28 69 64 20   
|   3808: 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20   INIMARY 
|   3904: 6f 2c 20 50 52 49 4d 41 52 59 20 4b 45 59 28 7EY(s
|   3920: 65 67 69 64 2c 20 74 65 72 6d 29 29 20 57 49 54  T
|   3936: 48 4f 55 54 20 52 4f 57 49 4 58 58 02 07 17 1d 1d  ..
|   3952: 01 81 03 74 61 62 6c 65 74 74 74 5f 64 61 74 61   .tt_data
|   3968: 74 74 74 5f 64 61 74 61 02 43 52 45 41 54 45 2ATE 
|   3984: 54 41 42 4c 45 20 27 74 74 74 5f 64 61 74 61 27  '
|   4000: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d   (iR PRIM
|   4016: 41 52 59 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42k B
|   4032: 4c 4f 42 29 3a 01 06 17 13 13 08 5f 74 61 62 6c   
|   4048: 65 74 74 74 74 74 74 43 52 45 41 54 45 20 56 49   ettTE VI
|   4064: 52 54 55 41 4c 20 54 41 42 4c 45 20 74 74 74 20 t 
|   4080: 55 53 49 4e 47 20 66 74 73 35 28 61 2c 20 62 29   U5(a, b)
| page 4 offset 12288
|      0: 0a 00 00 00 03 0f ea 00 0f fa 0f f2 0f ea 00 00   ........
|   4064: 00 00 00 00 00 00 00 00 00 00 07 04 01 01 01 05 ..
|   4080: 06 03 07 04 01 01 01 03 04 02 05 04 09 01 09 02   ........
| end ro2.t
}]} {}

do_test 9.1 {
  set R [sqlite3_recover_init db main test.db2]
  catch { $R run }
  list [catch { $R finish } msg] $msg
} {0 {}}


finish_test

Changes to ext/recover/sqlite3recover.c.
1821
1822
1823
1824
1825
1826
1827


1828
1829
1830
1831
1832
1833
1834
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836







+
+







      }else if( iField<pTab->nCol ){
        assert( apVal[iField]==0 );
        apVal[iField] = sqlite3_value_dup( pVal );
        if( apVal[iField]==0 ){
          recoverError(p, SQLITE_NOMEM, 0);
        }
        p1->nVal = iField+1;
      }else if( pTab->nCol==0 ){
        p1->nVal = pTab->nCol;
      }
      p1->iPrevCell = iCell;
      p1->iPrevPage = iPage;
    }
  }else{
    recoverReset(p, pSel);
    p1->pTab = 0;
Changes to ext/wasm/tester1.c-pp.js.
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1244
1245
1246
1247
1248
1249
1250


1251
1252
1253
1254
1255
1256
1257







-
-







    })

  ////////////////////////////////////////////////////////////////////
    .t('DB.Stmt', function(sqlite3){
      let st = this.db.prepare(
        new TextEncoder('utf-8').encode("select 3 as a")
      );
      //debug("statement =",st);
      T.assert( !this.progressHandlerCount );
      let rc;
      try {
        T.assert(wasm.isPtr(st.pointer))
          .mustThrowMatching(()=>st.pointer=1, /read-only/)
          .assert(1===this.db.openStatementCount())
          .assert(
            capi.sqlite3_stmt_status(
Changes to main.mk.
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
14
15
16
17
18
19
20

21
22
23
24
25
26
27







-







#  dependency. That var, in GNU Make, lists all of the makefile
#  currently loaded.
#
# The variables listed below must be defined before this script is
# invoked. This file will use defaults, very possibly invalid, for any
# which are not defined.
########################################################################
.POSIX: #maintenance reminder: X:=Y is not POSIX-portable
all:
#
# $(TOP) =
#
# The toplevel directory of the source tree.  For canonical builds
# this is the directory that contains this "Makefile.in" and the
# "configure.in" script. For out-of-tree builds, this will differ
102
103
104
105
106
107
108



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123


124
125
126
127

128
129
130
131
132
133
134
135
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

125
126
127
128
129

130

131
132
133
134
135
136
137







+
+
+














-
+
+



-
+
-







# one is a bare-bones build for the configure process, whereas we need
# to build it with another option enabled for use with the various
# code generators.
#
# JIMSH requires a leading path component, even if it's ./, so that it
# can be used as a shell command.
#
# On Windows platforms, if -DHAVE_REALPATH does not work then try
# -DHAVE__FULLPATH (note the double-underscore).
#
CFLAGS.jimsh ?= -DHAVE_REALPATH
JIMSH ?= ./jimsh$(T.exe)
#
# $(B.tclsh) =
#
# The TCL interpreter for in-tree code generation. May be either the
# in-tree JimTCL ($(JIMSH)) or the canonical TCL ($(TCLSH_CMD). If
# it's JimTCL, it must be compiled with -DHAVE_REALPATH or
# -DHAVE__FULLPATH.
#
B.tclsh ?= $(JIMSH)

#
# Autotools-conventional vars which are (in this tree) used only by
# package installation rules.
# package installation rules and for generating sqlite3.pc (pkg-config
# data file).
#
# The following ${XYZdir} vars are provided for the sake of clients
# who expect to be able to override these using autotools-conventional
# dir name vars. In this build they apply only to installation-related
# dir name vars.
# rules.
#
prefix      ?= /usr/local
datadir     ?= $(prefix)/share
mandir      ?= $(datadir)/man
includedir  ?= $(prefix)/include
exec_prefix ?= $(prefix)
bindir      ?= $(exec_prefix)/bin
156
157
158
159
160
161
162
163

164
165


166
167
168
169
170
171
172
158
159
160
161
162
163
164

165
166

167
168
169
170
171
172
173
174
175







-
+

-
+
+







# to use the one(s) it needs.
#
LDFLAGS.zlib ?= -lz
LDFLAGS.math ?= -lm
LDFLAGS.rpath ?= -Wl,-rpath -Wl,$(prefix)/lib
LDFLAGS.pthread ?= -lpthread
LDFLAGS.dlopen ?= -ldl
LDFLAGS.shobj ?= -shared
LDFLAGS.shlib ?= -shared
LDFLAGS.icu ?= # -licui18n -licuuc -licudata
LDFLAGS.soname.libsqlite3 ?=
CFLAGS.icu ?=
LDFLAGS.libsqlite3.soname ?= # see https://sqlite.org/src/forumpost/5a3b44f510df8ded
# libreadline (or a workalike):
# To activate readline in the shell: SHELL_OPT = -DHAVE_READLINE=1
LDFLAGS.readline ?= -lreadline # these vary across platforms
CFLAGS.readline ?= -I$(prefix)/include
# ^^^ When using linenoise instead of readline, do something like:
# SHELL_OPT += -DHAVE_LINENOISE=1
# CFLAGS.readline = -I$(HOME)/linenoise $(HOME)/linenoise/linenoise.c
198
199
200
201
202
203
204


205
206














207
208
209
210
211
212
213
214
215
216
217
218
219



220

221
222
223
224





225
226
227
228




229
230
231
232
233
234
235
236
237
238
239
240



241
242
243
244
245
246
247
248



249
250
251
252
253
254
255
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237

238
239
240
241
242




243
244
245
246
247
248



249
250
251
252
253
254
255
256
257
258
259
260
261
262
263

264
265
266
267
268
269
270
271



272
273
274
275
276
277
278
279
280
281







+
+


+
+
+
+
+
+
+
+
+
+
+
+
+
+












-
+
+
+

+
-
-
-
-
+
+
+
+
+

-
-
-
+
+
+
+











-
+
+
+





-
-
-
+
+
+







#
ENABLE_STATIC ?= 1
#
# $(USE_AMALGAMATION)
#
# 1 if the amalgamation (sqlite3.c/h) should be built/used, otherwise
# the library is built from all of its original source files.
# Certaint tools, like sqlite3$(T.exe), require the amalgamation and
# will ignore this preference.
#
USE_AMALGAMATION ?= 1
#
# $(LINK_TOOLS_DYNAMICALLY)
#
# If 1, certain binaries which typically statically link against
# libsqlite3 or its component object files will instead link against
# the DLL. The caveat is that running such builds from the source tree
# may require that the user specifically prepend "." to their
# $LD_LIBRARY_PATH so that the dynamic linker does not pick up a
# libsqlite3.so from outside the source tree. Alternately, symlinking
# the in-build-tree $(libsqlite3.SO) to some dir in the system's
# library path will work for giving the apps access to the in-tree
# DLL.
#
LINK_TOOLS_DYNAMICALLY ?= 0
#
# $(AMALGAMATION_GEN_FLAGS) =
#
# Optional flags for the amalgamation generator.
#
AMALGAMATION_GEN_FLAGS ?= --linemacros=0
#
# $(OPT_FEATURE_FLAGS) =
#
# Preprocessor flags for enabling and disabling specific libsqlite3
# features (-DSQLITE_OMIT*, -DSQLITE_ENABLE*). The same set of OMIT
# and ENABLE flags must be passed to the LEMON parser generator and
# the mkkeywordhash tool as well.
# the mkkeywordhash tool as well. This is normally set by the
# configure process, and passing a custom value to a
# coonfigure-filtered Makefile may not work.
#
# When using the canonical makefile, add $(OPTIONS)=... on the make
# Add OPTIONS=... on the make command line to append additional options
# to the OPT_FEATURE_FLAGS. Note that some flags only work if the
# build is specifically configured to account for them. Adding them
# later, when compiling the amalgamation, may or may not work.
# command line to append additional options to the
# $(OPT_FEATURE_FLAGS). Note that some flags, because they influence
# generation of the SQL parser, only work if the build is specifically
# configured to account for them. Adding them later, when compiling
# the amalgamation separately, may or may not work.
#
# TO CLARIFY: OPTS=... has historically been expected in some
# contexts, and is distinctly different from OPTIONS and
# OPT_FEATURE_FLAGS, but its name is confusingly close to $(OPTIONS).
# $(OPTS)=... is another way of influencing C compilation. It is
# distinctly separate from $(OPTIONS) and $(OPT_FEATURE_FLAGS) but,
# like those, $(OPTS) applies to all invocations of $(T.cc). The
# configure process does not set either of $(OPTIONS) or $(OPTS).
#
OPT_FEATURE_FLAGS ?=
#
# $(SHELL_OPT) =
#
# CFLAGS specific to the sqlite3 CLI shell app and its close cousins.
#
SHELL_OPT ?=
#
# TCL_CONFIG_SH must, for some of the build targets, refer to a valid
# tclConfig.sh. That script will be used to populate most of the other
# TCL-related vars the build needs.
# TCL-related vars the build needs. The core library does not require
# TCL, but TCL is needed for running tests and certain tools, e.g.
# sqlite3_analyzer.
#
TCL_CONFIG_SH ?=
#
# $(HAVE_WASI_SDK) =
#
# 1 when building with the WASI SDK. This disables certain build
# targets. It is expected that the invoker assigns CC to the wasi-sdk
# CC.
# Set to 1 when building with the WASI SDK. This disables certain
# build targets. It is expected that the invoker sets $(CC), $(LD),
# and $(AR) to their counterparts from the wasi-sdk.
#
HAVE_WASI_SDK ?= 0
#
# ... and many, many more. Sane defaults are selected where possible.
#
# With the above-described defined, the rest of this make script will
# build the project's deliverables and testing tools.
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
323
324
325
326
327
328
329

330

331
332
333
334
335


336
337
338
339
340
341
342
343

344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361






362
363
364
365
366
367
368







-
+
-





-
-
+
+






-
+

















-
-
-
-
-
-







# variable name to be stable, so do not rely on that capability!)
#
# A significant difference from the legacy build:
#
# The legacy build applied such LDFLAGS to all link operations for all
# deliverables. The 3.48+ build applies them (as of this writing) more
# selectively: search this file LDFLAGS.configure to see where they're
# set. As of this writing, they only affect targets which use
# set.
# $(LDFLAGS.libsqlite3) - see that var's docs for details.
#
LDFLAGS.configure ?=

#
# The difference between $(OPT_FEATURE_FLAGS) and $(OPTS) is that the
# former is historically provided by the configure script, whereas the
# latter is intended to be provided as arguments to the make
# former is historically provided by the configure script, whereas
# $(OPTS) is intended to be provided as arguments to the make
# invocation.
#
T.cc += $(OPT_FEATURE_FLAGS)

#
# Add in any optional global compilation flags on the make command
# line ie.  make "OPTS=-DSQLITE_ENABLE_FOO=1 -DSQLITE_OMIT_FOO=1".
# line i.e.  make "OPTS=-DSQLITE_ENABLE_FOO=1 -DSQLITE_OMIT_FOO=1".
#
T.cc += $(OPTS)

#
# $(INSTALL) invocation for use with non-executable files.
#
INSTALL.noexec = $(INSTALL) -m 0644
# ^^^ do not use GNU-specific flags to $(INSTALL), e.g. --mode=...

#
# $(T.compile) = generic target platform compiler invocation,
# differing only from $(T.cc) in that it appends $(T.compile.extras),
# which are primarily intended for use with gcov-related flags.
#
T.compile = $(T.cc) $(T.compile.extras)

#
# $(CFLAGS.libsqlite3) must contain any CFLAGS which are relevant for
# compiling the library's own sources, including (sometimes) when
# compiling sqlite3.c directly in to another app.
#
CFLAGS.libsqlite3 ?=
#
# $(T.cc.sqlite) is $(T.cc) plus any flags which are desired for the
# library as a whole, but not necessarily needed for every binary. It
# will normally get initially populated with flags by the
# configure-generated makefile.
#
T.cc.sqlite ?= $(T.cc)

370
371
372
373
374
375
376
377

378
379
380
381
382
383
384
389
390
391
392
393
394
395

396
397
398
399
400
401
402
403







-
+







# $(T.link.extras) = optional config-specific flags for $(T.link),
# primarily intended for use with gcov-related flags.
#
T.link = $(T.cc.sqlite) $(T.link.extras)
#
# $(T.link.shared) = $(T.link) invocation specifically for shared libraries
#
T.link.shared = $(T.link) $(LDFLAGS.shobj)
T.link.shared = $(T.link) $(LDFLAGS.shlib)

#
# $(LDFLAGS.libsqlite3) should be used with any deliverable for which
# any of the following apply:
#
#  - Results in building libsqlite3.so
#  - Compiles sqlite3.c in to an application
889
890
891
892
893
894
895



896
897
898
899
900
901
902
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924







+
+
+







# Standard options to testfixture
#
TESTOPTS = --verbose=file --output=test-out.txt

#
# Extra compiler options for various shell tools
#
# Note that some of these will only apply when embedding sqlite3.c
# into the shell, as these flags are not otherwise passed on to the
# library.
SHELL_OPT += -DSQLITE_DQS=0
SHELL_OPT += -DSQLITE_ENABLE_FTS4
#SHELL_OPT += -DSQLITE_ENABLE_FTS5
SHELL_OPT += -DSQLITE_ENABLE_RTREE
SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
974
975
976
977
978
979
980
981

982
983
984
985


986
987
988
989
990
991
992
993
994


995
996
997
998
999
1000
1001
996
997
998
999
1000
1001
1002

1003
1004
1005


1006
1007
1008
1009
1010
1011
1012
1013
1014


1015
1016
1017
1018
1019
1020
1021
1022
1023







-
+


-
-
+
+







-
-
+
+







#
#   . .tclenv.sh    ==> .tclenv.sh: not found
#   . ./.tclenv.sh  ==> fine
#
# It took half an hour to figure that out.
#
T.tcl.env.sh = ./.tclenv.sh
$(T.tcl.env.sh): $(TCLSH_CMD) $(TCL_CONFIG_SH) $(MAKEFILE_LIST) config.log
$(T.tcl.env.sh): $(TCLSH_CMD) $(TCL_CONFIG_SH) $(MAKEFILE_LIST)
	@if [ x = "x$(TCL_CONFIG_SH)" ]; then \
		echo 'TCL_CONFIG_SH must be set to point to a "tclConfig.sh"' 1>&2; exit 1; \
	fi
	@if [ x != "x$(TCLLIBDIR)" ]; then echo TCLLIBDIR="$(TCLLIBDIR)"; else \
	fi; \
	if [ x != "x$(TCLLIBDIR)" ]; then echo TCLLIBDIR="$(TCLLIBDIR)"; else \
		ld= ; \
		for d in `echo "puts stdout \\$$auto_path" | $(TCLSH_CMD)`; do \
			if [ -d "$$d" ]; then ld=$$d; break; fi; \
		done; \
		if [ x = "x$$ld" ]; then echo "Cannot determine TCLLIBDIR" 1>&2; exit 1; fi; \
		echo "TCLLIBDIR=$$ld/sqlite3"; \
	fi > $@; \
	echo ". \"$(TCL_CONFIG_SH)\" || exit \$$?" >> $@
	@echo "Created $@"
	echo ". \"$(TCL_CONFIG_SH)\" || exit \$$?" >> $@; \
	echo "Created $@"

#
# $(T.tcl.env.source) is shell code to be run as part of any
# compilation or link step which requires vars from
# $(TCL_CONFIG_SH). All targets which use this should also have a
# dependency on $(T.tcl.env.sh).
#
1013
1014
1015
1016
1017
1018
1019
1020

1021
1022
1023
1024
1025
1026
1027
1035
1036
1037
1038
1039
1040
1041

1042
1043
1044
1045
1046
1047
1048
1049







-
+







# This target creates a directory named "tsrc" and fills it with
# copies of all of the C source code and header files needed to
# build on the target system.  Some of the C source code and header
# files are automatically generated.  This target takes care of
# all that automatic generation.
#
.target_source: $(MAKE_SANITY_CHECK) $(SRC) $(TOP)/tool/vdbe-compress.tcl \
    fts5.c $(B.tclsh) # has_tclsh84
    fts5.c $(B.tclsh)
	rm -rf tsrc
	mkdir tsrc
	cp -f $(SRC) tsrc
	rm tsrc/sqlite.h.in tsrc/parse.y
	$(B.tclsh) $(TOP)/tool/vdbe-compress.tcl $(OPTS) <tsrc/vdbe.c >vdbe.new
	mv vdbe.new tsrc/vdbe.c
	cp fts5.c fts5.h tsrc
1039
1040
1041
1042
1043
1044
1045
1046

1047
1048
1049
1050

1051
1052
1053
1054
1055

1056
1057
1058

1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075

1076
1077
1078

1079
1080
1081
1082
1083

1084
1085
1086

1087
1088
1089

1090
1091
1092

1093
1094
1095

1096
1097
1098

1099
1100
1101

1102
1103
1104

1105
1106
1107

1108
1109
1110

1111
1112
1113

1114
1115
1116

1117
1118
1119

1120
1121
1122

1123
1124
1125

1126
1127
1128

1129
1130
1131

1132
1133
1134

1135
1136
1137

1138
1139
1140

1141
1142
1143

1144
1145
1146

1147
1148
1149

1150
1151
1152

1153
1154
1155

1156
1157
1158

1159
1160
1161

1162
1163
1164

1165
1166
1167

1168
1169
1170

1171
1172
1173

1174
1175
1176

1177
1178
1179

1180
1181
1182

1183
1184
1185

1186
1187
1188

1189
1190
1191

1192
1193
1194

1195
1196
1197

1198
1199
1200

1201
1202
1203

1204
1205
1206

1207
1208
1209

1210
1211
1212

1213
1214
1215

1216
1217
1218

1219
1220
1221

1222
1223
1224

1225
1226
1227

1228
1229
1230

1231
1232
1233

1234
1235
1236

1237
1238
1239

1240
1241
1242

1243
1244
1245

1246
1247
1248

1249
1250
1251

1252
1253
1254

1255
1256
1257

1258
1259
1260

1261
1262
1263

1264
1265
1266

1267
1268
1269

1270
1271
1272

1273
1274
1275

1276
1277
1278

1279
1280
1281

1282
1283
1284

1285
1286
1287

1288
1289
1290

1291
1292
1293

1294
1295
1296

1297
1298
1299

1300
1301
1302

1303
1304
1305

1306
1307
1308

1309
1310
1311

1312
1313
1314

1315
1316
1317

1318
1319
1320

1321
1322
1323

1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338





1339
1340
1341
1342

1343
1344
1345
1346

1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357

1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371

1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388


1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400


1401

1402







1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421






1422
1423
1424

1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436

1437
1438

1439
1440
1441
1442
1443




1444
1445

1446
1447
1448
1449
1450
1451




1452
1453
1454

1455
1456
1457
1458
1459
1460
1461
1061
1062
1063
1064
1065
1066
1067

1068
1069
1070
1071

1072
1073
1074
1075
1076

1077
1078
1079

1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096

1097
1098
1099

1100
1101
1102
1103
1104

1105
1106
1107

1108
1109
1110

1111
1112
1113

1114
1115
1116

1117
1118
1119

1120
1121
1122

1123
1124
1125

1126
1127
1128

1129
1130
1131

1132
1133
1134

1135
1136
1137

1138
1139
1140

1141
1142
1143

1144
1145
1146

1147
1148
1149

1150
1151
1152

1153
1154
1155

1156
1157
1158

1159
1160
1161

1162
1163
1164

1165
1166
1167

1168
1169
1170

1171
1172
1173

1174
1175
1176

1177
1178
1179

1180
1181
1182

1183
1184
1185

1186
1187
1188

1189
1190
1191

1192
1193
1194

1195
1196
1197

1198
1199
1200

1201
1202
1203

1204
1205
1206

1207
1208
1209

1210
1211
1212

1213
1214
1215

1216
1217
1218

1219
1220
1221

1222
1223
1224

1225
1226
1227

1228
1229
1230

1231
1232
1233

1234
1235
1236

1237
1238
1239

1240
1241
1242

1243
1244
1245

1246
1247
1248

1249
1250
1251

1252
1253
1254

1255
1256
1257

1258
1259
1260

1261
1262
1263

1264
1265
1266

1267
1268
1269

1270
1271
1272

1273
1274
1275

1276
1277
1278

1279
1280
1281

1282
1283
1284

1285
1286
1287

1288
1289
1290

1291
1292
1293

1294
1295
1296

1297
1298
1299

1300
1301
1302

1303
1304
1305

1306
1307
1308

1309
1310
1311

1312
1313
1314

1315
1316
1317

1318
1319
1320

1321
1322
1323

1324
1325
1326

1327
1328
1329

1330
1331
1332

1333
1334
1335

1336
1337
1338

1339
1340
1341

1342
1343
1344

1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358


1359
1360
1361
1362
1363
1364
1365
1366

1367
1368
1369
1370

1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381

1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395

1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412

1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424


1425
1426
1427
1428

1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448






1449
1450
1451
1452
1453
1454

1455

1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467

1468
1469

1470
1471




1472
1473
1474
1475
1476

1477

1478




1479
1480
1481
1482

1483

1484
1485
1486
1487
1488
1489
1490
1491







-
+



-
+




-
+


-
+
















-
+


-
+




-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+


-
+













-
-
+
+
+
+
+



-
+



-
+










-
+













-
+
















-
+
+










-
-
+
+

+
-
+
+
+
+
+
+
+













-
-
-
-
-
-
+
+
+
+
+
+
-

-
+











-
+

-
+

-
-
-
-
+
+
+
+

-
+
-

-
-
-
-
+
+
+
+
-

-
+







# Rules to build the program that generates the source-id
#
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) # has_tclsh84
		$(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) # has_tclsh84
		$(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) # has_tclsh84
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) # has_tclsh84
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)

sqlite3ext.h: .target_source
	cp tsrc/sqlite3ext.h .

# Rules to build individual *.o files from generated *.c files. This
# applies to:
#
#     parse.o
#     opcodes.o
#
DEPS_OBJ_COMMON = $(MAKE_SANITY_CHECK) $(HDR)
parse.o:	parse.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c parse.c
	$(T.cc.sqlite) -c parse.c

opcodes.o:	opcodes.c
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c opcodes.c
	$(T.cc.sqlite) -c opcodes.c

# Rules to build individual *.o files from files in the src directory.
#
alter.o:	$(TOP)/src/alter.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/alter.c
	$(T.cc.sqlite) -c $(TOP)/src/alter.c

analyze.o:	$(TOP)/src/analyze.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/analyze.c
	$(T.cc.sqlite) -c $(TOP)/src/analyze.c

attach.o:	$(TOP)/src/attach.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/attach.c
	$(T.cc.sqlite) -c $(TOP)/src/attach.c

auth.o:	$(TOP)/src/auth.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/auth.c
	$(T.cc.sqlite) -c $(TOP)/src/auth.c

backup.o:	$(TOP)/src/backup.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/backup.c
	$(T.cc.sqlite) -c $(TOP)/src/backup.c

bitvec.o:	$(TOP)/src/bitvec.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/bitvec.c
	$(T.cc.sqlite) -c $(TOP)/src/bitvec.c

btmutex.o:	$(TOP)/src/btmutex.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/btmutex.c
	$(T.cc.sqlite) -c $(TOP)/src/btmutex.c

btree.o:	$(TOP)/src/btree.c $(DEPS_OBJ_COMMON) $(TOP)/src/pager.h
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/btree.c
	$(T.cc.sqlite) -c $(TOP)/src/btree.c

build.o:	$(TOP)/src/build.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/build.c
	$(T.cc.sqlite) -c $(TOP)/src/build.c

callback.o:	$(TOP)/src/callback.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/callback.c
	$(T.cc.sqlite) -c $(TOP)/src/callback.c

complete.o:	$(TOP)/src/complete.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/complete.c
	$(T.cc.sqlite) -c $(TOP)/src/complete.c

ctime.o:	$(TOP)/src/ctime.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/ctime.c
	$(T.cc.sqlite) -c $(TOP)/src/ctime.c

date.o:	$(TOP)/src/date.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/date.c
	$(T.cc.sqlite) -c $(TOP)/src/date.c

dbpage.o:	$(TOP)/src/dbpage.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/dbpage.c
	$(T.cc.sqlite) -c $(TOP)/src/dbpage.c

dbstat.o:	$(TOP)/src/dbstat.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/dbstat.c
	$(T.cc.sqlite) -c $(TOP)/src/dbstat.c

delete.o:	$(TOP)/src/delete.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/delete.c
	$(T.cc.sqlite) -c $(TOP)/src/delete.c

expr.o:	$(TOP)/src/expr.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/expr.c
	$(T.cc.sqlite) -c $(TOP)/src/expr.c

fault.o:	$(TOP)/src/fault.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/fault.c
	$(T.cc.sqlite) -c $(TOP)/src/fault.c

fkey.o:	$(TOP)/src/fkey.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/fkey.c
	$(T.cc.sqlite) -c $(TOP)/src/fkey.c

func.o:	$(TOP)/src/func.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/func.c
	$(T.cc.sqlite) -c $(TOP)/src/func.c

global.o:	$(TOP)/src/global.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/global.c
	$(T.cc.sqlite) -c $(TOP)/src/global.c

hash.o:	$(TOP)/src/hash.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/hash.c
	$(T.cc.sqlite) -c $(TOP)/src/hash.c

insert.o:	$(TOP)/src/insert.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/insert.c
	$(T.cc.sqlite) -c $(TOP)/src/insert.c

json.o:	$(TOP)/src/json.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/json.c
	$(T.cc.sqlite) -c $(TOP)/src/json.c

legacy.o:	$(TOP)/src/legacy.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/legacy.c
	$(T.cc.sqlite) -c $(TOP)/src/legacy.c

loadext.o:	$(TOP)/src/loadext.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/loadext.c
	$(T.cc.sqlite) -c $(TOP)/src/loadext.c

main.o:	$(TOP)/src/main.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/main.c
	$(T.cc.sqlite) -c $(TOP)/src/main.c

malloc.o:	$(TOP)/src/malloc.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/malloc.c
	$(T.cc.sqlite) -c $(TOP)/src/malloc.c

mem0.o:	$(TOP)/src/mem0.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/mem0.c
	$(T.cc.sqlite) -c $(TOP)/src/mem0.c

mem1.o:	$(TOP)/src/mem1.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/mem1.c
	$(T.cc.sqlite) -c $(TOP)/src/mem1.c

mem2.o:	$(TOP)/src/mem2.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/mem2.c
	$(T.cc.sqlite) -c $(TOP)/src/mem2.c

mem3.o:	$(TOP)/src/mem3.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/mem3.c
	$(T.cc.sqlite) -c $(TOP)/src/mem3.c

mem5.o:	$(TOP)/src/mem5.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/mem5.c
	$(T.cc.sqlite) -c $(TOP)/src/mem5.c

memdb.o:	$(TOP)/src/memdb.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/memdb.c
	$(T.cc.sqlite) -c $(TOP)/src/memdb.c

memjournal.o:	$(TOP)/src/memjournal.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/memjournal.c
	$(T.cc.sqlite) -c $(TOP)/src/memjournal.c

mutex.o:	$(TOP)/src/mutex.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/mutex.c
	$(T.cc.sqlite) -c $(TOP)/src/mutex.c

mutex_noop.o:	$(TOP)/src/mutex_noop.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/mutex_noop.c
	$(T.cc.sqlite) -c $(TOP)/src/mutex_noop.c

mutex_unix.o:	$(TOP)/src/mutex_unix.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/mutex_unix.c
	$(T.cc.sqlite) -c $(TOP)/src/mutex_unix.c

mutex_w32.o:	$(TOP)/src/mutex_w32.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/mutex_w32.c
	$(T.cc.sqlite) -c $(TOP)/src/mutex_w32.c

notify.o:	$(TOP)/src/notify.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/notify.c
	$(T.cc.sqlite) -c $(TOP)/src/notify.c

pager.o:	$(TOP)/src/pager.c $(DEPS_OBJ_COMMON) $(TOP)/src/pager.h
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/pager.c
	$(T.cc.sqlite) -c $(TOP)/src/pager.c

pcache.o:	$(TOP)/src/pcache.c $(DEPS_OBJ_COMMON) $(TOP)/src/pcache.h
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/pcache.c
	$(T.cc.sqlite) -c $(TOP)/src/pcache.c

pcache1.o:	$(TOP)/src/pcache1.c $(DEPS_OBJ_COMMON) $(TOP)/src/pcache.h
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/pcache1.c
	$(T.cc.sqlite) -c $(TOP)/src/pcache1.c

os.o:	$(TOP)/src/os.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/os.c
	$(T.cc.sqlite) -c $(TOP)/src/os.c

os_kv.o:	$(TOP)/src/os_kv.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/os_kv.c
	$(T.cc.sqlite) -c $(TOP)/src/os_kv.c

os_unix.o:	$(TOP)/src/os_unix.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/os_unix.c
	$(T.cc.sqlite) -c $(TOP)/src/os_unix.c

os_win.o:	$(TOP)/src/os_win.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/os_win.c
	$(T.cc.sqlite) -c $(TOP)/src/os_win.c

pragma.o:	$(TOP)/src/pragma.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/pragma.c
	$(T.cc.sqlite) -c $(TOP)/src/pragma.c

prepare.o:	$(TOP)/src/prepare.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/prepare.c
	$(T.cc.sqlite) -c $(TOP)/src/prepare.c

printf.o:	$(TOP)/src/printf.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/printf.c
	$(T.cc.sqlite) -c $(TOP)/src/printf.c

random.o:	$(TOP)/src/random.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/random.c
	$(T.cc.sqlite) -c $(TOP)/src/random.c

resolve.o:	$(TOP)/src/resolve.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/resolve.c
	$(T.cc.sqlite) -c $(TOP)/src/resolve.c

rowset.o:	$(TOP)/src/rowset.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/rowset.c
	$(T.cc.sqlite) -c $(TOP)/src/rowset.c

select.o:	$(TOP)/src/select.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/select.c
	$(T.cc.sqlite) -c $(TOP)/src/select.c

status.o:	$(TOP)/src/status.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/status.c
	$(T.cc.sqlite) -c $(TOP)/src/status.c

sqlite3.o:	sqlite3.h sqlite3.c
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c sqlite3.c
	$(T.cc.sqlite) -c sqlite3.c

table.o:	$(TOP)/src/table.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/table.c
	$(T.cc.sqlite) -c $(TOP)/src/table.c

threads.o:	$(TOP)/src/threads.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/threads.c
	$(T.cc.sqlite) -c $(TOP)/src/threads.c

tokenize.o:	$(TOP)/src/tokenize.c keywordhash.h $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/tokenize.c
	$(T.cc.sqlite) -c $(TOP)/src/tokenize.c

treeview.o:	$(TOP)/src/treeview.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/treeview.c
	$(T.cc.sqlite) -c $(TOP)/src/treeview.c

trigger.o:	$(TOP)/src/trigger.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/trigger.c
	$(T.cc.sqlite) -c $(TOP)/src/trigger.c

update.o:	$(TOP)/src/update.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/update.c
	$(T.cc.sqlite) -c $(TOP)/src/update.c

upsert.o:	$(TOP)/src/upsert.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/upsert.c
	$(T.cc.sqlite) -c $(TOP)/src/upsert.c

utf.o:	$(TOP)/src/utf.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/utf.c
	$(T.cc.sqlite) -c $(TOP)/src/utf.c

util.o:	$(TOP)/src/util.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/util.c
	$(T.cc.sqlite) -c $(TOP)/src/util.c

vacuum.o:	$(TOP)/src/vacuum.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/vacuum.c
	$(T.cc.sqlite) -c $(TOP)/src/vacuum.c

vdbe.o:	$(TOP)/src/vdbe.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/vdbe.c
	$(T.cc.sqlite) -c $(TOP)/src/vdbe.c

vdbeapi.o:	$(TOP)/src/vdbeapi.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/vdbeapi.c
	$(T.cc.sqlite) -c $(TOP)/src/vdbeapi.c

vdbeaux.o:	$(TOP)/src/vdbeaux.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/vdbeaux.c
	$(T.cc.sqlite) -c $(TOP)/src/vdbeaux.c

vdbeblob.o:	$(TOP)/src/vdbeblob.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/vdbeblob.c
	$(T.cc.sqlite) -c $(TOP)/src/vdbeblob.c

vdbemem.o:	$(TOP)/src/vdbemem.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/vdbemem.c
	$(T.cc.sqlite) -c $(TOP)/src/vdbemem.c

vdbesort.o:	$(TOP)/src/vdbesort.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/vdbesort.c
	$(T.cc.sqlite) -c $(TOP)/src/vdbesort.c

vdbetrace.o:	$(TOP)/src/vdbetrace.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/vdbetrace.c
	$(T.cc.sqlite) -c $(TOP)/src/vdbetrace.c

vdbevtab.o:	$(TOP)/src/vdbevtab.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/vdbevtab.c
	$(T.cc.sqlite) -c $(TOP)/src/vdbevtab.c

vtab.o:	$(TOP)/src/vtab.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/vtab.c
	$(T.cc.sqlite) -c $(TOP)/src/vtab.c

wal.o:	$(TOP)/src/wal.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/wal.c
	$(T.cc.sqlite) -c $(TOP)/src/wal.c

walker.o:	$(TOP)/src/walker.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/walker.c
	$(T.cc.sqlite) -c $(TOP)/src/walker.c

where.o:	$(TOP)/src/where.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/where.c
	$(T.cc.sqlite) -c $(TOP)/src/where.c

wherecode.o:	$(TOP)/src/wherecode.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/wherecode.c
	$(T.cc.sqlite) -c $(TOP)/src/wherecode.c

whereexpr.o:	$(TOP)/src/whereexpr.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/whereexpr.c
	$(T.cc.sqlite) -c $(TOP)/src/whereexpr.c

window.o:	$(TOP)/src/window.c $(DEPS_OBJ_COMMON)
	$(T.cc.sqlite) $(CFLAGS.libsqlite3) -c $(TOP)/src/window.c
	$(T.cc.sqlite) -c $(TOP)/src/window.c

tclsqlite.o:	$(T.tcl.env.sh) $(TOP)/src/tclsqlite.c $(DEPS_OBJ_COMMON)
	$(T.compile.tcl) -DUSE_TCL_STUBS=1 $$TCL_INCLUDE_SPEC \
		-c $(TOP)/src/tclsqlite.c

tclsqlite-shell.o:	$(T.tcl.env.sh) $(TOP)/src/tclsqlite.c $(DEPS_OBJ_COMMON)
	$(T.compile.tcl) -DTCLSH -o $@ -c $(TOP)/src/tclsqlite.c $$TCL_INCLUDE_SPEC

tclsqlite-stubs.o:	$(T.tcl.env.sh) $(TOP)/src/tclsqlite.c $(DEPS_OBJ_COMMON)
	$(T.compile.tcl) -DUSE_TCL_STUBS=1 -o $@ -c $(TOP)/src/tclsqlite.c $$TCL_INCLUDE_SPEC

tclsqlite3$(T.exe):	$(T.tcl.env.sh) tclsqlite-shell.o $(libsqlite3.SO)
	$(T.link.tcl) -o $@ tclsqlite-shell.o \
		 $(libsqlite3.SO) $$TCL_INCLUDE_SPEC $$TCL_LIB_SPEC $(LDFLAGS.libsqlite3)
tcl: tclsqlite3$(T.exe)
		$(libsqlite3.SO) $$TCL_INCLUDE_SPEC $$TCL_LIB_SPEC \
		$(LDFLAGS.libsqlite3)
tclsqlite3$(T.exe)-1: tclsqlite3$(T.exe)
tclsqlite3$(T.exe)-0 tclsqlite3$(T.exe)-:
tcl: tclsqlite3$(T.exe)-$(HAVE_TCL)

# Rules to build opcodes.c and opcodes.h
#
opcodes.c:	opcodes.h $(TOP)/tool/mkopcodec.tcl $(B.tclsh) # has_tclsh84
opcodes.c:	opcodes.h $(TOP)/tool/mkopcodec.tcl $(B.tclsh)
	$(B.tclsh) $(TOP)/tool/mkopcodec.tcl opcodes.h >opcodes.c

opcodes.h:	parse.h $(TOP)/src/vdbe.c \
		$(TOP)/tool/mkopcodeh.tcl $(B.tclsh) # has_tclsh84
		$(TOP)/tool/mkopcodeh.tcl $(B.tclsh)
	cat parse.h $(TOP)/src/vdbe.c | $(B.tclsh) $(TOP)/tool/mkopcodeh.tcl >opcodes.h

# Rules to build parse.c and parse.h - the outputs of lemon.
#
parse.h:	parse.c

parse.c:	$(TOP)/src/parse.y lemon$(B.exe)
	cp $(TOP)/src/parse.y .
	./lemon$(B.exe) $(OPT_FEATURE_FLAGS) $(OPTS) -S parse.y

sqlite3rc.h:	$(TOP)/src/sqlite3.rc $(TOP)/VERSION $(B.tclsh) # has_tclsh84
sqlite3rc.h:	$(TOP)/src/sqlite3.rc $(TOP)/VERSION $(B.tclsh)
	echo '#ifndef SQLITE_RESOURCE_VERSION' >$@
	echo -n '#define SQLITE_RESOURCE_VERSION ' >>$@
	cat $(TOP)/VERSION | $(B.tclsh) $(TOP)/tool/replace.tcl exact . , >>$@
	echo '#endif' >>sqlite3rc.h

mkkeywordhash$(B.exe): $(TOP)/tool/mkkeywordhash.c
	$(B.cc) -o $@ $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)/tool/mkkeywordhash.c
keywordhash.h:	mkkeywordhash$(B.exe)
	./mkkeywordhash$(B.exe) > $@

#
# sqlite3.c split into many smaller files.
#
sqlite3-all.c:	sqlite3.c $(TOP)/tool/split-sqlite3c.tcl $(B.tclsh) # has_tclsh84
sqlite3-all.c:	sqlite3.c $(TOP)/tool/split-sqlite3c.tcl $(B.tclsh)
	$(B.tclsh) $(TOP)/tool/split-sqlite3c.tcl

#
# Static libsqlite3
#
$(libsqlite3.LIB): $(LIBOBJ)
	$(AR) $(AR.flags) $@ $(LIBOBJ)
$(libsqlite3.LIB)-1: $(libsqlite3.LIB)
$(libsqlite3.LIB)-0 $(libsqlite3.LIB)-:
lib: $(libsqlite3.LIB)-$(ENABLE_STATIC)
all: lib

#
# Dynamic libsqlite3
#
$(libsqlite3.SO):	$(LIBOBJ)
	$(T.link.shared) -o $@ $(LIBOBJ) $(LDFLAGS.soname.libsqlite3) $(LDFLAGS.libsqlite3)
	$(T.link.shared) -o $@ $(LIBOBJ) $(LDFLAGS.libsqlite3) \
		$(LDFLAGS.libsqlite3.soname)
$(libsqlite3.SO)-1: $(libsqlite3.SO)
$(libsqlite3.SO)-0 $(libsqlite3.SO)-:
so: $(libsqlite3.SO)-$(ENABLE_SHARED)
all: so

#
# Install the $(libsqlite3.SO) as $(libsqlite3.SO).$(PACKAGE_VERSION)
# and create symlinks which point to it:
#
# - libsqlite3.so.$(PACKAGE_VERSION)
# - libsqlite3.so.3 =symlink-> libsqlite3.so.$(PACKAGE_VERSION)
# - libsqlite3.so   =symlink-> libsqlite3.so.3
# - libsqlite3.so.0      =symlink-> libsqlite3.so.$(PACKAGE_VERSION) (see below)
# - libsqlite3.so        =symlink-> libsqlite3.so.3
#
# N.B. we initially had a link named libsqlite3.so.3 but it's
# Regarding the historcal installation name of libsqlite3.so.0.8.6:
# unnecessary unless we want to set SONAME to libsqlite3.so.3, which
# is also unnecessary.
#
# The link named libsqlite3.so.0 is provided in an attempt to reduce
# downstream disruption when performing upgrades from pre-3.48 to a
# version 3.48 or higher.  That name is considered a legacy remnant
# and will eventually be removed from this installation process.
#
# Historically libtool installed the library like so:
#
#  libsqlite3.so     -> libsqlite3.so.0.8.6
#  libsqlite3.so.0   -> libsqlite3.so.0.8.6
#  libsqlite3.so.0.8.6
#
# The historical SQLite build always used a version number of 0.8.6
# for reasons lost to history but having something to do with libtool
# (which is no longer used in this tree). In order to retain filename
# compatibility for systems which have libraries installed using those
# conventions:
#
# 1) If libsqlite3.so.0 is found in the target installation directory
#    then it and libsqlite3.so.0.8.6 are re-linked to point to the
#    newer-style names. We cannot retain both the old and new
#    installation because they both share the high-level name
#    $(libsqlite3.SO). The down-side of this is that it may well upset
#    packaging tools when we replace libsqlite3.so (from a legacy
# 1) If libsqlite3.so.0.8.6 is found in the target installation
#    directory then it is re-linked to point to the newer-style
#    names. We cannot retain both the old and new installation because
#    they both share the high-level name $(libsqlite3.SO). The
#    down-side of this is that it may upset packaging tools when we
#    replace libsqlite3.so (from a legacy package) with a new symlink.
#    package) with a new symlink.
#
# 2) If INSTALL_SO_086_LINKS=1 and point (1) does not apply then links
# 2) If INSTALL_SO_086_LINK=1 and point (1) does not apply then links
#    to the legacy-style names are created. The primary intent of this
#    is to enable chains of operations such as the hypothetical (apt
#    remove sqlite3-3.47.0 && apt install sqlite3-3.48.0). In such
#    cases, condition (1) would never trigger but applications might
#    still expect to see the legacy file names.
#
# In either case, libsqlite3.la, if found, is deleted because it would
# contain stale state, refering to non-libtool-generated libraries.
#
install-so-1: $(install-dir.lib) $(libsqlite3.SO)
	$(INSTALL) $(libsqlite3.SO) "$(install-dir.lib)"
	@echo "Setting up SO symlinks..."; \
	@echo "Setting up $(libsqlite3.SO) symlinks..."; \
		cd "$(install-dir.lib)" || exit $$?; \
		rm -f $(libsqlite3.SO).3 $(libsqlite3.SO).$(PACKAGE_VERSION) || exit $$?; \
		rm -f $(libsqlite3.SO).0 $(libsqlite3.SO).$(PACKAGE_VERSION) || exit $$?; \
		mv $(libsqlite3.SO) $(libsqlite3.SO).$(PACKAGE_VERSION) || exit $$?; \
		ln -s $(libsqlite3.SO).$(PACKAGE_VERSION) $(libsqlite3.SO).3 || exit $$?; \
		ln -s $(libsqlite3.SO).3 $(libsqlite3.SO) || exit $$?; \
		ls -la $(libsqlite3.SO) $(libsqlite3.SO).3*; \
		if [ -e $(libsqlite3.SO).0 ]; then \
		ln -s $(libsqlite3.SO).$(PACKAGE_VERSION) $(libsqlite3.SO) || exit $$?; \
		ln -s $(libsqlite3.SO).$(PACKAGE_VERSION) $(libsqlite3.SO).0 || exit $$?; \
		ls -la $(libsqlite3.SO) $(libsqlite3.SO).[03]*; \
		if [ -e $(libsqlite3.SO).0.8.6 ]; then \
			echo "ACHTUNG: legacy libtool-compatible install found. Re-linking it..."; \
			rm -f libsqlite3.la $(libsqlite3.SO).0* || exit $$?; \
			rm -f libsqlite3.la $(libsqlite3.SO).0.8.6 || exit $$?; \
			ln -s $(libsqlite3.SO).$(PACKAGE_VERSION) $(libsqlite3.SO).0 || exit $$?; \
			ln -s $(libsqlite3.SO).$(PACKAGE_VERSION) $(libsqlite3.SO).0.8.6 || exit $$?; \
			ls -la $(libsqlite3.SO).0*; \
		elif [ x1 = "x$(INSTALL_SO_086_LINKS)" ]; then \
			echo "ACHTUNG: installing legacy libtool-style links because INSTALL_SO_086_LINKS=1"; \
			rm -f libsqlite3.la $(libsqlite3.SO).0* || exit $$?; \
			ls -la $(libsqlite3.SO).0.8.6; \
		elif [ x1 = "x$(INSTALL_SO_086_LINK)" ]; then \
			echo "ACHTUNG: installing legacy libtool-style links because INSTALL_SO_086_LINK=1"; \
			rm -f libsqlite3.la $(libsqlite3.SO).0.8.6 || exit $$?; \
			ln -s $(libsqlite3.SO).$(PACKAGE_VERSION) $(libsqlite3.SO).0 || exit $$?; \
			ln -s $(libsqlite3.SO).$(PACKAGE_VERSION) $(libsqlite3.SO).0.8.6 || exit $$?; \
			ls -la $(libsqlite3.SO).0*; \
			ls -la $(libsqlite3.SO).0.8.6; \
		fi
install-so-0 install-so-:
install-so: install-so-$(ENABLE_SHARED)
install: install-so

#
# Install $(libsqlite3.LIB)
1474
1475
1476
1477
1478
1479
1480


1481

1482
1483
1484
1485
1486
1487
1488
1504
1505
1506
1507
1508
1509
1510
1511
1512

1513
1514
1515
1516
1517
1518
1519
1520







+
+
-
+







install: install-headers

#
# libtclsqlite3...
#
pkgIndex.tcl:
	echo 'package ifneeded sqlite3 $(PACKAGE_VERSION) [list load [file join $$dir libtclsqlite3[info sharedlibextension]] sqlite3]' > $@
pkgIndex.tcl-1: pkgIndex.tcl
pkgIndex.tcl-0 pkgIndex.tcl-:
tcl: pkgIndex.tcl
tcl: pkgIndex.tcl-$(HAVE_TCL)
libtclsqlite3.SO = libtclsqlite3$(T.dll)
$(libtclsqlite3.SO): $(T.tcl.env.sh) tclsqlite.o $(LIBOBJ)
	$(T.tcl.env.source); \
	$(T.link.shared) -o $@ tclsqlite.o \
		$$TCL_INCLUDE_SPEC $$TCL_STUB_LIB_SPEC $(LDFLAGS.libsqlite3) \
		$(LIBOBJ) -Wl,-rpath,$$TCLLIBDIR
# ^^^ that rpath bit is defined as TCL_LD_SEARCH_FLAGS in
1523
1524
1525
1526
1527
1528
1529
1530

1531
1532
1533
1534
1535
1536
1537
1555
1556
1557
1558
1559
1560
1561

1562
1563
1564
1565
1566
1567
1568
1569







-
+







	$(TCLSH_CMD) $(TOP)/tool/buildtclext.tcl --build-only --cc "$(T.cc)" $(CFLAGS.tclextension)

#
# Install the SQLite TCL extension in a way that is appropriate for $TCLSH_CMD
# to find it.
#
tclextension-install: tclsqlite3.c
	$(TCLSH_CMD) $(TOP)/tool/buildtclext.tcl --cc "$(T.cc)" $(CFLAGS.tclextension)
	$(TCLSH_CMD) $(TOP)/tool/buildtclext.tcl --destdir "$(DESTDIR)" --cc "$(T.cc)" $(CFLAGS.tclextension)

#
# Uninstall the SQLite TCL extension that is used by $TCLSH_CMD.
#
tclextension-uninstall:
	$(TCLSH_CMD) $(TOP)/tool/buildtclext.tcl --uninstall

1565
1566
1567
1568
1569
1570
1571
1572

1573
1574
1575
1576
1577
1578
1579
1597
1598
1599
1600
1601
1602
1603

1604
1605
1606
1607
1608
1609
1610
1611







-
+







fts5parse.c:	$(TOP)/ext/fts5/fts5parse.y lemon$(B.exe)
	cp $(TOP)/ext/fts5/fts5parse.y .
	rm -f fts5parse.h
	./lemon$(B.exe) $(OPTS) -S fts5parse.y

fts5parse.h: fts5parse.c

fts5.c: $(FTS5_SRC) $(B.tclsh) # has_tclsh84
fts5.c: $(FTS5_SRC) $(B.tclsh)
	$(B.tclsh) $(TOP)/ext/fts5/tool/mkfts5c.tcl
	cp $(TOP)/ext/fts5/fts5.h .

fts5.o:	fts5.c $(DEPS_OBJ_COMMON) $(EXTHDR)
	$(T.cc.extension) -c fts5.c

sqlite3rbu.o:	$(TOP)/ext/rbu/sqlite3rbu.c $(DEPS_OBJ_COMMON) $(EXTHDR)
1606
1607
1608
1609
1610
1611
1612
1613

1614
1615
1616
1617
1618
1619
1620
1638
1639
1640
1641
1642
1643
1644

1645
1646
1647
1648
1649
1650
1651
1652







-
+







TESTFIXTURE_SRC = $(TESTSRC) $(TOP)/src/tclsqlite.c
TESTFIXTURE_SRC += $(TESTFIXTURE_SRC$(USE_AMALGAMATION))

testfixture$(T.exe):	$(T.tcl.env.sh) has_tclsh85 $(TESTFIXTURE_SRC)
	$(T.link.tcl) -DSQLITE_NO_SYNC=1 $(TESTFIXTURE_FLAGS) \
		-o $@ $(TESTFIXTURE_SRC) \
		$$TCL_LIB_SPEC $$TCL_INCLUDE_SPEC \
		$(CFLAGS.libsqlite3) $(LDFLAGS.libsqlite3)
		$(LDFLAGS.libsqlite3)

coretestprogs:	testfixture$(B.exe) sqlite3$(B.exe)

testprogs:	$(TESTPROGS) srcck1$(B.exe) fuzzcheck$(T.exe) sessionfuzz$(T.exe)

# A very detailed test running most or all test cases
fulltest:	alltest fuzztest
1718
1719
1720
1721
1722
1723
1724





1725
1726
1727





1728







1729
1730









1731
1732
1733
1734

1735
1736
1737
1738


1739
1740
1741
1742
1743
1744
1745

1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759

1760
1761
1762
1763


1764
1765
1766
1767
1768

1769
1770
1771
1772

1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792

1793
1794
1795
1796


1797
1798
1799
1800
1801


1802
1803
1804
1805


1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817

1818
1819
1820
1821
1822
1823
1824
1825


1826
1827
1828
1829


1830
1831
1832
1833
1834
1835


1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846


1847
1848
1849
1850
1851
1852
1853
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762


1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775


1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787

1788
1789
1790
1791

1792
1793
1794
1795
1796
1797
1798
1799

1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813

1814
1815
1816
1817

1818
1819
1820
1821
1822
1823

1824
1825
1826
1827

1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847

1848
1849
1850
1851

1852
1853
1854
1855
1856
1857

1858
1859
1860
1861
1862

1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875

1876
1877
1878
1879
1880
1881
1882
1883

1884
1885
1886
1887
1888

1889
1890
1891
1892
1893
1894
1895

1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907

1908
1909
1910
1911
1912
1913
1914
1915
1916







+
+
+
+
+

-
-
+
+
+
+
+

+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+



-
+



-
+
+






-
+













-
+



-
+
+




-
+



-
+



















-
+



-
+
+




-
+
+



-
+
+











-
+







-
+
+



-
+
+





-
+
+










-
+
+







#
smoketest:	$(TESTPROGS) fuzzcheck$(T.exe)
	./testfixture$(T.exe) $(TOP)/test/main.test $(TESTOPTS)

shelltest:
	$(TCLSH_CMD) $(TOP)/test/testrunner.tcl release shell

#
# sqlite3_analyzer.c build depends on $(LINK_TOOLS_DYNAMICALLY).
#
sqlite3_analyzer.c.flags.0 = -DINCLUDE_SQLITE3_C=1
sqlite3_analyzer.c.flags.1 =
sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl \
                    $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in has_tclsh85
	$(B.tclsh) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in >sqlite3_analyzer.c
                    $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in
	$(B.tclsh) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in \
		$(sqlite3_analyzer.c.flags.$(LINK_TOOLS_DYNAMICALLY)) \
		$(OPT_FEATURE_FLAGS) \
		> $@

#
# sqlite3_analyzer's build mode depends on $(LINK_TOOLS_DYNAMICALLY).
#
sqlite3_analyzer.flags.1 = -L. -lsqlite3
sqlite3_analyzer.flags.0 = $(LDFLAGS.libsqlite3)
sqlite3_analyzer.deps.1 = $(libsqlite3.SO)
sqlite3_analyzer.deps.0 =
sqlite3_analyzer$(T.exe): $(T.tcl.env.sh) sqlite3_analyzer.c
	$(T.link.tcl) sqlite3_analyzer.c -o $@ $$TCL_LIB_SPEC $$TCL_INCLUDE_SPEC $(LDFLAGS.libsqlite3)
sqlite3_analyzer$(T.exe): $(T.tcl.env.sh) sqlite3_analyzer.c \
                          $(sqlite3_analyzer.deps.$(LINK_TOOLS_DYNAMICALLY))
	$(T.link.tcl) sqlite3_analyzer.c -o $@ \
		$(sqlite3_analyzer.flags.$(LINK_TOOLS_DYNAMICALLY)) \
		$$TCL_LIB_SPEC $$TCL_INCLUDE_SPEC $$TCL_LIBS
# ^^^^ the order of those flags is relevant for
# $(sqlite3_analyzer.flags.1): if the $$TCL_... flags come first they
# can cause the $@ to link to an out-of-tree libsqlite3.so, which may
# or may not fail or otherwise cause confusion.

sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl \
            $(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl \
            $(TOP)/tool/sqltclsh.c.in has_tclsh85
            $(TOP)/tool/sqltclsh.c.in
	$(B.tclsh) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in >sqltclsh.c

sqltclsh$(T.exe): $(T.tcl.env.sh) sqltclsh.c
	$(T.link.tcl) sqltclsh.c -o $@ $$TCL_INCLUDE_SPEC $(CFLAGS.libsqlite3) $$TCL_LIB_SPEC $(LDFLAGS.libsqlite3)
	$(T.link.tcl) sqltclsh.c -o $@ $$TCL_INCLUDE_SPEC \
		$(LDFLAGS.libsqlite3) $$TCL_LIB_SPEC $$TCL_LIBS
# xbin: target for generic binaries which aren't usually built. It is
# used primarily for testing the build process.
xbin: sqltclsh$(T.exe) sqlite3_analyzer$(T.exe)

sqlite3_expert$(T.exe): $(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqlite3expert.c \
                       $(TOP)/ext/expert/expert.c sqlite3.c
	$(T.link)	$(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqlite3expert.c \
	$(T.link) $(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqlite3expert.c \
		$(TOP)/ext/expert/expert.c sqlite3.c -o sqlite3_expert $(LDFLAGS.libsqlite3)
xbin: sqlite3_expert$(T.exe)

CHECKER_DEPS =\
  $(TOP)/tool/mkccode.tcl \
  sqlite3.c \
  $(TOP)/src/tclsqlite.c \
  $(TOP)/ext/repair/sqlite3_checker.tcl \
  $(TOP)/ext/repair/checkindex.c \
  $(TOP)/ext/repair/checkfreelist.c \
  $(TOP)/ext/misc/btreeinfo.c \
  $(TOP)/ext/repair/sqlite3_checker.c.in

sqlite3_checker.c:	$(CHECKER_DEPS) has_tclsh85
sqlite3_checker.c:	$(CHECKER_DEPS)
	$(B.tclsh) $(TOP)/tool/mkccode.tcl $(TOP)/ext/repair/sqlite3_checker.c.in >$@

sqlite3_checker$(T.exe):	$(T.tcl.env.sh) sqlite3_checker.c
	$(T.link.tcl) sqlite3_checker.c -o $@ $$TCL_INCLUDE_SPEC $(CFLAGS.libsqlite3) $$TCL_LIB_SPEC $(LDFLAGS.libsqlite3)
	$(T.link.tcl) sqlite3_checker.c -o $@ $$TCL_INCLUDE_SPEC \
		$$TCL_LIB_SPEC $(LDFLAGS.libsqlite3)
xbin: sqlite3_checker$(T.exe)

dbdump$(T.exe): $(TOP)/ext/misc/dbdump.c sqlite3.o
	$(T.link) -DDBDUMP_STANDALONE -o $@ \
           $(TOP)/ext/misc/dbdump.c sqlite3.o $(LDFLAGS.libsqlite3)
		$(TOP)/ext/misc/dbdump.c sqlite3.o $(LDFLAGS.libsqlite3)
xbin: dbdump$(T.exe)

dbtotxt$(T.exe): $(TOP)/tool/dbtotxt.c
	$(T.link)-o $@ $(TOP)/tool/dbtotxt.c
	$(T.link)-o $@ $(TOP)/tool/dbtotxt.c $(LDFLAGS.configure)
xbin: dbtotxt$(T.exe)

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

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

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

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

showshm$(T.exe):	$(TOP)/tool/showshm.c
	$(T.link) -o $@ $(TOP)/tool/showshm.c
	$(T.link) -o $@ $(TOP)/tool/showshm.c $(LDFLAGS.configure)
xbin: showshm$(T.exe)

index_usage$(T.exe): $(TOP)/tool/index_usage.c sqlite3.o
	$(T.link) $(SHELL_OPT) -o $@ $(TOP)/tool/index_usage.c sqlite3.o $(LDFLAGS.libsqlite3)
	$(T.link) $(SHELL_OPT) -o $@ $(TOP)/tool/index_usage.c sqlite3.o \
		$(LDFLAGS.libsqlite3)
xbin: index_usage$(T.exe)

# Reminder: changeset does not build without -DSQLITE_ENABLE_SESSION
changeset$(T.exe):	$(TOP)/ext/session/changeset.c sqlite3.o
	$(T.link) -o $@ $(TOP)/ext/session/changeset.c sqlite3.o $(LDFLAGS.libsqlite3)
	$(T.link) -o $@ $(TOP)/ext/session/changeset.c sqlite3.o \
		$(LDFLAGS.libsqlite3)
xbin: changeset$(T.exe)

changesetfuzz$(T.exe):	$(TOP)/ext/session/changesetfuzz.c sqlite3.o
	$(T.link) -o $@ $(TOP)/ext/session/changesetfuzz.c sqlite3.o $(LDFLAGS.libsqlite3)
	$(T.link) -o $@ $(TOP)/ext/session/changesetfuzz.c sqlite3.o \
		$(LDFLAGS.libsqlite3)
xbin: changesetfuzz$(T.exe)

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

atrc$(T.exe): $(TOP)/test/atrc.c sqlite3.o
	$(T.link) -o $@ $(TOP)/test/atrc.c sqlite3.o $(LDFLAGS.libsqlite3)
xbin: atrc$(T.exe)

LogEst$(T.exe):	$(TOP)/tool/logest.c sqlite3.h
	$(T.link) -I. -o $@ $(TOP)/tool/logest.c
	$(T.link) -I. -o $@ $(TOP)/tool/logest.c $(LDFLAGS.configure)
xbin: LogEst$(T.exe)

wordcount$(T.exe):	$(TOP)/test/wordcount.c sqlite3.o
	$(T.link) -o $@ $(TOP)/test/wordcount.c sqlite3.o $(LDFLAGS.libsqlite3)
xbin: wordcount$(T.exe)

speedtest1$(T.exe):	$(TOP)/test/speedtest1.c sqlite3.c Makefile
	$(T.link) $(ST_OPT) -o $@ $(TOP)/test/speedtest1.c sqlite3.c $(LDFLAGS.libsqlite3)
	$(T.link) $(ST_OPT) -o $@ $(TOP)/test/speedtest1.c sqlite3.c \
		$(LDFLAGS.libsqlite3)
xbin: speedtest1$(T.exe)

startup$(T.exe):	$(TOP)/test/startup.c sqlite3.c
	$(T.link) -Os -g -USQLITE_THREADSAFE -DSQLITE_THREADSAFE=0 -o $@ $(TOP)/test/startup.c sqlite3.c $(LDFLAGS.libsqlite3)
	$(T.link) -Os -g -USQLITE_THREADSAFE -DSQLITE_THREADSAFE=0 \
		-o $@ $(TOP)/test/startup.c sqlite3.c $(LDFLAGS.libsqlite3)
xbin: startup$(T.exe)

KV_OPT += -DSQLITE_DIRECT_OVERFLOW_READ

kvtest$(T.exe):	$(TOP)/test/kvtest.c sqlite3.c
	$(T.link) $(KV_OPT) -o $@ $(TOP)/test/kvtest.c sqlite3.c $(LDFLAGS.libsqlite3)
	$(T.link) $(KV_OPT) -o $@ $(TOP)/test/kvtest.c sqlite3.c \
		$(LDFLAGS.libsqlite3)
xbin: kvtest$(T.exe)

#
# rbu$(T.exe) requires building with -DSQLITE_ENABLE_RBU, which
# specifically does not have an --enable-rbu flag in the configure
# script.
rbu$(T.exe): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.o
	$(T.link) -I. -o $@ $(TOP)/ext/rbu/rbu.c sqlite3.o $(LDFLAGS.libsqlite3)

loadfts$(T.exe): $(TOP)/tool/loadfts.c $(libsqlite3.LIB)
	$(T.link) $(TOP)/tool/loadfts.c $(libsqlite3.LIB) -o $@ $(LDFLAGS.libsqlite3)
	$(T.link) $(TOP)/tool/loadfts.c $(libsqlite3.LIB) \
		-o $@ $(LDFLAGS.libsqlite3)
xbin: loadfts$(T.exe)

# This target will fail if the SQLite amalgamation contains any exported
# symbols that do not begin with "sqlite3_". It is run as part of the
# releasetest.tcl script.
#
VALIDIDS=' sqlite3(changeset|changegroup|session|rebaser)?_'
1885
1886
1887
1888
1889
1890
1891
1892


1893
1894
1895
1896
1897
1898
1899
1900
1901









1902
1903
1904
1905

1906
1907
1908
1909
1910
1911
1912
1913

1914









1915
1916
1917
1918

1919
1920


1921
1922






1923
1924
1925
1926
1927
1928
1929
1948
1949
1950
1951
1952
1953
1954

1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977

1978
1979

1980
1981
1982
1983
1984

1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998

1999
2000
2001
2002
2003


2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016







-
+
+









+
+
+
+
+
+
+
+
+



-
+

-





-
+

+
+
+
+
+
+
+
+
+



-
+


+
+
-
-
+
+
+
+
+
+







                  $(TOP)/test/tt3_checkpoint.c \
                  $(TOP)/test/tt3_index.c      \
                  $(TOP)/test/tt3_vacuum.c      \
                  $(TOP)/test/tt3_stress.c      \
                  $(TOP)/test/tt3_lookaside1.c

threadtest3$(T.exe): sqlite3.o $(THREADTEST3_SRC)
	$(T.link) $(TOP)/test/threadtest3.c $(TOP)/src/test_multiplex.c sqlite3.o -o $@ $(LDFLAGS.libsqlite3)
	$(T.link) $(TOP)/test/threadtest3.c $(TOP)/src/test_multiplex.c sqlite3.o \
		-o $@ $(LDFLAGS.libsqlite3)
xbin: threadtest3$(T.exe)

threadtest: threadtest3$(T.exe)
	./threadtest3$(T.exe)

threadtest5: sqlite3.c $(TOP)/test/threadtest5.c
	$(T.link) $(TOP)/test/threadtest5.c sqlite3.c -o $@ $(LDFLAGS.libsqlite3)
xbin: threadtest5

#
# When building sqlite3$(T.exe) we specifically embed a copy of
# sqlite3.c, and not link to libsqlite3.so or libsqlite3.a, because
# the shell needs to be able to enable arbitrary library features,
# some of which have significant performance impacts. For example,,
# SQLITE_ENABLE_EXPLAIN_COMMENTS has been measured as having a 5.2%
# runtime performance hit, which is fine for use in the shell but is
# not appropriate for the canonical library build.
#
sqlite3$(T.exe):	shell.c sqlite3.c
	$(T.link) -o $@ \
		shell.c sqlite3.c \
		$(CFLAGS.readline) $(SHELL_OPT) \
		$(CFLAGS.readline) $(SHELL_OPT) $(CFLAGS.icu) \
		$(LDFLAGS.libsqlite3) $(LDFLAGS.readline)

#
# Build sqlite3$(T.exe) by default except in wasi-sdk builds.  Yes, the
# semantics of 0 and 1 are confusingly swapped here.
#
sqlite3$(T.exe)-1:
sqlite3$(T.exe)-0 sqlite3$(T.exe)-: sqlite3$(T.exe)
sqlite3$(T.exe)-0: sqlite3$(T.exe)
all: sqlite3$(T.exe)-$(HAVE_WASI_SDK)

# The "sqlite3d" CLI is build using separate source files.  This
# is useful during development and debugging.
#
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-shell-:
install-shell-1:
install: install-shell-$(HAVE_WASI_SDK)

# How to build sqldiff$(T.exe) depends on $(LINK_TOOLS_DYNAMICALLY)
#
sqldiff$(T.exe):	$(TOP)/tool/sqldiff.c $(TOP)/ext/misc/sqlite3_stdio.h sqlite3.o sqlite3.h
	$(T.link) -o $@ $(TOP)/tool/sqldiff.c sqlite3.o $(LDFLAGS.libsqlite3)
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)
1975
1976
1977
1978
1979
1980
1981
1982

1983
1984
1985
1986
1987
1988
1989
2062
2063
2064
2065
2066
2067
2068

2069
2070
2071
2072
2073
2074
2075
2076







-
+







xbin: src-verify$(B.exe)

verify-source:	./src-verify$(B.exe)
	./src-verify$(B.exe) $(TOP)

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

fuzzcheck$(T.exe):	$(FUZZCHECK_SRC) sqlite3.c sqlite3.h $(FUZZCHECK_DEP)
	$(T.link) -o $@ $(FUZZCHECK_OPT) $(FUZZCHECK_SRC) sqlite3.c $(LDFLAGS.libsqlite3)
fuzzy: fuzzcheck$(T.exe)
xbin: fuzzcheck$(T.exe)
2013
2014
2015
2016
2017
2018
2019
2020

2021
2022
2023
2024
2025
2026
2027
2028
2029


2030
2031
2032
2033
2034
2035
2036
2100
2101
2102
2103
2104
2105
2106

2107
2108
2109
2110
2111
2112
2113
2114
2115

2116
2117
2118
2119
2120
2121
2122
2123
2124







-
+








-
+
+







	@if test "$(FUZZDB)" = ""; then echo 'ERROR: No FUZZDB specified. Rerun with FUZZDB=filename'; exit 1; fi
	./fuzzcheck$(T.exe) --spinner $(FUZZDB)
	./fuzzcheck-asan$(T.exe) --spinner $(FUZZDB)
	./fuzzcheck-ubsan$(T.exe) --spinner $(FUZZDB)

ossshell$(T.exe):	$(TOP)/test/ossfuzz.c $(TOP)/test/ossshell.c sqlite3.c sqlite3.h
	$(T.link) -o $@ $(FUZZCHECK_OPT) $(TOP)/test/ossshell.c \
             $(TOP)/test/ossfuzz.c sqlite3.c $(LDFLAGS.libsqlite3)
		$(TOP)/test/ossfuzz.c sqlite3.c $(LDFLAGS.libsqlite3)
fuzzy: ossshell$(T.exe)
xbin: ossshell$(T.exe)

sessionfuzz$(T.exe):	$(TOP)/test/sessionfuzz.c sqlite3.c sqlite3.h
	$(T.link) -o $@ $(TOP)/test/sessionfuzz.c $(LDFLAGS.libsqlite3)
fuzzy: sessionfuzz$(T.exe)

dbfuzz$(T.exe):	$(TOP)/test/dbfuzz.c sqlite3.c sqlite3.h
	$(T.link) -o $@ $(DBFUZZ_OPT) $(TOP)/test/dbfuzz.c sqlite3.c $(LDFLAGS.libsqlite3)
	$(T.link) -o $@ $(DBFUZZ_OPT) $(TOP)/test/dbfuzz.c sqlite3.c \
		$(LDFLAGS.libsqlite3)
fuzzy: dbfuzz$(T.exe)
xbin: dbfuzz$(T.exe)

DBFUZZ2_OPTS = \
  -USQLITE_THREADSAFE \
  -DSQLITE_THREADSAFE=0 \
  -DSQLITE_OMIT_LOAD_EXTENSION \
2095
2096
2097
2098
2099
2100
2101
2102

2103
2104
2105
2106
2107
2108
2109
2110

2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125

2126
2127
2128
2129
2130
2131
2132
2183
2184
2185
2186
2187
2188
2189

2190
2191
2192
2193
2194
2195
2196
2197

2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212

2213
2214
2215
2216
2217
2218
2219
2220







-
+







-
+














-
+







    $(TOP)/ext/misc/zipfile.c \
    $(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) # has_tclsh84
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
	$(T.cc.extension) -c $(TOP)/ext/icu/icu.c $(CFLAGS.icu)

fts3.o:	$(TOP)/ext/fts3/fts3.c $(DEPS_EXT_COMMON)
	$(T.cc.extension) -c $(TOP)/ext/fts3/fts3.c

fts3_aux.o:	$(TOP)/ext/fts3/fts3_aux.c $(DEPS_EXT_COMMON)
	$(T.cc.extension) -c $(TOP)/ext/fts3/fts3_aux.c

fts3_expr.o:	$(TOP)/ext/fts3/fts3_expr.c $(DEPS_EXT_COMMON)
	$(T.cc.extension) -c $(TOP)/ext/fts3/fts3_expr.c

fts3_hash.o:	$(TOP)/ext/fts3/fts3_hash.c $(DEPS_EXT_COMMON)
	$(T.cc.extension) -c $(TOP)/ext/fts3/fts3_hash.c

fts3_icu.o:	$(TOP)/ext/fts3/fts3_icu.c $(DEPS_EXT_COMMON)
	$(T.cc.extension) -c $(TOP)/ext/fts3/fts3_icu.c
	$(T.cc.extension) -c $(TOP)/ext/fts3/fts3_icu.c $(CFLAGS.icu)

fts3_porter.o:	$(TOP)/ext/fts3/fts3_porter.c $(DEPS_EXT_COMMON)
	$(T.cc.extension) -c $(TOP)/ext/fts3/fts3_porter.c

fts3_snippet.o:	$(TOP)/ext/fts3/fts3_snippet.c $(DEPS_EXT_COMMON)
	$(T.cc.extension) -c $(TOP)/ext/fts3/fts3_snippet.c

2163
2164
2165
2166
2167
2168
2169
2170
2171


2172
2173
2174
2175
2176
2177
2178
2251
2252
2253
2254
2255
2256
2257


2258
2259
2260
2261
2262
2263
2264
2265
2266







-
-
+
+







dll: sqlite3.dll
sqlite3.def: $(LIBOBJ)
	echo 'EXPORTS' >sqlite3.def
	nm $(LIBOBJ) | grep ' T ' | grep ' _sqlite3_' \
		| sed 's/^.* _//' >>sqlite3.def

sqlite3.dll: $(LIBOBJ) sqlite3.def
	$(T.cc.sqlite) $(LDFLAGS.shobj) -o $@ sqlite3.def \
		-Wl,"--strip-all" $(LIBOBJ)
	$(T.cc.sqlite) $(LDFLAGS.shlib) -o $@ sqlite3.def \
		-Wl,"--strip-all" $(LIBOBJ) $(LDFLAGS.configure)

#
# Emit a list of commonly-used targets
help:
	@echo; echo "Frequently-used high-level make targets:"; echo; \
	echo " - all [default] = builds most components"; \
	echo " - clean         = cleans up most build products"; \
Deleted sqlite_cfg.h.in.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194


































































































































































































-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
/* sqlite_cfg.h.in - autosetup input template for sqlite_cfg.h.  */

/* Define to 1 if you have the <dlfcn.h> header file. */
/*#undef HAVE_DLFCN_H*/
@if HAVE_DLFCN_H
#define HAVE_DLFCN_H @HAVE_DLFCN_H@
@endif

/* Define to 1 if you have the `fdatasync' function. */
/*#undef HAVE_FDATASYNC*/
#define HAVE_FDATASYNC @HAVE_FDATASYNC@

/* Define to 1 if you have the `gmtime_r' function. */
/*#undef HAVE_GMTIME_R*/
#define HAVE_GMTIME_R @HAVE_GMTIME_R@

/* Define to 1 if the system has the type `int16_t'. */
/*#undef HAVE_INT16_T*/
#define HAVE_INT16_T @HAVE_INT16_T@

/* Define to 1 if the system has the type `int32_t'. */
/*#undef HAVE_INT32_T*/
#define HAVE_INT32_T @HAVE_INT32_T@

/* Define to 1 if the system has the type `int64_t'. */
/*#undef HAVE_INT64_T*/
#define HAVE_INT64_T @HAVE_INT64_T@

/* Define to 1 if the system has the type `int8_t'. */
/*#undef HAVE_INT8_T*/
#define HAVE_INT8_T @HAVE_INT8_T@

/* Define to 1 if the system has the type `intptr_t'. */
/*#undef HAVE_INTPTR_T*/
#define HAVE_INTPTR_T @HAVE_INTPTR_T@

/* Define to 1 if you have the <inttypes.h> header file. */
/*#undef HAVE_INTTYPES_H*/
#define HAVE_INTTYPES_H @HAVE_INTTYPES_H@

/* Define to 1 if you have the `isnan' function. */
/*#undef HAVE_ISNAN*/
#define HAVE_ISNAN @HAVE_ISNAN@

/* Define to 1 if you have the `localtime_r' function. */
/*#undef HAVE_LOCALTIME_R*/
#define HAVE_LOCALTIME_R @HAVE_LOCALTIME_R@

/* Define to 1 if you have the `localtime_s' function. */
/*#undef HAVE_LOCALTIME_S*/
#define HAVE_LOCALTIME_S @HAVE_LOCALTIME_S@

/* Define to 1 if you have the <malloc.h> header file. */
/*#undef HAVE_MALLOC_H*/
#define HAVE_MALLOC_H @HAVE_MALLOC_H@

/* Define to 1 if you have the `malloc_usable_size' function. */
/*#undef HAVE_MALLOC_USABLE_SIZE*/
#define HAVE_MALLOC_USABLE_SIZE @HAVE_MALLOC_USABLE_SIZE@

/* Define to 1 if you have the <memory.h> header file. */
/*#undef HAVE_MEMORY_H*/
#define HAVE_MEMORY_H @HAVE_MEMORY_H@

/* Define to 1 if you have the `pread' function. */
/*#undef HAVE_PREAD*/
#define HAVE_PREAD @HAVE_PREAD@

/* Define to 1 if you have the `pread64' function. */
/*#undef HAVE_PREAD64*/
#define HAVE_PREAD64 @HAVE_PREAD64@

/* Define to 1 if you have the `pwrite' function. */
/*#undef HAVE_PWRITE*/
#define HAVE_PWRITE @HAVE_PWRITE@

/* Define to 1 if you have the `pwrite64' function. */
/*#undef HAVE_PWRITE64*/
#define HAVE_PWRITE64 @HAVE_PWRITE64@

/* Define to 1 if you have the <stdint.h> header file. */
/*#undef HAVE_STDINT_H*/
#define HAVE_STDINT_H @HAVE_STDINT_H@

/* Define to 1 if you have the <stdlib.h> header file. */
/*#undef HAVE_STDLIB_H*/
#define HAVE_STDLIB_H @HAVE_STDLIB_H@

/* Define to 1 if you have the `strchrnul' function. */
/*#undef HAVE_STRCHRNUL*/
#define HAVE_STRCHRNUL @HAVE_STRCHRNUL@

/* Define to 1 if you have the <strings.h> header file. */
/*#undef HAVE_STRINGS_H*/
#define HAVE_STRINGS_H @HAVE_STRINGS_H@

/* Define to 1 if you have the <string.h> header file. */
/*#undef HAVE_STRING_H*/
#define HAVE_STRING_H @HAVE_STRING_H@

/* Define to 1 if you have the <sys/stat.h> header file. */
/*#undef HAVE_SYS_STAT_H*/
#define HAVE_SYS_STAT_H @HAVE_SYS_STAT_H@

/* Define to 1 if you have the <sys/types.h> header file. */
/*#undef HAVE_SYS_TYPES_H*/
#define HAVE_SYS_TYPES_H @HAVE_SYS_TYPES_H@

/* Define to 1 if the system has the type `uint16_t'. */
/*#undef HAVE_UINT16_T*/
#define HAVE_UINT16_T @HAVE_UINT16_T@

/* Define to 1 if the system has the type `uint32_t'. */
/*#undef HAVE_UINT32_T*/
#define HAVE_UINT32_T @HAVE_UINT32_T@

/* Define to 1 if the system has the type `uint64_t'. */
/*#undef HAVE_UINT64_T*/
#define HAVE_UINT64_T @HAVE_UINT64_T@

/* Define to 1 if the system has the type `uint8_t'. */
/*#undef HAVE_UINT8_T*/
#define HAVE_UINT8_T @HAVE_UINT8_T@

/* Define to 1 if the system has the type `uintptr_t'. */
/*#undef HAVE_UINTPTR_T*/
#define HAVE_UINTPTR_T @HAVE_UINTPTR_T@

/* Define to 1 if you have the <unistd.h> header file. */
/*#undef HAVE_UNISTD_H*/
#define HAVE_UNISTD_H @HAVE_UNISTD_H@

/* Define to 1 if you have the `usleep' function. */
/*#undef HAVE_USLEEP*/
#define HAVE_USLEEP @HAVE_USLEEP@

/* Define to 1 if you have the `utime' function. */
/*#undef HAVE_UTIME*/
#define HAVE_UTIME @HAVE_UTIME@

/* Define to 1 if you have the <zlib.h> header file. */
/*#undef HAVE_ZLIB_H*/
#define HAVE_ZLIB_H @HAVE_ZLIB_H@

/* Define to the sub-directory in which libtool stores uninstalled libraries.
   */
/*#undef LT_OBJDIR*/
/*#define LT_OBJDIR @LT_OBJDIR@*/

/* Define to the address where bug reports for this package should be sent. */
/*#undef PACKAGE_BUGREPORT*/
#define PACKAGE_BUGREPORT ""

/* Define to the full name of this package. */
/*#undef PACKAGE_NAME*/
#define PACKAGE_NAME "sqlite"

/* Define to the full name and version of this package. */
/*#undef PACKAGE_STRING*/
#define PACKAGE_STRING "sqlite @RELEASE@"

/* Define to the one symbol short name of this package. */
/*#undef PACKAGE_TARNAME*/
#define PACKAGE_TARNAME "sqlite"

/* Define to the home page for this package. */
/*#undef PACKAGE_URL*/
#define PACKAGE_URL @PACKAGE_URL@

/* Define to the version of this package. */
/*#undef PACKAGE_VERSION*/
#define PACKAGE_VERSION @VERSION@

/* Define to 1 if you have the ANSI C header files. */
/*#undef STDC_HEADERS*/
#define STDC_HEADERS 1 /* @STDC_HEADERS@ */

/* Enable large inode numbers on Mac OS X 10.5.  */
#ifndef _DARWIN_USE_64_BIT_INODE
# define _DARWIN_USE_64_BIT_INODE 1
#endif

/* Number of bits in a file offset, on hosts where this is settable. */
/*#undef _FILE_OFFSET_BITS*/
/*#define _FILE_OFFSET_BITS @_FILE_OFFSET_BITS@*/
/*@if _FILE_OFFSET_BITS != ""*/
/*#define _FILE_OFFSET_BITS @_FILE_OFFSET_BITS@*/
/*@endif*/

/* Define for large files, on AIX-style hosts. */
/*#undef _LARGE_FILES*/
/*@if _LARGE_FILES*/
/*#define _LARGE_FILES @_LARGE_FILES@*/
/*@endif*/
Changes to src/dbpage.c.
389
390
391
392
393
394
395


396
397
398
399
400
401
402
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404







+
+







  if( rc==SQLITE_OK ){
    const void *pData = sqlite3_value_blob(argv[3]);
    if( (rc = sqlite3PagerWrite(pDbPage))==SQLITE_OK && pData ){
      unsigned char *aPage = sqlite3PagerGetData(pDbPage);
      memcpy(aPage, pData, szPage);
      pTab->pgnoTrunc = 0;
    }
  }else{
    pTab->pgnoTrunc = 0;
  }
  sqlite3PagerUnref(pDbPage);
  return rc;

update_fail:
  sqlite3_free(pVtab->zErrMsg);
  pVtab->zErrMsg = sqlite3_mprintf("%s", zErr);
Changes to src/expr.c.
6176
6177
6178
6179
6180
6181
6182



6183
6184

6185
6186
6187
6188
6189

6190
6191
6192




6193
6194
6195
6196
6197
6198
6199
6200
6201
6202

6203
6204
6205
6206
6207
6208
6209
6210
6211
6212
6213
6214
6176
6177
6178
6179
6180
6181
6182
6183
6184
6185
6186

6187
6188
6189
6190
6191

6192
6193
6194
6195
6196
6197
6198
6199
6200
6201
6202
6203
6204
6205
6206
6207
6208

6209
6210
6211
6212
6213

6214
6215
6216
6217
6218
6219
6220







+
+
+

-
+




-
+



+
+
+
+









-
+




-







** or NULL value - then the VDBE currently being prepared is configured
** to re-prepare each time a new value is bound to variable pVar.
**
** Additionally, if pExpr is a simple SQL value and the value is the
** same as that currently bound to variable pVar, non-zero is returned.
** Otherwise, if the values are not the same or if pExpr is not a simple
** SQL value, zero is returned.
**
** If the SQLITE_EnableQPSG flag is set on the database connection, then
** this routine always returns false.
*/
static int exprCompareVariable(
static SQLITE_NOINLINE int exprCompareVariable(
  const Parse *pParse,
  const Expr *pVar,
  const Expr *pExpr
){
  int res = 0;
  int res = 2;
  int iVar;
  sqlite3_value *pL, *pR = 0;
 
  if( pExpr->op==TK_VARIABLE && pVar->iColumn==pExpr->iColumn ){
    return 0;
  }
  if( (pParse->db->flags & SQLITE_EnableQPSG)!=0 ) return 2;
  sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, SQLITE_AFF_BLOB, &pR);
  if( pR ){
    iVar = pVar->iColumn;
    sqlite3VdbeSetVarmask(pParse->pVdbe, iVar);
    pL = sqlite3VdbeGetBoundValue(pParse->pReprepare, iVar, SQLITE_AFF_BLOB);
    if( pL ){
      if( sqlite3_value_type(pL)==SQLITE_TEXT ){
        sqlite3_value_text(pL); /* Make sure the encoding is UTF-8 */
      }
      res =  0==sqlite3MemCompare(pL, pR, 0);
      res = sqlite3MemCompare(pL, pR, 0) ? 2 : 0;
    }
    sqlite3ValueFree(pR);
    sqlite3ValueFree(pL);
  }

  return res;
}

/*
** Do a deep comparison of two expression trees.  Return 0 if the two
** expressions are completely identical.  Return 1 if they differ only
** by a COLLATE operator at the top level.  Return 2 if there are differences
6226
6227
6228
6229
6230
6231
6232
6233
6234
6235



6236
6237
6238

6239
6240
6241
6242
6243
6244
6245
6246
6247
6248
6249
6250
6251


6252
6253
6254
6255
6256
6257
6258
6232
6233
6234
6235
6236
6237
6238



6239
6240
6241



6242
6243
6244
6245
6246
6247
6248
6249
6250
6251
6252
6253


6254
6255
6256
6257
6258
6259
6260
6261
6262







-
-
-
+
+
+
-
-
-
+











-
-
+
+







** returns 2, then you do not really know for certain if the two
** expressions are the same.  But if you get a 0 or 1 return, then you
** can be sure the expressions are the same.  In the places where
** this routine is used, it does not hurt to get an extra 2 - that
** just might result in some slightly slower code.  But returning
** an incorrect 0 or 1 could lead to a malfunction.
**
** If pParse is not NULL then TK_VARIABLE terms in pA with bindings in
** pParse->pReprepare can be matched against literals in pB.  The
** pParse->pVdbe->expmask bitmask is updated for each variable referenced.
** If pParse is not NULL and SQLITE_EnableQPSG is off then TK_VARIABLE
** terms in pA with bindings in pParse->pReprepare can be matched against
** literals in pB.  The pParse->pVdbe->expmask bitmask is updated for
** If pParse is NULL (the normal case) then any TK_VARIABLE term in
** Argument pParse should normally be NULL. If it is not NULL and pA or
** pB causes a return value of 2.
** each variable referenced.
*/
int sqlite3ExprCompare(
  const Parse *pParse,
  const Expr *pA,
  const Expr *pB,
  int iTab
){
  u32 combinedFlags;
  if( pA==0 || pB==0 ){
    return pB==pA ? 0 : 2;
  }
  if( pParse && pA->op==TK_VARIABLE && exprCompareVariable(pParse, pA, pB) ){
    return 0;
  if( pParse && pA->op==TK_VARIABLE ){
    return exprCompareVariable(pParse, pA, pB);
  }
  combinedFlags = pA->flags | pB->flags;
  if( combinedFlags & EP_IntValue ){
    if( (pA->flags&pB->flags&EP_IntValue)!=0 && pA->u.iValue==pB->u.iValue ){
      return 0;
    }
    return 2;
6438
6439
6440
6441
6442
6443
6444
6445
6446


















































6447
6448
6449
6450
6451
6452
6453
6454
6455
6456
6457









6458
6459
6460
6461
6462
6463
6464
6442
6443
6444
6445
6446
6447
6448
6449
6450
6451
6452
6453
6454
6455
6456
6457
6458
6459
6460
6461
6462
6463
6464
6465
6466
6467
6468
6469
6470
6471
6472
6473
6474
6475
6476
6477
6478
6479
6480
6481
6482
6483
6484
6485
6486
6487
6488
6489
6490
6491
6492
6493
6494
6495
6496
6497
6498
6499
6500
6501
6502
6503
6504







6505
6506
6507
6508
6509
6510
6511
6512
6513
6514
6515
6516
6517
6518
6519
6520









+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+




-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+







    case TK_BITNOT:
    case TK_NOT: {
      return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1);
    }
  }
  return 0;
}

/*
** Return true if the boolean value of the expression is always either
** FALSE or NULL.
*/
static int sqlite3ExprIsNotTrue(Expr *pExpr){
  int v;
  if( pExpr->op==TK_NULL ) return 1;
  if( pExpr->op==TK_TRUEFALSE && sqlite3ExprTruthValue(pExpr)==0 ) return 1;
  v = 1;
  if( sqlite3ExprIsInteger(pExpr, &v, 0) && v==0 ) return 1;
  return 0;
}

/*
** Return true if the expression is one of the following:
**
**    CASE WHEN x THEN y END
**    CASE WHEN x THEN y ELSE NULL END
**    CASE WHEN x THEN y ELSE false END
**    iif(x,y)
**    iif(x,y,NULL)
**    iif(x,y,false)
*/
static int sqlite3ExprIsIIF(sqlite3 *db, const Expr *pExpr){
  ExprList *pList;
  if( pExpr->op==TK_FUNCTION ){
    const char *z = pExpr->u.zToken;
    FuncDef *pDef;
    if( (z[0]!='i' && z[0]!='I') ) return 0;
    if( pExpr->x.pList==0 ) return 0;
    pDef = sqlite3FindFunction(db, z, pExpr->x.pList->nExpr, ENC(db), 0);
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
    if( pDef==0 ) return 0;
#else
    if( NEVER(pDef==0) ) return 0;
#endif
    if( (pDef->funcFlags & SQLITE_FUNC_INLINE)==0 ) return 0;
    if( SQLITE_PTR_TO_INT(pDef->pUserData)!=INLINEFUNC_iif ) return 0;
  }else if( pExpr->op==TK_CASE ){
    if( pExpr->pLeft!=0 ) return 0;
  }else{
    return 0;
  }
  pList = pExpr->x.pList;
  assert( pList!=0 );
  if( pList->nExpr==2 ) return 1;
  if( pList->nExpr==3 && sqlite3ExprIsNotTrue(pList->a[2].pExpr) ) return 1;
  return 0;
}

/*
** Return true if we can prove the pE2 will always be true if pE1 is
** true.  Return false if we cannot complete the proof or if pE2 might
** be false.  Examples:
**
**     pE1: x==5       pE2: x==5             Result: true
**     pE1: x>0        pE2: x==5             Result: false
**     pE1: x=21       pE2: x=21 OR y=43     Result: true
**     pE1: x!=123     pE2: x IS NOT NULL    Result: true
**     pE1: x!=?1      pE2: x IS NOT NULL    Result: true
**     pE1: x IS NULL  pE2: x IS NOT NULL    Result: false
**     pE1: x IS ?2    pE2: x IS NOT NULL    Result: false
**     pE1: x==5        pE2: x==5             Result: true
**     pE1: x>0         pE2: x==5             Result: false
**     pE1: x=21        pE2: x=21 OR y=43     Result: true
**     pE1: x!=123      pE2: x IS NOT NULL    Result: true
**     pE1: x!=?1       pE2: x IS NOT NULL    Result: true
**     pE1: x IS NULL   pE2: x IS NOT NULL    Result: false
**     pE1: x IS ?2     pE2: x IS NOT NULL    Result: false
**     pE1: iif(x,y)    pE2: x                Result: true
**     PE1: iif(x,y,0)  pE2: x                Result: true
**
** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has
** Expr.iTable<0 then assume a table number given by iTab.
**
** If pParse is not NULL, then the values of bound variables in pE1 are
** compared against literal values in pE2 and pParse->pVdbe->expmask is
** modified to record which bound variables are referenced.  If pParse
6484
6485
6486
6487
6488
6489
6490



6491
6492
6493
6494
6495
6496
6497
6540
6541
6542
6543
6544
6545
6546
6547
6548
6549
6550
6551
6552
6553
6554
6555
6556







+
+
+







    return 1;
  }
  if( pE2->op==TK_NOTNULL
   && exprImpliesNotNull(pParse, pE1, pE2->pLeft, iTab, 0)
  ){
    return 1;
  }
  if( sqlite3ExprIsIIF(pParse->db, pE1) ){
    return sqlite3ExprImpliesExpr(pParse,pE1->x.pList->a[0].pExpr,pE2,iTab);
  }
  return 0;
}

/* This is a helper function to impliesNotNullRow().  In this routine,
** set pWalker->eCode to one only if *both* of the input expressions
** separately have the implies-not-null-row property.
*/
Changes to src/func.c.
2810
2811
2812
2813
2814
2815
2816

2817


2818
2819
2820
2821
2822
2823
2824
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827







+

+
+







    MFUNCTION(sqrt,              1, sqrt,      math1Func   ),
    MFUNCTION(radians,           1, degToRad,  math1Func   ),
    MFUNCTION(degrees,           1, radToDeg,  math1Func   ),
    MFUNCTION(pi,                0, 0,         piFunc      ),
#endif /* SQLITE_ENABLE_MATH_FUNCTIONS */
    FUNCTION(sign,               1, 0, 0,      signFunc    ),
    INLINE_FUNC(coalesce,       -1, INLINEFUNC_coalesce, 0 ),
    INLINE_FUNC(iif,             2, INLINEFUNC_iif,      0 ),
    INLINE_FUNC(iif,             3, INLINEFUNC_iif,      0 ),
    INLINE_FUNC(if,              2, INLINEFUNC_iif,      0 ),
    INLINE_FUNC(if,              3, INLINEFUNC_iif,      0 ),
  };
#ifndef SQLITE_OMIT_ALTERTABLE
  sqlite3AlterFunctions();
#endif
  sqlite3WindowFunctions();
  sqlite3RegisterDateTimeFunctions();
  sqlite3RegisterJsonFunctions();
Changes to src/main.c.
2921
2922
2923
2924
2925
2926
2927
2928
2929


2930
2931
2932
2933
2934
2935
2936
2921
2922
2923
2924
2925
2926
2927


2928
2929
2930
2931
2932
2933
2934
2935
2936







-
-
+
+







  if( limitId<0 || limitId>=SQLITE_N_LIMIT ){
    return -1;
  }
  oldLimit = db->aLimit[limitId];
  if( newLimit>=0 ){                   /* IMP: R-52476-28732 */
    if( newLimit>aHardLimit[limitId] ){
      newLimit = aHardLimit[limitId];  /* IMP: R-51463-25634 */
    }else if( newLimit<1 && limitId==SQLITE_LIMIT_LENGTH ){
      newLimit = 1;
    }else if( newLimit<SQLITE_MIN_LENGTH && limitId==SQLITE_LIMIT_LENGTH ){
      newLimit = SQLITE_MIN_LENGTH;
    }
    db->aLimit[limitId] = newLimit;
  }
  return oldLimit;                     /* IMP: R-53341-35419 */
}

/*
4284
4285
4286
4287
4288
4289
4290

4291
4292
4293
4294
4295
4296
4297
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298







+







        sqlite3ShowTriggerList(0);
#endif
#ifndef SQLITE_OMIT_WINDOWFUNC
        sqlite3ShowWindow(0);
        sqlite3ShowWinFunc(0);
#endif
        sqlite3ShowSelect(0);
        sqlite3ShowWhereTerm(0);
      }
#endif
      break;
    }


    /*
Changes to src/os_unix.c.
3983
3984
3985
3986
3987
3988
3989





3990
3991
3992
3993
3994
3995
3996
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001







+
+
+
+
+







    }
    case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: {
      int rc = osIoctl(pFile->h, F2FS_IOC_ABORT_VOLATILE_WRITE);
      return rc ? SQLITE_IOERR_ROLLBACK_ATOMIC : SQLITE_OK;
    }
#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */

    case SQLITE_FCNTL_NULL_IO: {
      osClose(pFile->h);
      pFile->h = -1;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_LOCKSTATE: {
      *(int*)pArg = pFile->eFileLock;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_LAST_ERRNO: {
      *(int*)pArg = pFile->lastErrno;
      return SQLITE_OK;
Changes to src/os_win.c.
3595
3596
3597
3598
3599
3600
3601





3602
3603
3604
3605
3606
3607
3608
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613







+
+
+
+
+







      pFile->h = *phFile;
      *phFile = hOldFile;
      OSTRACE(("FCNTL oldFile=%p, newFile=%p, rc=SQLITE_OK\n",
               hOldFile, pFile->h));
      return SQLITE_OK;
    }
#endif
    case SQLITE_FCNTL_NULL_IO: {
      (void)osCloseHandle(pFile->h);
      pFile->h = NULL;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_TEMPFILENAME: {
      char *zTFile = 0;
      int rc = winGetTempname(pFile->pVfs, &zTFile);
      if( rc==SQLITE_OK ){
        *(char**)pArg = zTFile;
      }
      OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
5044
5045
5046
5047
5048
5049
5050
5051

5052
5053
5054
5055
5056
5057
5058
5049
5050
5051
5052
5053
5054
5055

5056
5057
5058
5059
5060
5061
5062
5063







-
+







  /* If argument zPath is a NULL pointer, this function is required to open
  ** a temporary file. Use this buffer to store the file name in.
  */
  char *zTmpname = 0; /* For temporary filename, if necessary. */

  int rc = SQLITE_OK;            /* Function Return Code */
#if !defined(NDEBUG) || SQLITE_OS_WINCE
  int eType = flags&0xFFFFFF00;  /* Type of file to open */
  int eType = flags&0x0FFF00;  /* Type of file to open */
#endif

  int isExclusive  = (flags & SQLITE_OPEN_EXCLUSIVE);
  int isDelete     = (flags & SQLITE_OPEN_DELETEONCLOSE);
  int isCreate     = (flags & SQLITE_OPEN_CREATE);
  int isReadonly   = (flags & SQLITE_OPEN_READONLY);
  int isReadWrite  = (flags & SQLITE_OPEN_READWRITE);
Changes to src/parse.y.
39
40
41
42
43
44
45
46

47
48
49
50
51
52
53
39
40
41
42
43
44
45

46
47
48
49
50
51
52
53







-
+







%extra_context {Parse *pParse}

// This code runs whenever there is a syntax error
//
%syntax_error {
  UNUSED_PARAMETER(yymajor);  /* Silence some compiler warnings */
  if( TOKEN.z[0] ){
    sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
    parserSyntaxError(pParse, &TOKEN);
  }else{
    sqlite3ErrorMsg(pParse, "incomplete input");
  }
}
%stack_overflow {
  sqlite3OomFault(pParse->db);
}
106
107
108
109
110
111
112







113
114
115
116
117
118
119
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126







+
+
+
+
+
+
+







**      UPDATE ON (a,b,c)
**
** Then the "b" IdList records the list "a,b,c".
*/
struct TrigEvent { int a; IdList * b; };

struct FrameBound     { int eType; Expr *pExpr; };

/*
** Generate a syntax error
*/
static void parserSyntaxError(Parse *pParse, Token *p){
  sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", p);
}

/*
** Disable lookaside memory allocation for objects that might be
** shared across database connections.
*/
static void disableLookaside(Parse *pParse){
  sqlite3 *db = pParse->db;
1152
1153
1154
1155
1156
1157
1158
1159

1160
1161
1162
1163
1164
1165
1166
1159
1160
1161
1162
1163
1164
1165

1166
1167
1168
1169
1170
1171
1172
1173







-
+







  }else{
    /* When doing a nested parse, one can include terms in an expression
    ** that look like this:   #1 #2 ...  These terms refer to registers
    ** in the virtual machine.  #N is the N-th register. */
    Token t = X; /*A-overwrites-X*/
    assert( t.n>=2 );
    if( pParse->nested==0 ){
      sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t);
      parserSyntaxError(pParse, &t);
      A = 0;
    }else{
      A = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
      if( A ) sqlite3GetInt32(&t.z[1], &A->iTable);
    }
  }
}
Changes to src/printf.c.
934
935
936
937
938
939
940

941
942
943
944
945
946
947
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948







+







void sqlite3RecordErrorOffsetOfExpr(sqlite3 *db, const Expr *pExpr){
  while( pExpr
     && (ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) || pExpr->w.iOfst<=0)
  ){
    pExpr = pExpr->pLeft;
  }
  if( pExpr==0 ) return;
  if( ExprHasProperty(pExpr, EP_FromDDL) ) return;
  db->errByteOffset = pExpr->w.iOfst;
}

/*
** Enlarge the memory allocation on a StrAccum object so that it is
** able to accept at least N more bytes of text.
**
Changes to src/shell.c.in.
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891

4892
4893
4894
4895
4896
4897
4898
4882
4883
4884
4885
4886
4887
4888

4889
4890
4891
4892
4893
4894
4895
4896
4897
4898







-


+







    sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery);
    rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);
    if( rc ){
      sqlite3_fprintf(p->out, "/****** ERROR: %s ******/\n", zErr);
    }else{
      rc = SQLITE_CORRUPT;
    }
    sqlite3_free(zErr);
    free(zQ2);
  }
  sqlite3_free(zErr);
  return rc;
}

/*
** Text of help messages.
**
** The help text for each individual command begins with a line that starts
4947
4948
4949
4950
4951
4952
4953

4954
4955
4956
4957
4958
4959
4960
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961







+







  ".connection [close] [#]  Open or close an auxiliary database connection",
  ".crlf ?on|off?           Whether or not to use \\r\\n line endings",
  ".databases               List names and files of attached databases",
  ".dbconfig ?op? ?val?     List or change sqlite3_db_config() options",
#if SQLITE_SHELL_HAVE_RECOVER
  ".dbinfo ?DB?             Show status information about the database",
#endif
  ".dbtotxt                 Hex dump of the database file",
  ".dump ?OBJECTS?          Render database content as SQL",
  "   Options:",
  "     --data-only            Output only INSERT statements",
  "     --newlines             Allow unescaped newline characters in output",
  "     --nosys                Omit system tables (ex: \"sqlite_stat1\")",
  "     --preserve-rowids      Include ROWID values in the output",
  "   OBJECTS is a LIKE pattern for tables, indexes, triggers or views to dump",
6617
6618
6619
6620
6621
6622
6623



























































































6624
6625
6626
6627
6628
6629
6630
6618
6619
6620
6621
6622
6623
6624
6625
6626
6627
6628
6629
6630
6631
6632
6633
6634
6635
6636
6637
6638
6639
6640
6641
6642
6643
6644
6645
6646
6647
6648
6649
6650
6651
6652
6653
6654
6655
6656
6657
6658
6659
6660
6661
6662
6663
6664
6665
6666
6667
6668
6669
6670
6671
6672
6673
6674
6675
6676
6677
6678
6679
6680
6681
6682
6683
6684
6685
6686
6687
6688
6689
6690
6691
6692
6693
6694
6695
6696
6697
6698
6699
6700
6701
6702
6703
6704
6705
6706
6707
6708
6709
6710
6711
6712
6713
6714
6715
6716
6717
6718
6719
6720
6721
6722







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







  }
  sqlite3_free(zSchemaTab);
  sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_DATA_VERSION, &iDataVersion);
  sqlite3_fprintf(p->out, "%-20s %u\n", "data version", iDataVersion);
  return 0;
}
#endif /* SQLITE_SHELL_HAVE_RECOVER */

/*
** Implementation of the ".dbtotxt" command.
**
** Return 1 on error, 2 to exit, and 0 otherwise.
*/
static int shell_dbtotxt_command(ShellState *p, int nArg, char **azArg){
  sqlite3_stmt *pStmt = 0;
  sqlite3_int64 nPage = 0;
  int pgSz = 0;
  const char *zTail;
  char *zName = 0;
  int rc, i, j;
  unsigned char bShow[256];   /* Characters ok to display */

  memset(bShow, '.', sizeof(bShow));
  for(i=' '; i<='~'; i++){
    if( i!='{' && i!='}' && i!='"' && i!='\\' ) bShow[i] = (unsigned char)i;
  }
  rc = sqlite3_prepare_v2(p->db, "PRAGMA page_size", -1, &pStmt, 0);
  if( rc ) goto dbtotxt_error;
  rc = 0;
  if( sqlite3_step(pStmt)!=SQLITE_ROW ) goto dbtotxt_error;
  pgSz = sqlite3_column_int(pStmt, 0);
  sqlite3_finalize(pStmt);
  pStmt = 0;
  if( pgSz<512 || pgSz>65536 || (pgSz&(pgSz-1))!=0 ) goto dbtotxt_error;
  rc = sqlite3_prepare_v2(p->db, "PRAGMA page_count", -1, &pStmt, 0);
  if( rc ) goto dbtotxt_error;
  rc = 0;
  if( sqlite3_step(pStmt)!=SQLITE_ROW ) goto dbtotxt_error;
  nPage = sqlite3_column_int64(pStmt, 0);
  sqlite3_finalize(pStmt);
  pStmt = 0;
  if( nPage<1 ) goto dbtotxt_error;
  rc = sqlite3_prepare_v2(p->db, "PRAGMA databases", -1, &pStmt, 0);
  if( rc ) goto dbtotxt_error;
  if( sqlite3_step(pStmt)!=SQLITE_ROW ){
    zTail = "unk.db";
  }else{
    const char *zFilename = (const char*)sqlite3_column_text(pStmt, 2);
    if( zFilename==0 || zFilename[0]==0 ) zFilename = "unk.db";
    zTail = strrchr(zFilename, '/');
#if defined(_WIN32)
    if( zTail==0 ) zTail = strrchr(zFilename, '\\');
#endif
  }
  zName = strdup(zTail);
  shell_check_oom(zName);
  sqlite3_fprintf(p->out, "| size %lld pagesize %d filename %s\n",
                  nPage*pgSz, pgSz, zName);
  sqlite3_finalize(pStmt);
  pStmt = 0;
  rc = sqlite3_prepare_v2(p->db,
           "SELECT pgno, data FROM sqlite_dbpage ORDER BY pgno", -1, &pStmt, 0);
  if( rc ) goto dbtotxt_error;
  while( sqlite3_step(pStmt)==SQLITE_ROW ){
    sqlite3_int64 pgno = sqlite3_column_int64(pStmt, 0);
    const u8 *aData = sqlite3_column_blob(pStmt, 1);
    int seenPageLabel = 0;
    for(i=0; i<pgSz; i+=16){
      const u8 *aLine = aData+i;
      for(j=0; j<16 && aLine[j]==0; j++){}
      if( j==16 ) continue;
      if( !seenPageLabel ){
        sqlite3_fprintf(p->out, "| page %lld offset %lld\n", pgno, pgno*pgSz);
        seenPageLabel = 1;
      }
      sqlite3_fprintf(p->out, "|  %5d:", i);
      for(j=0; j<16; j++) sqlite3_fprintf(p->out, " %02x", aLine[j]);
      sqlite3_fprintf(p->out, "   ");
      for(j=0; j<16; j++){
        unsigned char c = (unsigned char)aLine[j];
        sqlite3_fprintf(p->out, "%c", bShow[c]);
      }
      sqlite3_fprintf(p->out, "\n");
    }
  }
  sqlite3_finalize(pStmt);
  sqlite3_fprintf(p->out, "| end %s\n", zName);
  free(zName);
  return 0;

dbtotxt_error:
  if( rc ){
    sqlite3_fprintf(stderr, "ERROR: %s\n", sqlite3_errmsg(p->db));
  }
  sqlite3_finalize(pStmt);
  free(zName);
  return 1;
}

/*
** Print the given string as an error message.
*/
static void shellEmitError(const char *zErr){
  sqlite3_fprintf(stderr,"Error: %s\n", zErr);
}
8794
8795
8796
8797
8798
8799
8800




8801
8802
8803
8804
8805
8806
8807
8886
8887
8888
8889
8890
8891
8892
8893
8894
8895
8896
8897
8898
8899
8900
8901
8902
8903







+
+
+
+







    if( nArg==2 ){
      setOrClearFlag(p, SHFLG_Echo, azArg[1]);
    }else{
      eputz("Usage: .echo on|off\n");
      rc = 1;
    }
  }else

  if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbtotxt", n)==0 ){
    rc = shell_dbtotxt_command(p, nArg, azArg);
  }else

  if( c=='e' && cli_strncmp(azArg[0], "eqp", n)==0 ){
    if( nArg==2 ){
      p->autoEQPtest = 0;
      if( p->autoEQPtrace ){
        if( p->db ) sqlite3_exec(p->db, "PRAGMA vdbe_trace=OFF;", 0, 0, 0);
        p->autoEQPtrace = 0;
10307
10308
10309
10310
10311
10312
10313

10314



10315
10316
10317
10318
10319
10320
10321
10403
10404
10405
10406
10407
10408
10409
10410

10411
10412
10413
10414
10415
10416
10417
10418
10419
10420







+
-
+
+
+







      shellDatabaseError(p->db);
      rc = 1;
    }
    close_db(pSrc);
  }else
#endif /* !defined(SQLITE_SHELL_FIDDLE) */

  if( c=='s' &&
  if( c=='s' && cli_strncmp(azArg[0], "scanstats", n)==0 ){
     (cli_strncmp(azArg[0], "scanstats",  n)==0 ||
      cli_strncmp(azArg[0], "scanstatus", n)==0)
  ){
    if( nArg==2 ){
      if( cli_strcmp(azArg[1], "vm")==0 ){
        p->scanstatsOn = 3;
      }else
      if( cli_strcmp(azArg[1], "est")==0 ){
        p->scanstatsOn = 2;
      }else{
11881
11882
11883
11884
11885
11886
11887
11888
11889
11890
11891
11892
11893
11894
11895
11980
11981
11982
11983
11984
11985
11986

11987
11988
11989
11990
11991
11992
11993







-







*/
static QuickScanState quickscan(char *zLine, QuickScanState qss,
                                SCAN_TRACKER_REFTYPE pst){
  char cin;
  char cWait = (char)qss; /* intentional narrowing loss */
  if( cWait==0 ){
  PlainScan:
    assert( cWait==0 );
    while( (cin = *zLine++)!=0 ){
      if( IsSpace(cin) )
        continue;
      switch (cin){
      case '-':
        if( *zLine!='-' )
          break;
11933
11934
11935
11936
11937
11938
11939
11940
11941
11942
11943
11944
11945
11946
11947
11948
11949
11950
11951
11952
11953
11954
11955
11956
11957
11958
11959
12031
12032
12033
12034
12035
12036
12037

12038
12039
12040
12041
12042
12043
12044
12045
12046
12047
12048

12049
12050
12051
12052
12053
12054
12055







-











-







    while( (cin = *zLine++)!=0 ){
      if( cin==cWait ){
        switch( cWait ){
        case '*':
          if( *zLine != '/' )
            continue;
          ++zLine;
          cWait = 0;
          CONTINUE_PROMPT_AWAITC(pst, 0);
          qss = QSS_SETV(qss, 0);
          goto PlainScan;
        case '`': case '\'': case '"':
          if(*zLine==cWait){
            /* Swallow doubled end-delimiter.*/
            ++zLine;
            continue;
          }
          deliberate_fall_through;
        case ']':
          cWait = 0;
          CONTINUE_PROMPT_AWAITC(pst, 0);
          qss = QSS_SETV(qss, 0);
          goto PlainScan;
        default: assert(0);
        }
      }
    }
12133
12134
12135
12136
12137
12138
12139
12140




12141
12142
12143
12144
12145
12146
12147
12229
12230
12231
12232
12233
12234
12235

12236
12237
12238
12239
12240
12241
12242
12243
12244
12245
12246







-
+
+
+
+







  }

  if( doAutoDetectRestore(p, zSql) ) return 1;
  return 0;
}

static void echo_group_input(ShellState *p, const char *zDo){
  if( ShellHasFlag(p, SHFLG_Echo) ) sqlite3_fprintf(p->out, "%s\n", zDo);
  if( ShellHasFlag(p, SHFLG_Echo) ){
    sqlite3_fprintf(p->out, "%s\n", zDo);
    fflush(p->out);
  }
}

#ifdef SQLITE_SHELL_FIDDLE
/*
** Alternate one_input_line() impl for wasm mode. This is not in the primary
** impl because we need the global shellState and cannot access it from that
** function without moving lots of code around (creating a larger/messier diff).
12593
12594
12595
12596
12597
12598
12599









12600
12601
12602
12603
12604
12605
12606
12692
12693
12694
12695
12696
12697
12698
12699
12700
12701
12702
12703
12704
12705
12706
12707
12708
12709
12710
12711
12712
12713
12714







+
+
+
+
+
+
+
+
+







  }
  return argv[i];
}

static void sayAbnormalExit(void){
  if( seenInterrupt ) eputz("Program interrupted.\n");
}

/* Routine to output from vfstrace
*/
static int vfstraceOut(const char *z, void *pArg){
  ShellState *p = (ShellState*)pArg;
  sqlite3_fputs(z, p->out);
  fflush(p->out);
  return 1;
}

#ifndef SQLITE_SHELL_IS_UTF8
#  if (defined(_WIN32) || defined(WIN32)) \
   && (defined(_MSC_VER) || (defined(UNICODE) && defined(__GNUC__)))
#    define SQLITE_SHELL_IS_UTF8          (0)
#  else
#    define SQLITE_SHELL_IS_UTF8          (1)
12830
12831
12832
12833
12834
12835
12836
12837
12838
12839
12840
12841
12842
12843
12844
12845
12938
12939
12940
12941
12942
12943
12944


12945
12946
12947
12948
12949
12950
12951







-
-







      verify_uninitialized();
      switch( n ){
         case 0:  sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);  break;
         case 2:  sqlite3_config(SQLITE_CONFIG_MULTITHREAD);   break;
         default: sqlite3_config(SQLITE_CONFIG_SERIALIZED);    break;
      }
    }else if( cli_strcmp(z,"-vfstrace")==0 ){
      vfstrace_register("trace",0,(int(*)(const char*,void*))sqlite3_fputs,
                        stderr,1);
      bEnableVfstrace = 1;
#ifdef SQLITE_ENABLE_MULTIPLEX
    }else if( cli_strcmp(z,"-multiplex")==0 ){
      extern int sqlite3_multiplex_initialize(const char*,int);
      sqlite3_multiplex_initialize(0, 1);
#endif
    }else if( cli_strcmp(z,"-mmap")==0 ){
12928
12929
12930
12931
12932
12933
12934



12935
12936
12937
12938
12939
12940
12941
13034
13035
13036
13037
13038
13039
13040
13041
13042
13043
13044
13045
13046
13047
13048
13049
13050







+
+
+







#else
    sqlite3_fprintf(stderr,
                    "%s: Error: no database filename specified\n", Argv0);
    return 1;
#endif
  }
  data.out = stdout;
  if( bEnableVfstrace ){
    vfstrace_register("trace",0,vfstraceOut, &data, 1);
  }
#ifndef SQLITE_SHELL_FIDDLE
  sqlite3_appendvfs_init(0,0,0);
#endif

  /* Go ahead and open the database file if it already exists.  If the
  ** file does not exist, delay opening it.  This prevents empty database
  ** files from being created if a user mistypes the database name argument
13172
13173
13174
13175
13176
13177
13178
13179
13180
13181
13182
13183
13184
13185

13186
13187

13188
13189
13190
13191
13192
13193
13194
13281
13282
13283
13284
13285
13286
13287





13288

13289
13290

13291
13292
13293
13294
13295
13296
13297
13298







-
-
-
-
-

-
+

-
+







  }else{
    /* Run commands received from standard input
    */
    if( stdin_is_interactive ){
      char *zHome;
      char *zHistory;
      int nHistory;
#if CIO_WIN_WC_XLATE
# define SHELL_CIO_CHAR_SET (stdout_is_console? " (UTF-16 console I/O)" : "")
#else
# define SHELL_CIO_CHAR_SET ""
#endif
      sqlite3_fprintf(stdout,
            "SQLite version %s %.19s%s\n" /*extra-version-info*/
            "SQLite version %s %.19s\n" /*extra-version-info*/
            "Enter \".help\" for usage hints.\n",
            sqlite3_libversion(), sqlite3_sourceid(), SHELL_CIO_CHAR_SET);
            sqlite3_libversion(), sqlite3_sourceid());
      if( warnInmemoryDb ){
        sputz(stdout, "Connected to a ");
        printBold("transient in-memory database");
        sputz(stdout, ".\nUse \".open FILENAME\" to reopen on a"
              " persistent database.\n");
      }
      zHistory = getenv("SQLITE_HISTORY");
Changes to src/sqlite.h.in.
1096
1097
1098
1099
1100
1101
1102





1103
1104
1105
1106
1107
1108
1109
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114







+
+
+
+
+







**
** <li>[[SQLITE_FCNTL_WIN32_SET_HANDLE]]
** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging.  This
** opcode causes the xFileControl method to swap the file handle with the one
** pointed to by the pArg argument.  This capability is used during testing
** and only needs to be supported when SQLITE_TEST is defined.
**
** <li>[[SQLITE_FCNTL_NULL_IO]]
** The [SQLITE_FCNTL_NULL_IO] opcode sets the low-level file descriptor
** or file handle for the [sqlite3_file] object such that it will no longer
** read or write to the database file.
**
** <li>[[SQLITE_FCNTL_WAL_BLOCK]]
** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might
** be advantageous to block on the next WAL lock if the lock is not immediately
** available.  The WAL subsystem issues this signal during rare
** circumstances in order to fix a problem with priority inversion.
** Applications should <em>not</em> use this file-control.
**
1249
1250
1251
1252
1253
1254
1255

1256
1257
1258
1259
1260
1261
1262
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268







+







#define SQLITE_FCNTL_SIZE_LIMIT             36
#define SQLITE_FCNTL_CKPT_DONE              37
#define SQLITE_FCNTL_RESERVE_BYTES          38
#define SQLITE_FCNTL_CKPT_START             39
#define SQLITE_FCNTL_EXTERNAL_READER        40
#define SQLITE_FCNTL_CKSM_FILE              41
#define SQLITE_FCNTL_RESET_CACHE            42
#define SQLITE_FCNTL_NULL_IO                43

/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE      SQLITE_FCNTL_GET_LOCKPROXYFILE
#define SQLITE_SET_LOCKPROXYFILE      SQLITE_FCNTL_SET_LOCKPROXYFILE
#define SQLITE_LAST_ERRNO             SQLITE_FCNTL_LAST_ERRNO


2627
2628
2629
2630
2631
2632
2633
2634

2635
2636
2637




2638
2639
2640
2641
2642
2643
2644
2633
2634
2635
2636
2637
2638
2639

2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654







-
+



+
+
+
+







** CAPI3REF: Count The Number Of Rows Modified
** METHOD: sqlite3
**
** ^These functions return the number of rows modified, inserted or
** deleted by the most recently completed INSERT, UPDATE or DELETE
** statement on the database connection specified by the only parameter.
** The two functions are identical except for the type of the return value
** and that if the number of rows modified by the most recent INSERT, UPDATE
** and that if the number of rows modified by the most recent INSERT, UPDATE,
** or DELETE is greater than the maximum value supported by type "int", then
** the return value of sqlite3_changes() is undefined. ^Executing any other
** type of SQL statement does not modify the value returned by these functions.
** For the purposes of this interface, a CREATE TABLE AS SELECT statement
** does not count as an INSERT, UPDATE or DELETE statement and hence the rows
** added to the new table by the CREATE TABLE AS SELECT statement are not
** counted.
**
** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are
** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
** [foreign key actions] or [REPLACE] constraint resolution are not counted.
**
** Changes to a view that are intercepted by
** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value
Changes to src/sqliteLimit.h.
19
20
21
22
23
24
25

26
27
28
29
30
31
32
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33







+







**
** The hard limit is the ability of a 32-bit signed integer
** to count the size: 2^31-1 or 2147483647.
*/
#ifndef SQLITE_MAX_LENGTH
# define SQLITE_MAX_LENGTH 1000000000
#endif
#define SQLITE_MIN_LENGTH 30   /* Minimum value for the length limit */

/*
** This is the maximum number of
**
**    * Columns in a table
**    * Columns in an index
**    * Columns in a view
Changes to src/tclsqlite.c.
4030
4031
4032
4033
4034
4035
4036
4037

4038
4039

4040
4041

4042

4043
4044
4045
4046
4047
4048
4049
4030
4031
4032
4033
4034
4035
4036

4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052







-
+


+


+

+







*/
static const char *tclsh_main_loop(void){
  static const char zMainloop[] =
    "if {[llength $argv]>=1} {\n"
#ifdef WIN32
      "set new [list]\n"
      "foreach arg $argv {\n"
        "if {[file exists $arg]} {\n"
        "if {[string match -* $arg] || [file exists $arg]} {\n"
          "lappend new $arg\n"
        "} else {\n"
          "set once 0\n"
          "foreach match [lsort [glob -nocomplain $arg]] {\n"
            "lappend new $match\n"
            "set once 1\n"
          "}\n"
          "if {!$once} {lappend new $arg}\n"
        "}\n"
      "}\n"
      "set argv $new\n"
      "unset new\n"
#endif
      "set argv0 [lindex $argv 0]\n"
      "set argv [lrange $argv 1 end]\n"
Changes to src/test_hexio.c.
183
184
185
186
187
188
189
190

191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207

208
209
210









211
212
213

214
215
216
217
218
219
220
221
222
223
224
225



226


227
228
229
230
231
232
233
183
184
185
186
187
188
189

190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209


210
211
212
213
214
215
216
217
218
219
220

221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236

237
238
239
240
241
242
243
244
245







-
+

















+

-
-
+
+
+
+
+
+
+
+
+


-
+












+
+
+
-
+
+







  sqlite3_free(aOut);
  fclose(out);
  Tcl_SetObjResult(interp, Tcl_NewIntObj(written));
  return TCL_OK;
}

/*
** USAGE:   hexio_get_int   HEXDATA
** USAGE:   hexio_get_int [-littleendian] HEXDATA
**
** Interpret the HEXDATA argument as a big-endian integer.  Return
** the value of that integer.  HEXDATA can contain between 2 and 8
** hexadecimal digits.
*/
static int SQLITE_TCLAPI hexio_get_int(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int val;
  Tcl_Size nIn;
  int nOut;
  const unsigned char *zIn;
  unsigned char *aOut;
  unsigned char aNum[4];
  int bLittle = 0;

  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "HEXDATA");
  if( objc==3 ){
    Tcl_Size n;
    char *z = Tcl_GetStringFromObj(objv[1], &n);
    if( n>=2 && n<=13 && memcmp(z, "-littleendian", n)==0 ){
      bLittle = 1;
    }
  }
  if( (objc-bLittle)!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "[-littleendian] HEXDATA");
    return TCL_ERROR;
  }
  zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[1], &nIn);
  zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[1+bLittle], &nIn);
  aOut = sqlite3_malloc64( 1 + nIn/2 );
  if( aOut==0 ){
    return TCL_ERROR;
  }
  nOut = sqlite3TestHexToBin(zIn, (int)nIn, aOut);
  if( nOut>=4 ){
    memcpy(aNum, aOut, 4);
  }else{
    memset(aNum, 0, sizeof(aNum));
    memcpy(&aNum[4-nOut], aOut, nOut);
  }
  sqlite3_free(aOut);
  if( bLittle ){
    val = (int)((u32)aNum[3]<<24) | (aNum[2]<<16) | (aNum[1]<<8) | aNum[0];
  }else{
  val = (aNum[0]<<24) | (aNum[1]<<16) | (aNum[2]<<8) | aNum[3];
    val = (int)((u32)aNum[0]<<24) | (aNum[1]<<16) | (aNum[2]<<8) | aNum[3];
  }
  Tcl_SetObjResult(interp, Tcl_NewIntObj(val));
  return TCL_OK;
}


/*
** USAGE:   hexio_render_int16   INTEGER
Changes to src/treeview.c.
1298
1299
1300
1301
1302
1303
1304




1305
1306
1307
1308
1309
1310
1311
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315







+
+
+
+







** parameters.  These variants are intended to be used from a symbolic
** debugger, such as "gdb", during interactive debugging sessions.
**
** This routines are given external linkage so that they will always be
** accessible to the debugging, and to avoid warnings about unused
** functions.  But these routines only exist in debugging builds, so they
** do not contaminate the interface.
**
** See Also:
**
**     sqlite3ShowWhereTerm() in where.c
*/
void sqlite3ShowExpr(const Expr *p){ sqlite3TreeViewExpr(0,p,0); }
void sqlite3ShowExprList(const ExprList *p){ sqlite3TreeViewExprList(0,p,0,0);}
void sqlite3ShowIdList(const IdList *p){ sqlite3TreeViewIdList(0,p,0,0); }
void sqlite3ShowSrcList(const SrcList *p){ sqlite3TreeViewSrcList(0,p); }
void sqlite3ShowSelect(const Select *p){ sqlite3TreeViewSelect(0,p,0); }
void sqlite3ShowWith(const With *p){ sqlite3TreeViewWith(0,p,0); }
Changes to src/where.c.
2328
2329
2330
2331
2332
2333
2334
2335

2336
2337
2338
2339
2340
2341
2342
2328
2329
2330
2331
2332
2333
2334

2335
2336
2337
2338
2339
2340
2341
2342







-
+







  }
  assert( pBuilder->nRecValid==nRecValid );
  return rc;
}
#endif /* SQLITE_ENABLE_STAT4 */


#ifdef WHERETRACE_ENABLED
#if defined(WHERETRACE_ENABLED) || defined(SQLITE_DEBUG)
/*
** Print the content of a WhereTerm object
*/
void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm){
  if( pTerm==0 ){
    sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm);
  }else{
2371
2372
2373
2374
2375
2376
2377



2378
2379
2380
2381
2382
2383
2384
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387







+
+
+







    }
    if( pTerm->iParent>=0 ){
      sqlite3DebugPrintf(" iParent=%d", pTerm->iParent);
    }
    sqlite3DebugPrintf("\n");
    sqlite3TreeViewExpr(0, pTerm->pExpr, 0);
  }
}
void sqlite3ShowWhereTerm(WhereTerm *pTerm){
  sqlite3WhereTermPrint(pTerm, 0);
}
#endif

#ifdef WHERETRACE_ENABLED
/*
** Show the complete content of a WhereClause
*/
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3560
3561
3562
3563
3564
3565
3566

3567
3568
3569
3570
3571
3572
3573







-








  if( jointype & JT_LTORJ ) return 0;
  pParse = pWC->pWInfo->pParse;
  while( pWhere->op==TK_AND ){
    if( !whereUsablePartialIndex(iTab,jointype,pWC,pWhere->pLeft) ) return 0;
    pWhere = pWhere->pRight;
  }
  if( pParse->db->flags & SQLITE_EnableQPSG ) pParse = 0;
  for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
    Expr *pExpr;
    pExpr = pTerm->pExpr;
    if( (!ExprHasProperty(pExpr, EP_OuterON) || pExpr->w.iJoin==iTab)
     && ((jointype & JT_OUTER)==0 || ExprHasProperty(pExpr, EP_OuterON))
     && sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab)
     && (pTerm->wtFlags & TERM_VNULL)==0
Changes to src/wherecode.c.
611
612
613
614
615
616
617

618
619
620
621
622
623
624
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625







+







      }
      sqlite3ExprListDelete(db, pOrigRhs);
      if( pOrigLhs ){
        sqlite3ExprListDelete(db, pOrigLhs);
        pNew->pLeft->x.pList = pLhs;
      }
      pSelect->pEList = pRhs;
      pSelect->selId = ++pParse->nSelect; /* Req'd for SubrtnSig validity */
      if( pLhs && pLhs->nExpr==1 ){
        /* Take care here not to generate a TK_VECTOR containing only a
        ** single value. Since the parser never creates such a vector, some
        ** of the subroutines do not handle this case.  */
        Expr *p = pLhs->a[0].pExpr;
        pLhs->a[0].pExpr = 0;
        sqlite3ExprDelete(db, pNew->pLeft);
Changes to src/window.c.
1666
1667
1668
1669
1670
1671
1672

1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687












1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707

1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727













1728
1729
1730
1731
1732
1733
1734







+















+
+
+
+
+
+
+
+
+
+
+
+




















+






-
-
-
-
-
-
-
-
-
-
-
-
-







  Vdbe *v = sqlite3GetVdbe(pParse);
  Window *pWin;
  for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
    FuncDef *pFunc = pWin->pWFunc;
    int regArg;
    int nArg = pWin->bExprArgs ? 0 : windowArgCount(pWin);
    int i;
    int addrIf = 0;

    assert( bInverse==0 || pWin->eStart!=TK_UNBOUNDED );

    /* All OVER clauses in the same window function aggregate step must
    ** be the same. */
    assert( pWin==pMWin || sqlite3WindowCompare(pParse,pWin,pMWin,0)!=1 );

    for(i=0; i<nArg; i++){
      if( i!=1 || pFunc->zName!=nth_valueName ){
        sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+i, reg+i);
      }else{
        sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+i, reg+i);
      }
    }
    regArg = reg;

    if( pWin->pFilter ){
      int regTmp;
      assert( ExprUseXList(pWin->pOwner) );
      assert( pWin->bExprArgs || !nArg ||nArg==pWin->pOwner->x.pList->nExpr );
      assert( pWin->bExprArgs || nArg  ||pWin->pOwner->x.pList==0 );
      regTmp = sqlite3GetTempReg(pParse);
      sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp);
      addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1);
      VdbeCoverage(v);
      sqlite3ReleaseTempReg(pParse, regTmp);
    }

    if( pMWin->regStartRowid==0
     && (pFunc->funcFlags & SQLITE_FUNC_MINMAX)
     && (pWin->eStart!=TK_UNBOUNDED)
    ){
      int addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regArg);
      VdbeCoverage(v);
      if( bInverse==0 ){
        sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1, 1);
        sqlite3VdbeAddOp2(v, OP_SCopy, regArg, pWin->regApp);
        sqlite3VdbeAddOp3(v, OP_MakeRecord, pWin->regApp, 2, pWin->regApp+2);
        sqlite3VdbeAddOp2(v, OP_IdxInsert, pWin->csrApp, pWin->regApp+2);
      }else{
        sqlite3VdbeAddOp4Int(v, OP_SeekGE, pWin->csrApp, 0, regArg, 1);
        VdbeCoverageNeverTaken(v);
        sqlite3VdbeAddOp1(v, OP_Delete, pWin->csrApp);
        sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
      }
      sqlite3VdbeJumpHere(v, addrIsNull);
    }else if( pWin->regApp ){
      assert( pWin->pFilter==0 );
      assert( pFunc->zName==nth_valueName
           || pFunc->zName==first_valueName
      );
      assert( bInverse==0 || bInverse==1 );
      sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1);
    }else if( pFunc->xSFunc!=noopStepFunc ){
      int addrIf = 0;
      if( pWin->pFilter ){
        int regTmp;
        assert( ExprUseXList(pWin->pOwner) );
        assert( pWin->bExprArgs || !nArg ||nArg==pWin->pOwner->x.pList->nExpr );
        assert( pWin->bExprArgs || nArg  ||pWin->pOwner->x.pList==0 );
        regTmp = sqlite3GetTempReg(pParse);
        sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp);
        addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1);
        VdbeCoverage(v);
        sqlite3ReleaseTempReg(pParse, regTmp);
      }
     
      if( pWin->bExprArgs ){
        int iOp = sqlite3VdbeCurrentAddr(v);
        int iEnd;

        assert( ExprUseXList(pWin->pOwner) );
        nArg = pWin->pOwner->x.pList->nExpr;
        regArg = sqlite3GetTempRange(pParse, nArg);
1750
1751
1752
1753
1754
1755
1756
1757
1758


1759
1760
1761
1762
1763
1764
1765
1751
1752
1753
1754
1755
1756
1757

1758
1759
1760
1761
1762
1763
1764
1765
1766
1767







-

+
+







      sqlite3VdbeAddOp3(v, bInverse? OP_AggInverse : OP_AggStep,
                        bInverse, regArg, pWin->regAccum);
      sqlite3VdbeAppendP4(v, pFunc, P4_FUNCDEF);
      sqlite3VdbeChangeP5(v, (u8)nArg);
      if( pWin->bExprArgs ){
        sqlite3ReleaseTempRange(pParse, regArg, nArg);
      }
      if( addrIf ) sqlite3VdbeJumpHere(v, addrIf);
    }

    if( addrIf ) sqlite3VdbeJumpHere(v, addrIf);
  }
}

/*
** Values that may be passed as the second argument to windowCodeOp().
*/
#define WINDOW_RETURN_ROW 1
Changes to test/corruptN.test.
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
137
138
139
140
141
142
143









144
145
146
147
148
149
150







-
-
-
-
-
-
-
-
-







|   4080: 00 00 00 00 00 05 03 01 01 09 02 04 03 01 09 04   ................
| page 4 offset 12288
|      0: 0a 00 00 00 02 0f f5 00 0f fb 0f f5 00 00 00 00   ................
|   4080: 00 00 00 00 00 05 03 01 01 0d 02 04 03 00 00 00   ................
| end c-b92b.txt.db
}]} {}

# This test only works with the legacy RC4 PRNG
if 0 {
  prng_seed 0 db
  do_catchsql_test 2.1 {
  SELECT count(*) FROM sqlite_schema;
  WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1000)
  INSERT INTO t1(a) SELECT randomblob(null) FROM c;
  } {1 {database disk image is malformed}}
}

reset_db
if {![info exists ::G(perm:presql)]} {
  do_execsql_test 3.0 {
    CREATE TABLE t1(x INTEGER PRIMARY KEY AUTOINCREMENT, y);
    PRAGMA writable_schema = 1;
    UPDATE sqlite_schema 
Changes to test/e_expr.test.
1228
1229
1230
1231
1232
1233
1234
1235

1236
1237
1238




1239
1240



1241
1242
1243
1244
1245
1246
1247
1228
1229
1230
1231
1232
1233
1234

1235
1236
1237

1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253







-
+


-
+
+
+
+


+
+
+







  END
} {null}
db nullvalue {}

# EVIDENCE-OF: R-13943-13592 A NULL result is considered untrue when
# evaluating WHEN terms.
#
do_execsql_test e_expr-21.4.1 {
do_execsql_test e_expr-21.4.1a {
  SELECT CASE WHEN NULL THEN 'A' WHEN 1 THEN 'B' END, iif(NULL,8,99);
} {B 99}
do_execsql_test e_expr-21.4.2 {
do_execsql_test e_expr-21.4.1b {
  SELECT CASE WHEN NULL THEN 'A' WHEN 1 THEN 'B' END, if(NULL,8,99);
} {B 99}
do_execsql_test e_expr-21.4.2a {
  SELECT CASE WHEN 0 THEN 'A' WHEN NULL THEN 'B' ELSE 'C' END, iif(0,8,99);
} {C 99}
do_execsql_test e_expr-21.4.2b {
  SELECT CASE WHEN 0 THEN 'A' WHEN NULL THEN 'B' ELSE 'C' END, if(0,8,99);
} {C 99}

# EVIDENCE-OF: R-38620-19499 In a CASE with a base expression, the base
# expression is evaluated just once and the result is compared against
# the evaluation of each WHEN expression from left to right.
#
# Note: This test case tests the "evaluated just once" part of the above
# statement. Tests associated with the next two statements test that the
1965
1966
1967
1968
1969
1970
1971
1972

1973
1974



1975
1976
1977
1978
1979
1980
1981
1971
1972
1973
1974
1975
1976
1977

1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990







-
+


+
+
+







do_execsql_test e_expr-37.5 {
   SELECT CASE WHEN '0' THEN 'true' ELSE 'false' END, iif('0','true','false');
} {false false}

# EVIDENCE-OF: R-55532-10108 Values 1, 1.0, 0.1, -0.1 and '1english' are
# considered to be true.
#
do_execsql_test e_expr-37.6 {
do_execsql_test e_expr-37.6a {
   SELECT CASE WHEN 1 THEN 'true' ELSE 'false' END, iif(1,'true','false');
} {true true}
do_execsql_test e_expr-37.6b {
   SELECT CASE WHEN 1 THEN 'true' ELSE 'false' END, if(1,'true');
} {true true}
do_execsql_test e_expr-37.7 {
   SELECT CASE WHEN 1.0 THEN 'true' ELSE 'false' END, iif(1.0,'true','false');
} {true true}
do_execsql_test e_expr-37.8 {
   SELECT CASE WHEN 0.1 THEN 'true' ELSE 'false' END, iif(0.1,'true','false');
} {true true}
do_execsql_test e_expr-37.9 {
Added test/errofst1.test.































1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# 2024-11-20
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# Test cases for sqlite3_error_offset()
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

do_execsql_test errofst1-1.1 {
  CREATE TABLE t1 as select 1 as aa;
  CREATE VIEW t2 AS
     WITH t3 AS (SELECT 1 FROM t1 AS bb, t1 AS cc WHERE cc.aa <= sts.aa)
     SELECT 1 FROM t3 AS dd;
}
do_catchsql_test errofst1-1.2 {
  SELECT * FROM t2;
} {1 {no such column: sts.aa}}
do_test errofst1-1.3 {
  sqlite3_error_offset db
} {-1}

finish_test
Added test/fork-test.c.






















































































































































































































































































































1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/*
** The program demonstrates how a child process created using fork()
** can continue to use SQLite for a database that the parent had opened and
** and was writing into when the fork() occurred.
**
** This program executes the following steps:
**
**   1.  Create a new database file.  Open it, and populate it.
**   2.  Start a transaction and make changes.
**       ^-- close the transaction prior to fork() if --commit-before-fork
**   3.  Fork()
**   4.  In the child, close the database connection.  Special procedures
**       are needed to close the database connection in the child.  See the
**       implementation below.
**   5.  Commit the transaction in the parent.
**   6.  Verify that the transaction committed in the parent.
**   7.  In the child, after a delay to allow time for (5) and (6),
**       open a new database connection and verify that the transaction
**       committed by (5) is seen.
**   8.  Add make further changes and commit them in the child, using the
**       new database connection.
**   9.  In the parent, after a delay to account for (8), verify that
**       the new transaction added by (8) can be seen.
**
** Usage:
**
**    fork-test FILENAME [options]
**
** Options:
**
**    --wal                       Run the database in WAL mode
**    --vfstrace                  Enable VFS tracing for debugging
**    --commit-before-fork        COMMIT prior to the fork() in step 3
**    --delay-after-4 N           Pause for N seconds after step 4
**
** How To Compile:
**
**   gcc -O0 -g -Wall -I$(SQLITESRC) \
**         f1.c $(SQLITESRC)/ext/misc/vfstrace.c $(SQLITESRC/sqlite3.c \
**         -ldl -lpthread -lm
**
** Test procedure:
**
**   (1)  Run "fork-test x1.db".  Verify no I/O errors occur and that
**        both parent and child see all three rows in the t1 table.
**
**   (2)  Repeat (1) adding the --wal option.
**
**   (3)  Repeat (1) and (2) adding the --commit-before-fork option.
**
**   (4)  Repeat all prior steps adding the --delay-after-4 option with
**        a timeout of 15 seconds or so.  Then, while both parent and child
**        are paused, run the CLI against the x1.db database from a separate
**        window and verify that all the correct file locks are still working
**        correctly.
**
** Take-Aways:
**
**   *   If a process has open SQLite database connections when it fork()s,
**       the child can call exec() and all it well.  Nothing special needs
**       to happen.
**
**   *   If a process has open SQLite database connections when it fork()s,
**       the child can do anything that does not involve using SQLite without
**       causing problems in the parent.  No special actions are needed in
**       the child.
**
**   *   If a process has open SQLite database connections when it fork()s,
**       the child can call sqlite3_close() on those database connections
**       as long as there were no pending write transactions when the fork()
**       occurred.
**
**   *   If a process has open SQLite database connections that are in the
**       middle of a write transaction and then the processes fork()s, the
**       child process should close the database connections using the
**       procedures demonstrated in Step 4 below before trying to do anything
**       else with SQLite.
**
**   *   If a child process can safely close SQLite database connections that
**       it inherited via fork() using the procedures shown in Step 4 below
**       even if the database connections were not involved in a write
**       transaction at the time of the fork().  The special procedures are
**       required if a write transaction was active.  They are optional
**       otherwise.  No harm results from using the special procedures when
**       they are not necessary.
**
**   *   Child processes that use SQLite should open their own database
**       connections.  They should not attempt to use a database connection
**       that is inherited from the parent.
*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include "sqlite3.h"

/*
** Process ID of the parent
*/
static pid_t parentPid = 0;

/*
** Return either "parent" or "child", as appropriate.
*/
static const char *whoAmI(void){
  return getpid()==parentPid ? "parent" : "child";
}

/*
** This is an sqlite3_exec() callback routine that prints all results.
*/
static int execCallback(void *pNotUsed, int nCol, char **aVal, char **aCol){
  int i;
  const char *zWho = whoAmI();
  for(i=0; i<nCol; i++){
    const char *zVal = aVal[i];
    const char *zCol = aCol[i];
    if( zVal==0 ) zVal = "NULL";
    if( zCol==0 ) zCol = "NULL";
    printf("%s: %s = %s\n", zWho, zCol, zVal);
    fflush(stdout);
  }
  return 0;
}

/*
** Execute one or more SQL statements.
*/
static void sqlExec(sqlite3 *db, const char *zSql, int bCallback){
  int rc;
  char *zErr = 0;
  printf("%s: %s\n", whoAmI(), zSql);
  fflush(stdout);
  rc = sqlite3_exec(db, zSql, bCallback ? execCallback : 0, 0, &zErr);
  if( rc || zErr!=0 ){
    printf("%s: %s: rc=%d: %s\n", 
      whoAmI(), zSql, rc, zErr);
    exit(1);
  }
}

/*
** Trace callback for the vfstrace extension.
*/
static int vfsTraceCallback(const char *zMsg, void *pNotUsed){
  printf("%s: %s", whoAmI(), zMsg);
  fflush(stdout);
  return 0;
}

/* External VFS module provided by ext/misc/vfstrace.c
*/
extern int vfstrace_register(
  const char *zTraceName,         // Name of the newly constructed VFS
  const char *zOldVfsName,        // Name of the underlying VFS
  int (*xOut)(const char*,void*), // Output routine.  ex: fputs
  void *pOutArg,                  // 2nd argument to xOut.  ex: stderr
  int makeDefault                 // Make the new VFS the default
);


int main(int argc, char **argv){
  sqlite3 *db;
  int rc;
  int i;
  int useWal = 0;
  const char *zFilename = 0;
  pid_t child = 0, c2;
  int status;
  int bCommitBeforeFork = 0;
  int nDelayAfter4 = 0;

  for(i=1; i<argc; i++){
    const char *z = argv[i];
    if( z[0]=='-' && z[1]=='-' && z[2]!=0 ) z++;
    if( strcmp(z, "-wal")==0 ){
      useWal = 1;
    }else if( strcmp(z, "-commit-before-fork")==0 ){
      bCommitBeforeFork = 1;
    }else if( strcmp(z, "-delay-after-4")==0 && i+1<argc ){
      i++;
      nDelayAfter4 = atoi(argv[i]);
    }else if( strcmp(z, "-vfstrace")==0 ){
      vfstrace_register("vfstrace", 0, vfsTraceCallback, 0, 1);
    }else if( z[0]=='-' ){
      printf("unknown option: \"%s\"\n", argv[i]);
      exit(1);
    }else if( zFilename!=0 ){
      printf("unknown argument: \"%s\"\n", argv[i]);
      exit(1);
    }else{
      zFilename = argv[i];
    }
  }
  if( zFilename==0 ){
    printf("Usage: %s FILENAME\n", argv[0]);
    return 1;
  }

  /**  Step 1 **/
  printf("Step 1:\n");
  parentPid = getpid();
  unlink(zFilename);
  rc = sqlite3_open(zFilename, &db);
  if( rc ){
    printf("sqlite3_open() returns %d\n", rc);
    exit(1);
  }
  if( useWal ){
    sqlExec(db, "PRAGMA journal_mode=WAL;", 0);
  }
  sqlExec(db, "CREATE TABLE t1(x);", 0);
  sqlExec(db, "INSERT INTO t1 VALUES('First row');", 0);
  sqlExec(db, "SELECT x FROM t1;", 1);

  /**  Step 2 **/
  printf("Step 2:\n");
  sqlExec(db, "BEGIN IMMEDIATE;", 0);
  sqlExec(db, "INSERT INTO t1 VALUES('Second row');", 0);
  sqlExec(db, "SELECT x FROM t1;", 1);
  if( bCommitBeforeFork ) sqlExec(db, "COMMIT", 0);

  /**  Step 3 **/
  printf("Step 3:\n"); fflush(stdout);
  child = fork();
  if( child!=0 ){
    printf("Parent = %d\nChild = %d\n", getpid(), child);
  }

  /**  Step 4 **/
  if( child==0 ){
    int k;
    printf("Step 4:\n"); fflush(stdout);

    /***********************************************************************
    ** The following block of code closes the database connection without
    ** rolling back or changing any files on disk.  This is necessary to
    ** preservce the pending transaction in the parent. 
    */
    for(k=0; 1/*exit-by-break*/; k++){
      const char *zDbName = sqlite3_db_name(db, k);
      sqlite3_file *pJrnl = 0;
      if( k==1 ) continue;
      if( zDbName==0 ) break;
      sqlite3_file_control(db, zDbName, SQLITE_FCNTL_NULL_IO, 0);
      sqlite3_file_control(db, zDbName, SQLITE_FCNTL_JOURNAL_POINTER, &pJrnl);
      if( pJrnl && pJrnl->pMethods && pJrnl->pMethods->xFileControl ){
        pJrnl->pMethods->xFileControl(pJrnl, SQLITE_FCNTL_NULL_IO, 0);
      }
    }    
    sqlite3_close(db);
    /*
    ** End of special close procedures for SQLite database connections
    ** inherited via fork().
    ***********************************************************************/

    printf("%s: database connection closed\n", whoAmI()); fflush(stdout);
  }else{
    /* Pause the parent briefly to give the child a chance to close its
    ** database connection */
    sleep(1);
  }

  if( nDelayAfter4>0 ){
    printf("%s: Delay for %d seconds\n", whoAmI(), nDelayAfter4);
    fflush(stdout);
    sleep(nDelayAfter4);
    printf("%s: Continue after %d delay\n", whoAmI(), nDelayAfter4);
    fflush(stdout);
  }

  /**  Step 5 **/
  if( child!=0 ){
    printf("Step 5:\n");
    if( !bCommitBeforeFork ) sqlExec(db, "COMMIT", 0);
    sqlExec(db, "SELECT x FROM t1;", 1);
  }    
  

  /** Step 7 **/
  if( child==0 ){
    sleep(2);
    printf("Steps 7 and 8:\n");
    rc = sqlite3_open(zFilename, &db);
    if( rc ){
      printf("Child unable to reopen the database.  rc = %d\n", rc);
      exit(1);
    }
    sqlExec(db, "SELECT * FROM t1;", 1);

    /** Step 8 **/
    sqlExec(db, "INSERT INTO t1 VALUES('Third row');", 0);
    sqlExec(db, "SELECT * FROM t1;", 1);
    sleep(1);
    return 0;
  }
  c2 = wait(&status);
  printf("Process %d finished with status %d\n", c2, status);

  /** Step 9 */
  if( child!=0 ){
    printf("Step 9:\n");
    sqlExec(db, "SELECT * FROM t1;", 1);
  }

  return 0;
}
Changes to test/fts3corrupt7.test.
197
198
199
200
201
202
203











































































204
205
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


|   4080: 00 00 00 00 00 05 04 08 09 01 02 04 04 08 08 09   ................
| end x.db
}]} {}

do_catchsql_test 1.1 {
  SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'rtree NEAR rtree NEAR "json1 enable"';
} {0 {}}

#-------------------------------------------------------------------------
reset_db
do_test 1.0 {
  sqlite3 db {}
  db deserialize [decode_hexdb {
| size 24576 pagesize 4096 filename crash-10b0f1037e9c85.db
| page 1 offset 0
|      0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00   SQLite format 3.
|     16: 10 00 00 00 00 40 20 20 00 00 00 01 00 00 00 07   .....@  ........
|     32: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00   ................
|     80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01   ................
|     96: 00 2e 82 40 0d 00 00 00 06 00 00 00 0f 8d 0f 21   ...@...........!
|    112: 0e b9 0d c8 0e 7e 0d a4 00 00 00 00 00 00 00 00   .....~..........
|   3488: 00 00 00 00 21 ff 06 17 10 10 01 30 74 61 62 6c   ....!......0tabl
|   3504: 65 74 32 74 32 00 43 52 45 41 54 45 20 54 41 42   et2t2.CREATE TAB
|   3520: 4c 45 20 74 32 28 70 29 81 33 00 07 17 1f 1f 01   LE t2(p).3......
|   3536: 82 35 74 61 62 6c 65 74 31 5f 73 65 67 64 69 72   .5tablet1_segdir
|   3552: 74 31 5f 73 65 67 64 69 72 05 43 52 45 41 54 45   t1_segdir.CREATE
|   3568: 20 54 41 42 4c 45 20 27 74 31 5f 73 65 67 64 69    TABLE 't1_segdi
|   3584: 72 27 28 6c 65 76 65 6c 20 09 4e 50 45 47 45 50   r'(level .NPEGEP
|   3600: 2c 69 64 78 20 09 4e 50 45 47 45 50 2c 73 74 61   ,idx .NPEGEP,sta
|   3616: 72 74 5f 62 6c 6f 63 6b 20 09 4e 50 45 47 45 50   rt_block .NPEGEP
|   3632: 2c 6c 65 61 76 65 73 5f 65 6e 64 5f 62 6c 6f 63   ,leaves_end_bloc
|   3648: 6b 20 09 4e 50 45 47 45 50 2c 65 6e 64 5f 62 6c   k .NPEGEP,end_bl
|   3664: 6f 63 6b 20 09 4e 50 45 47 45 50 2c 72 6f 6f 74   ock .NPEGEP,root
|   3680: 20 42 0c 4f 42 2c 50 52 49 4d 41 52 59 20 4b 45    B.OB,PRIMARY KE
|   3696: 59 28 6c 65 76 65 6c 2c 20 69 64 78 29 29 31 00   Y(level, idx))1.
|   3712: 06 17 45 1f 01 00 00 00 00 00 00 73 71 6c 69 74   ..E........sqlit
|   3728: 65 5f 61 75 74 6f 69 6e 64 65 78 5f 74 31 5f 73   e_autoindex_t1_s
|   3744: 65 67 64 69 72 5f 31 00 00 00 00 00 00 00 00 00   egdir_1.........
|   3760: 06 00 00 00 00 00 00 00 00 66 00 07 17 23 23 01   .........f...##.
|   3776: 81 13 74 61 62 6c 65 74 31 5f 73 65 67 6d 65 6e   ..tablet1_segmen
|   3792: 74 73 74 31 5f 73 65 67 6d 65 6e 74 73 00 43 52   tst1_segments.CR
|   3808: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 73   EATE TABLE 't1_s
|   3824: 65 67 6d 65 6e 74 73 27 28 0c 6f 63 6b 09 64 0a   egments'(.ock.d.
|   3840: 20 09 4e 50 45 47 45 50 20 50 50 09 04 31 50 09    .NPEGEP PP..1P.
|   3856: 20 0b 45 09 0c 20 62 0c 6f 63 6b 20 42 0c 4f 42    .E.. b.ock B.OB
|   3872: 29 6a 00 07 17 20 20 01 81 1f 74 61 62 6c 65 74   )j...  ...tablet
|   3888: 31 5f 63 6f 6e 74 65 6e 74 74 31 5f 63 6f 6e 74   1_contentt1_cont
|   3904: 65 6e 74 00 43 52 45 41 54 45 20 54 41 42 4c 45   ent.CREATE TABLE
|   3920: 20 27 74 31 5f 63 6f 6e 74 65 6e 74 27 28 64 6f    't1_content'(do
|   3936: 09 64 20 09 4e 50 45 47 45 50 20 50 50 09 0d 0c   .d .NPEGEP PP...
|   3952: 50 09 20 0b 45 09 0c 20 27 03 03 01 27 0c 20 0a   P. .E.. '...'. .
|   3968: 27 03 01 02 27 0c 20 27 03 02 03 27 29 38 00 06   '...'. '...')8..
|   3984: 17 10 10 08 5f 74 61 62 6c 65 74 31 74 31 43 52   ...._tablet1t1CR
|   4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42   EATE VIRTUAL TAB
|   4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 33   LE t1 USING fts3
| page 5 offset 16384
|      0: 0d 00 00 00 02 00 00 00 00 00 0b a0 00 00 00 00   ................
|   2976: 82 0a 02 08 00 00 00 00 17 84 06 00 00 00 00 00   ................
|   2992: 00 01 00 04 00 00 00 00 00 08 00 00 00 00 00 00   ................
|   3008: 00 00 03 00 00 00 00 01 00 03 00 00 00 00 01 00   ................
|   3024: 03 00 00 00 00 07 00 00 00 00 00 00 00 03 00 00   ................
|   3040: 00 00 08 00 00 00 00 00 00 00 00 03 00 00 00 00   ................
|   3056: 06 00 00 00 00 00 00 03 00 00 00 00 04 00 00 00   ................
|   3072: 00 03 00 00 00 00 06 65 6e 61 62 6c 65 09 25 09   .......enable.%.
|   3088: 05 04 04 04 04 00 00 00 08 00 00 00 00 00 00 00   ................
|   3104: 00 03 00 00 00 00 04 00 00 00 00 03 00 00 00 00   ................
|   3120: 01 00 03 00 00 00 00 03 00 00 00 03 00 00 00 00   ................
|   3136: 06 00 00 00 00 00 00 03 00 00 00 00 05 6a 73 6f   .............jso
|   3152: 6e 31 03 25 13 00 00 04 00 00 00 00 03 00 00 00   n1.%............
|   3168: 00 03 00 00 00 03 00 00 00 00 05 00 00 00 00 00   ................
|   3184: 03 00 00 00 00 04 00 00 00 00 03 00 00 00 00 04   ................
|   3200: 00 00 00 00 03 00 00 00 00 05 72 74 72 65 65 03   ..........rtree.
|   3216: 25 01 00 0d 0a 07 08 01 ff ff ff ff ff 01 00 00   %...............
| page 6 offset 20480
|      0: 0a 00 00 00 02 00 00 00 0f fb 0f f5 00 00 00 00   ................
|   4080: 00 00 00 00 00 05 04 09 00 01 02 04 00 00 00 00   ................
| end crash-10b0f1037e9c85.db
}]} {}

do_catchsql_test 2.1 {
  SELECT 0 FROM t1 WHERE t1 MATCH 'rtree NEAR rtree"json1 enable"';
} {1 {database disk image is malformed}}

finish_test
Changes to test/fts3fault.test.
211
212
213
214
215
216
217








218
219
220
221
222
223
224
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232







+
+
+
+
+
+
+
+







do_faultsim_test 8.4 -prep { 
  faultsim_restore_and_reopen
  db func mit mit
} -body {
  execsql { SELECT mit(matchinfo(t8, 'l')) FROM t8 WHERE t8 MATCH 'a b c' }
} -test {
  faultsim_test_result {0 3}
}
do_faultsim_test 8.5 -prep { 
  faultsim_restore_and_reopen
  db func mit mit
} -body {
  execsql { SELECT mit(matchinfo(t8, 'l')) FROM t8 WHERE t8 MATCH '"a b c"' }
} -test {
  faultsim_test_result {0 3}
}

do_test 9.0 {
  faultsim_delete_and_reopen
  execsql {
    CREATE VIRTUAL TABLE t9 USING fts4(tokenize=porter);
    INSERT INTO t9 VALUES(
Changes to test/in7.test.
188
189
190
191
192
193
194

195

























196
197
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







+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


  SELECT * FROM v1 WHERE u IN w1
  UNION ALL
  SELECT * FROM v2 WHERE u IN w2
} {
  1 2 3 4 5 6
}

# 2024-11-20 https://sqlite.org/forum/forumpost/0b9ded2f8428ac00

#
# Bug in SubrtnSig logic.  If a SELECT statement is copied and the copy
# is subsequently modified, we need to change the Select.selId on the
# copy so that when the copy is used to generate code, the SubrtnSig
# logic won't try to substitute the original SELECT in place of the
# copy which is now different.
#
do_execsql_test 3.5 {
  DROP TABLE IF EXISTS t1;
  DROP TABLE IF EXISTS t2;
  CREATE TABLE t1 (a int UNIQUE);
  CREATE TABLE t2 (b int UNIQUE);
  INSERT INTO t1 VALUES (1);
  INSERT INTO t2 VALUES (1), (2);
  SELECT t1.a, t2.b FROM t1, t2 WHERE (t1.a, t2.b) = (1, 1);
} {1 1}
do_execsql_test 3.6 {
  SELECT t1.a, t2.b FROM t1, t2 WHERE (t1.a, t2.b) IN ((1, 1));
} {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
Changes to test/json102.test.
726
727
728
729
730
731
732
























733
734
735
736
737
738
739
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







  DELETE FROM t1;
  INSERT INTO t1(x) VALUES('[null,123,4.5,"six",[7,8],{"b":9}]');
  WITH c(y) AS (VALUES(0),(1),(2),(3),(4),(5),(6))
  SELECT
    y,
    x->y AS '->',
    CASE WHEN subtype(x->y) THEN 'json' ELSE typeof(x->y) END AS 'type',
    x->>y AS '->>',
    CASE WHEN subtype(x->>y) THEN 'json' ELSE typeof(x->>y) END AS 'type',
    json_extract(x,format('$[%d]',y)) AS 'json_extract',
    CASE WHEN subtype(json_extract(x,format('$[%d]',y)))
      THEN 'json' ELSE typeof(json_extract(x,format('$[%d]',y))) END AS 'type'
  FROM c, t1 ORDER BY y;    
} [list \
  0 null      json {}        null    {}        null       \
  1 123       json 123       integer 123       integer    \
  2 4.5       json 4.5       real    4.5       real       \
  3 {"six"}   json six       text    six       text       \
  4 {[7,8]}   json {[7,8]}   text    {[7,8]}   json       \
  5 {{"b":9}} json {{"b":9}} text    {{"b":9}} json       \
  6 {}        null {}        null    {}        null
]
do_execsql_test json102-1620 {
  DELETE FROM t1;
  INSERT INTO t1(x) VALUES('[null,123,4.5,"six",[7,8],{"b":9}]');
  WITH c(y) AS (VALUES(0),(1),(2),(3),(4),(5),(6))
  SELECT
    y,
    x->y AS '->',
    CASE WHEN subtype(if(json_valid(x),x->y)) THEN 'json'
         ELSE typeof(x->y) END AS 'type',
    x->>y AS '->>',
    CASE WHEN subtype(x->>y) THEN 'json' ELSE typeof(x->>y) END AS 'type',
    json_extract(x,format('$[%d]',y)) AS 'json_extract',
    CASE WHEN subtype(json_extract(x,format('$[%d]',y)))
      THEN 'json' ELSE typeof(json_extract(x,format('$[%d]',y))) END AS 'type'
  FROM c, t1 ORDER BY y;    
} [list \
Changes to test/savepoint6.test.
11
12
13
14
15
16
17




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







+
+
+
+







#
# $Id: savepoint6.test,v 1.4 2009/06/05 17:09:12 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

proc sql {zSql} {
  if {0 && $::debug_op} {
    puts stderr "$zSql ;"
    flush stderr
  }
  uplevel db eval [list $zSql]
  #puts stderr "$zSql ;"
}

set DATABASE_SCHEMA {
    PRAGMA auto_vacuum = incremental;
    CREATE TABLE t1(x, y);
63
64
65
66
67
68
69

70
71
72
73
74

75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

92
93
94
95
96
97
98
99
100
101
102
103
104
105
106

107
108
109
110
111
112
113
114
115
116
117
118

119
120
121
122
123
124
125
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134







+





+

















+















+












+







#   rollback  NAME
#   release   NAME
#
#   insert_rows XVALUES
#   delete_rows XVALUES
#
proc savepoint {zName} {
  if {$::debug_op} { puts stderr "savepoint $zName" ; flush stderr }
  catch { sql "SAVEPOINT $zName" }
  lappend ::lSavepoint [list $zName [array get ::aEntry]]
}

proc rollback {zName} {
  if {$::debug_op} { puts stderr "rollback $zName" ; flush stderr }
  catch { sql "ROLLBACK TO $zName" }
  for {set i [expr {[llength $::lSavepoint]-1}]} {$i>=0} {incr i -1} {
    set zSavepoint [lindex $::lSavepoint $i 0]
    if {$zSavepoint eq $zName} {
      unset -nocomplain ::aEntry
      array set ::aEntry [lindex $::lSavepoint $i 1]


      if {$i+1 < [llength $::lSavepoint]} {
        set ::lSavepoint [lreplace $::lSavepoint [expr $i+1] end]
      }
      break
    }
  }
}

proc release {zName} {
  if {$::debug_op} { puts stderr "release $zName" ; flush stderr }
  catch { sql "RELEASE $zName" }
  for {set i [expr {[llength $::lSavepoint]-1}]} {$i>=0} {incr i -1} {
    set zSavepoint [lindex $::lSavepoint $i 0]
    if {$zSavepoint eq $zName} {
      set ::lSavepoint [lreplace $::lSavepoint $i end]
      break
    }
  }

  if {[llength $::lSavepoint] == 0} {
    #puts stderr "-- End of transaction!!!!!!!!!!!!!"
  }
}

proc insert_rows {lX} {
  if {$::debug_op} { puts stderr "insert_rows $lX" ; flush stderr }
  foreach x $lX {
    set y [x_to_y $x]

    # Update database [db]
    sql "INSERT OR REPLACE INTO t1 VALUES($x, '$y')"

    # Update the Tcl database.
    set ::aEntry($x) $y
  }
}

proc delete_rows {lX} {
  if {$::debug_op} { puts stderr "delete_rows $lX" ; flush stderr }
  foreach x $lX {
    # Update database [db]
    sql "DELETE FROM t1 WHERE x = $x"

    # Update the Tcl database.
    unset -nocomplain ::aEntry($x)
  }
159
160
161
162
163
164
165





166
167
168
169
170
171
172
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186







+
+
+
+
+







  set ret [list]
  for {set i 0} {$i<$nRes} {incr i} {
    lappend ret [expr int(rand()*$nRange)]
  }
  return $ret
} 
#-------------------------------------------------------------------------

set ::debug_op 0
proc debug_ops {} {
  set ::debug_op 1
}

proc database_op {} {
  set i [expr int(rand()*2)] 
  if {$i==0} {
    insert_rows [random_integers 100 1000]
  }
  if {$i==1} {
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
195
196
197
198
199
200
201



202
203
204
205
206
207
208







-
-
-







proc savepoint_op {} {
  set names {one two three four five}
  set cmds  {savepoint savepoint savepoint savepoint release rollback}

  set C [lindex $cmds [expr int(rand()*6)]]
  set N [lindex $names [expr int(rand()*5)]]

  #puts stderr "   $C $N ;  "
  #flush stderr

  $C $N
  return ok
}

expr srand(0)

############################################################################
Changes to test/sqllimits1.test.
70
71
72
73
74
75
76







77
78
79
80
81
82
83
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90







+
+
+
+
+
+
+







} {-1}
do_test sqllimits1-1.22 {
  sqlite3_limit db SQLITE_LIMIT_TOOBIG 123
} {-1}
do_test sqllimits1-1.23 {
  sqlite3_limit db SQLITE_LIMIT_TOOBIG 123
} {-1}

# Minimum value for SQLITE_LIMIT_LENGTH is 30
#
do_test sqllimits1-1.30 {
  sqlite3_limit db SQLITE_LIMIT_LENGTH 1
  sqlite3_limit db SQLITE_LIMIT_LENGTH 1000000000
} 30


# Decrease all limits by half.  Verify that the new limits take.
#
if {$SQLITE_MAX_LENGTH>=2} {
  do_test sqllimits1-2.1.1 {
    sqlite3_limit db SQLITE_LIMIT_LENGTH \
Changes to test/subtype1.test.
69
70
71
72
73
74
75










76
77
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87







+
+
+
+
+
+
+
+
+
+


  SELECT *, json_quote(y) FROM (SELECT +json('1') AS y);
} {1 {"1"}}
do_execsql_test subtype1-320 {
  SELECT *, json_quote(y) FROM (SELECT +json('1') AS y)
   WHERE json_quote(y)='"1"';
} {1 {"1"}}

# 2024-11-26
# subtype survives if()
#
do_execsql_test subtype1-400 {
  WITH t400(id,j) AS (VALUES
    (1,'{a:{x:1,y:2},b:{x:3,y:4}}'),
    (2,'not json')
  )
  SELECT id, subtype(if(json_valid(j,6),j->'a')) FROM t400;
} {1 74 2 0}

finish_test
Changes to test/symlink2.test.
53
54
55
56
57
58
59

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







+







# Ensure that test.db has been created.
#
do_execsql_test 1.0 {
  CREATE TABLE t1(x, y);
  INSERT INTO t1 VALUES(1,9999);
}

forcedelete link.db
do_test 2.0 {
  createWin32Symlink link.db test.db
} {}

do_test 2.1 {
  file exists test.db
} {1}
83
84
85
86
87
88
89

90
91
92
93
94
95

96
97
98
99
100
101
102
84
85
86
87
88
89
90
91
92
93
94
95
96

97
98
99
100
101
102
103
104







+





-
+







  execsql { SELECT x, y FROM t1; } db3
} {1 9999}

do_test 3.4 {
  db3 close
} {}

# The -nofollow option does not work on Windows
do_test 3.5 {
  list [catch {
    sqlite3 db4 link.db -nofollow true
    execsql { SELECT x, y FROM t1; } db4
  } res] $res
} {1 {unable to open database file}}
} {0 {1 9999}}

catch {db4 close}

do_test 4.0 {
  db2 close
  deleteWin32Symlink link.db
} {}
Changes to test/testrunner.tcl.
461
462
463
464
465
466
467

468
469
470
471
472
473
474
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475







+







  exit
}

# Compute an elapse time string MM:SS or HH:MM:SS based on the
# number of milliseconds in the argument.
#
proc elapsetime {ms} {
  if {$ms==""} {set ms 0}
  set s [expr {int(($ms+500.0)*0.001)}]
  set hr [expr {$s/3600}]
  set mn [expr {($s/60)%60}]
  set sc [expr {$s%60}]
  if {$hr>0} {
    return [format %02d:%02d:%02d $hr $mn $sc]
  } else {
1599
1600
1601
1602
1603
1604
1605


1606
1607
1608
1609
1610
1611
1612
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615







+
+







  } break;
  set et [elapsetime $totaltime]
  set pltfm {}
  trdb eval {
     SELECT pltfm, count(*) FROM jobs WHERE pltfm IS NOT NULL
      ORDER BY 2 DESC LIMIT 1
  } break
  if {$totalerr==""} {set totalerr 0}
  if {$totaltest==""} {set totaltest 0}
  puts "$totalerr errors out of $totaltest tests in $et $pltfm"
  trdb eval {
     SELECT DISTINCT substr(svers,1,79) as v1 FROM jobs WHERE svers IS NOT NULL
  } {puts $v1}

}

Changes to test/wal2.test.
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
30
31
32
33
34
35
36





































37
38
39
40
41
42
43







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







    incr sqlite_sync_count $adj
  } {
    ifcapable !dirsync {
      incr sqlite_sync_count $adj
    }
  }
}

proc set_tvfs_hdr {file args} {

  # Set $nHdr to the number of bytes in the wal-index header:
  set nHdr 48
  set nInt [expr {$nHdr/4}]

  if {[llength $args]>2} {
    error {wrong # args: should be "set_tvfs_hdr fileName ?val1? ?val2?"}
  }

  set blob [tvfs shm $file]
  if {$::tcl_platform(byteOrder)=="bigEndian"} {set fmt I} {set fmt i}

  if {[llength $args]} {
    set ia [lindex $args 0]
    set ib $ia
    if {[llength $args]==2} {
      set ib [lindex $args 1]
    }
    binary scan $blob a[expr $nHdr*2]a* dummy tail
    set blob [binary format ${fmt}${nInt}${fmt}${nInt}a* $ia $ib $tail]
    tvfs shm $file $blob
  }

  binary scan $blob ${fmt}${nInt} ints
  return $ints
}

proc incr_tvfs_hdr {file idx incrval} {
  set ints [set_tvfs_hdr $file]
  set v [lindex $ints $idx]
  incr v $incrval
  lset ints $idx $v
  set_tvfs_hdr $file $ints
}


#-------------------------------------------------------------------------
# Test case wal2-1.*:
#
# Set up a small database containing a single table. The database is not
# checkpointed during the test - all content resides in the log file.
#
Changes to test/wal_common.tcl.
83
84
85
86
87
88
89








































83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
  upvar $hdrvar hdr
  set c1 0
  set c2 0
  wal_cksum_intlist c1 c2 [lrange $hdr 0 9]
  lset hdr 10 $c1
  lset hdr 11 $c2
}

# This command assumes that $file is the name of a database file opened
# in wal mode using a [testvfs] VFS. It returns a list of the 12 32-bit
# integers that make up the wal-index-header for the named file.
#
proc set_tvfs_hdr {file args} {

  # Set $nHdr to the number of bytes in the wal-index header:
  set nHdr 48
  set nInt [expr {$nHdr/4}]

  if {[llength $args]>2} {
    error {wrong # args: should be "set_tvfs_hdr fileName ?val1? ?val2?"}
  }

  set blob [tvfs shm $file]
  if {$::tcl_platform(byteOrder)=="bigEndian"} {set fmt I} {set fmt i}

  if {[llength $args]} {
    set ia [lindex $args 0]
    set ib $ia
    if {[llength $args]==2} {
      set ib [lindex $args 1]
    }
    binary scan $blob a[expr $nHdr*2]a* dummy tail
    set blob [binary format ${fmt}${nInt}${fmt}${nInt}a* $ia $ib $tail]
    tvfs shm $file $blob
  }

  binary scan $blob ${fmt}${nInt} ints
  return $ints
}

proc incr_tvfs_hdr {file idx incrval} {
  set ints [set_tvfs_hdr $file]
  set v [lindex $ints $idx]
  incr v $incrval
  lset ints $idx $v
  set_tvfs_hdr $file $ints
}
Changes to test/window8.tcl.
485
486
487
488
489
490
491






























































492
493
494
495
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+




  SELECT (
    SELECT max(a) OVER ( ORDER BY (SELECT sum(a) FROM t1) )
         + min(a) OVER() 
  )
  FROM t1
}

==========

execsql_test 10.0 {
  DROP TABLE IF EXISTS t1;
  CREATE TABLE t1(a INTEGER, b INTEGER);
  INSERT INTO t1 VALUES (10, 1), 
                        (20, -1), 
                        (5, 2), 
                        (15, 0), 
                        (25, 3);
}

execsql_test 10.1 {
  SELECT 
    a, b, MIN(a) FILTER(WHERE b > 0) OVER win 
    FROM t1
    WINDOW win AS (ORDER BY a ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING);
}

execsql_test 10.2 {
  SELECT 
    a, b, MIN(a) FILTER(WHERE b > 0) OVER win 
    FROM t1
    WINDOW win AS ();
}

execsql_test 10.3 {
  SELECT 
    a, b, MIN(a) FILTER(WHERE b > 0) OVER win 
    FROM t1
    WINDOW win AS (ORDER BY a);
}

execsql_test 10.4 {
  SELECT 
    a, b, MIN(a) OVER win 
    FROM t1
    WINDOW win AS (ORDER BY a ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING);
}

==========

execsql_test 11.0 {
  DROP TABLE IF EXISTS t2;
  CREATE TABLE t2(a INTEGER, b INTEGER);
  INSERT INTO t2 VALUES(1, 12);
  INSERT INTO t2 VALUES(2, 10);
  INSERT INTO t2 VALUES(3, 15);
  INSERT INTO t2 VALUES(4, 22);
  INSERT INTO t2 VALUES(5,  1);
  INSERT INTO t2 VALUES(6,  4);
  INSERT INTO t2 VALUES(7,  7);
  INSERT INTO t2 VALUES(8,  6);
  INSERT INTO t2 VALUES(9, 22);
  INSERT INTO t2 VALUES(10, 2);
}

execsql_test 11.1 {
  SELECT a, min(b) FILTER (WHERE a%2 != 0) OVER win
  FROM t2
  WINDOW win AS (ORDER BY a ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING);
}

finish_test


Changes to test/window8.test.
6535
6536
6537
6538
6539
6540
6541































































6542
6543
6535
6536
6537
6538
6539
6540
6541
6542
6543
6544
6545
6546
6547
6548
6549
6550
6551
6552
6553
6554
6555
6556
6557
6558
6559
6560
6561
6562
6563
6564
6565
6566
6567
6568
6569
6570
6571
6572
6573
6574
6575
6576
6577
6578
6579
6580
6581
6582
6583
6584
6585
6586
6587
6588
6589
6590
6591
6592
6593
6594
6595
6596
6597
6598
6599
6600
6601
6602
6603
6604
6605
6606







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


do_execsql_test 9.2 {
  SELECT (
    SELECT max(a) OVER ( ORDER BY (SELECT sum(a) FROM t1) )
         + min(a) OVER() 
  )
  FROM t1
} {}

#==========================================================================

do_execsql_test 10.0 {
  DROP TABLE IF EXISTS t1;
  CREATE TABLE t1(a INTEGER, b INTEGER);
  INSERT INTO t1 VALUES (10, 1), 
                        (20, -1), 
                        (5, 2), 
                        (15, 0), 
                        (25, 3);
} {}

do_execsql_test 10.1 {
  SELECT 
    a, b, MIN(a) FILTER(WHERE b > 0) OVER win 
    FROM t1
    WINDOW win AS (ORDER BY a ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING);
} {5 2 5   10 1 5   15 0 10   20 -1 25   25 3 25}

do_execsql_test 10.2 {
  SELECT 
    a, b, MIN(a) FILTER(WHERE b > 0) OVER win 
    FROM t1
    WINDOW win AS ();
} {10 1 5   20 -1 5   5 2 5   15 0 5   25 3 5}

do_execsql_test 10.3 {
  SELECT 
    a, b, MIN(a) FILTER(WHERE b > 0) OVER win 
    FROM t1
    WINDOW win AS (ORDER BY a);
} {5 2 5   10 1 5   15 0 5   20 -1 5   25 3 5}

do_execsql_test 10.4 {
  SELECT 
    a, b, MIN(a) OVER win 
    FROM t1
    WINDOW win AS (ORDER BY a ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING);
} {5 2 5   10 1 5   15 0 10   20 -1 15   25 3 20}

#==========================================================================

do_execsql_test 11.0 {
  DROP TABLE IF EXISTS t2;
  CREATE TABLE t2(a INTEGER, b INTEGER);
  INSERT INTO t2 VALUES(1, 12);
  INSERT INTO t2 VALUES(2, 10);
  INSERT INTO t2 VALUES(3, 15);
  INSERT INTO t2 VALUES(4, 22);
  INSERT INTO t2 VALUES(5,  1);
  INSERT INTO t2 VALUES(6,  4);
  INSERT INTO t2 VALUES(7,  7);
  INSERT INTO t2 VALUES(8,  6);
  INSERT INTO t2 VALUES(9, 22);
  INSERT INTO t2 VALUES(10, 2);
} {}

do_execsql_test 11.1 {
  SELECT a, min(b) FILTER (WHERE a%2 != 0) OVER win
  FROM t2
  WINDOW win AS (ORDER BY a ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING);
} {1 12   2 12   3 1   4 1   5 1   6 1   7 1   8 7   9 7   10 22}

finish_test
Changes to test/window9.test.
277
278
279
280
281
282
283


























































284
285
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







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+



do_catchsql_test 9.1 {
  SELECT sum(c) OVER (
    ORDER BY c RANGE BETWEEN 0 PRECEDING AND '-700' PRECEDING
  )
  FROM t1
} {1 {frame ending offset must be a non-negative number}}

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

do_execsql_test 10.0 {
  CREATE TABLE t1(a, b);
  INSERT INTO t1 VALUES(1, 'a');
  INSERT INTO t1 VALUES(2, 'b');
  INSERT INTO t1 VALUES(3, 'c');
  INSERT INTO t1 VALUES(4, 'd');
  INSERT INTO t1 VALUES(5, 'e');
  INSERT INTO t1 VALUES(6, 'f');
}

do_execsql_test 10.1 {
  SELECT a, min(b) OVER win
  FROM t1
  WINDOW win AS (ORDER BY a ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING)
} {
  1 a
  2 a
  3 a
  4 b
  5 c
  6 d
}

do_execsql_test 10.2 {
  SELECT a, min(b) FILTER (WHERE a%2) OVER win
  FROM t1
  WINDOW win AS (ORDER BY a ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING)
} {
  1 a
  2 a
  3 a
  4 c
  5 c
  6 e
}

do_execsql_test 10.3 {
  SELECT a, min(b) FILTER (WHERE (a%2)=0) OVER win
  FROM t1
  WINDOW win AS (ORDER BY a ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING)
} {
  1 b
  2 b
  3 b
  4 b
  5 d
  6 d
}

do_catchsql_test 10.4 {
  SELECT a, nth_value(b, 1) FILTER (WHERE (a%2)=0) OVER win
  FROM t1
  WINDOW win AS (ORDER BY a ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING)
} {1 {FILTER clause may only be used with aggregate window functions}}

finish_test
Changes to tool/buildtclext.tcl.
11
12
13
14
15
16
17

18
19
20
21
22
23
24
25
26
27

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44



45
46
47
48
49
50
51
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56







+










+

















+
+
+







Options:

   --build-only         Only build the extension, don't install it
   --cc COMPILER        Build using this compiler
   --info               Show info on existing SQLite TCL extension installs
   --install-only       Install an extension previously build
   --uninstall          Uninstall the extension
   --destdir DIR        Installation root (used by "make install DESTDIR=...")

Other options are retained and passed through into the compiler.}


set build 1
set install 1
set uninstall 0
set infoonly 0
set CC {}
set OPTS {}
set DESTDIR ""; # --destdir "$(DESTDIR)"
for {set ii 0} {$ii<[llength $argv]} {incr ii} {
  set a0 [lindex $argv $ii]
  if {$a0=="--install-only"} {
    set build 0
  } elseif {$a0=="--build-only"} {
    set install 0
  } elseif {$a0=="--uninstall"} {
    set build 0
    set install 0
    set uninstall 1
  } elseif {$a0=="--info"} {
    set build 0
    set install 0
    set infoonly 1
  } elseif {$a0=="--cc" && $ii+1<[llength $argv]} {
    incr ii
    set CC [lindex $argv $ii]
  } elseif {$a0=="--destdir" && $ii+1<[llength $argv]} {
    incr ii
    set DESTDIR [lindex $argv $ii]
  } elseif {[string match -* $a0]} {
    append OPTS " $a0"
  } else {
    puts stderr "Unknown option: \"$a0\"\n"
    puts stderr $help
    exit 1
  }
103
104
105
106
107
108
109
110

111
112
113
114
115
116
117
108
109
110
111
112
113
114

115
116
117
118
119
120
121
122







-
+








  # Read the tclConfig.sh file into the $tclConfig variable
  #
  #puts "using $LIBDIR/tclConfig.sh"
  set fd [open $LIBDIR/tclConfig.sh rb]
  set tclConfig [read $fd]
  close $fd
  

  # Extract parameter we will need from the tclConfig.sh file
  #
  set TCLMAJOR 8
  regexp {TCL_MAJOR_VERSION='(\d)'} $tclConfig all TCLMAJOR
  set SUFFIX so
  regexp {TCL_SHLIB_SUFFIX='\.([^']+)'} $tclConfig all SUFFIX
  if {$CC==""} {
136
137
138
139
140
141
142
143
144
145
146
147
148




149
150

151
152
153
154
155
156
157
141
142
143
144
145
146
147

148
149
150
151
152
153
154
155
156
157

158
159
160
161
162
163
164
165







-





+
+
+
+

-
+







  }
  set cmd {${CC} ${CFLAGS} ${LDFLAGS} -shared}
  regexp {TCL_SHLIB_LD='([^']+)'} $tclConfig all cmd
  set LDFLAGS "$INC -DUSE_TCL_STUBS"
  if {[string length $OPTS]>1} {
    append LDFLAGS $OPTS
  }
  set CMD [subst $cmd]
  if {$TCLMAJOR>8} {
    set OUT libtcl9sqlite$VERSION.$SUFFIX
  } else {
    set OUT libsqlite$VERSION.$SUFFIX
  }
  set @ $OUT; # Workaround for https://sqlite.org/forum/forumpost/0683a49cb02f31a1
              # in which Gentoo edits their tclConfig.sh to include an soname
              # linker flag which includes ${@} (the target file's name).
  set CMD [subst $cmd]
}
  

# Show information about prior installs
#
if {$infoonly} {
  set cnt 0
  foreach dir $auto_path {
    foreach subdir [glob -nocomplain -types d $dir/sqlite3*] {
      if {[file exists $subdir/pkgIndex.tcl]} {
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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221

222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240

241
242
243
244
245
246
247
248







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+

















-
+








if {$install} {
  # Figure out where the extension will be installed.  Put the extension
  # in the first writable directory on $auto_path.
  #
  set DEST {}
  foreach dir $auto_path {
    if {[string match //*:* $dir]} {
      # We can't install to //zipfs: paths
      continue
    } elseif {"" ne $DESTDIR && ![file writable $DESTDIR]} {
      # In the common case, ${DESTDIR}${dir} will not exist when we
      # get to this point of the installation, and the "is writable?"
      # check just below this will fail for that case.
      #
      # Assumption made for simplification's sake: if ${DESTDIR} is
      # not writable, no part of the remaining path will
      # be. ${DESTDIR} is typically used by OS package maintainers,
      # not normal installations, and it "shouldn't" ever happen that
      # the DESTDIR is read-only while the target ${DESTDIR}${prefix}
      # is not, as it's typical for such installations to create
      # ${prefix} on-demand under ${DESTDIR}.
      break
    }
    set dir ${DESTDIR}$dir
    if {[file writable $dir]} {
    if {[file writable $dir] || "" ne $DESTDIR} {
      # the dir will be created later ^^^^^^^^
      set DEST $dir
      break
    } elseif {[glob -nocomplain $dir/sqlite3*/pkgIndex.tcl]!=""} {
      set conflict [lindex [glob $dir/sqlite3*/pkgIndex.tcl] 0]
      puts "Unable to install. There is already a conflicting version"
      puts "of the SQLite TCL Extension that cannot be overwritten at\n"
      puts "   [file dirname $conflict]\n"
      puts "Consider running using sudo to work around this problem."
      exit 1
    }
  }
  if {$DEST==""} {
    puts "None of the directories on \$auto_path are writable by this process,"
    puts "so the installation cannot take place.  Consider running using sudo"
    puts "to work around this problem.\n"
    puts "These are the (unwritable) \$auto_path directories:\n"
    foreach dir $auto_path {
      puts "  *  $dir"
      puts "  *  ${DESTDIR}$dir"
    }
    exit 1
  }
}

if {$build} {
  # Generate the pkgIndex.tcl file
Changes to tool/mkccode.tcl.
1
2
3
4
5
6
7
8
9

10
11
12
13
14
15
16
1
2
3
4
5
6
7
8

9
10
11
12
13
14
15
16








-
+







#!/usr/bin/tclsh
#
# Use this script to build C-language source code for a program that uses
# tclsqlite.c together with custom TCL scripts and/or C extensions for
# either SQLite or TCL.
#
# Usage example:
#
#     tclsh mkccode.tcl demoapp.c.in >demoapp.c
#     tclsh mkccode.tcl -DENABLE_FEATURE_XYZ demoapp.c.in >demoapp.c
#
# The demoapp.c.in file contains a mixture of C code, TCL script, and
# processing directives used by mktclsqliteprog.tcl to build the final C-code
# output file.  Most lines of demoapp.c.in are copied straight through into
# the output.  The following control directives are recognized:
#
# BEGIN_STRING
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48


49
50
51
52

53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99







+
+
+
+
+
+
+
+
+




-
-
+
+


-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+





-
+




+
+
+


+


+







#      not begin with either $ROOT or $HOME, then it is interpreted relative
#      to the current working directory.
#
#      If the INCLUDE occurs in the middle of BEGIN_STRING...END_STRING
#      then all of the text in the input file is converted into C-language
#      string literals.
#
# IFDEF macro
# IFNDEF macro
# ELSE
# ENDIF
#
#      The text from "IFDEF macro" down to the next ELSE or ENDIF is
#      included only if -Dmacro appears as a command-line argument.
#      The "IFNDEF macro" simply inverts the initial test.
#
# None of the control directives described above will nest.  Only the
# top-level input file ("demoapp.c.in" in the example) is interpreted.
# referenced files are copied verbatim.
#
if {[llength $argv]!=1} {
  puts stderr "Usage: $argv0 TEMPLATE >OUTPUT"
proc usage {} {
  puts stderr "Usage: $::argv0 \[OPTIONS\] TEMPLATE >OUTPUT"
  exit 1
}
set infile [lindex $argv 0]
set infile {}
foreach ax $argv {
  if {[string match -D* $ax]} {
    if {[string match *=* $ax]} {
      regexp -- {-D([^=]+)=(.*)} $ax all name value
      set DEF($name) $value
    } else {
      set DEF([string range $ax 2 end]) 1
    }
    continue
  }
  if {[string match -* $ax]} {
    puts stderr "$::argv0:  Unknown option \"$ax\""
    usage
  }
  if {$infile!=""} {
    puts stderr "$::argv0:  Surplus argument: \"$ax\""
    usage
  }
  set infile $ax
}
set ROOT [file normalize [file dir $argv0]/..]
set HOME [file normalize [file dir $infile]]
set in [open $infile rb]
puts [subst {/* DO NOT EDIT
**
** This file was generated by \"$argv0 $infile\".
** This file was generated by \"$argv0 $argv\".
** To make changes, edit $infile then rerun the generator
** command.
*/}]
set instr 0
set omit {}
set nomit 0
set ln 0
while {1} {
  set line [gets $in]
  incr ln
  if {[eof $in]} break
  if {[regexp {^INCLUDE (.*)} $line all path]} {
    if {$nomit>0 && [string match *1* $omit]} continue
    if {0} {
      # https://github.com/msteveb/jimtcl/issues/320
      regsub {^\$ROOT\y} $path $ROOT path
      regsub {^\$HOME\y} $path $HOME path
    } else {
      set path [string map "\$ROOT $ROOT" $path]
      set path [string map "\$HOME $HOME" $path]
87
88
89
90
91
92
93





























94

95
96
97
98
99
100




121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156

157
158
159
160
161
162
163
164
165
166
167







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+






+
+
+
+
    continue
  }
  if {[regexp {^END_STRING} $line]} {
    set instr 0
    puts "/* END_STRING */"
    continue
  }
  if {[regexp {^IFNDEF +([A-Za-z_0-9]+)} $line all name]} {
    set omit $omit[info exists DEF($name)]
    incr nomit
    continue
  }
  if {[regexp {^IFDEF +([A-Za-z_0-9]+)} $line all name]} {
    set omit $omit[expr {![info exists DEF($name)]}]
    incr nomit
    continue
  }
  if {[regexp {^ELSE} $line]} {
    if {!$nomit} {
      puts stderr "$infile:$ln: ELSE without a prior IFDEF"
      exit 1
    }
    set omit [string range $omit 0 end-1][expr {![string index $omit end]}]
    continue
  }
  if {[regexp {^ENDIF} $line]} {
    if {!$nomit} {
      puts stderr "$infile:$ln: ENDIF without a prior IFDEF"
      exit 1
    }
    incr nomit -1
    set omit [string range $omit 0 [expr {$nomit-1}]]
    continue
  }
  if {$nomit>0 && [string match *1* $omit]} {
    # noop
  if {$instr} {
  } elseif {$instr} {
    set x [string map "\\\\ \\\\\\\\ \\\" \\\\\"" $line]
    puts "\"$x\\n\""
  } else {
    puts $line
  }
}
if {$nomit} {
  puts stderr "$infile:$ln: One or more unterminated IFDEFs"
  exit 1
}
Changes to tool/sqlite3_analyzer.c.in.
1
2
3
4
5


6
7
8
9
10
11
12
13
14
15
16
17
18

19


20
21
22
23
24
25
26
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

19
20

21
22
23
24
25
26
27
28
29





+
+











-

+
-
+
+







/*
** Read an SQLite database file and analyze its space utilization.  Generate
** text on standard output.
*/
#define TCLSH_INIT_PROC sqlite3_analyzer_init_proc
IFDEF INCLUDE_SQLITE3_C
#undef SQLITE_ENABLE_DBSTAT_VTAB
#define SQLITE_ENABLE_DBSTAT_VTAB 1
#undef SQLITE_THREADSAFE
#define SQLITE_THREADSAFE 0
#undef SQLITE_ENABLE_COLUMN_METADATA
#define SQLITE_OMIT_DECLTYPE 1
#define SQLITE_OMIT_DEPRECATED 1
#define SQLITE_OMIT_PROGRESS_CALLBACK 1
#define SQLITE_OMIT_SHARED_CACHE 1
#define SQLITE_DEFAULT_MEMSTATUS 0
#define SQLITE_MAX_EXPR_DEPTH 0
#define SQLITE_OMIT_LOAD_EXTENSION 1
#if !defined(SQLITE_AMALGAMATION) && !defined(USE_EXTERNAL_SQLITE)
INCLUDE sqlite3.c
ELSE
#endif
#include "sqlite3.h"
ENDIF
INCLUDE $ROOT/src/tclsqlite.c

#if defined(_WIN32)
INCLUDE $ROOT/ext/misc/sqlite3_stdio.h
INCLUDE $ROOT/ext/misc/sqlite3_stdio.c

/* Substitute "puts" command.  Only these forms recognized:
Added tool/tclConfigShToAutoDef.sh.





























1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#!/bin/sh
#
# A level of indirection for use soley by the configure script
# (auto.def).
#
# Expects to be passed a full path to a tclConfig.sh. It sources it
# and emits TCL code which sets some vars which are exported by
# tclConfig.sh.
#
# This script expects that the caller has already validated that the
# file exists, is not a directory, and is readable.
#
# If passed no filename, or an empty one, then it emits config code
# suitable for the "config not found" case.
if test x = "x$1"; then
  TCL_INCLUDE_SPEC=
  TCL_LIB_SPEC=
  TCL_STUB_LIB_SPEC=
  TCL_EXEC_PREFIX=
  TCL_VERSION=
else
  . "$1"
fi

echo "define TCL_INCLUDE_SPEC {$TCL_INCLUDE_SPEC} ;"
echo "define TCL_LIB_SPEC {$TCL_LIB_SPEC} ;"
echo "define TCL_STUB_LIB_SPEC {$TCL_STUB_LIB_SPEC} ;"
echo "define TCL_EXEC_PREFIX {$TCL_EXEC_PREFIX} ;"
echo "define TCL_VERSION {$TCL_VERSION} ;"
Deleted tool/tclConfigShToTcl.sh.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29





























-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
#!/bin/sh
#
# A level of indirection for use soley by the configure script
# (auto.def).
#
# Expects to be passed a full path to a tclConfig.sh. It sources it
# and emits TCL code which sets some vars which are exported by
# tclConfig.sh.
#
# This script expects that the caller has already validated that the
# file exists, is not a directory, and is readable.
#
# If passed no filename, or an empty one, then it emits config code
# suitable for the "config not found" case.
if test x = "x$1"; then
  TCL_INCLUDE_SPEC=
  TCL_LIB_SPEC=
  TCL_STUB_LIB_SPEC=
  TCL_EXEC_PREFIX=
  TCL_VERSION=
else
  . "$1"
fi

echo "define TCL_INCLUDE_SPEC {$TCL_INCLUDE_SPEC} ;"
echo "define TCL_LIB_SPEC {$TCL_LIB_SPEC} ;"
echo "define TCL_STUB_LIB_SPEC {$TCL_STUB_LIB_SPEC} ;"
echo "define TCL_EXEC_PREFIX {$TCL_EXEC_PREFIX} ;"
echo "define TCL_VERSION {$TCL_VERSION} ;"